Commit 1ce04c30 authored by Martin Reinecke's avatar Martin Reinecke
Browse files

creation

parents
/*
* This file is part of libcxxsupport.
*
* libcxxsupport 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 2 of the License, or
* (at your option) any later version.
*
* libcxxsupport 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 libcxxsupport; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* libcxxsupport is being developed at the Max-Planck-Institut fuer Astrophysik
* and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt
* (DLR).
*/
/*! \file datatypes.h
* This file defines various platform-independent data types.
* If any of the requested types is not available, compilation aborts
* with an error (unfortunately a rather obscure one).
*
* Copyright (C) 2004-2015 Max-Planck-Society
* \author Martin Reinecke
*/
#ifndef MRBASE_DATATYPES_H
#define MRBASE_DATATYPES_H
#include <string>
#include <cstddef>
#include <cstdint>
#include "error_handling.h"
using int8 = std::int8_t;
using uint8 = std::uint8_t;
using int16 = std::int16_t;
using uint16 = std::uint16_t;
using int32 = std::int32_t;
using uint32 = std::uint32_t;
using int64 = std::int64_t;
using uint64 = std::uint64_t;
using float32 = float;
using float64 = double;
/*! unsigned integer type which should be used for array sizes */
using tsize = std::size_t;
/*! signed integer type which should be used for relative array indices */
using tdiff = std::ptrdiff_t;
/*! Returns a C string describing the data type \a T. */
template<typename T> inline const char *type2typename ()
{ myfail(T::UNSUPPORTED_DATA_TYPE); }
template<> inline const char *type2typename<signed char> ()
{ return "signed char"; }
template<> inline const char *type2typename<unsigned char> ()
{ return "unsigned char"; }
template<> inline const char *type2typename<short> ()
{ return "short"; }
template<> inline const char *type2typename<unsigned short> ()
{ return "unsigned short"; }
template<> inline const char *type2typename<int> ()
{ return "int"; }
template<> inline const char *type2typename<unsigned int> ()
{ return "unsigned int"; }
template<> inline const char *type2typename<long> ()
{ return "long"; }
template<> inline const char *type2typename<unsigned long> ()
{ return "unsigned long"; }
template<> inline const char *type2typename<long long> ()
{ return "long long"; }
template<> inline const char *type2typename<unsigned long long> ()
{ return "unsigned long long"; }
template<> inline const char *type2typename<float> ()
{ return "float"; }
template<> inline const char *type2typename<double> ()
{ return "double"; }
template<> inline const char *type2typename<long double> ()
{ return "long double"; }
template<> inline const char *type2typename<bool> ()
{ return "bool"; }
template<> inline const char *type2typename<std::string> ()
{ return "std::string"; }
/*! mapping of "native" data types to integer constants */
enum NDT {
NAT_CHAR,
NAT_SCHAR,
NAT_UCHAR,
NAT_SHORT,
NAT_USHORT,
NAT_INT,
NAT_UINT,
NAT_LONG,
NAT_ULONG,
NAT_LONGLONG,
NAT_ULONGLONG,
NAT_FLOAT,
NAT_DOUBLE,
NAT_LONGDOUBLE,
NAT_BOOL,
NAT_STRING };
/*! Returns the \a NDT constant associated with \a T. */
template<typename T> inline NDT nativeType()
{ myfail(T::UNSUPPORTED_DATA_TYPE); }
template<> inline NDT nativeType<char> () { return NAT_CHAR; }
template<> inline NDT nativeType<signed char> () { return NAT_SCHAR; }
template<> inline NDT nativeType<unsigned char> () { return NAT_UCHAR; }
template<> inline NDT nativeType<short> () { return NAT_SHORT; }
template<> inline NDT nativeType<unsigned short> () { return NAT_USHORT; }
template<> inline NDT nativeType<int> () { return NAT_INT; }
template<> inline NDT nativeType<unsigned int> () { return NAT_UINT; }
template<> inline NDT nativeType<long> () { return NAT_LONG; }
template<> inline NDT nativeType<unsigned long> () { return NAT_ULONG; }
template<> inline NDT nativeType<long long> () { return NAT_LONGLONG; }
template<> inline NDT nativeType<unsigned long long>() { return NAT_ULONGLONG; }
template<> inline NDT nativeType<float> () { return NAT_FLOAT; }
template<> inline NDT nativeType<double> () { return NAT_DOUBLE; }
template<> inline NDT nativeType<long double> () { return NAT_LONGDOUBLE;}
template<> inline NDT nativeType<bool> () { return NAT_BOOL; }
template<> inline NDT nativeType<std::string> () { return NAT_STRING; }
/*! Returns the size (in bytes) of the native data type \a type. */
inline int ndt2size (NDT type)
{
switch (type)
{
case NAT_CHAR :
case NAT_SCHAR :
case NAT_UCHAR : return sizeof(char);
case NAT_SHORT :
case NAT_USHORT : return sizeof(short);
case NAT_INT :
case NAT_UINT : return sizeof(int);
case NAT_LONG :
case NAT_ULONG : return sizeof(long);
case NAT_LONGLONG :
case NAT_ULONGLONG : return sizeof(long long);
case NAT_FLOAT : return sizeof(float);
case NAT_DOUBLE : return sizeof(double);
case NAT_LONGDOUBLE: return sizeof(long double);
case NAT_BOOL : return sizeof(bool);
default:
myfail ("ndt2size: unsupported data type");
}
}
#endif
#include "error_handling.h"
using namespace std;
bool abort_in_progress__ = false;
ostream &CodeLocation::print(ostream &os) const
{
os << "file: " << file << ", line: " << line;
if (func) os << ", function: " << func;
return os;
}
void killjob__()
{
// perhaps print stack trace?
exit(1);
}
#ifndef MRBASE_ERROR_HANDLING_H
#define MRBASE_ERROR_HANDLING_H
#include <iostream>
#include <cstdlib>
#if defined (__GNUC__)
#define LOC_ CodeLocation(__FILE__, __LINE__, __PRETTY_FUNCTION__)
#else
#define LOC_ CodeLocation(__FILE__, __LINE__)
#endif
#define myfail(...) \
do { \
if (!abort_in_progress__) \
{ \
abort_in_progress__ = true; \
streamDump__(std::cerr, LOC_, "\n", ##__VA_ARGS__, "\n"); \
killjob__(); \
} \
std::exit(1); \
} while(0)
#define myassert(cond,...) \
do { \
if (cond); \
else { myfail("Assertion failure\n", ##__VA_ARGS__); } \
} while(0)
// to be replaced with std::source_location once available
class CodeLocation
{
private:
const char *file, *func;
int line;
public:
CodeLocation(const char *file_, int line_, const char *func_=nullptr)
: file(file_), func(func_), line(line_) {}
std::ostream &print(std::ostream &os) const;
};
inline std::ostream &operator<<(std::ostream &os, const CodeLocation &loc)
{ return loc.print(os); }
extern bool abort_in_progress__;
void killjob__();
#if 1
template<typename T>
inline void streamDump__(std::ostream &os, const T& value)
{ os << value; }
template<typename T, typename ... Args>
inline void streamDump__(std::ostream &os, const T& value,
const Args& ... args)
{
os << value;
streamDump__(os, args...);
}
#else
// hyper-elegant C++2017 version
template<typename ...Args>
inline void streamDump__(std::ostream &os, Args&&... args)
{ (os << ... << args); }
#endif
#endif
#ifndef MRBASE_MISC_UTILS_H
#define MRBASE_MISC_UTILS_H
#include <type_traits>
/* Unsorted small useful functions needed in many situations */
/*! Returns the smallest multiple of \a sz that is >= \a n. */
template<typename I, typename I2> inline I roundup_to_multiple_of (I n, I2 sz)
{
static_assert(std::is_integral<I>::value, "integer type needed");
static_assert(std::is_integral<I2>::value, "integer type needed");
return ((n+sz-1)/sz)*sz;
}
/*! Returns the largest integer \a n that fulfills \a 2^n<=arg. */
template<typename I> inline int ilog2 (I arg)
{
static_assert(std::is_integral<I>::value, "integer type needed");
#ifdef __GNUC__
if (arg==0) return 0;
if (sizeof(I)<=sizeof(int))
return 8*sizeof(int)-1-__builtin_clz(arg);
if (sizeof(I)==sizeof(long))
return 8*sizeof(long)-1-__builtin_clzl(arg);
if (sizeof(I)==sizeof(long long))
return 8*sizeof(long long)-1-__builtin_clzll(arg);
#endif
int res=0;
while (arg > 0xFFFF) { res+=16; arg>>=16; }
if (arg > 0x00FF) { res|=8; arg>>=8; }
if (arg > 0x000F) { res|=4; arg>>=4; }
if (arg > 0x0003) { res|=2; arg>>=2; }
if (arg > 0x0001) { res|=1; }
return res;
}
/*! Returns the smallest power of 2 that is >= \a n. */
template<typename I> inline I roundup_to_power_of_2 (I n)
{
static_assert(std::is_integral<I>::value, "integer type needed");
if (n<=1) return 1;
return I(1)<<(ilog2(n-1)+1);
}
#endif
/*
* This file is part of libcxxsupport.
*
* libcxxsupport 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 2 of the License, or
* (at your option) any later version.
*
* libcxxsupport 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 libcxxsupport; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* libcxxsupport is being developed at the Max-Planck-Institut fuer Astrophysik
* and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt
* (DLR).
*/
/*
* This file contains the implementation of various convenience functions
* used by the Planck LevelS package.
*
* Copyright (C) 2002-2014 Max-Planck-Society
* Author: Martin Reinecke
*/
#include <sstream>
#include <fstream>
#include <iostream>
#include <iomanip>
#include <string>
#include <cstring>
#include <cctype>
#include "string_utils.h"
using namespace std;
string trim (const string &orig)
{
string::size_type p1=orig.find_first_not_of(" \t");
if (p1==string::npos) return "";
string::size_type p2=orig.find_last_not_of(" \t");
return orig.substr(p1,p2-p1+1);
}
template<typename T> string dataToString (const T &x)
{
ostringstream strstrm;
strstrm << x;
return trim(strstrm.str());
}
template<> string dataToString (const bool &x)
{ return x ? "T" : "F"; }
template<> string dataToString (const string &x)
{ return trim(x); }
template<> string dataToString (const float &x)
{
ostringstream strstrm;
strstrm << setprecision(8) << x;
return trim(strstrm.str());
}
template<> string dataToString (const double &x)
{
ostringstream strstrm;
strstrm << setprecision(16) << x;
return trim(strstrm.str());
}
template<> string dataToString (const long double &x)
{
ostringstream strstrm;
strstrm << setprecision(25) << x;
return trim(strstrm.str());
}
template string dataToString (const signed char &x);
template string dataToString (const unsigned char &x);
template string dataToString (const short &x);
template string dataToString (const unsigned short &x);
template string dataToString (const int &x);
template string dataToString (const unsigned int &x);
template string dataToString (const long &x);
template string dataToString (const unsigned long &x);
template string dataToString (const long long &x);
template string dataToString (const unsigned long long &x);
string intToString(int64 x, tsize width)
{
ostringstream strstrm;
(x>=0) ? strstrm << setw(width) << setfill('0') << x
: strstrm << "-" << setw(width-1) << setfill('0') << -x;
string res = strstrm.str();
myassert(res.size()==width,"number too large");
return trim(res);
}
namespace {
void end_stringToData (const string &x, const char *tn, istringstream &strstrm)
{
myassert (strstrm,
"conversion error in stringToData<", tn, ">('", x, "')");
string rest;
strstrm >> rest;
// rest=trim(rest);
myassert (rest.length()==0,
"conversion error in stringToData<", tn, ">('", x, "')");
}
} // unnamed namespace
template<typename T> void stringToData (const string &x, T &value)
{
istringstream strstrm(x);
strstrm >> value;
end_stringToData (x,type2typename<T>(),strstrm);
}
template<> void stringToData (const string &x, string &value)
{ value = trim(x); }
template<> void stringToData (const string &x, bool &value)
{
const char *fval[] = {"f","n","false",".false."};
const char *tval[] = {"t","y","true",".true."};
for (tsize i=0; i< sizeof(fval)/sizeof(fval[0]); ++i)
if (equal_nocase(x,fval[i])) { value=false; return; }
for (tsize i=0; i< sizeof(tval)/sizeof(tval[0]); ++i)
if (equal_nocase(x,tval[i])) { value=true; return; }
myfail("conversion error in stringToData<bool>(",x,")");
}
template void stringToData (const string &x, signed char &value);
template void stringToData (const string &x, unsigned char &value);
template void stringToData (const string &x, short &value);
template void stringToData (const string &x, unsigned short &value);
template void stringToData (const string &x, int &value);
template void stringToData (const string &x, unsigned int &value);
template void stringToData (const string &x, long &value);
template void stringToData (const string &x, unsigned long &value);
template void stringToData (const string &x, long long &value);
template void stringToData (const string &x, unsigned long long &value);
template void stringToData (const string &x, float &value);
template void stringToData (const string &x, double &value);
template void stringToData (const string &x, long double &value);
bool equal_nocase (const string &a, const string &b)
{
if (a.size()!=b.size()) return false;
for (tsize m=0; m<a.size(); ++m)
if (tolower(a[m])!=tolower(b[m])) return false;
return true;
}
string tolower(const string &input)
{
string result=input;
for (tsize m=0; m<result.size(); ++m)
result[m]=char(tolower(result[m]));
return result;
}
void parse_file (const string &filename, map<string,string> &dict)
{
int lineno=0;
dict.clear();
ifstream inp(filename.c_str());
myassert (inp, "Could not open parameter file '", filename, "'.");
while (inp)
{
string line;
getline(inp, line);
++lineno;
// remove potential carriage returns at the end of the line
line=line.substr(0,line.find("\r"));
line=line.substr(0,line.find("#"));
line=trim(line);
if (line.size()>0)
{
string::size_type eqpos=line.find("=");
if (eqpos!=string::npos)
{
string key=trim(line.substr(0,eqpos)),
value=trim(line.substr(eqpos+1,string::npos));
if (key=="")
cerr << "Warning: empty key in '" << filename << "', line "
<< lineno << endl;
else
{
if (dict.find(key)!=dict.end())
cerr << "Warning: key '" << key << "' multiply defined in '"
<< filename << "', line " << lineno << endl;
dict[key]=value;
}
}
else
cerr << "Warning: unrecognized format in '" << filename << "', line "
<< lineno << ":\n" << line << endl;
}
}
}
namespace {
bool isParam (const string &s)
{
if (s.size()<2) return false;
if (s[0]!='-') return false;
return !(isdigit(s[1]) || (s[1]=='.'));
}
} // unnamed namespace
void parse_cmdline_classic (int argc, const char **argv,
const vector<string> &leading_args, map<string,string> &dict)
{
dict.clear();
myassert(tsize(argc)>leading_args.size(),"not enough arguments");
for (tsize i=0; i<leading_args.size(); ++i)
dict[leading_args[i]] = argv[i+1];
int curarg=leading_args.size()+1;
while (curarg<argc)
{
string param=argv[curarg];
myassert(isParam(param),"unrecognized command line format");
if ((curarg==argc-1) || isParam(argv[curarg+1]))
{
dict[param.substr(1)]="true";
++curarg;
}
else
{
dict[param.substr(1)]=argv[curarg+1];
curarg+=2;
}
}
}
void parse_cmdline_classic (int argc, const char **argv,
map<string,string> &dict)
{ parse_cmdline_classic (argc, argv, vector<string>(), dict); }
void parse_cmdline_equalsign (int argc, const char **argv,
const vector<string> &leading_args, map<string,string> &dict)
{
dict.clear();
myassert(tsize(argc)>leading_args.size(),"not enough arguments");
for (tsize i=0; i<leading_args.size(); ++i)
dict[leading_args[i]] = argv[i+1];
for (int i=leading_args.size()+1; i<argc; ++i)
{
string arg=trim(argv[i]);
if (arg.size()>0)
{
string::size_type eqpos=arg.find("=");
if (eqpos!=string::npos)
{
string key=trim(arg.substr(0,eqpos)),
value=trim(arg.substr(eqpos+1,string::npos));
if (key=="")
cerr << "Warning: empty key in argument'" << arg << "'" << endl;
else
{
if (dict.find(key)!=dict.end())
cerr << "Warning: key '" << key << "' multiply defined" << endl;
dict[key]=value;
}
}
else
cerr << "Warning: unrecognized format in argument '" << arg << "'"
<< endl;
}
}
}
void parse_cmdline_equalsign (int argc, const char **argv,
map<string,string> &dict)
{ parse_cmdline_equalsign (argc, argv, vector<string>(), dict); }
namespace {
template<typename T> void split (istream &stream, vector<T> &list)
{
list.clear();
while (stream)
{
string word;
stream >> word;
myassert (stream||stream.eof(),
"error while splitting stream into ", type2typename<T>(), " components");
if (stream) list.push_back(stringToData<T>(word));
}
}
} // unnamed namespace
template<typename T> void split (const string &inp, vector<T> &list)
{
istringstream stream(inp);
split (stream,list);
}
template void split (const string &inp, vector<string> &list);
template void split (const string &inp, vector<float> &list);
template void split (const string