Add Fastor library

This commit is contained in:
Bassem Girgis
2025-03-22 01:17:52 -05:00
parent 5546e086f6
commit 4dd5939693
132 changed files with 55086 additions and 0 deletions

View File

@@ -0,0 +1,99 @@
#ifndef EXTENDED_ALGORITHMS_H
#define EXTENDED_ALGORITHMS_H
#include <algorithm>
#include <functional>
#include <utility>
#include <type_traits>
#include <array>
#include <vector>
#include <numeric>
#include <cstring>
#if defined(FASTOR_UNIX_OS)
#include <sys/resource.h>
#endif
namespace Fastor {
// Implementation of STL iota to work on other types such as
// std::complex. For std::complex iota_impl increments the real
// part only
template<class ForwardIt, class T>
inline void iota_impl(ForwardIt first, ForwardIt last, T value)
{
while(first != last) {
*first++ = value;
value += T(1);
}
}
template <typename T, size_t N>
inline std::array<int,N> argsort(const std::array<T,N> &v) {
std::array<int,N> idx;
std::iota(idx.begin(),idx.end(),0);
std::sort(idx.begin(), idx.end(), [&v](int i1, int i2) {return v[i1] < v[i2];});
return idx;
}
template<typename T, size_t N, typename std::enable_if<std::is_arithmetic<T>::value,bool>::type = 0>
inline std::string itoa(const std::array<T,N>& arr) {
std::string out = std::to_string(arr[0]);
for (size_t i=1; i<N; ++i)
out += ","+std::to_string(arr[i]);
return out;
}
#if defined(FASTOR_UNIX_OS)
inline size_t set_stack_size(size_t size) {
// If the function does not work, copy-paste it within
// the body of the main
// size is stack size in MB (for instance provide 80 for 80MB)
// returns old stack size in MB
const rlim_t stacksize = size*1024*1024;
struct rlimit rl;
int result;
result = getrlimit(RLIMIT_STACK, &rl);
rlim_t old = rl.rlim_cur = stacksize;
if (result==0) {
if (rl.rlim_cur < stacksize) {
rl.rlim_cur = stacksize;
result = setrlimit(RLIMIT_STACK,&rl);
FASTOR_ASSERT(result !=0, "CHANGING STACK SIZE FAILED");
}
}
return old;
}
#endif
// Get sign of a number
template <typename T>
inline constexpr int signum(T x, [[gnu::unused]] std::false_type is_signed) {
return T(0) < x;
}
template <typename T>
inline constexpr int signum(T x, [[gnu::unused]] std::true_type is_signed) {
return (T(0) < x) - (x < T(0));
}
template <typename T>
inline constexpr int signum(T x) {
return signum(x, std::is_signed<T>());
}
// Get a string +/- based on sign
template <typename T> std::string signum_string(T val) {
return signum(val) == 1 ? "+" : "-";
}
} // end of namespace Fastor
#endif // EXTENDED_ALGORITHMS_H

View File

