Logo ROOT  
Reference Guide
TreeUtils.cxx
Go to the documentation of this file.
1// @(#)root/tree:$Id$
2// Author: Timur Pocheptsov 30/01/2014
3
4/*************************************************************************
5 * Copyright (C) 1995-2014, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12/** \class TreeUtils
13\ingroup tree
14
15Different standalone functions to work with trees and tuples,
16not reqiuired to be a member of any class.
17*/
18
19#include <istream>
20#include <cassert>
21#include <cctype>
22
23#include "TreeUtils.h"
24#include "TNtupleD.h"
25#include "TNtuple.h"
26#include "TError.h"
27#include "TTree.h"
28
29namespace ROOT {
30namespace TreeUtils {
31
32//Some aux. functions to read tuple from a text file. No reason to make them memeber-functions.
33void SkipEmptyLines(std::istream &input);
34void SkipWSCharacters(std::istream &input);
35bool NextCharacterIsEOL(std::istream &input);
36
37//Enforce/limit what can be a Tuple.
38//Actually, at the moment you can only use
39//the fill function for TNtuple/TNtupleD
40//(enforced by hidden definition and explicit instantiations).
41//But in future this can potentially change.
42
43//TODO: there is no line number in any of error messages.
44//It can be improved, though, we can have mixed line endings
45//so I can not rely on this numbering (for example, my vim shows these lines:
46//aaaa\r\r\nbbb as
47//aaaa
48//bbbb
49//Though it can be also treated as
50//aaaa
51//
52//bbb
53//or even as
54//aaaa
55//
56//
57//bbb - so line numbers can be useless and misleading.
58
59template<class> struct InvalidTupleType;
60
61template<>
63{
65 {
66 }
67};
68
69template<>
71{
73 {
74 }
75};
76
77////////////////////////////////////////////////////////////////////////////////
78
79template<class DataType, class Tuple>
80Long64_t FillNtupleFromStream(std::istream &inputStream, Tuple &tuple, char delimiter, bool strictMode)
81{
82 InvalidTupleType<Tuple> typeChecker;
83
84 if (delimiter == '\r' || delimiter == '\n') {
85 ::Error("FillNtupleFromStream", "invalid delimiter - newline character");
86 return 0;
87 }
88
89 if (delimiter == '#') {
90 ::Error("FillNtuplesFromStream", "invalid delimiter, '#' symbols can only start a comment");
91 return 0;
92 }
93
94 const Int_t nVars = tuple.GetNvar();
95 if (nVars <= 0) {
96 ::Error("FillNtupleFromStream", "invalid number of elements");
97 return 0;
98 }
99
100 DataType *args = tuple.GetArgs();
101 assert(args != 0 && "FillNtupleFromStream, args buffer is a null");
102
103 Long64_t nLines = 0;
104
105 if (strictMode) {
106 while (true) {
107 //Skip empty-lines (containing only newlines, comments, whitespaces + newlines
108 //and combinations).
109 SkipEmptyLines(inputStream);
110
111 if (!inputStream.good()) {
112 if (!nLines)
113 ::Error("FillNtupleFromStream", "no data read");
114 return nLines;
115 }
116
117 //Now, we have to be able to read _the_ _required_ number of entires.
118 for (Int_t i = 0; i < nVars; ++i) {
119 SkipWSCharacters(inputStream);//skip all wses except newlines.
120 if (!inputStream.good()) {
121 ::Error("FillNtupleFromStream", "failed to read a tuple (not enough values found)");
122 return nLines;
123 }
124
125 if (i > 0 && !std::isspace(delimiter)) {
126 const char test = inputStream.peek();
127 if (!inputStream.good() || test != delimiter) {
128 ::Error("FillNtupleFromStream", "delimiter expected");
129 return nLines;
130 }
131
132 inputStream.get();//we skip a dilimiter whatever it is.
133 SkipWSCharacters(inputStream);
134 }
135
136 if (NextCharacterIsEOL(inputStream)) {
137 //This is unexpected!
138 ::Error("FillNtupleFromStream", "unexpected character or eof found");
139 return nLines;
140 }
141
142 inputStream>>args[i];
143
144 if (!(inputStream.eof() && i + 1 == nVars) && !inputStream.good()){
145 ::Error("FillNtupleFromStream", "error while reading a value");
146 return nLines;
147 }
148 }
149
150 SkipWSCharacters(inputStream);
151 if (!NextCharacterIsEOL(inputStream)) {
152 ::Error("FillNtupleFromStream",
153 "only whitespace and new line can follow the last number on the line");
154 return nLines;
155 }
156
157 //Only God forgives :) Ugly but ...
158 //for TNtuple it's protected :)
159 static_cast<TTree &>(tuple).Fill();
160 ++nLines;
161 }
162 } else {
163 Int_t i = 0;//how many values we found for a given tuple's entry.
164 while (true) {
165 //Skip empty lines, comments and whitespaces before
166 //the first 'non-ws' symbol:
167 //it can be a delimiter/a number (depends on a context) or an invalid symbol.
168 SkipEmptyLines(inputStream);
169
170 if (!inputStream.good()) {
171 //No data to read, check what we read by this moment:
172 if (!nLines)
173 ::Error("FillNtupleFromStream", "no data read");
174 else if (i > 0)//we've read only a part of a row.
175 ::Error("FillNtupleFromStream", "unexpected character or eof found");
176 return nLines;
177 }
178
179 if (i > 0 && !std::isspace(delimiter)) {
180 //The next one must be a delimiter.
181 const char test = inputStream.peek();
182 if (!inputStream.good() || test != delimiter) {
183 ::Error("FillNtupleFromStream", "delimiter expected (non-strict mode)");
184 return nLines;
185 }
186
187 inputStream.get();//skip the delimiter.
188 SkipEmptyLines(inputStream);//probably, read till eof.
189 }
190
191 //Here must be a number.
192 inputStream>>args[i];
193
194 if (!(inputStream.eof() && i + 1 == nVars) && !inputStream.good()){
195 ::Error("FillNtupleFromStream", "error while reading a value");
196 return nLines;
197 }
198
199 if (i + 1 == nVars) {
200 //We god the row, can fill now and continue.
201 static_cast<TTree &>(tuple).Fill();
202 ++nLines;
203 i = 0;
204 } else
205 ++i;
206 }
207 }
208
209 return nLines;
210}
211
212template Long64_t FillNtupleFromStream<Float_t, TNtuple>(std::istream &, TNtuple &, char, bool);
213template Long64_t FillNtupleFromStream<Double_t, TNtupleD>(std::istream &, TNtupleD &, char, bool);
214
215//Aux. functions to read tuples from text files.
216
217//file:
218// lines
219//
220//lines:
221// line
222// line lines
223//
224//line:
225// comment
226// tuple
227// empty-line
228
229//comment:
230// '#' non-newline-character-sequence newline-character
231//
232//non-newline-character-sequence:
233// any symbol except '\r' or '\n'
234//
235//newline-character:
236// '\r' | '\n'
237////////////////////////////////////////////////////////////////////////////////
238/// Skips everything from '#' to (including) '\\r' or '\\n'.
239
240void SkipComment(std::istream &input)
241{
242 while (input.good()) {
243 const char next = input.peek();
244 if (input.good()) {
245 input.get();
246 if (next == '\r' || next == '\n')
247 break;
248 }
249 }
250}
251
252//empty-line:
253// newline-character
254// ws-sequence newline-character
255// ws-sequence comment
256////////////////////////////////////////////////////////////////////////////////
257/// Skips empty lines (newline-characters), ws-lines (consisting only of whitespace characters + newline-characters).
258
259void SkipEmptyLines(std::istream &input)
260{
261 while (input.good()) {
262 const char c = input.peek();
263 if (!input.good())
264 break;
265
266 if (c == '#')
268 else if (!std::isspace(c))//'\r' and '\n' are also 'isspaces'.
269 break;
270 else
271 input.get();
272 }
273}
274
275//ws-sequence:
276// c such that isspace(c) and c is not a newline-character.
277////////////////////////////////////////////////////////////////////////////////
278/// Skip whitespace characters, but not newline-characters we support ('\\r' or '\\n').
279
280void SkipWSCharacters(std::istream &input)
281{
282 while (input.good()) {
283 const char next = input.peek();
284 if (input.good()) {
285 if (std::isspace(next) && next != '\n' && next != '\r')
286 input.get();
287 else
288 break;
289 }
290 }
291}
292
293//Next character is either newline-character, eof or we have some problems reading
294//the next symbol.
295////////////////////////////////////////////////////////////////////////////////
296/// Either '\\r' | '\\n' or eof of some problem.
297
298bool NextCharacterIsEOL(std::istream &input)
299{
300 if (!input.good())
301 return true;
302
303 const char next = input.peek();
304 if (!input.good())
305 return true;
306
307 return next == '\r' || next == '\n';
308}
309
310}//TreeUtils
311}//ROOT
#define c(i)
Definition: RSha256.hxx:101
long long Long64_t
Definition: RtypesCore.h:80
void Error(const char *location, const char *msgfmt,...)
Use this function in case an error occurred.
Definition: TError.cxx:187
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void input
A simple TTree restricted to a list of double variables only.
Definition: TNtupleD.h:28
A simple TTree restricted to a list of float variables only.
Definition: TNtuple.h:28
A TTree represents a columnar dataset.
Definition: TTree.h:79
Different standalone functions to work with trees and tuples, not reqiuired to be a member of any cla...
template Long64_t FillNtupleFromStream< Float_t, TNtuple >(std::istream &, TNtuple &, char, bool)
Long64_t FillNtupleFromStream(std::istream &inputStream, Tuple &tuple, char delimiter, bool strictMode)
Function to fill tuples (TNtuple/TNtupleD) from a simple ASCII data file.
Definition: TreeUtils.cxx:80
void SkipEmptyLines(std::istream &input)
Skips empty lines (newline-characters), ws-lines (consisting only of whitespace characters + newline-...
Definition: TreeUtils.cxx:259
void SkipWSCharacters(std::istream &input)
Skip whitespace characters, but not newline-characters we support ('\r' or '\n').
Definition: TreeUtils.cxx:280
bool NextCharacterIsEOL(std::istream &input)
Either '\r' | '\n' or eof of some problem.
Definition: TreeUtils.cxx:298
void SkipComment(std::istream &input)
Skips everything from '#' to (including) '\r' or '\n'.
Definition: TreeUtils.cxx:240
template Long64_t FillNtupleFromStream< Double_t, TNtupleD >(std::istream &, TNtupleD &, char, bool)
This file contains a specialised ROOT message handler to test for diagnostic in unit tests.
Definition: test.py:1