Garfield++ v1r0
A toolkit for the detailed simulation of particle detectors based on ionisation measurement in gases and semiconductors
Loading...
Searching...
No Matches
prstream.h
Go to the documentation of this file.
1#ifndef PRSTREAM_H
2#define PRSTREAM_H
3/*
4This is the main file which determines the output matters:
5default streams and indentation.
6
7There are two default strems in C++: cout and cerr.
8In the program we often need to use stream for regular output and
9the same or another stream for emergency or exstraordinary cases,
10exceptions, error, etc. These logical streams can be realized not only to
11default tty, but to files. Perhaps there are many ways to control this,
12but the simplest one is the use symbolic stream
13notations mcout amnd mcerr (my cout and my cerr) thorought all the program,
14and to bound them with real streams through trivial macro-driven replacements,
15as done below.
16
17The practice shows that whatever advanced debugger and proficient skills
18the programmer has in his computer, sooner or later
19he will encode the print of all members of each significant
20not trivial class of his program in readable and understandable form.
21At least it is so in numerical calculations.
22Each such printing is usually controlled by a key determining
23the level of details. At large level the user expects to see
24the output of all structured components of the current object.
25Then the initial call of object->print(stream, key)
26triggers similar calls of print of components, usually with less
27key of details, component->print(stream, key-1).
28It is very important to allow the reader of such listing
29to distinguish visually the output from main object,
30from components of the main object, components of components, etc.
31Also it is useful to emphasis the name of classes,
32the printing of sequences of similar elements
33such as elements of arrays performed in loops. The user may want
34to stress any other structures appearing in his classes.
35This is possible by inclusion of indentation with which
36the objects are printed. There should be some number of blanks
37established which should be printed prior to content of
38any line printed from any object. Any object should be allowed to
39add additional blanks and required to remove the additions at the
40end of its output.
41
42It appered that it is not trivial to arrange such system that makes this
43and is completely safe from any misuse. Despite of all the power of C++
44it appears to be not possible without significant intrusion in internal
45functioning of streams. There was some discussion in a news-group which
46does not point to any appropriate solution. Therefore here this is done
47by means which could be crititized in some respects by the lovers of
48object-oriented approach, but it has the pronounced advantages that
49it is compartible with any streams, it is convenuent enough for practice,
50it really works, and it really exists.
51
52There is a class indentation and the global object of this
53class called shortly "indn". This object keeps the current number of blanks
54needed to insert in output listing before each line.
55This object is not tied to certain stream. Therefore this current
56number will be valid for any stream.
57
58The indentation is invoked if you print
59 Imcout<<something // indentation is invoked
60instead of
61 mcout<<something // indentation is not invoked
62Also you can use Ifile instead of file.
63Also indentation in 2 sequencial lines will be made by
64 Imcout<<something_in_1_line<<'\n'<<indn<<something_in_next_line<<'\n';
65To change the number of blanks you put
66 indn.n+=2; // or 1, or 4, or what you want.
67And don't forget to restore the previous value by
68 indn.n-=2;
69If you output the composite class with redefined operator<<
70and this latter operator uses indentation, particularly it
71starts from Ifile<<...,
72and you want this class continues the line, for example:
73 Ifile<<"name_of_object="<<object;
74then you probably don't want to see additional blanks between
75"name_of_object=" and the first line of the object itself.
76Then you want to prohibit the indentation when printing the first line of
77the object. To provide this you can print:
78 Ifile<<"name_of_object="<<noindent<<object;
79The directive "noindent" turns off the request for indentation
80immidiately after it, but switched off later. Thus indentation will be
81automatically turned on after when the first file<<indn is met and skipped.
82The rest of the object will be printed with correct indentation despite of
83"noindent" statement.
84
85In addition, at the bottom of this file a few useful Iprint-like macro are
86defined. The idea is to print not only variable, but start from its name
87and "=". Thus instead of
88 Imcout << "my_favorite_variable=" << my_favorite_variable << '\n';
89you will need to say:
90 Iprintn( mcout, my_favorite_variable);
91Note, that's two times shorter.
92 Iprint - just print a variable without saying << '\n' at the end.
93 Iprintn - print a variable and pass to next line.
94 Iprint_l(file , name , l ) - call a function name.print(file, l),
95Here l is meant a key determining the print level.
96 Iprint_al(file , name , l ) - the same, but the name is not the object but
97pointer to it (address).
98
99
100Copyright (c) 2001 I. B. Smirnov
101
102Permission to use, copy, modify, distribute and sell this file
103and its documentation for any purpose is hereby granted without fee,
104provided that the above copyright notice, this permission notice,
105and notices about any modifications of the original text
106appear in all copies and in supporting documentation.
107It is provided "as is" without express or implied warranty.
108*/
109
110#include <iostream> // to define cout and cerr
111 // using std::ostream;
112 // using std::cout;
113
114#define USE_DEFAULT_STREAMS
115// otherwise everything will be flushed to a file
116// If the macro OPEN_LOGFILE_EXPLICITLY (see below) is NOT defined,
117// the file name is fixed as "prstream_log.out" (see below).
118// Othewise the file can be opened with any name by lines like those:
119// HelperForMcout::get_ofstream().clear();
120// HelperForMcout::get_ofstream().open("logfile.out");
121// if(!HelperForMcout::get_ofstream())
122// {
123// cout<<"cannot open file\n";
124// }
125//
126// If user wants this file to contain all the protocol from the full program,
127// this file prstream.h should be included in the main program
128// (which is ordinary practice).
129
130#ifdef USE_DEFAULT_STREAMS
131
132//#ifndef mcout
133#define mcout std::cout /* change to ordinary default C++ stream */
134 //#endif
135#define mcerr std::cerr
136//#define mcerr cerr
137
138#else
139
140#define OPEN_LOGFILE_EXPLICITLY
141
142#include <fstream>
143
144class HelperForMcout // and also for mcerr. Used for switching them to file
145 {
146 public:
147 static long count; // will be common for all modules
148
149 static std::ofstream& get_ofstream(void) {
150 static std::ofstream prstream_output_file;
151 return prstream_output_file;
152 }
153
154 HelperForMcout(void) {
155#ifndef OPEN_LOGFILE_EXPLICITLY
156 if (count++ == 0) {
157 get_ofstream().open("prstream_log.out");
158 }
159#else
160 count++;
161#endif
162 }
163 ~HelperForMcout(void) {
164 if (--count == 0) {
165 get_ofstream().flush();
166 get_ofstream().close();
167 }
168 }
169};
170
171namespace {
172HelperForMcout __helper_for_mcout;
173} // thanks to
174 // unnamed namespace the object __helper_for_mcout will be different for
175 // all modules, but the counter will be nevertheless common.
176
177#define mcout HelperForMcout::get_ofstream()
178#define mcerr HelperForMcout::get_ofstream()
179
180#endif
181
182#define eeee '\n';
183#define scout(a) #a << " = " << a
184
186 public:
187 int n; // current number of blanks to print
188 int s_not;
189 indentation(void) { n = 0; }
190};
191
192extern indentation indn;
193
194inline std::ostream& operator<<(std::ostream& file, indentation& ind) {
195 int n;
196 if (ind.s_not == 1)
197 ind.s_not = 0;
198 else
199 for (n = 0; n < ind.n; n++)
200 file << ' ';
201 return file;
202}
203
204std::ostream& noindent(std::ostream& f);
205std::ostream& yesindent(std::ostream& f);
206
207#define Ifile file << indn
208#define Imcout mcout << indn
209#define Iprint(file, name) \
210 file << indn << #name << "=" << noindent << name << yesindent;
211#define Iprintf(file, name) \
212 { \
213 file << indn << #name << "=" << noindent << name << yesindent; \
214 file.flush(); \
215 }
216#define Iprintn(file, name) \
217 file << indn << #name << "=" << noindent << name << '\n' << yesindent;
218#define Iprintnf(file, name) \
219 { \
220 file << indn << #name << "=" << noindent << name << '\n' << yesindent; \
221 file.flush(); \
222 }
223#define Iprintan(file, name, addition) \
224 file << indn << #name << "=" << noindent << name << ' ' << addition << '\n' \
225 << yesindent;
226// addition is convenient as notation of units
227#define Iprintanf(file, name, addition) \
228 { \
229 file << indn << #name << "=" << noindent << name << ' ' << addition \
230 << '\n' << yesindent; \
231 file.flush(); \
232 }
233#define Iprint2(file, name1, name2) \
234 file << indn << #name1 << "=" << noindent << name1 << ", " << #name2 << "=" \
235 << noindent << name2 << yesindent;
236#define Iprint2n(file, name1, name2) \
237 file << indn << #name1 << "=" << noindent << name1 << ", " << #name2 << "=" \
238 << noindent << name2 << '\n' << yesindent;
239#define Iprint2nf(file, name1, name2) \
240 { \
241 file << indn << #name1 << "=" << noindent << name1 << ", " << #name2 \
242 << "=" << noindent << name2 << '\n' << yesindent; \
243 file.flush(); \
244 }
245#define Iprint3(file, name1, name2, name3) \
246 file << indn << #name1 << "=" << noindent << name1 << ", " << #name2 << "=" \
247 << noindent << name2 << ", " << #name3 << "=" << noindent << name3 \
248 << yesindent;
249#define Iprint3n(file, name1, name2, name3) \
250 file << indn << #name1 << "=" << noindent << name1 << ", " << #name2 << "=" \
251 << noindent << name2 << ", " << #name3 << "=" << noindent << name3 \
252 << '\n' << yesindent;
253#define Iprint3nf(file, name1, name2, name3) \
254 { \
255 file << indn << #name1 << "=" << noindent << name1 << ", " << #name2 \
256 << "=" << noindent << name2 << ", " << #name3 << "=" << noindent \
257 << name3 << '\n' << yesindent; \
258 file.flush(); \
259 }
260#define Iprint4n(file, name1, name2, name3, name4) \
261 file << indn << #name1 << "=" << noindent << name1 << ", " << #name2 << "=" \
262 << noindent << name2 << ", " << #name3 << "=" << noindent << name3 \
263 << ", " << #name4 << "=" << noindent << name4 << '\n' << yesindent;
264#define Iprint4nf(file, name1, name2, name3, name4) \
265 { \
266 file << indn << #name1 << "=" << noindent << name1 << ", " << #name2 \
267 << "=" << noindent << name2 << ", " << #name3 << "=" << noindent \
268 << name3 << ", " << #name4 << "=" << noindent << name4 << '\n' \
269 << yesindent; \
270 file.flush(); \
271 }
272#define Iprint5n(file, name1, name2, name3, name4, name5) \
273 file << indn << #name1 << "=" << noindent << name1 << ", " << #name2 << "=" \
274 << noindent << name2 << ", " << #name3 << "=" << noindent << name3 \
275 << ", " << #name4 << "=" << noindent << name4 << ", " << #name5 << "=" \
276 << noindent << name5 << '\n' << yesindent;
277
278#define Iprint_l(file, name, l) \
279 { \
280 file << indn << #name << "=" << noindent; \
281 name.print(file, l); \
282 file << yesindent; \
283 }
284#define Iprint_al(file, name, l) \
285 { \
286 file << indn << #name << "=" << noindent; \
287 name->print(file, l); \
288 file << yesindent; \
289 }
290
291#define Iprint_p(file, name) \
292 { \
293 file << indn << #name << "=" << noindent; \
294 name.print(file); \
295 file << yesindent; \
296 }
297#define Iprint_ap(file, name) \
298 { \
299 file << indn << #name << "=" << noindent; \
300 name->print(file); \
301 file << yesindent; \
302 }
303
304extern int s_short_output; // sign which allows to make output shorter
305// simultaneously for all classes. Useful for writting "persistence classes"
306// by standard <</>> operators.
307// If instead of this one tries to use special functions like
308// class_name::short_write,
309// he finds an obstacle that such functions are abcent for inbuilt types.
310
311#endif
indentation(void)
Definition: prstream.h:189
std::ostream & operator<<(std::ostream &file, indentation &ind)
Definition: prstream.h:194
indentation indn
Definition: prstream.cpp:13
std::ostream & yesindent(std::ostream &f)
Definition: prstream.cpp:19
std::ostream & noindent(std::ostream &f)
Definition: prstream.cpp:15
int s_short_output
Definition: prstream.cpp:23