@@ -0,0 +1,219 @@
#ifndef PRINT_H
#define PRINT_H
#include <iostream>
#include <iomanip>
#include <vector>
#include <array>
#include <string>
#include <sstream>
#ifdef FASTOR_SSE2_IMPL
#include <emmintrin.h>
#endif
#ifdef FASTOR_AVX_IMPL
#include <immintrin.h>
#endif
namespace Fastor {
//! IOFormat class for tensors
struct IOFormat {
inline IOFormat(
int precision,
const std::string& colsep,
const std::string& rowsep,
const std::string& rowprefix,
const std::string& rowsuffix,
bool print_dimensions
) {
_precision = precision;
_colsep = colsep;
_rowsep = rowsep;
_rowprefix = rowprefix;
_rowsuffix = rowsuffix;
_print_dimensions = print_dimensions;
}
int _precision;
std::string _colsep;
std::string _rowsep;
std::string _rowprefix;
std::string _rowsuffix;
bool _print_dimensions;
};
#ifndef FASTOR_DEFINE_IO_FORMAT
#define FASTOR_DEFINE_IO_FORMAT {std::numeric_limits<double>::digits10,", ","\n","[","]",true};
// #define FASTOR_DEFINE_IO_FORMAT IOFormat(9,",","\n","[","]",true);
#endif
#ifdef FASTOR_SSE2_IMPL
inline void print(__m128 b) {
const float* a = (const float*)&b;
std::cout << a[0] << " " << a[1] << " " << a[2] << " " << a[3] << '\n';
}
inline void print(__m128d b) {
const double* a = (const double*)&b;
std::cout << a[0] << " " << a[1] << '\n';
}
#endif
#ifdef FASTOR_AVX_IMPL
inline void print(__m256 b) {
const float* a = (const float*)&b;
std::cout << a[0] << " " << a[1] << " " << a[2] << " " << a[3] << " " <<
a[4] << " " << a[5] << " " << a[6] << " " << a[7] << '\n';
}
inline void print(__m256d b) {
const double* a = (const double*)&b;
std::cout << a[0] << " " << a[1] << " " << a[2] << " " << a[3] << '\n';
}
#endif
template<typename T>
inline void print(const std::vector<T> &v) {
for (auto &k: v) {
std::cout << k << '\n';
}
std::cout << std::endl;
}
template<typename T, std::size_t N>
inline void print(const std::array<T,N> &arr) {
for (std::size_t i=0; i<N; i++) {
std::cout << arr[i] << '\n';
}
std::cout << std::endl;
}
template<typename T>
inline void print(const std::vector<std::vector<T>> &arr) {
for (std::size_t i=0; i<arr.size(); i++) {
for (std::size_t j=0; j<arr[i].size(); j++) {
std::cout << arr[i][j] << " ";
}
std::cout << '\n';
}
std::cout << std::endl;
}
template<typename T, std::size_t M>
inline void print(const std::vector<std::array<T,M>> &arr) {
for (std::size_t i=0; i<arr.size(); i++) {
for (std::size_t j=0; j<M; j++) {
std::cout << arr[i][j] << " ";
}
std::cout << '\n';
}
std::cout << std::endl;
}
template<typename T, std::size_t M, std::size_t N>
inline void print(const std::array<std::array<T,M>,N> &arr) {
for (std::size_t i=0; i<N; i++) {
for (std::size_t j=0; j<M; j++) {
std::cout << arr[i][j] << " ";
}
std::cout << '\n';
}
std::cout << std::endl;
}
template<typename T,std::size_t N>
inline void print(const T *arr) {
for (std::size_t i=0; i<N; i++) {
std::cout << arr[i] << '\n';
}
std::cout << std::endl;
}
template<typename T>
inline void print(const T &a) {
std::cout << a << '\n';
}
template<typename T, typename ... Rest>
inline void print(const T &first, const Rest& ... rest) {
print(first);
print(rest...);
}
inline void print() {
std::cout << '\n';
}
/*--------------------------------------*/
// Print horizontally
/*--------------------------------------*/
template<typename T>
inline void println(const std::vector<T> &v) {
for (auto &k: v) {
std::cout << k << ' ';
}
std::cout << '\n';
}
template<typename T, std::size_t N>
inline void println(const std::array<T,N> &arr) {
for (std::size_t i=0; i<N; i++) {
std::cout << arr[i] << " ";
}
std::cout << '\n';
}
template<typename T,std::size_t N>
inline void println(const T *arr) {
for (std::size_t i=0; i<N; i++) {
std::cout << arr[i] << " ";
}
std::cout << '\n';
}
template<typename T>
inline void println(const T &a) {
std::cout << a;
}
template<typename T, typename ... Rest>
inline void println(const T &first, const Rest& ... rest) {
println(first);
std::cout << ' ';
println(rest...);
}
inline void println() {
std::cout << ' ';
}
/*--------------------------------------*/
// Warn
/*--------------------------------------*/
template<typename T>
inline void warn(const T &a) {
std::cerr << a << '\n';
}
template<typename T, typename ... Rest>
inline void warn(const T &first, const Rest& ... rest) {
warn(first);
warn(rest...);
}
} // end of namespace
#endif

