Parameters.h 15.7 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
// ============================================================================
// ==                                                                        ==
// == AMDiS - Adaptive multidimensional simulations                          ==
// ==                                                                        ==
// ============================================================================
// ==                                                                        ==
// ==  crystal growth group                                                  ==
// ==                                                                        ==
// ==  Stiftung caesar                                                       ==
// ==  Ludwig-Erhard-Allee 2                                                 ==
// ==  53175 Bonn                                                            ==
// ==  germany                                                               ==
// ==                                                                        ==
// ============================================================================
// ==                                                                        ==
// ==  http://www.caesar.de/cg/AMDiS                                         ==
// ==                                                                        ==
// ============================================================================

/** \file Parameters.h */

#ifndef AMDIS_PARAMETERS_H
#define AMDIS_PARAMETERS_H

#include <stdio.h>
#include <string>
#include <list>
#include <fstream>
#include "Global.h"
#include "Serializable.h"

namespace AMDiS {

  // ============================================================================
  // ===== class Parameters =====================================================
  // ============================================================================

  /** \ingroup Common
   * \brief
   * Many procedures need parameters, for example the maximal number of 
   * iterations for an iterative solver, the tolerance for the error in the 
   * adaptive procedure, etc. It is often very helpful to change the values of 
   * these parameters without recompiling the program by initializing them from 
   * a parameter file.
   * In order to avoid a fixed list of parameters, we use the following concept: 
   * Every parameter consists of two strings: a key string by which the parameter
   * is identified, and a second string containing the parameter values. These 
   * values are stored as ASCII-characters and can be converted to int, double, 
   * etc. according to a format specified by the user. Using this concept, 
   * parameters can be accessed at any point of the program.
   * Usually parameters are initialized from parameter files. Each line of the 
   * file describes either a single parameter: the key definition terminated by 
   * a ':' character followed by the parameter values, or specifies another 
   * parameter file to be included at that point (this can also be done 
   * recursively).
   */
  class Parameters : public Serializable
  {
  public:
    /** \brief
     * Initializes parameters from a file; filename is a string holding the name 
     * of the file and if values of the argument print and the global variable 
     * msg info are not zero, a list of all defined parameters is printed to the 
     * message stream; if init() can not open the input file, no parameter is 
     * defined.
     * One call of this function should be the first executable statement in the 
     * main program. Several calls of init() are possible. If a key is defined 
     * more than once, parameter values from the latest definition are valid. 
     * Parameter values from previous definition(s) are ignored.
     * If flags are set, the file is first processed by the C-preprocessor with 
     * argument flags, replacing macros by their definitions in the parameter 
     * file and including files specified by \#include"...".
     */
    static void init(int         print, 
75
		     std::string filename, 
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
		     const char *flags=NULL);

    /** \brief
     * Reads all arguments which are provided to the program. The init filenames
     * are ignored. The functions search for the following parameters:
     *
     * -rs filename: The program is restarted with the given serialization.
     *
     * All found parameters are added to the global parameter list with the prefix 
     * argv-> (e.g. argv->rs).
     */
    static void readArgv(int argc, char **argv);

    /** \brief
     * Initializes a parameter identified by key with values vpar; if the 
     * parameter already exists, the old values are replaced by the new one; 
     * if fname is not NULL it contains the name of the calling function.
     * file and line specifies source file and line number of the function
     * call. If one uses the macro \ref ADD_PARAMETER these last three arguments
     * are filled automatically.
     *
     * If p is non zero, the parameter list is printed.
     */
    static void addGlobalParameter(int                p,
100
101
				   const std::string  key,
				   const std::string  par, 
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
				   const char        *fname = NULL, 
				   const char        *file  = NULL, 
				   int                line  = 0);

