Garfield++ 4.0
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 streams 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) throughout 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 can use the shorter
90 Iprintn(mcout, my_favorite_variable);
91
92 Iprint - just print a variable without saying << '\n' at the end.
93 Iprintn - print a variable and pass to next line.
94
95Copyright (c) 2001 I. B. Smirnov
96
97Permission to use, copy, modify, distribute and sell this file
98and its documentation for any purpose is hereby granted without fee,
99provided that the above copyright notice, this permission notice,
100and notices about any modifications of the original text
101appear in all copies and in supporting documentation.
102It is provided "as is" without express or implied warranty.
103*/
104
105#include <iostream>
106
107#define USE_DEFAULT_STREAMS
108// otherwise everything will be flushed to a file
109// If the macro OPEN_LOGFILE_EXPLICITLY (see below) is NOT defined,
110// the file name is fixed as "prstream_log.out" (see below).
111// Otherwise the file can be opened with any name by lines like those:
112// HelperForMcout::get_ofstream().clear();
113// HelperForMcout::get_ofstream().open("logfile.out");
114// if(!HelperForMcout::get_ofstream())
115// {
116// cout<<"cannot open file\n";
117// }
118//
119// If user wants this file to contain all the protocol from the full program,
120// this file prstream.h should be included in the main program
121// (which is ordinary practice).
122
123#ifdef USE_DEFAULT_STREAMS
124
125//#ifndef mcout
126#define mcout std::cout /* change to ordinary default C++ stream */
127//#endif
128#define mcerr std::cerr
129
130#else
131
132#define OPEN_LOGFILE_EXPLICITLY
133
134#include <fstream>
135
136class HelperForMcout {
137 // and also for mcerr. Used for switching them to file
138 public:
139 static long count; // will be common for all modules
140
141 static std::ofstream& get_ofstream(void) {
142 static std::ofstream prstream_output_file;
143 return prstream_output_file;
144 }
145
146 HelperForMcout(void) {
147#ifndef OPEN_LOGFILE_EXPLICITLY
148 if (count++ == 0) {
149 get_ofstream().open("prstream_log.out");
150 }
151#else
152 count++;
153#endif
154 }
155 ~HelperForMcout(void) {
156 if (--count == 0) {
157 get_ofstream().flush();
158 get_ofstream().close();
159 }
160 }
161};
162
163namespace {
164HelperForMcout __helper_for_mcout;
165} // thanks to
166 // unnamed namespace the object __helper_for_mcout will be different for
167 // all modules, but the counter will be nevertheless common.
168
169#define mcout HelperForMcout::get_ofstream()
170#define mcerr HelperForMcout::get_ofstream()
171
172#endif
173
174namespace Heed {
175
177 public:
178 int n = 0; // current number of blanks to print
179 int s_not = 1;
180};
181
182extern indentation indn;
183
184inline std::ostream& operator<<(std::ostream& file, indentation& ind) {
185 if (ind.s_not == 1)
186 ind.s_not = 0;
187 else
188 for (int n = 0; n < ind.n; n++) file << ' ';
189 return file;
190}
191
192std::ostream& noindent(std::ostream& f);
193std::ostream& yesindent(std::ostream& f);
194
195#define Ifile file << indn
196#define Imcout mcout << indn
197#define Iprint(file, name) \
198 file << indn << #name << "=" << noindent << name << yesindent;
199#define Iprintf(file, name) \
200 { \
201 file << indn << #name << "=" << noindent << name << yesindent; \
202 file.flush(); \
203 }
204#define Iprintn(file, name) \
205 file << indn << #name << "=" << noindent << name << '\n' << yesindent;
206#define Iprintnf(file, name) \
207 { \
208 file << indn << #name << "=" << noindent << name << '\n' << yesindent; \
209 file.flush(); \
210 }
211#define Iprintan(file, name, addition) \
212 file << indn << #name << "=" << noindent << name << ' ' << addition << '\n' \
213 << yesindent;
214// addition is convenient as notation of units
215
216#define Iprint2(file, name1, name2) \
217 file << indn << #name1 << "=" << noindent << name1 << ", " << #name2 << "=" \
218 << noindent << name2 << yesindent;
219#define Iprint2n(file, name1, name2) \
220 file << indn << #name1 << "=" << noindent << name1 << ", " << #name2 << "=" \
221 << noindent << name2 << '\n' << yesindent;
222#define Iprint2nf(file, name1, name2) \
223 { \
224 file << indn << #name1 << "=" << noindent << name1 << ", " << #name2 \
225 << "=" << noindent << name2 << '\n' << yesindent; \
226 file.flush(); \
227 }
228#define Iprint3(file, name1, name2, name3) \
229 file << indn << #name1 << "=" << noindent << name1 << ", " << #name2 << "=" \
230 << noindent << name2 << ", " << #name3 << "=" << noindent << name3 \
231 << yesindent;
232#define Iprint3n(file, name1, name2, name3) \
233 file << indn << #name1 << "=" << noindent << name1 << ", " << #name2 << "=" \
234 << noindent << name2 << ", " << #name3 << "=" << noindent << name3 \
235 << '\n' << yesindent;
236#define Iprint3nf(file, name1, name2, name3) \
237 { \
238 file << indn << #name1 << "=" << noindent << name1 << ", " << #name2 \
239 << "=" << noindent << name2 << ", " << #name3 << "=" << noindent \
240 << name3 << '\n' << yesindent; \
241 file.flush(); \
242 }
243#define Iprint4n(file, name1, name2, name3, name4) \
244 file << indn << #name1 << "=" << noindent << name1 << ", " << #name2 << "=" \
245 << noindent << name2 << ", " << #name3 << "=" << noindent << name3 \
246 << ", " << #name4 << "=" << noindent << name4 << '\n' << yesindent;
247
248extern int s_short_output; // sign which allows to make output shorter
249// simultaneously for all classes. Useful for writing "persistence classes"
250// by standard <</>> operators.
251// If instead of this one tries to use special functions like
252// class_name::short_write,
253// he finds an obstacle that such functions are absent for inbuilt types.
254}
255
256#endif
Definition: BGMesh.cpp:6
int s_short_output
Definition: prstream.cpp:25
std::ostream & noindent(std::ostream &f)
Definition: prstream.cpp:17
std::ostream & operator<<(std::ostream &file, const BGMesh &bgm)
Definition: BGMesh.cpp:37
indentation indn
Definition: prstream.cpp:15
std::ostream & yesindent(std::ostream &f)
Definition: prstream.cpp:21