View File

@@ -0,0 +1,499 @@
#ifndef TIMEIT_H
#define TIMEIT_H
#include <algorithm>
#include <array>
#include <chrono>
#include <cmath>
#include <cstdint>
#include <iomanip>
#include <iostream>
#include <numeric>
#include <string>
#include <limits>
#include <tuple>
#include <utility>
#ifdef _WIN32
#include <intrin.h>
#endif
#include "Fastor/config/cpuid.h"
#ifndef FASTOR_NO_COLOUR_PRINT
/* FOREGROUND */
#define RST "\x1B[0m"
#define KRED "\x1B[31m"
#define KGRN "\x1B[32m"
#define KYEL "\x1B[33m"
#define KBLU "\x1B[34m"
#define KMAG "\x1B[35m"
#define KCYN "\x1B[36m"
#define KWHT "\x1B[37m"
#define FRED(x) KRED x RST
#define FGRN(x) KGRN x RST
#define FYEL(x) KYEL x RST
#define FBLU(x) KBLU x RST
#define FMAG(x) KMAG x RST
#define FCYN(x) KCYN x RST
#define FWHT(x) KWHT x RST
#define BOLD(x) "\x1B[1m" x RST
#define UNDL(x) "\x1B[4m" x RST
#else
#define RST
#define KRED
#define KGRN
#define KYEL
#define KBLU
#define KMAG
#define KCYN
#define KWHT
#define FRED(x) x
#define FGRN(x) x
#define FYEL(x) x
#define FBLU(x) x
#define FMAG(x) x
#define FCYN(x) x
#define FWHT(x) x
#define BOLD(x) x
#define UNDL(x) x
#endif // FASTOR_NO_COLOUR_PRINT
namespace Fastor {
#ifndef FASTOR_USE_RDTSC
#define FASTOR_USE_RDTSC
#endif
#ifndef FASTOR_SIMPLE_RDTSC
#define FASTOR_SIMPLE_RDTSC
#endif
#ifndef FASTOR_RDTSC_OVERHEAD
#define FASTOR_RDTSC_OVERHEAD 0UL
#endif
#ifndef FASTOR_BENCH_RUNTIME
#define FASTOR_BENCH_RUNTIME 1.0
#endif
// Get cpu cycle count
#ifdef _WIN32
inline uint64_t rdtsc() {
return __rdtsc();
}
inline uint64_t rdtsc_begin() {
return __rdtsc();
}
inline uint64_t rdtsc_end() {
return __rdtsc();
}
// Linux/GCC
#else
inline uint64_t rdtsc() {
unsigned int lo, hi;
// This does not clobber the register so rdtsc overwrites
// the register, see
// How to Benchmark Code Execution Times on Intel® IA-32
// and IA-64 Instruction Set Architectures pp-9
// https://intel.ly/3dXFfQN
#ifdef FASTOR_SIMPLE_RDTSC
__asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
return ((uint64_t)hi << 32) | lo;
#else
// Use this instead
__asm__ __volatile__ ("RDTSC\n\t"
"mov %%edx, %0\n\t"
"mov %%eax, %1\n\t": "=r" (hi), "=r" (lo) ::
// we need to clobber
// "%eax", "%edx" // IA-32
"%rax", "%rdx" // IA-64
);
#endif
return ((uint64_t)hi << 32) | lo;
}
#ifndef FASTOR_SIMPLE_RDTSC
// There is still one problem with the function above [rdtsc()]
// and that is it does not take care of cpu's out-of-order
// executation. In order to serialise we make a call to cpuid
// just before rdtsc. While this does not effect timing of the
// function itself, it introduces a lot of overhead when called
// multiple times within a loop
// https://intel.ly/3dXFfQN
inline uint64_t rdtsc_begin() {
unsigned int lo, hi;
__asm__ __volatile__ ("CPUID\n\t"
"RDTSC\n\t"
"mov %%edx, %0\n\t"
"mov %%eax, %1\n\t": "=r" (hi), "=r" (lo) ::
"%rax", "%rbx", "%rcx", "%rdx" // clobber memory
);
return ((uint64_t)hi << 32) | lo;
}
// and then a call to cpuid immediately after rdtsc
inline uint64_t rdtsc_end() {
unsigned int lo, hi;
__asm__ __volatile__("RDTSCP\n\t"
"mov %%edx, %0\n\t"
"mov %%eax, %1\n\t"
"CPUID\n\t": "=r" (hi), "=r" (lo)::
"%rax", "%rbx", "%rcx", "%rdx" // clobber memory
);
return ((uint64_t)hi << 32) | lo;
}
#else
inline uint64_t rdtsc_begin() { return rdtsc();}
inline uint64_t rdtsc_end() { return rdtsc();}
#endif
#endif
namespace useless {
inline
double format_time(double _time) {
if (_time >= 1.0e-3 && _time < 1.) return _time / 1e-3;
else if (_time >= 1.0e-6 && _time < 1.0e-3) return _time / 1e-6;
else if (_time < 1.0e-6) return _time / 1e-9;
else return _time;
}
inline
std::string format_time_string(double _time) {
if (_time >= 1.0e-3 && _time < 1.) return " ms";
#ifdef _WIN32
else if (_time >= 1.0e-6 && _time < 1.0e-3) return " us";
#else
else if (_time >= 1.0e-6 && _time < 1.0e-3) return " \xC2\xB5s";
#endif
else if (_time < 1.0e-6) return " ns";
else return " s";
}
}
#define FASTOR_FORMAT_BENCH_TIME_DISPLAY_1()\
std::cout << counter\
<< FGRN(BOLD(" runs, min time: "))\
<< std::setprecision(6) << useless::format_time(best_time) << useless::format_time_string(best_time) << ". " \
<< FGRN(BOLD("mean time: "))\
<< useless::format_time(mean_time) << useless::format_time_string(mean_time) << ". "\
<< FGRN(BOLD("max time: "))\
<< useless::format_time(worst_time) << useless::format_time_string(worst_time) << ". "\
<< FGRN(BOLD("Average no of RDTSC CPU cycles "))\
<< uint64_t(cycles/(1.0*counter)) << std::endl;\
#define FASTOR_FORMAT_BENCH_TIME_DISPLAY_2()\
std::cout << counter\
<< FGRN(BOLD(" runs, min time: "))\
<< std::setprecision(6) << useless::format_time(best_time) << useless::format_time_string(best_time) << ". " \
<< FGRN(BOLD("mean time: "))\
<< useless::format_time(mean_time) << useless::format_time_string(mean_time) << ". "\
<< FGRN(BOLD("max time: "))\
<< useless::format_time(worst_time) << useless::format_time_string(worst_time) << std::endl;\
template<typename T, typename ... Params, typename ... Args>
inline
std::tuple<double,double,double> // min, mean, max times
timeit(T (*func)(Params...), Args...args)
{
uint64_t counter = 1;
double accum_time = 0.0;
double mean_time = 0.0;
double best_time = std::numeric_limits<double>::max();
double worst_time = 0.0;
#if defined(FASTOR_USE_RDTSC)
uint64_t cycles = 0;
CPUID cpuID(0);
// A cycle is 1 second per max cpu frequency assuming constant_tsc
// Caution: in theory, there is no guarantee that rdtsc would have
// strong relation to CPU cycles
// https://stackoverflow.com/questions/36663379/seconds-calculation-using-rdtsc
double tsc_to_time = 1.0/cpuID.EBX();
// rdtsc_begin();
// rdtsc_end();
#endif
// We collect many samples
constexpr uint64_t num_samples = 100UL;
// Every sample is composed of multiple runs
constexpr uint64_t num_run_per_sample = 5E6;
auto __min_element = [&](std::array<double,num_samples> &a) {
double v = a[0];
for (uint64_t n = 1; n < a.size(); n++) {
if ((a[n] < v && (a[n] != 0 || a[n] > 1E-14) ) || v == 0) v = a[n];
}
return v;
};
std::array<double,num_samples> best_times;
std::fill(best_times.begin(),best_times.end(),std::numeric_limits<double>::max());
std::array<double,num_samples> mean_times = {};
std::array<double,num_samples> worst_times = {};
uint64_t num_collected_samples = 0;
for (uint64_t sample = 0; sample < num_samples && accum_time < FASTOR_BENCH_RUNTIME; ++sample) {
for (uint64_t run=0; run < num_run_per_sample; ++run)
{
#if defined(FASTOR_USE_SYSTEM_CLOCK)
std::chrono::time_point<std::chrono::system_clock> start, end;
start = std::chrono::system_clock::now();
#elif defined(FASTOR_USE_RDTSC)
auto cycle = rdtsc_begin();
#else
std::chrono::time_point<std::chrono::steady_clock> start, end;
start = std::chrono::steady_clock::now();
#endif
// Run the function
func(std::forward<Params>(args)...);
// Ignore the few first runs for cache hot measurements
if (run < 1 && sample < 1) continue;
#if defined(FASTOR_USE_RDTSC)
cycle = rdtsc_end() - cycle - FASTOR_RDTSC_OVERHEAD;
cycles += cycle;
double elapsed_t = tsc_to_time*cycle;
if (elapsed_t < best_times[sample] && (elapsed_t != 0.0 || elapsed_t > 1E-15)) {
best_times[sample] = elapsed_t;
};
if (elapsed_t > worst_times[sample]) {
worst_times[sample] = elapsed_t;
};
mean_times[sample] += elapsed_t;
accum_time += elapsed_t;
#elif defined(FASTOR_USE_SYSTEM_CLOCK)
end = std::chrono::system_clock::now();
std::chrono::duration<double> elapsed_seconds = end-start;
if (elapsed_seconds.count() < best_times[sample] && elapsed_seconds.count() != 0.0) {
best_times[sample] = elapsed_seconds.count();
};
if (elapsed_seconds.count() > worst_times[sample]) {
worst_times[sample] = elapsed_seconds.count();
};
mean_times[sample] += elapsed_seconds.count();
accum_time += elapsed_seconds.count();
#else
end = std::chrono::steady_clock::now();
std::chrono::duration<double> elapsed_seconds = end-start;
if (elapsed_seconds.count() < best_times[sample] && elapsed_seconds.count() != 0.0) {
best_times[sample] = elapsed_seconds.count();
};
if (elapsed_seconds.count() > worst_times[sample]) {
worst_times[sample] = elapsed_seconds.count();
};
mean_times[sample] += elapsed_seconds.count();
accum_time += elapsed_seconds.count();
#endif
counter++;
if (accum_time > FASTOR_BENCH_RUNTIME)
{
break;
}
}
num_collected_samples++;
}
best_time = __min_element(best_times);
worst_time = *std::max_element(worst_times.begin(),worst_times.begin()+num_collected_samples);
mean_time = std::accumulate(mean_times.begin(), mean_times.begin()+num_collected_samples, 0.0);
mean_time /= (double)counter;
#if defined(FASTOR_USE_RDTSC)
FASTOR_FORMAT_BENCH_TIME_DISPLAY_1()
#else
FASTOR_FORMAT_BENCH_TIME_DISPLAY_2()
#endif
return std::make_tuple(best_time, mean_time, worst_time);
}
#if 0
// One loop timer
template<typename T, typename ... Params, typename ... Args>
inline
std::tuple<double,double,double> // min, mean, max times
timeit(T (*func)(Params...), Args...args)
{
uint64_t counter = 1;
double mean_time = 0.0;
double best_time = std::numeric_limits<double>::max();
double worst_time = 0.0;
#if defined(FASTOR_USE_RDTSC)
uint64_t cycles = 0;
CPUID cpuID(0);
// A cycle is 1 second per max cpu frequency assuming constant_tsc
// Caution: in theory, there is no guarantee that rdtsc would have
// strong relation to CPU cycles
// https://stackoverflow.com/questions/36663379/seconds-calculation-using-rdtsc
double tsc_to_time = 1.0/cpuID.EBX();
// rdtsc_begin();
// rdtsc_end();
#endif
for (auto iter=0; iter<1e09; ++iter)
{
#if defined(FASTOR_USE_SYSTEM_CLOCK)
std::chrono::time_point<std::chrono::system_clock> start, end;
start = std::chrono::system_clock::now();
#elif defined(FASTOR_USE_RDTSC)
auto cycle = rdtsc_begin();
#else
std::chrono::time_point<std::chrono::steady_clock> start, end;
start = std::chrono::steady_clock::now();
#endif
// Run the function
func(std::forward<Params>(args)...);
// Ignore the few first runs for cache hot measurements
if (iter < 1) continue;
#if defined(FASTOR_USE_RDTSC)
cycle = rdtsc_end() - cycle;
cycles += cycle;
double elapsed_t = tsc_to_time*cycle;
if (elapsed_t < best_time && elapsed_t != 0.0) {
best_time = elapsed_t;
};
if (elapsed_t > worst_time) {
worst_time = elapsed_t;
};
mean_time += elapsed_t;
#else
end = std::chrono::steady_clock::now();
std::chrono::duration<double> elapsed_seconds = end-start;
if (elapsed_seconds.count() < best_time && elapsed_seconds.count() != 0.0) {
best_time = elapsed_seconds.count();
};
if (elapsed_seconds.count() > worst_time) {
worst_time = elapsed_seconds.count();
};
mean_time += elapsed_seconds.count();
#endif
counter++;
if (mean_time > FASTOR_BENCH_RUNTIME)
{
mean_time /= (double)counter;
#if defined(FASTOR_USE_RDTSC)
FASTOR_FORMAT_BENCH_TIME_DISPLAY_1()
#else
FASTOR_FORMAT_BENCH_TIME_DISPLAY_2()
#endif
break;
}
}
return std::make_tuple(best_time, mean_time, worst_time);
}
#endif
// timeit with return values
template<typename T, typename ... Params, typename ... Args>
inline std::tuple<double,uint64_t> rtimeit(T (*func)(Params...), Args...args)
{
uint64_t counter = 1;
double mean_time = 0.0;
double best_time = std::numeric_limits<double>::max();
double worst_time = 0;
uint64_t cycles = 0;
for (auto iter=0; iter<1e09; ++iter)
{
std::chrono::time_point<std::chrono::system_clock> start, end;
start = std::chrono::system_clock::now();
auto cycle = rdtsc();
// Run the function
func(std::forward<Params>(args)...);
// Ignore the few first runs for cache hot measurements
if (iter < 1) continue;
end = std::chrono::system_clock::now();
std::chrono::duration<double> elapsed_seconds = end-start;
cycle = rdtsc() - cycle;
cycles += cycle;
mean_time += elapsed_seconds.count();
if (elapsed_seconds.count() < best_time && elapsed_seconds.count() != 0) {
best_time = elapsed_seconds.count();
};
if (elapsed_seconds.count() > worst_time) {
worst_time = elapsed_seconds.count();
};
counter++;
if (mean_time > FASTOR_BENCH_RUNTIME)
{
mean_time /= counter;
break;
}
}
return std::make_tuple(mean_time,uint64_t(cycles/(1.0*counter)));
}
// tic toc
template<typename T=double>
struct timer
{
inline void tic() {t0 = std::chrono::steady_clock::now();}
inline T toc(const std::string &msg="") {
using namespace std::chrono;
elapsed = steady_clock::now() - t0;
T elapsed_seconds = duration<T,seconds::period>(elapsed).count();
if (msg.empty()) std::cout << FGRN(BOLD("Elapsed time is: ")) <<
elapsed_seconds << FGRN(BOLD(" seconds \n"));
else std::cout << std::string("\x1B[32m ")+std::string("\x1B[1m")+msg+std::string("\x1B[0m")+" "
<< elapsed_seconds << FGRN(BOLD(" seconds \n"));
return elapsed_seconds;
}
std::chrono::steady_clock::time_point t0;
std::chrono::steady_clock::duration elapsed;
};
// Define a no operation function
inline void no_op(){}
} // end of namespace
#endif