    /** \brief
     * Looks for a parameter which matches the identifying key string key and 
     * converts the values of the corresponding string containing the parameter 
     * values according to the control string format. Pointers to variable(s) of 
     * suitable types are placed in the unnamed argument list (compare the syntax
     * of scanf()). The first argument flag defines the level of information 
     * during the initialization of parameters with a range of 0 to 4: no to full
     * information. The return value is the number of successfully matched and 
     * assigned input items.
     * If there is no parameter key matching key, getGlobalParameter() returns 
     * without an initialization. The return value is zero. It will also return 
     * without an initialization and return value zero if no parameter has been 
     * defined by init parameters().
     * In the case that a parameter matching the key is found, 
     * getGlobalParameter() acts like a simplified version of sscanf(). The input
     * string is the string containing the parameter values. The function reads 
     * characters from this string, interprets them according to a format, and 
     * stores the results in its arguments. It expects, as arguments, a control 
     * string, format (described below) and a set of pointer arguments indicating
     *  where the converted input should be stored. If there are insufficient 
     * arguments for the format, the behavior is undefined. If the format is 
     * exhausted while arguments remain, the excess arguments are simply ignored.
     * The return value is the number of converted arguments.
     *
     * The control string must only contain the following characters used as 
     * conversion specification: \%s, \%c, \%d, \%e, \%f, \%g, \%U, \%S, or \%*. 
     * All other characters are ignored. In contrast to scanf(), a numerical 
     * value for a field width is not allowed. For each element of the control 
     * string the next word of the parameter string is converted as follows:
     * 
     * -\%s: a character string is expected; the corresponding argument should 
     *       be a character pointer pointing to an array of characters large 
     *       enough to accept the string and a terminating `\0', which will be 
     *       added automatically; the string is one single word of the parameter 
     *       string; as mentioned above strings enclosed in single or double 
     *       quotes are not supported at the moment;
     *
     * -\%c: matches a single character; the corresponding argument should be a 
     *       pointer to a char variable; if the corresponding word of the 
     *       parameter string consists of more than one character, the rest of 
     *       the word is ignored; no space character is possible as argument;
     *
     * -\%d: matches an decimal integer, whose format is the same as expected for
     *       the subject sequence of the atoi() function; the corresponding 
     *       argument should be a pointer to an int variable;
     *
     * -\%e,%f,%g: matches an optionally signed floating point number, whose 
     *       format is the same as expected for the subject string of the atof()
     *       function; the corresponding argument should be a pointer to a double
     *       variable;
     *
     * -\%U: matches an unsigned decimal integer in the range [0,255], whose 
     *       format is the same as expected for the subject sequence of the 
     *       atoi() function; the corresponding argument should be a pointer to 
     *       an unsigned char variable;
     *
     * -\%S: matches an optionally signed decimal integer in the range 
     *       [-128,127], whose format is the same as expected for the subject 
     *       sequence of the atoi() function; the corresponding argument should 
     *       be a pointer to an signed char variable;
     *
     * -\%*: next word of parameter string should be skipped; there must not be
     *       a corresponding argument.
     *
     * getGlobalParameter() will always finish its work, successfully or not. 
     * It may fail if a misspelled key is handed over or there are not so many 
     * parameter values as format specifiers (the remaining variables are not 
     * initialized!). If flag is zero, getGlobalParameter() works silently; no 
     * error message is produced. Otherwise the key and the initialized values 
     * and error messages are printed. The second way to influence messages 
     * produced by get parameter() namely by is a parameter parameter information
     * specified in a parameter file.
     * \see GET_PARAMETER
     */
    static int getGlobalParameter(int                 flag,
181
				  const std::string&  key,
182
183
184
185
186
187
188
				  const char         *format, 
				  ...);  

    /** \brief
     * Like getGlobalParameter(flag, key, "%s", param->c_str()).
     */
    static int getGlobalParameter(int                 flag, 
189
190
				  const std::string&  key, 
				  std::string        *param);
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207

    /** \brief
     * Prints all defined parameters to the message stream
     */
    static void printParameters();

    /** \brief
     * Used by macro \ref GET_PARAMETER to generate infos about the calling
     * function.
     */
    static int initFuncName(const char *, 
			    const char *, 
			    int call_line);

    /** \brief
     * Returns specified info level
     */
208
209
210
    static int getMsgInfo() { 
      return (singlett) ? singlett->msgInfo : 0; 
    }
211
212
213
214

    /** \brief
     * Returns specified wait value
     */
215
216
217
    static int getMsgWait() { 
      return (singlett) ? singlett->msgWait : 0; 
    }
218
219
220
221
222
223
224

    /** \brief
     * Writes all up to now initialized parameters to file according to the 
     * parameter file format; if the value of info is different from zero, the 
     * location of the initialization is supplied for each parameter as a 
     * comment; no original comment is written, since these are not stored.
     */
225
    static void save(const std::string file, int info);
226
227
228
229

    /** \brief
     * Checks whether parameters are initialized. if not, call init()
     */
230
231
    static bool initialized() { 
      return (singlett != NULL); 
232
    }
233

234
235
    static Parameters *getSingleton() { 
      return singlett; 
236
237
238
    }

    static void clear();
239
240
241

