source: trunk/yat/utility/utility.h @ 2906

Last change on this file since 2906 was 2906, checked in by Peter, 9 years ago

New functions chdir, chmod, copy_file, fnmatch, remove, rename, and replace
refs #717

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 11.7 KB
Line 
1#ifndef _theplu_yat_utility_utility_
2#define _theplu_yat_utility_utility_
3
4// $Id: utility.h 2906 2012-12-15 06:29:55Z 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, 2012 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#include "yat_assert.h"
37
38#include <gsl/gsl_math.h>
39
40#include <algorithm>
41#include <cctype>
42#include <cmath>
43#include <functional>
44#include <limits>
45#include <locale>
46#include <istream>
47#include <string>
48#include <stdexcept>
49#include <sstream>
50#include <utility>
51#include <vector>
52
53namespace theplu {
54namespace yat {
55namespace utility {
56
57  /**
58     \return everything after last '/'
59
60     \since New in yat 0.10
61   */
62  std::string basename(const std::string& fn);
63
64  /**
65     For each element in resulting range assign it to 0.0 if
66     corresponding element in input range is NaN else assign it to
67     1.0.
68
69     \return true if there is at least one NaN in input range
70     [first, last).
71
72     \since New in yat 0.5
73  */
74  template<typename InputIterator, typename OutputIterator>
75  bool binary_weight(InputIterator first, InputIterator last, 
76                     OutputIterator result);
77
78  /**
79     wrapper around GNU C Library function chdir
80
81     \throw if underlying chdir call does not return 0
82
83     \since New in yat 0.10
84   */
85  void chdir(const std::string& dir);
86
87  /**
88     \since New in yat 0.10
89   */
90  void chmod(const std::string& filename, mode_t mode);
91
92  /**
93     \brief convert T to a string
94
95     T is supposed to be a numerical type.
96
97     \since new in yat 0.8
98   */
99  template<typename T>
100  std::string convert(T input);
101
102  /**
103     \brief convert string to (numerical) type
104
105     \throw runtime_error if conversion fails
106   */
107  template<typename T>
108  T convert(const std::string& s);
109
110  /**
111     @brief Copy file \a source to \a target.
112
113     @throw std::runtime_error when read error of \a source or write
114     error for \a target is encountered.
115  */
116  void copy_file(const std::string& source, const std::string& target);
117
118  /**
119     \return everything prior last '/'.
120
121     \since New in yat 0.10
122   */
123  std::string dirname(const std::string& fn);
124
125  /**
126     \return true if \a str matches \a pattern
127
128     \see fnmatch(3)
129
130     \since New in yat 0.10
131  */
132  bool fnmatch(const std::string& pattern, const std::string& str);
133
134  /**
135     \brief check if string is convertible to (numerical) type \c T
136
137     \since New in yat 0.5
138   */
139  template<typename T>
140  bool is(const std::string& s);
141
142  ///
143  /// @return true if string is a double
144  ///
145  /// \deprecated Provided for backward compatibility with the 0.4
146  /// API. Use is<double>(const std::string&)
147  ///
148  bool is_double(const std::string&) YAT_DEPRECATE;
149
150  /**
151     This function takes the first word (separated by whitespace) in
152     \a s, replaces all upper case with lower case, and compares it
153     with \a other.
154
155     \return true if processed \a s is equal to \a other. It returns
156     false otherwise or if \a s contains more than one word.
157  */
158  bool is_equal(std::string s, std::string other);
159
160  ///
161  /// @return true if string is a float
162  ///
163  /// \deprecated Provided for backward compatibility with the 0.4
164  /// API. Use is<float>(const std::string&)
165  ///
166  bool is_float(const std::string&) YAT_DEPRECATE;
167
168  ///
169  /// @return true if string is an int
170  ///
171  /// \deprecated Provided for backward compatibility with the 0.4
172  /// API. Use is<int>(const std::string&)
173  ///
174  bool is_int(const std::string&) YAT_DEPRECATE;
175
176  ///
177  /// @return true if string is "nan" (case-insensitive)
178  ///
179  bool is_nan(const std::string& s);
180
181  /**
182     The std::istream will be interpreted as outlined here:
183
184     Lines are separated by character \a line_sep and rows are
185     separated by character \a sep.
186     
187     The first line is read into a stringstream, which is used to
188     load the first vector (vec[0]) with elements using
189     load(stringstream, vec[0], sep).
190     
191     Therefore, column elements separation has two modes depending
192     on the value of \a sep.
193     
194     - If \a sep is the default '\\0' value then column elements are
195     separated with white space characters except the new line
196     character. Multiple sequential white space characters are treated
197     as one separator.
198     
199     - Setting \a sep to something else than the default value will
200     change the behaviour to use the \a sep character as the separator
201     between column elements. Multiple sequential \a sep characters
202     will be treated as separating elements with missing values.
203
204     If \a rectangle is true, rows must contain same number of
205     elements or function will throw.
206
207     If \a ignore_empty is true empty lines are ignored.
208
209     \see load(std::istream&, std::vector<T>&, char sep='\\0')
210
211     \note Requirement on T: utility::convert<T> must be supported
212     (from yat 0.7 T=string is also supported)
213
214     \since New in yat 0.6
215   */
216  template<typename T>
217  void load(std::istream& is, std::vector<std::vector<T> >& vec, char sep='\0', 
218            char line_sep='\n', bool ignore_empty=false, bool rectangle=true);
219
220  /**
221     \brief Fill a vector<T> with elements from istream
222
223     Element separation has two modes depending on the value of \a
224     sep.
225     
226     - If \a sep is the default '\\0' value then elements are
227     separated with white space characters. Multiple sequential white
228     space characters are treated as one separator.
229     
230     - Setting \a sep to something else than the default value will
231     change the behaviour to use the \a sep character as the
232     separator between column elements. Multiple sequential \a sep
233     characters will be treated as separating elements with missing
234     values. Missing values are set to std::numeric_limits<T>::quiet_NaN
235     
236     \note Requirement on T: utility::convert<T> must be supported
237     (from yat 0.7 T=string is also supported)
238
239     \since New in yat 0.6
240   */
241  template<typename T>
242  void load(std::istream& is, std::vector<T>& vec, char sep='\0');
243
244  /**
245     \return base-2 logarithm of x
246
247     \since New in yat 0.10
248   */
249  // c++11 provides std::log2 so perhaps we should call that one if
250  // availalable (but a bit tricky since this is a public header)
251  template<typename T>
252  T log2(T x) { return std::log(x)/M_LN2; }
253
254// private namespace
255namespace detail {
256
257  /**
258     \brief convert s to t
259
260     used in function is<T> and convert<T>
261
262     \return true if conversion was successful
263
264     \internal
265   */
266  template<typename T>
267  bool convert(const std::string& s, T& t);
268
269  /**
270     Functor used in load function
271   */
272  template<typename T>
273  struct VectorPusher
274  {
275    /**
276       convert element to T and push on vec's back
277
278       \internal
279     */
280    void operator()(const std::string& element, std::vector<T>& vec)
281    { 
282      if (!element.size())
283        vec.push_back(std::numeric_limits<T>::quiet_NaN());
284      else {
285        vec.push_back(theplu::yat::utility::convert<T>(element));
286      }
287    }
288  };
289
290  /**
291     specialization for string
292
293     \internal
294   */
295  template<>
296  struct VectorPusher<std::string>
297  {
298    /**
299       push element on vec's back
300     */
301    void operator()(const std::string& element, std::vector<std::string>& vec)
302    { 
303      vec.push_back(element);
304    }
305  };
306
307} // end of namespace detail
308
309
310  /**
311     create a directory \a dir
312
313     \throw if creation failed
314   */
315  void mkdir(const std::string& dir);
316
317  /**
318     Similar to 'mkdir -p'. Does not throw on error and create parent
319     directories if missing.
320   */
321  void mkdir_p(const std::string& dir);
322
323  /**
324     same as C function remove but throws errno_error at failure
325
326     \see man remove
327   */
328  void remove(const std::string& fn);
329
330  /**
331     same as rename(2) but throws errno_error if error is encountered
332
333     \see man rename
334
335     \since New in yat 0.10
336   */
337  void rename(const std::string& from, const std::string to);
338
339  /**
340     In \a full_str replace every sub-string \a old_str with \a
341     new_str;
342   */
343  void replace(std::string& full_str, std::string old_str, std::string new_str);
344
345  // template implementations
346
347  template<typename InputIterator, typename OutputIterator>
348  bool binary_weight(InputIterator first, InputIterator last, 
349                     OutputIterator result)
350  {
351    bool nan=false;
352    while (first!=last) {
353      if (std::isnan(*first)) {
354        *result=0;
355        nan=true;
356      }
357      else
358        *result = 1.0;
359      ++first;
360      ++result;
361    }
362    return nan;
363  }
364
365
366  // template implementations
367  template<typename T>
368  std::string convert(T input)
369  {
370    std::ostringstream ss;
371    ss << input;
372    return ss.str();
373  }
374
375
376  template<typename T>
377  T convert(const std::string& s)
378  {
379    T result;
380    if (!detail::convert(s, result))
381      throw runtime_error(std::string("yat::utility::convert(\"")+s+
382                          std::string("\")"));
383    return result;
384  }
385
386
387  template<typename T>
388  bool is(const std::string& s)
389  {
390    T tmp;
391    return detail::convert(s, tmp);
392  }
393
394
395  template<typename T>
396  void load(std::istream& is, std::vector<std::vector<T> >& matrix, 
397            char sep, char line_sep, bool ignore_empty, 
398            bool rectangle)
399  {
400    size_t nof_columns=0;
401    std::string line;
402    while(getline(is, line, line_sep)){
403      if (line.empty() && ignore_empty)
404        continue;
405      matrix.push_back(std::vector<T>());
406      std::vector<T>& v=matrix.back();
407      v.reserve(nof_columns);
408      std::stringstream ss(line);
409      load(ss, v, sep);
410      // add NaN for final separator (or empty string if T=std::string)
411      detail::VectorPusher<T> pusher;
412      if(sep!='\0' && !line.empty() && line[line.size()-1]==sep) 
413        pusher("", v);
414     
415      if (rectangle && nof_columns && v.size()!=nof_columns) {
416        std::ostringstream s;
417        s << "load stream error: "
418          << "line " << matrix.size() << " has " << v.size()
419          << " columns; expected " << nof_columns << " columns.";
420        throw utility::IO_error(s.str());
421      }       
422      nof_columns = std::max(nof_columns, v.size());
423    }
424
425    // manipulate the state of the stream to be good
426    is.clear(std::ios::goodbit);
427  }
428
429  template<typename T>
430  void load(std::istream& is, std::vector<T>& vec, char sep)
431  {
432    detail::VectorPusher<T> pusher;
433    std::string element;
434    bool ok=true;
435    while(true) {
436      if(sep=='\0')
437        ok=(is>>element);
438      else
439        ok=getline(is, element, sep);
440      if(!ok)
441        break;
442      pusher(element, vec);
443    }
444  }
445
446namespace detail {
447  template<typename T>
448  bool convert(const std::string& s, T& result)
449  {
450    if (!std::numeric_limits<T>::is_signed) {
451      // first non-whitespace character
452      std::string::const_iterator iter = s.begin();
453      while (iter!=s.end() && std::isspace(*iter))
454        ++iter;
455      // unsigned int cannot start with a '-' and with some compilers
456      // operation ss >> result won't fail so catch it like this instead.
457      if (iter==s.end() || *iter=='-')
458        return false;
459    }
460    std::istringstream ss(s);
461    ss >> result;
462    if (ss.fail()) {
463      if (is_nan(s)) {
464        result = std::numeric_limits<T>::quiet_NaN();
465        return true;
466      }
467      if (is_equal(s, "inf")) {
468        result = std::numeric_limits<T>::infinity();
469        return true;
470      }
471      if (is_equal(s, "-inf")) {
472        // unsigned types are caught in prologue
473        YAT_ASSERT(std::numeric_limits<T>::is_signed);
474        result = -std::numeric_limits<T>::infinity();
475        return true;
476      }
477      return false;
478    }
479    // Check that nothing is left on stream
480    std::string b;
481    ss >> b;
482    return b.empty();
483  }
484} // of namespace detail
485
486}}} // of namespace utility, yat, and theplu
487
488#endif
Note: See TracBrowser for help on using the repository browser.