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