    // ===== Serializable implementation =====

242
    void serialize(std::ostream &out) {
243
244
245
246
247
248
249
250
      out.write(reinterpret_cast<const char*>(&paramInfo), sizeof(int));
      out.write(reinterpret_cast<const char*>(&msgInfo), sizeof(int));
      out.write(reinterpret_cast<const char*>(&msgWait), sizeof(int));
      int i, size = static_cast<int>(allParam.size());
      out.write(reinterpret_cast<const char*>(&size), sizeof(int));
      for(i = 0; i < size; i++) {
	allParam[i].serialize(out);
      }
251
    }
252

253
    void deserialize(std::istream &in) {
254
255
256
257
258
259
260
261
262
      in.read(reinterpret_cast<char*>(&paramInfo), sizeof(int));
      in.read(reinterpret_cast<char*>(&msgInfo), sizeof(int));
      in.read(reinterpret_cast<char*>(&msgWait), sizeof(int));
      int i, size;
      in.read(reinterpret_cast<char*>(&size), sizeof(int));
      allParam.resize(size);
      for(i = 0; i < size; i++) {
	allParam[i].deserialize(in);
      }
263
    }
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280

  private:
    static Parameters * singlett;

    static const char *param_call_fct;

    static const char *param_call_file;

    static int param_call_line;


    /** \brief
     * Used internally.
     */
    class param : public Serializable
    {
    public:
281
      param() {}
282

283
      virtual ~param() {}
284

285
286
287
288
      param(const std::string& nkey,
	    const std::string& nparameters, 
	    const std::string& nfilename,
	    const std::string& nfuncName, 
289
290
291
292
293
294
	    int                line) 
	: key(nkey),
	  parameters(nparameters),
	  filename(nfilename),
	  funcName(nfuncName),
	  lineNo(line) 
295
      {}
296

297
298
299
      param(const std::string& k) 
        : key(k) 
      {}
300
301
302
303
304

      int operator==(const class param& aParam) const;

      int operator!=(const class param& aParam) const {
	return !(aParam==*this);
305
      }
306
307
308

      // ===== Serializable implementation =====

309
310
311
312
313
      void serialize(std::ostream &out) {
	out << key << std::endl;
	out << parameters << std::endl;
	out << filename << std::endl;
	out << funcName << std::endl;
314
	out.write(reinterpret_cast<const char*>(&lineNo), sizeof(int));
315
      }
316

317
      void deserialize(std::istream &in) {
318
319
320
321
322
	in >> key; in.get();
	in >> parameters; in.get();
	in >> filename; in.get();
	in >> funcName; in.get();
	in.read(reinterpret_cast<char*>(&lineNo), sizeof(int));
323
      }
324
325

    public:
326
327
328
329
      std::string key;
      std::string parameters;
      std::string filename;
      std::string funcName;
330
      int lineNo;
331
332
333
334
    };

    static const char comment;

335
    std::string buffer;
336

337
338
339
340
    inline bool isBlankChar(const char s) {
      return (s == ' ' || s == '\t' || s == '\f' || s == '\r'); 
    }

341
    const char *getNextWord(std::string *s) const;
342

343
    void read(const std::string& filename,const std::string& maxKey="");
344

345
    const std::string& getActFile(const std::string& filename);
346

347
    const std::string getKey(const std::string& s, 
348
			       int nLine, 
349
			       const std::string& filename);
350

351
352
    const std::string getPar(const std::string& key, 
			       const std::string& s, 
353
			       int *nl, 
354
			       const std::string& fn);
355

356
357
358
    void addParam(const std::string& key, 
		  const std::string& parameter,
		  const std::string& actfile, 
359
		  int  nLine, 
360
		  const std::string& fname);
361

362
363
364
365
    Parameters() 
      : paramInfo(1),
        msgInfo(1),
        msgWait(1)     
366
    {}
367

368
    virtual ~Parameters() {}
369
370
371

    static void initIntern();

372
    int binSearch(const std::string& key, int n_keys);
373
374
375
376
377
378

    void swap(int i, int j);

    void qsort(int left, int right);

  private:
379
380
381
    std::string cppFlags;
    std::ifstream inputFile;
    std::list< std::string> filenames;
382
    size_t maxFiles;
383
    std::string filename;
384
385
386
    int paramInfo;
    int msgInfo;
    int msgWait;
387
    std::vector<param> allParam;
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
 
  };


  /** \brief
   * Acts as add parameter(flag, key, value) but the function is additionally 
   * supplied with the name of the calling function, source file and line, which
   * results in more detailed messages during parameter definition.
   */
#define ADD_PARAMETER(p, key, param)					\
  Parameters::addGlobalParameter(p, key, param, funcName, __FILE__, __LINE__);

  /** \brief
   * Is a macro and acts in the same way as the function 
   * getGlobalParameter() but the function is additionally supplied with the 
   * name of the calling function, source file and line, which results in more 
   * detailed messages during parameter definition.
   */
#define GET_PARAMETER						\
  Parameters::initFuncName(funcName, __FILE__, __LINE__);	\
    Parameters::getGlobalParameter

}

#endif // AMDIS_PARAMETERS_H