HermesCommon  2.0
mixins.cpp
1 // This file is part of HermesCommon
2 //
3 // Hermes is free software; you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation; either version 2 of the License, or
6 // (at your option) any later version.
7 //
8 // Hermes is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with Hermes; if not, see <http://www.gnu.prg/licenses/>.
15 #include "mixins.h"
16 #include <map>
17 #include <string>
18 #include "common.h"
19 
20 namespace Hermes
21 {
22  namespace Mixins
23  {
24  Loggable::LoggerMonitor Loggable::logger_monitor;
25 
26  std::map<std::string, bool> Loggable::logger_written;
27 
28  Loggable::Loggable(bool verbose_output, callbackFn verbose_callback) : verbose_output(verbose_output), verbose_callback(verbose_callback)
29  {
30  }
31 
32  bool Loggable::get_verbose_output() const
33  {
34  return this->verbose_output;
35  }
36 
37  Loggable::callbackFn Loggable::get_verbose_callback() const
38  {
39  return this->verbose_callback;
40  }
41 
42  void Loggable::Static::info(const char* msg, ...)
43  {
44  char text[BUF_SZ];
45  char* text_contents = text + 1;
46 
47  text[0] = HERMES_EC_INFO;
48  text[1] = ' ';
49  text_contents++;
50 
51  //print the message
52  va_list arglist;
53  va_start(arglist, msg);
54  vsprintf(text_contents, msg, arglist);
55  va_end(arglist);
56 
57  //Windows platform
58  #ifdef WIN32
59  HANDLE h_console = GetStdHandle(STD_OUTPUT_HANDLE);
60 
61  //generate console settings
62  WORD console_attr_red = FOREGROUND_RED, console_attr_green = FOREGROUND_GREEN, console_attr_blue = FOREGROUND_BLUE;
63 
64  WORD console_attrs = 0;
65  console_attrs |= console_attr_green;
66 
67  //set new console settings
68  SetConsoleTextAttribute(h_console, console_attrs);
69 
70  //write text
71  DWORD num_written;
72  BOOL write_success = WriteConsoleA(h_console, text_contents, strlen(text_contents), &num_written, NULL);
73  std::cout << std::endl;
74 
75  //Linux platform
76  #else
77  # define FOREGROUND_RED 1
78  # define FOREGROUND_GREEN 2
79  # define FOREGROUND_BLUE 4
80  //console color code
81  int console_attrs = 0;
82  bool console_bold = true;
83 
84  printf("\033[%dm", console_attrs + 30);
85 
86  //emphasize and console bold
87  if(console_bold)
88  printf("\033[1m");
89 
90  //print text and reset settings
91  printf("%s\033[0m\n", text_contents);
92 
93  #endif
94  }
95 
96  void Loggable::Static::warn(const char* msg, ...)
97  {
98  char text[BUF_SZ];
99  char* text_contents = text + 1;
100 
101  text[0] = HERMES_EC_WARNING;
102  text[1] = ' ';
103  text_contents++;
104 
105  //print the message
106  va_list arglist;
107  va_start(arglist, msg);
108  vsprintf(text_contents, msg, arglist);
109  va_end(arglist);
110 
111  //Windows platform
112  #ifdef WIN32
113  HANDLE h_console = GetStdHandle(STD_OUTPUT_HANDLE);
114 
115  //generate console settings
116  WORD console_attr_red = FOREGROUND_RED, console_attr_green = FOREGROUND_GREEN, console_attr_blue = FOREGROUND_BLUE;
117 
118  WORD console_attrs = 0;
119  console_attrs |= console_attr_red | console_attr_green;
120 
121  //set new console settings
122  SetConsoleTextAttribute(h_console, console_attrs);
123 
124  //write text
125  DWORD num_written;
126  BOOL write_success = WriteConsoleA(h_console, text_contents, strlen(text_contents), &num_written, NULL);
127  std::cout << std::endl;
128  //Linux platform
129  #else
130  # define FOREGROUND_RED 1
131  # define FOREGROUND_GREEN 2
132  # define FOREGROUND_BLUE 4
133  //console color code
134  int console_attrs = 1;
135  console_attrs |= FOREGROUND_RED | FOREGROUND_GREEN;
136  bool console_bold = false;
137 
138  printf("\033[%dm", console_attrs + 30);
139 
140  //emphasize and console bold
141  if(console_bold)
142  printf("\033[1m");
143 
144  //print text and reset settings
145  printf("%s\033[0m\n", text_contents);
146 
147  #endif
148  }
149 
150  void Loggable::Static::error(const char* msg, ...)
151  {
152  char text[BUF_SZ];
153  char* text_contents = text + 1;
154 
155  text[0] = HERMES_EC_ERROR;
156  text[1] = ' ';
157  text_contents++;
158 
159  //print the message
160  va_list arglist;
161  va_start(arglist, msg);
162  vsprintf(text_contents, msg, arglist);
163  va_end(arglist);
164 
165  //Windows platform
166  #ifdef WIN32
167  HANDLE h_console = GetStdHandle(STD_OUTPUT_HANDLE);
168 
169  //generate console settings
170  WORD console_attr_red = FOREGROUND_RED, console_attr_green = FOREGROUND_GREEN, console_attr_blue = FOREGROUND_BLUE;
171 
172  WORD console_attrs = 0;
173  console_attrs |= console_attr_red;
174 
175  //set new console settings
176  SetConsoleTextAttribute(h_console, console_attrs);
177 
178  //write text
179  DWORD num_written;
180  BOOL write_success = WriteConsoleA(h_console, text_contents, strlen(text_contents), &num_written, NULL);
181  std::cout << std::endl;
182  //Linux platform
183  #else
184  # define FOREGROUND_RED 1
185  # define FOREGROUND_GREEN 2
186  # define FOREGROUND_BLUE 4
187  //console color code
188  int console_attrs = 1;
189  console_attrs |= FOREGROUND_RED;
190  bool console_bold = false;
191 
192  printf("\033[%dm", console_attrs + 30);
193 
194  //emphasize and console bold
195  if(console_bold)
196  printf("\033[1m");
197 
198  //print text and reset settings
199  printf("%s\033[0m\n", text_contents);
200 
201  #endif
202  }
203 
204  void Loggable::error(const char* msg, ...) const
205  {
206  if(!this->verbose_output)
207  return;
208 
209  char text[BUF_SZ];
210  char* text_contents = text + 1;
211 
212  text[0] = HERMES_EC_ERROR;
213  text[1] = ' ';
214  text_contents++;
215 
216  //print the message
217  va_list arglist;
218  va_start(arglist, msg);
219  vsprintf(text_contents, msg, arglist);
220  va_end(arglist);
221  hermes_log_message(HERMES_EC_ERROR, text_contents);
222  }
223 
224  void Loggable::error_if(bool cond, const char* msg, ...) const
225  {
226  if(!this->verbose_output)
227  return;
228 
229  if(cond)
230  {
231  char text[BUF_SZ];
232  char* text_contents = text + 1;
233 
234  text[0] = HERMES_EC_ERROR;
235  text[1] = ' ';
236  text_contents++;
237 
238  //print the message
239  va_list arglist;
240  va_start(arglist, msg);
241  vsprintf(text_contents, msg, arglist);
242  va_end(arglist);
243  hermes_log_message(HERMES_EC_ERROR, text_contents);
244  }
245  }
246 
247  void Loggable::warn(const char* msg, ...) const
248  {
249  if(!this->verbose_output)
250  return;
251 
252  char text[BUF_SZ];
253  char* text_contents = text + 1;
254 
255  text[0] = HERMES_EC_WARNING;
256  text[1] = ' ';
257  text_contents++;
258 
259  //print the message
260  va_list arglist;
261  va_start(arglist, msg);
262  vsprintf(text_contents, msg, arglist);
263  va_end(arglist);
264  hermes_log_message(HERMES_EC_WARNING, text_contents);
265  }
266 
267  void Loggable::warn_if(bool cond, const char* msg, ...) const
268  {
269  if(!this->verbose_output)
270  return;
271 
272  if(cond)
273  {
274  char text[BUF_SZ];
275  char* text_contents = text + 1;
276 
277  text[0] = HERMES_EC_WARNING;
278  text[1] = ' ';
279  text_contents++;
280 
281  //print the message
282  va_list arglist;
283  va_start(arglist, msg);
284  vsprintf(text_contents, msg, arglist);
285  va_end(arglist);
286  hermes_log_message(HERMES_EC_WARNING, text_contents);
287  }
288  }
289  void Loggable::info(const char* msg, ...) const
290  {
291  if(!this->verbose_output)
292  return;
293 
294  char text[BUF_SZ];
295  char* text_contents = text + 1;
296 
297  text[0] = HERMES_EC_INFO;
298  text[1] = ' ';
299  text_contents++;
300 
301  //print the message
302  va_list arglist;
303  va_start(arglist, msg);
304  vsprintf(text_contents, msg, arglist);
305  va_end(arglist);
306  hermes_log_message(HERMES_EC_INFO, text_contents);
307  }
308  void Loggable::info_if(bool cond, const char* msg, ...) const
309  {
310  if(!this->verbose_output)
311  return;
312 
313  if(cond)
314  {
315  char text[BUF_SZ];
316  char* text_contents = text + 1;
317 
318  text[0] = HERMES_EC_INFO;
319  text[1] = ' ';
320  text_contents++;
321 
322  //print the message
323  va_list arglist;
324  va_start(arglist, msg);
325  vsprintf(text_contents, msg, arglist);
326  va_end(arglist);
327  hermes_log_message(HERMES_EC_INFO, text_contents);
328  }
329  }
330 
331  bool Loggable::write_console(const char code, const char* text) const
332  {
333  //Windows platform
334  #ifdef WIN32
335  HANDLE h_console = GetStdHandle(STD_OUTPUT_HANDLE);
336  if(h_console == INVALID_HANDLE_VALUE)
337  return false;
338 
339  //read current console settings
340  CONSOLE_SCREEN_BUFFER_INFO console_info;
341  if(!GetConsoleScreenBufferInfo(h_console, &console_info))
342  return false;
343 
344  //generate console settings
345  WORD console_attr_red = FOREGROUND_RED, console_attr_green = FOREGROUND_GREEN, console_attr_blue = FOREGROUND_BLUE;
346 
347  WORD console_attrs = 0;
348  switch(code)
349  {
350  case HERMES_EC_ERROR: console_attrs |= console_attr_red; break;
351  case HERMES_EC_WARNING: console_attrs |= console_attr_red | console_attr_green; break;
352  case HERMES_EC_INFO:console_attrs |= console_attr_green; break;
353  default: throw Hermes::Exceptions::Exception("Unknown error code: '%c'", code);
354  }
355 
356  //set new console settings
357  SetConsoleTextAttribute(h_console, console_attrs);
358 
359  //write text
360  DWORD num_written;
361  BOOL write_success = WriteConsoleA(h_console, text, strlen(text), &num_written, NULL);
362 
363  //return previous settings
364  SetConsoleTextAttribute(h_console, console_info.wAttributes);
365 
366  if(write_success)
367  return true;
368  else
369  return false;
370  //Linux platform
371  #else
372  # define FOREGROUND_RED 1
373  # define FOREGROUND_GREEN 2
374  # define FOREGROUND_BLUE 4
375  //console color code
376  int console_attrs = 0;
377  bool console_bold = false;
378  switch(code)
379  {
380  case HERMES_EC_WARNING: console_attrs |= FOREGROUND_RED | FOREGROUND_GREEN; break;
381  case HERMES_EC_INFO: console_bold = true; break;
382  default: throw Hermes::Exceptions::Exception("Unknown error code: '%c'", code);
383  }
384 
385  printf("\033[%dm", console_attrs + 30);
386 
387  //emphasize and console bold
388  if(console_bold)
389  printf("\033[1m");
390 
391  //print text and reset settings
392  printf("%s\033[0m", text);
393 
394  return true;
395  #endif
396  }
397 
398  Loggable::HermesLogEventInfo* Loggable::hermes_build_log_info(char event) const
399  {
400  return new Loggable::HermesLogEventInfo(event, HERMES_LOG_FILE, __CURRENT_FUNCTION, __FILE__, __LINE__);
401  }
402 
403  void Loggable::hermes_fwrite(const void* ptr, size_t size, size_t nitems, FILE* stream) const
404  {
405  if(fwrite(ptr, size, nitems, stream) != nitems || ferror(stream))
406  throw Hermes::Exceptions::Exception("Error writing to file: %s", strerror(ferror(stream)));
407  }
408 
409  void Loggable::hermes_fread(void* ptr, size_t size, size_t nitems, FILE* stream) const
410  {
411  size_t ret = fread(ptr, size, nitems, stream);
412  if(ret < nitems)
413  throw Hermes::Exceptions::Exception("Premature end of file.");
414  else if(ferror(stream))
415  throw Hermes::Exceptions::Exception("Error reading file: %s", strerror(ferror(stream)));
416  }
417 
418  Loggable::HermesLogEventInfo::HermesLogEventInfo(const char code, const char* log_file, const char* src_function, const char* src_file, const int src_line)
419  : code(code), log_file(log_file), src_function(src_function), src_file(src_file), src_line(src_line)
420  {}
421 
422  void Loggable::hermes_log_message(const char code, const char* msg) const
423  {
424  logger_monitor.enter();
425 
426  //print the message
427  if(!write_console(code, msg))
428  printf("%s", msg); //safe fallback
429  printf("\n"); //write a new line
430 
431  HermesLogEventInfo* info = this->hermes_build_log_info(code);
432 
433  //print to file
434  if(info->log_file != NULL)
435  {
436  FILE* file = fopen(info->log_file, "at");
437  if(file != NULL)
438  {
439  //check whether log file was already written
440  std::map<std::string, bool>::const_iterator found = logger_written.find(info->log_file);
441  if(found == logger_written.end()) { //first write, write delimited to a file
442  logger_written[info->log_file] = true;
443  fprintf(file, "\n");
444  for(int i = 0; i < HERMES_LOG_FILE_DELIM_SIZE; i++)
445  fprintf(file, "-");
446  fprintf(file, "\n\n");
447  }
448 
449  //build a long version of location
450  std::ostringstream location;
451  location << '(';
452  if(info->src_function != NULL)
453  {
454  location << info->src_function;
455  if(info->src_file != NULL)
456  location << '@';
457  }
458  if(info->src_file != NULL)
459  location << info->src_file << ':' << info->src_line;
460  location << ')';
461 
462  //get time
463  time_t now;
464  time(&now);
465  struct tm* now_tm = gmtime(&now);
466  char time_buf[BUF_SZ];
467  strftime(time_buf, BUF_SZ, "%y%m%d-%H:%M", now_tm);
468 
469  //write
470  fprintf(file, "%s\t%s %s\n", time_buf, msg, location.str().c_str());
471  fclose(file);
472 
473  if(this->verbose_callback != NULL)
474  this->verbose_callback(msg);
475  }
476  }
477 
478  delete info;
479 
480  logger_monitor.leave();
481  }
482 
484  {
485  this->verbose_output = to_set;
486  }
487 
488  void Loggable::set_verbose_callback(callbackFn callback)
489  {
490  this->verbose_callback = callback;
491  }
492 
493  TimeMeasurable::TimeMeasurable(const char *name) : period_name(name == NULL ? "unnamed" : name)
494  {
495  //initialization
496  #ifdef WIN32 //Windows
497  LARGE_INTEGER freq;
498  if(QueryPerformanceFrequency(&freq))
499  frequency = (double)freq.QuadPart;
500  else
501  frequency = -1;
502  #endif //Linux
503  tick_reset();
504  }
505 
506  TimeMeasurable::SysTime TimeMeasurable::get_time() const
507  {
508  #ifdef WIN32 //Windows
509  if(frequency > 0)
510  {
511  LARGE_INTEGER ticks;
512  QueryPerformanceCounter(&ticks);
513  return ticks.QuadPart;
514  }
515  else
516  {
517  return clock();
518  }
519  #elif defined(__APPLE__) //Mac
520  // FIXME: implement time measurement on Mac
521  timespec tm;
522  return tm;
523  #else //Linux
524  timespec tm;
525  clock_gettime(CLOCK_REALTIME, &tm);
526  return tm;
527  #endif
528  }
529 
530  double TimeMeasurable::period_in_seconds(const SysTime& begin, const SysTime& end) const
531  {
532  #ifdef WIN32 //Windows
533  uint64_t period = end - begin;
534  if(frequency > 0)
535  return period / frequency;
536  else
537  return period / (double)CLOCKS_PER_SEC;
538  #else //Linux
539  int sec_corr = 0;
540  long period_nsec = end.tv_nsec - begin.tv_nsec;
541  if(period_nsec < 0)
542  {
543  sec_corr += -1;
544  period_nsec += 1000000000UL;
545  }
546  long period_sec = (long)(end.tv_sec - begin.tv_sec) + sec_corr;
547  return period_sec + (period_nsec / 1E9);
548  #endif
549  }
550 
552  {
553  SysTime cur_time = get_time();
554  if(type == HERMES_ACCUMULATE)
555  {
556  double secs = period_in_seconds(last_time, cur_time);
557  accum += secs;
558  last_period = secs;
559  }
560  else
561  last_period = 0.0;
562 
563  last_time = cur_time;
564  return *this;
565  }
566 
567  const std::string& TimeMeasurable::name() const
568  {
569  return period_name;
570  }
571 
573  {
574  return accum;
575  }
576 
577  std::string TimeMeasurable::accumulated_str() const {
578  return to_string(accum);
579  }
580 
581  double TimeMeasurable::last() const
582  {
583  return last_period;
584  }
585 
586  std::string TimeMeasurable::last_str() const
587  {
588  return to_string(last_period);
589  }
590 
592  {
593  tick(HERMES_SKIP);
594  reset();
595  return *this;
596  }
597 
599  {
600  accum = 0;
601  last_time = get_time();
602  last_period = 0.0;
603  return *this;
604  }
605 
606  std::string TimeMeasurable::to_string(double secs) const
607  {
608  if(secs < 0)
609  return "NO TIME";
610  else
611  {
612  int hours = (int) secs / (3600);
613  int mins = (int) fmod(secs, 3600) / 60;
614  secs = fmod(secs, 60);
615 
616  std::stringstream str;
617  if(hours > 0)
618  str << hours << "h ";
619  if(hours > 0 || mins > 0)
620  str << mins << "m ";
621  str << secs << "s";
622 
623  return str.str();
624  }
625  }
626 
627  IntegrableWithGlobalOrder::IntegrableWithGlobalOrder() : global_integration_order_set(false), global_integration_order(0)
628  {}
629 
630  void IntegrableWithGlobalOrder::set_global_integration_order(unsigned int order)
631  {
632  this->global_integration_order = order;
633  this->global_integration_order_set = true;
634  }
635 
636  SettableComputationTime::SettableComputationTime() : time(0.0), time_step(0.0)
637  {
638  }
639 
641  {
642  this->time = time;
643  }
644 
645  void SettableComputationTime::set_time_step(double time_step)
646  {
647  this->time_step = time_step;
648  }
649 
650  OutputAttachable::OutputAttachable()
651  {
652  }
653 
654  void OutputAttachable::on_initialization()
655  {
656 
657  }
658 
659  void OutputAttachable::on_step_begin()
660  {
661 
662  }
663 
664  void OutputAttachable::on_step_end()
665  {
666 
667  }
668 
669  void OutputAttachable::on_finish()
670  {
671 
672  }
673  }
674 }