source: trunk/yat/utility.h @ 1336

Last change on this file since 1336 was 1336, checked in by Peter Johansson, 12 years ago

latest yat

  • Property svn:eol-style set to native
File size: 9.0 KB
Line 
1#ifndef _theplu_yat_utility_utility_
2#define _theplu_yat_utility_utility_
3
4// $Id: utility.h 2386 2010-12-22 20:12:49Z peter $
5
6/*
7  Copyright (C) 2005 Jari Häkkinen, Peter Johansson, Markus Ringnér
8  Copyright (C) 2006 Jari Häkkinen
9  Copyright (C) 2007, 2008 Jari Häkkinen, Peter Johansson
10  Copyright (C) 2009, 2010 Peter Johansson
11
12  This file is part of the yat library, http://dev.thep.lu.se/yat
13
14  The yat library is free software; you can redistribute it and/or
15  modify it under the terms of the GNU General Public License as
16  published by the Free Software Foundation; either version 3 of the
17  License, or (at your option) any later version.
18
19  The yat library is distributed in the hope that it will be useful,
20  but WITHOUT ANY WARRANTY; without even the implied warranty of
21  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22  General Public License for more details.
23
24  You should have received a copy of the GNU General Public License
25  along with yat. If not, see <http://www.gnu.org/licenses/>.
26*/
27
28///
29/// \file yat/utility/utility.h
30///
31/// @brief Some useful functions are placed here
32///
33
34#include "deprecate.h"
35#include "Exception.h"
36
37#include <cmath>
38#include <limits>
39#include <istream>
40#include <string>
41#include <stdexcept>
42#include <sstream>
43#include <utility>
44#include <vector>
45
46namespace theplu {
47namespace yat {
48namespace utility {
49
50  /**
51     For each element in resulting range assign it to 0.0 if
52     corresponding element in input range is NaN else assign it to
53     1.0.
54
55     \return true if there is at least one NaN in input range
56     [first, last).
57
58     \since New in yat 0.5
59  */
60  template<typename InputIterator, typename OutputIterator>
61  bool binary_weight(InputIterator first, InputIterator last, 
62                     OutputIterator result);
63
64
65  /**
66     \brief convert string to (numerical) type
67
68     \throw runtime_error if conversion fails
69   */
70  template<typename T>
71  T convert(const std::string& s);
72
73  /**
74     \brief check if string is convertible to (numerical) type
75
76     \since New in yat 0.5
77   */
78  template<typename T>
79  bool is(const std::string& s);
80
81  ///
82  /// @return true if string is a double
83  ///
84  /// \deprecated Provided for backward compatibility with the 0.4
85  /// API. Use is<double>(const std::string&)
86  ///
87  bool is_double(const std::string&) YAT_DEPRECATE;
88
89  /**
90     This function takes the first word (separated by whitespace) in
91     \a s, replaces all upper case with lower case, and compares it
92     with \a other.
93
94     \return true if processed \a s is equal to \a other. It returns
95     false otherwise or if \a s contains more than one word.
96  */
97  bool is_equal(std::string s, std::string other);
98
99  ///
100  /// @return true if string is a float
101  ///
102  /// \deprecated Provided for backward compatibility with the 0.4
103  /// API. Use is<float>(const std::string&)
104  ///
105  bool is_float(const std::string&) YAT_DEPRECATE;
106
107  ///
108  /// @return true if string is an int
109  ///
110  /// \deprecated Provided for backward compatibility with the 0.4
111  /// API. Use is<int>(const std::string&)
112  ///
113  bool is_int(const std::string&) YAT_DEPRECATE;
114
115  ///
116  /// @return true if string is "nan" (case-insensitive)
117  ///
118  bool is_nan(const std::string& s);
119
120  /**
121     The std::istream will be interpreted as outlined here:
122
123     Lines are separated by character \a line_sep and rows are
124     separated by character \a sep.
125     
126     The first line is read into a stringstream, which is used to
127     load the first vector (vec[0]) with elements using
128     load(stringstream, vec[0], sep).
129     
130     Therefore, column elements separation has two modes depending
131     on the value of \a sep.
132     
133     - If \a sep is the default '\\0' value then column elements are
134     separated with white space characters except the new line
135     character. Multiple sequential white space characters are treated
136     as one separator.
137     
138     - Setting \a sep to something else than the default value will
139     change the behaviour to use the \a sep character as the separator
140     between column elements. Multiple sequential \a sep characters
141     will be treated as separating elements with missing values.
142
143     If \a rectangle is true, rows must contain same number of
144     elements or function will throw.
145
146     If \a ignore_empty is true empty lines are ignored.
147
148     \see load(std::istream&, std::vector<T>&, char sep='\\0')
149
150     \note Requirement on T: utility::convert<T> must be supported
151     (from yat 0.7 T=string is also supported)
152
153     \since New in yat 0.6
154   */
155  template<typename T>
156  void load(std::istream& is, std::vector<std::vector<T> >& vec, char sep='\0', 
157            char line_sep='\n', bool ignore_empty=false, bool rectangle=true);
158
159  /**
160     \brief Fill a vector<T> with elements from istream
161
162     Element separation has two modes depending on the value of \a
163     sep.
164     
165     - If \a sep is the default '\\0' value then elements are
166     separated with white space characters. Multiple sequential white
167     space characters are treated as one separator.
168     
169     - Setting \a sep to something else than the default value will
170     change the behaviour to use the \a sep character as the
171     separator between column elements. Multiple sequential \a sep
172     characters will be treated as separating elements with missing
173     values. Missing values are set to std::numeric_limits<T>::quiet_NaN
174     
175     \note Requirement on T: utility::convert<T> must be supported
176     (from yat 0.7 T=string is also supported)
177
178     \since New in yat 0.6
179   */
180  template<typename T>
181  void load(std::istream& is, std::vector<T>& vec, char sep='\0');
182 
183// private namespace
184namespace detail {
185
186  /**
187     \brief convert s to t
188
189     used in function is<T> and convert<T>
190
191     \return true if conversion was successful
192
193     \internal
194   */
195  template<typename T>
196  bool convert(const std::string& s, T& t);
197
198  /**
199     Functor used in load function
200   */
201  template<typename T>
202  struct VectorPusher
203  {
204    /**
205       convert element to T and push on vec's back
206
207       \internal
208     */
209    void operator()(const std::string& element, std::vector<T>& vec)
210    { 
211      if (!element.size())
212        vec.push_back(std::numeric_limits<T>::quiet_NaN());
213      else {
214        vec.push_back(theplu::yat::utility::convert<T>(element));
215      }
216    }
217  };
218
219  /**
220     specialization for string
221
222     \internal
223   */
224  template<>
225  struct VectorPusher<std::string>
226  {
227    /**
228       push element on vec's back
229     */
230    void operator()(const std::string& element, std::vector<std::string>& vec)
231    { 
232      vec.push_back(element);
233    }
234  };
235
236} // end of namespace detail
237
238
239  // template implementations
240
241  template<typename InputIterator, typename OutputIterator>
242  bool binary_weight(InputIterator first, InputIterator last, 
243                     OutputIterator result)
244  {
245    bool nan=false;
246    while (first!=last) {
247      if (std::isnan(*first)) {
248        *result=0;
249        nan=true;
250      }
251      else
252        *result = 1.0;
253      ++first;
254      ++result;
255    }
256    return nan;
257  }
258
259
260  // template implementations
261  template<typename T>
262  T convert(const std::string& s)
263  {
264    T result;
265    if (!detail::convert(s, result))
266      throw runtime_error(std::string("yat::utility::convert(\"")+s+
267                          std::string("\")"));
268    return result;
269  }
270
271
272  template<typename T>
273  bool is(const std::string& s)
274  {
275    T tmp;
276    return detail::convert(s, tmp);
277  }
278
279
280  template<typename T>
281  void load(std::istream& is, std::vector<std::vector<T> >& matrix, 
282            char sep, char line_sep, bool ignore_empty, 
283            bool rectangle)
284  {
285    size_t nof_columns=0;
286    std::string line;
287    while(getline(is, line, line_sep)){
288      if (line.empty() && ignore_empty)
289        continue;
290      matrix.push_back(std::vector<T>());
291      std::vector<T>& v=matrix.back();
292      v.reserve(nof_columns);
293      std::stringstream ss(line);
294      load(ss, v, sep);
295      // add NaN for final separator (or empty string if T=std::string)
296      detail::VectorPusher<T> pusher;
297      if(sep!='\0' && !line.empty() && line[line.size()-1]==sep) 
298        pusher("", v);
299     
300      if (rectangle && nof_columns && v.size()!=nof_columns) {
301        std::ostringstream s;
302        s << "load stream error: "
303          << "line " << matrix.size() << " has " << v.size()
304          << " columns; expected " << nof_columns << " columns.";
305        throw utility::IO_error(s.str());
306      }       
307      nof_columns = std::max(nof_columns, v.size());
308    }
309
310    // manipulate the state of the stream to be good
311    is.clear(std::ios::goodbit);
312  }
313
314  template<typename T>
315  void load(std::istream& is, std::vector<T>& vec, char sep='\0')
316  {
317    detail::VectorPusher<T> pusher;
318    std::string element;
319    bool ok=true;
320    while(true) {
321      if(sep=='\0')
322        ok=(is>>element);
323      else
324        ok=getline(is, element, sep);
325      if(!ok)
326        break;
327      pusher(element, vec);
328    }
329  }           
330
331
332namespace detail {
333  template<typename T>
334  bool convert(const std::string& s, T& result)
335  {
336    std::istringstream ss(s);
337    ss >> result;
338    if (ss.fail()) {
339      if (is_nan(s)) {
340        result = std::numeric_limits<T>::quiet_NaN();
341        return true;
342      }
343      if (is_equal(s, "inf")) {
344        result = std::numeric_limits<T>::infinity();
345        return true;
346      }
347      if (std::numeric_limits<T>::is_signed && is_equal(s, "-inf")) {
348        result = -std::numeric_limits<T>::infinity();
349        return true;
350      }
351      return false;
352    }
353    // Check that nothing is left on stream
354    std::string b;
355    ss >> b;
356    return b.empty();
357  }
358} // of namespace detail
359
360}}} // of namespace utility, yat, and theplu
361
362#endif
Note: See TracBrowser for help on using the repository browser.