source: trunk/yat/utility.h @ 1351

Last change on this file since 1351 was 1351, checked in by Peter Johansson, 10 years ago

update to latest libyat. closes #471

  • Property svn:eol-style set to native
File size: 9.3 KB
Line 
1#ifndef _theplu_yat_utility_utility_
2#define _theplu_yat_utility_utility_
3
4// $Id: utility.h 2451 2011-03-28 23:16:14Z 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, 2011 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     \brief convert T to a string
66
67     T is supposed to be a numerical type.
68
69     \since new in yat 0.8
70   */
71  template<typename T>
72  std::string convert(T input);
73
74  /**
75     \brief convert string to (numerical) type
76
77     \throw runtime_error if conversion fails
78   */
79  template<typename T>
80  T convert(const std::string& s);
81
82  /**
83     \brief check if string is convertible to (numerical) type
84
85     \since New in yat 0.5
86   */
87  template<typename T>
88  bool is(const std::string& s);
89
90  ///
91  /// @return true if string is a double
92  ///
93  /// \deprecated Provided for backward compatibility with the 0.4
94  /// API. Use is<double>(const std::string&)
95  ///
96  bool is_double(const std::string&) YAT_DEPRECATE;
97
98  /**
99     This function takes the first word (separated by whitespace) in
100     \a s, replaces all upper case with lower case, and compares it
101     with \a other.
102
103     \return true if processed \a s is equal to \a other. It returns
104     false otherwise or if \a s contains more than one word.
105  */
106  bool is_equal(std::string s, std::string other);
107
108  ///
109  /// @return true if string is a float
110  ///
111  /// \deprecated Provided for backward compatibility with the 0.4
112  /// API. Use is<float>(const std::string&)
113  ///
114  bool is_float(const std::string&) YAT_DEPRECATE;
115
116  ///
117  /// @return true if string is an int
118  ///
119  /// \deprecated Provided for backward compatibility with the 0.4
120  /// API. Use is<int>(const std::string&)
121  ///
122  bool is_int(const std::string&) YAT_DEPRECATE;
123
124  ///
125  /// @return true if string is "nan" (case-insensitive)
126  ///
127  bool is_nan(const std::string& s);
128
129  /**
130     The std::istream will be interpreted as outlined here:
131
132     Lines are separated by character \a line_sep and rows are
133     separated by character \a sep.
134     
135     The first line is read into a stringstream, which is used to
136     load the first vector (vec[0]) with elements using
137     load(stringstream, vec[0], sep).
138     
139     Therefore, column elements separation has two modes depending
140     on the value of \a sep.
141     
142     - If \a sep is the default '\\0' value then column elements are
143     separated with white space characters except the new line
144     character. Multiple sequential white space characters are treated
145     as one separator.
146     
147     - Setting \a sep to something else than the default value will
148     change the behaviour to use the \a sep character as the separator
149     between column elements. Multiple sequential \a sep characters
150     will be treated as separating elements with missing values.
151
152     If \a rectangle is true, rows must contain same number of
153     elements or function will throw.
154
155     If \a ignore_empty is true empty lines are ignored.
156
157     \see load(std::istream&, std::vector<T>&, char sep='\\0')
158
159     \note Requirement on T: utility::convert<T> must be supported
160     (from yat 0.7 T=string is also supported)
161
162     \since New in yat 0.6
163   */
164  template<typename T>
165  void load(std::istream& is, std::vector<std::vector<T> >& vec, char sep='\0', 
166            char line_sep='\n', bool ignore_empty=false, bool rectangle=true);
167
168  /**
169     \brief Fill a vector<T> with elements from istream
170
171     Element separation has two modes depending on the value of \a
172     sep.
173     
174     - If \a sep is the default '\\0' value then elements are
175     separated with white space characters. Multiple sequential white
176     space characters are treated as one separator.
177     
178     - Setting \a sep to something else than the default value will
179     change the behaviour to use the \a sep character as the
180     separator between column elements. Multiple sequential \a sep
181     characters will be treated as separating elements with missing
182     values. Missing values are set to std::numeric_limits<T>::quiet_NaN
183     
184     \note Requirement on T: utility::convert<T> must be supported
185     (from yat 0.7 T=string is also supported)
186
187     \since New in yat 0.6
188   */
189  template<typename T>
190  void load(std::istream& is, std::vector<T>& vec, char sep='\0');
191 
192// private namespace
193namespace detail {
194
195  /**
196     \brief convert s to t
197
198     used in function is<T> and convert<T>
199
200     \return true if conversion was successful
201
202     \internal
203   */
204  template<typename T>
205  bool convert(const std::string& s, T& t);
206
207  /**
208     Functor used in load function
209   */
210  template<typename T>
211  struct VectorPusher
212  {
213    /**
214       convert element to T and push on vec's back
215
216       \internal
217     */
218    void operator()(const std::string& element, std::vector<T>& vec)
219    { 
220      if (!element.size())
221        vec.push_back(std::numeric_limits<T>::quiet_NaN());
222      else {
223        vec.push_back(theplu::yat::utility::convert<T>(element));
224      }
225    }
226  };
227
228  /**
229     specialization for string
230
231     \internal
232   */
233  template<>
234  struct VectorPusher<std::string>
235  {
236    /**
237       push element on vec's back
238     */
239    void operator()(const std::string& element, std::vector<std::string>& vec)
240    { 
241      vec.push_back(element);
242    }
243  };
244
245} // end of namespace detail
246
247
248  // template implementations
249
250  template<typename InputIterator, typename OutputIterator>
251  bool binary_weight(InputIterator first, InputIterator last, 
252                     OutputIterator result)
253  {
254    bool nan=false;
255    while (first!=last) {
256      if (std::isnan(*first)) {
257        *result=0;
258        nan=true;
259      }
260      else
261        *result = 1.0;
262      ++first;
263      ++result;
264    }
265    return nan;
266  }
267
268
269  // template implementations
270  template<typename T>
271  std::string convert(T input)
272  {
273    std::ostringstream ss;
274    ss << input;
275    return ss.str();
276  }
277
278
279  template<typename T>
280  T convert(const std::string& s)
281  {
282    T result;
283    if (!detail::convert(s, result))
284      throw runtime_error(std::string("yat::utility::convert(\"")+s+
285                          std::string("\")"));
286    return result;
287  }
288
289
290  template<typename T>
291  bool is(const std::string& s)
292  {
293    T tmp;
294    return detail::convert(s, tmp);
295  }
296
297
298  template<typename T>
299  void load(std::istream& is, std::vector<std::vector<T> >& matrix, 
300            char sep, char line_sep, bool ignore_empty, 
301            bool rectangle)
302  {
303    size_t nof_columns=0;
304    std::string line;
305    while(getline(is, line, line_sep)){
306      if (line.empty() && ignore_empty)
307        continue;
308      matrix.push_back(std::vector<T>());
309      std::vector<T>& v=matrix.back();
310      v.reserve(nof_columns);
311      std::stringstream ss(line);
312      load(ss, v, sep);
313      // add NaN for final separator (or empty string if T=std::string)
314      detail::VectorPusher<T> pusher;
315      if(sep!='\0' && !line.empty() && line[line.size()-1]==sep) 
316        pusher("", v);
317     
318      if (rectangle && nof_columns && v.size()!=nof_columns) {
319        std::ostringstream s;
320        s << "load stream error: "
321          << "line " << matrix.size() << " has " << v.size()
322          << " columns; expected " << nof_columns << " columns.";
323        throw utility::IO_error(s.str());
324      }       
325      nof_columns = std::max(nof_columns, v.size());
326    }
327
328    // manipulate the state of the stream to be good
329    is.clear(std::ios::goodbit);
330  }
331
332  template<typename T>
333  void load(std::istream& is, std::vector<T>& vec, char sep='\0')
334  {
335    detail::VectorPusher<T> pusher;
336    std::string element;
337    bool ok=true;
338    while(true) {
339      if(sep=='\0')
340        ok=(is>>element);
341      else
342        ok=getline(is, element, sep);
343      if(!ok)
344        break;
345      pusher(element, vec);
346    }
347  }           
348
349
350namespace detail {
351  template<typename T>
352  bool convert(const std::string& s, T& result)
353  {
354    std::istringstream ss(s);
355    ss >> result;
356    if (ss.fail()) {
357      if (is_nan(s)) {
358        result = std::numeric_limits<T>::quiet_NaN();
359        return true;
360      }
361      if (is_equal(s, "inf")) {
362        result = std::numeric_limits<T>::infinity();
363        return true;
364      }
365      if (std::numeric_limits<T>::is_signed && is_equal(s, "-inf")) {
366        result = -std::numeric_limits<T>::infinity();
367        return true;
368      }
369      return false;
370    }
371    // Check that nothing is left on stream
372    std::string b;
373    ss >> b;
374    return b.empty();
375  }
376} // of namespace detail
377
378}}} // of namespace utility, yat, and theplu
379
380#endif
Note: See TracBrowser for help on using the repository browser.