View File

@@ -0,0 +1,84 @@
#ifndef TYPE_NAMES_H
#define TYPE_NAMES_H
#if __cplusplus >= 201703L
#include <string_view>
namespace Fastor {
namespace useless {
class probe_type;
inline void extract_type(std::string_view& name, std::string_view probe_type_name);
} // useless
template <typename T>
constexpr std::string_view type_name() {
std::string_view probe_type_name("class useless::probe_type");
const std::string_view class_specifier("class ");
std::string_view name;
#ifdef __clang__
name = __PRETTY_FUNCTION__;
probe_type_name.remove_prefix (class_specifier.length ());
#elif defined(__GNUC__)
name = __PRETTY_FUNCTION__;
probe_type_name.remove_prefix (class_specifier.length ());
#elif defined(_MSC_VER)
name = __FUNCSIG__;
#endif
useless::extract_type(name, probe_type_name);
return name;
}
namespace useless {
inline void extract_type(std::string_view& name, std::string_view probe_type_name) {
if (name.find(probe_type_name) == std::string_view::npos) {
//For known type probe_type get raw name and then prefix and suffix sizes
const std::string_view probe_type_raw_name = type_name<probe_type> ();
const size_t prefix_size = probe_type_raw_name.find(probe_type_name);
const size_t suffix_size = probe_type_raw_name.length () - prefix_size - probe_type_name.length();
name.remove_prefix (prefix_size);
name.remove_suffix (suffix_size);
}
}
} // useless
} // end of namespace Fastor
#else
#include <string>
#include <typeinfo>
#include <type_traits>
#include <memory>
#if defined(__GNUC__)
#include <cxxabi.h>
#endif
namespace Fastor {
template <class T>
std::string type_name()
{
typedef typename std::remove_reference<T>::type TR;
std::unique_ptr<char, void(*)(void*)> own(nullptr, std::free);
#if defined(__GNUC__)
int status = 0;
char* demangled = abi::__cxa_demangle(typeid(TR).name(), nullptr, nullptr, &status);
std::string r = own != nullptr ? own.get() : std::string(demangled);
#else
std::string r = own != nullptr ? own.get() : typeid(TR).name();
#endif
if (std::is_const<TR>::value)
r += " const";
if (std::is_volatile<TR>::value)
r += " volatile";
if (std::is_lvalue_reference<T>::value)
r += "&";
else if (std::is_rvalue_reference<T>::value)
r += "&&";
return r;
}
} // end of namespace Fastor
#endif
#endif // TYPE_NAMES_H

View File

@@ -0,0 +1,9 @@
#ifndef UTILS_H
#define UTILS_H
#include "Fastor/util/timeit.h"
#include "Fastor/util/print.h"
#include "Fastor/util/write.h"
#include "Fastor/util/types.h"
#endif

View File

@@ -0,0 +1,43 @@
#ifndef WRITE_H
#define WRITE_H
#include <fstream>
namespace Fastor {
template<typename T>
inline void write(const std::string &filename, const T &a) {
// if ( filename.empty() )
// filename = "output";
std::ofstream outfile;
outfile.open(filename,std::ios_base::app);
outfile << a << "\n";
outfile.close();
}
template<typename T, typename ... Rest>
inline void write(const std::string &filename, const T &first, const Rest& ... rest) {
write(filename,first);
write(filename,rest...);
}
inline void write(const std::string &filename) {
std::ofstream outfile;
outfile.open(filename,std::ios_base::app);
outfile << "\n";
outfile.close();
}
//void write() {
// const std::string &filename = "output";
// std::ofstream outfile;
// outfile.open(filename,std::ios_base::app);
// outfile << "\n";
// outfile.close();
//}
} // end of namespace
#endif // WRITE_H