#ifndef _theplu_yat_utility_utility_
#define _theplu_yat_utility_utility_
// $Id: utility.h 2943 2013-01-04 06:38:38Z peter $
/*
Copyright (C) 2005 Jari Häkkinen, Peter Johansson, Markus Ringnér
Copyright (C) 2006 Jari Häkkinen
Copyright (C) 2007, 2008 Jari Häkkinen, Peter Johansson
Copyright (C) 2009, 2010, 2011, 2012, 2013 Peter Johansson
This file is part of the yat library, http://dev.thep.lu.se/yat
The yat library is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 3 of the
License, or (at your option) any later version.
The yat library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with yat. If not, see .
*/
///
/// \file yat/utility/utility.h
///
/// @brief Some useful functions are placed here
///
#include "deprecate.h"
#include "Exception.h"
#include "yat_assert.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
namespace theplu {
namespace yat {
namespace utility {
/**
Same as posix C function with same name but works on \c
std::string rather than \c char*.
\see http://linux.die.net/man/3/basename
\return everything after last '/'
\since New in yat 0.10
*/
std::string basename(const std::string& fn);
/**
For each element in resulting range assign it to 0.0 if
corresponding element in input range is NaN else assign it to
1.0.
\return true if there is at least one NaN in input range
[first, last).
\since New in yat 0.5
*/
template
bool binary_weight(InputIterator first, InputIterator last,
OutputIterator result);
/**
Same as C function \c chdir but throws on failure (instead of
retrning non-zero).
\throw runtime_error if underlying chdir returns non-zero
\see http://linux.die.net/man/3/chdir
\since New in yat 0.10
*/
void chdir(const std::string& dir);
/**
same as C function \c chmod but throws on failure (instead of
returning non-zero).
\see http://linux.die.net/man/3/chmod
\since New in yat 0.10
*/
void chmod(const std::string& filename, mode_t mode);
/**
\brief convert T to a string
T is supposed to be a numerical type.
\since new in yat 0.8
*/
template
std::string convert(T input);
/**
\brief convert string to (numerical) type
\throw runtime_error if conversion fails
*/
template
T convert(const std::string& s);
/**
@brief Copy file \a source to \a target.
@throw runtime_error if read error of \a source or write error
for \a target is encountered.
*/
void copy_file(const std::string& source, const std::string& target);
/**
Same as posix C function with same name but works on \c
std::string rather than \c char*.
\see http://linux.die.net/man/3/dirname
\return everything prior last '/'.
\since New in yat 0.10
*/
std::string dirname(const std::string& fn);
/**
\return true if \a str matches \a pattern
\see http://linux.die.net/man/3/fnmatch
\throw runtime_error if returned value from underlying fnmatch is
neither zero nor \c FNM_NOMATCH.
\since New in yat 0.10
*/
bool fnmatch(const std::string& pattern, const std::string& str,
int flags=0);
/**
\brief check if string is convertible to (numerical) type \c T
\since New in yat 0.5
*/
template
bool is(const std::string& s);
///
/// @return true if string is a double
///
/// \deprecated Provided for backward compatibility with the 0.4
/// API. Use is(const std::string&)
///
bool is_double(const std::string&) YAT_DEPRECATE;
/**
This function takes the first word (separated by whitespace) in
\a s, replaces all upper case with lower case, and compares it
with \a other.
\return true if processed \a s is equal to \a other. It returns
false otherwise or if \a s contains more than one word.
*/
bool is_equal(std::string s, std::string other);
///
/// @return true if string is a float
///
/// \deprecated Provided for backward compatibility with the 0.4
/// API. Use is(const std::string&)
///
bool is_float(const std::string&) YAT_DEPRECATE;
///
/// @return true if string is an int
///
/// \deprecated Provided for backward compatibility with the 0.4
/// API. Use is(const std::string&)
///
bool is_int(const std::string&) YAT_DEPRECATE;
///
/// @return true if string is "nan" (case-insensitive)
///
bool is_nan(const std::string& s);
/**
The std::istream will be interpreted as outlined here:
Lines are separated by character \a line_sep and rows are
separated by character \a sep.
The first line is read into a stringstream, which is used to
load the first vector (vec[0]) with elements using
load(stringstream, vec[0], sep).
Therefore, column elements separation has two modes depending
on the value of \a sep.
- If \a sep is the default '\\0' value then column elements are
separated with white space characters except the new line
character. Multiple sequential white space characters are treated
as one separator.
- Setting \a sep to something else than the default value will
change the behaviour to use the \a sep character as the separator
between column elements. Multiple sequential \a sep characters
will be treated as separating elements with missing values.
If \a rectangle is true, rows must contain same number of
elements or function will throw.
If \a ignore_empty is true empty lines are ignored.
\see load(std::istream&, std::vector&, char sep='\\0')
\note Requirement on T: utility::convert must be supported
(from yat 0.7 T=string is also supported)
\since New in yat 0.6
*/
template
void load(std::istream& is, std::vector >& vec, char sep='\0',
char line_sep='\n', bool ignore_empty=false, bool rectangle=true);
/**
\brief Fill a vector with elements from istream
Element separation has two modes depending on the value of \a
sep.
- If \a sep is the default '\\0' value then elements are
separated with white space characters. Multiple sequential white
space characters are treated as one separator.
- Setting \a sep to something else than the default value will
change the behaviour to use the \a sep character as the
separator between column elements. Multiple sequential \a sep
characters will be treated as separating elements with missing
values. Missing values are set to std::numeric_limits::quiet_NaN
\note Requirement on T: utility::convert must be supported
(from yat 0.7 T=string is also supported)
\since New in yat 0.6
*/
template
void load(std::istream& is, std::vector& vec, char sep='\0');
/**
\return base-2 logarithm of x
\since New in yat 0.10
*/
// c++11 provides std::log2 so perhaps we should call that one if
// availalable (but a bit tricky since this is a public header)
template
T log2(T x) { return std::log(x)/M_LN2; }
// private namespace
namespace detail {
/**
\brief convert s to t
used in function is and convert
\return true if conversion was successful
\internal
*/
template
bool convert(const std::string& s, T& t);
/**
Functor used in load function
*/
template
struct VectorPusher
{
/**
convert element to T and push on vec's back
\internal
*/
void operator()(const std::string& element, std::vector& vec)
{
if (!element.size())
vec.push_back(std::numeric_limits::quiet_NaN());
else {
vec.push_back(theplu::yat::utility::convert(element));
}
}
};
/**
specialization for string
\internal
*/
template<>
struct VectorPusher
{
/**
push element on vec's back
*/
void operator()(const std::string& element, std::vector& vec)
{
vec.push_back(element);
}
};
} // end of namespace detail
/**
\brief create a directory \a dir
\see http://linux.die.net/man/3/mkdir
\throw runtime_error if creation failed
*/
void mkdir(const std::string& dir, mode_t mode=0777);
/**
Similar to mkdir(const std::string&, mode_t).
No error if \a dir already exist. Make parent directories as needed.
*/
void mkdir_p(const std::string& dir, mode_t mode=0777);
/**
same as C function remove but throws errno_error at failure
\see http://linux.die.net/man/3/remove
*/
void remove(const std::string& fn);
/**
same as C function with same name but throws errno_error if error
is encountered
\see http://linux.die.net/man/3/rename
\since New in yat 0.10
*/
void rename(const std::string& from, const std::string to);
/**
In \a full_str replace every sub-string \a old_str with \a
new_str;
*/
void replace(std::string& full_str, std::string old_str, std::string new_str);
// template implementations
template
bool binary_weight(InputIterator first, InputIterator last,
OutputIterator result)
{
bool nan=false;
while (first!=last) {
if (std::isnan(*first)) {
*result=0;
nan=true;
}
else
*result = 1.0;
++first;
++result;
}
return nan;
}
// template implementations
template
std::string convert(T input)
{
std::ostringstream ss;
ss << input;
return ss.str();
}
template
T convert(const std::string& s)
{
T result;
if (!detail::convert(s, result))
throw runtime_error(std::string("yat::utility::convert(\"")+s+
std::string("\")"));
return result;
}
template
bool is(const std::string& s)
{
T tmp;
return detail::convert(s, tmp);
}
template
void load(std::istream& is, std::vector >& matrix,
char sep, char line_sep, bool ignore_empty,
bool rectangle)
{
size_t nof_columns=0;
std::string line;
while(getline(is, line, line_sep)){
if (line.empty() && ignore_empty)
continue;
matrix.push_back(std::vector());
std::vector& v=matrix.back();
v.reserve(nof_columns);
std::stringstream ss(line);
load(ss, v, sep);
// add NaN for final separator (or empty string if T=std::string)
detail::VectorPusher pusher;
if(sep!='\0' && !line.empty() && line[line.size()-1]==sep)
pusher("", v);
if (rectangle && nof_columns && v.size()!=nof_columns) {
std::ostringstream s;
s << "load stream error: "
<< "line " << matrix.size() << " has " << v.size()
<< " columns; expected " << nof_columns << " columns.";
throw utility::IO_error(s.str());
}
nof_columns = std::max(nof_columns, v.size());
}
// manipulate the state of the stream to be good
is.clear(std::ios::goodbit);
}
template
void load(std::istream& is, std::vector& vec, char sep)
{
detail::VectorPusher pusher;
std::string element;
bool ok=true;
while(true) {
if(sep=='\0')
ok=(is>>element);
else
ok=getline(is, element, sep);
if(!ok)
break;
pusher(element, vec);
}
}
namespace detail {
template
bool convert(const std::string& s, T& result)
{
if (!std::numeric_limits::is_signed) {
// first non-whitespace character
std::string::const_iterator iter = s.begin();
while (iter!=s.end() && std::isspace(*iter))
++iter;
// unsigned int cannot start with a '-' and with some compilers
// operation ss >> result won't fail so catch it like this instead.
if (iter==s.end() || *iter=='-')
return false;
}
std::istringstream ss(s);
ss >> result;
if (ss.fail()) {
if (is_nan(s)) {
result = std::numeric_limits::quiet_NaN();
return true;
}
if (is_equal(s, "inf")) {
result = std::numeric_limits::infinity();
return true;
}
if (is_equal(s, "-inf")) {
// unsigned types are caught in prologue
YAT_ASSERT(std::numeric_limits::is_signed);
result = -std::numeric_limits::infinity();
return true;
}
return false;
}
// Check that nothing is left on stream
std::string b;
ss >> b;
return b.empty();
}
} // of namespace detail
}}} // of namespace utility, yat, and theplu
#endif