Skip to content
Snippets Groups Projects
adiosTemplates.h 7.36 KiB
Newer Older
/*
 * adiosTemplates.h
 *
 *  Created on: Jan 26, 2017
 *      Author: wfg
 */

#ifndef ADIOSTEMPLATES_H_
#define ADIOSTEMPLATES_H_

wfg's avatar
wfg committed
/// \cond EXCLUDE_FROM_DOXYGEN
#include <cstring> //std::memcpy
#include <vector>
#include <thread>
wfg's avatar
wfg committed
#include <set>
#include <cmath> //std::sqrt
wfg's avatar
wfg committed
#include <iostream>
wfg's avatar
wfg committed
/// \endcond


/**
 * Get the primitive type in a string from a template
 * @return if T is a char, returns string = "char"
 */
template<class T> inline std::string GetType( ) noexcept { return "compound"; }
template<> inline std::string GetType<void>() noexcept { return "unknown"; }
template<> inline std::string GetType<char>() noexcept { return "char"; }
template<> inline std::string GetType<unsigned char>() noexcept { return "unsigned char"; }
template<> inline std::string GetType<short>() noexcept { return "short"; }
template<> inline std::string GetType<unsigned short>() noexcept { return "unsigned short"; }
template<> inline std::string GetType<int>() noexcept { return "int"; }
template<> inline std::string GetType<unsigned int>() noexcept { return "unsigned int"; }
template<> inline std::string GetType<long int>() noexcept { return "long int"; }
template<> inline std::string GetType<unsigned long int>() noexcept { return "unsigned long int"; }
wfg's avatar
wfg committed
template<> inline std::string GetType<long long int>() noexcept { return "long long int"; }
template<> inline std::string GetType<unsigned long long int>() noexcept { return "unsigned long long int"; }
template<> inline std::string GetType<float>() noexcept { return "float"; }
template<> inline std::string GetType<double>() noexcept { return "double"; }
template<> inline std::string GetType<long double>() noexcept { return "long double"; }
template<> inline std::string GetType<std::complex<float>>() noexcept { return "float complex"; }
template<> inline std::string GetType<std::complex<double>>() noexcept { return "double complex"; }
template<> inline std::string GetType<std::complex<long double>>() noexcept { return "long double complex"; }

/**
 * Check in types set if "type" is one of the aliases for a certain type,
 * (e.g. if type = integer is an accepted alias for "int", returning true)
 * @param type input to be compared with an alias
 * @param aliases set containing aliases to a certain type, typically Support::DatatypesAliases from Support.h
 * @return true: is an alias, false: is not
 */
template<class T>
bool IsTypeAlias( const std::string type,
		          const std::map<std::string, std::set<std::string>>& aliases ) noexcept
{
	if( type == GetType<T>() ) //most of the time we will pass the same type, which is a key in aliases
		return true;

	bool isAlias = false;
	if( aliases.at( GetType<T>() ).count( type ) == 1 )
	    isAlias = true;
	return isAlias;
wfg's avatar
wfg committed
/**
 * Get the minimum and maximum values in one loop
 * @param values array of primitives
 * @param size of the values array
 * @param min from values
 * @param max from values
 * @param nthreads threaded version not yet implemented
wfg's avatar
wfg committed
 */
template<class T> inline
void GetMinMax( const T* values, const std::size_t size, T& min, T& max, const unsigned int nthreads = 1 ) noexcept
wfg's avatar
wfg committed
{
    min = values[0];
wfg's avatar
wfg committed

    for( std::size_t i = 1; i < size; ++i )
wfg's avatar
wfg committed
    {
        if( values[i] < min )
        {
            min = values[i];
            continue;
        }

        if( values[i] > max  )
            max = values[i];
wfg's avatar
wfg committed
    }
}

/**
 * Overloaded version for complex types, gets the "doughnut" range between min and max modulus
 * @param values array of complex numbers
 * @param size of the values array
 * @param min modulus from values
 * @param max modulus from values
 */
template<class T> inline
void GetMinMax( const std::complex<T>* values, const std::size_t size, T& min, T& max, const unsigned int nthreads = 1 ) noexcept
{

    min = std::norm( values[0] );
    max = min;

    for( std::size_t i = 1; i < size; ++i )
    {
        T norm = std::norm( values[i] );

        if( norm < min )
        if( norm > max )
        {
            max = norm;
        }
    }

    min = std::sqrt( min );
    max = std::sqrt( max );
}
wfg's avatar
wfg committed

/**
 * threaded version of std::memcpy
 * @param dest
 * @param source
 * @param count total number of bytes (as in memcpy)
 * @param nthreads
wfg's avatar
wfg committed
 */
template<class T, class U>
void MemcpyThreads( T* destination, const U* source, std::size_t count, const unsigned int nthreads = 1 )
wfg's avatar
wfg committed
{
    // do not decompose tasks to less than 4MB pieces
    const std::size_t minBlockSize = 4194304;
    const std::size_t maxNThreads = std::max( (std::size_t)nthreads, count / minBlockSize );

    if( maxNThreads == 1)
wfg's avatar
wfg committed
    {
wfg's avatar
wfg committed
        std::memcpy( destination, source, count );
wfg's avatar
wfg committed
        return;
    }

    const std::size_t stride =  count/maxNThreads;
    const std::size_t remainder = count % maxNThreads;
wfg's avatar
wfg committed
    const std::size_t last = stride + remainder;
wfg's avatar
wfg committed

    std::vector<std::thread> memcpyThreads;
    memcpyThreads.reserve( maxNThreads );
wfg's avatar
wfg committed

    for( unsigned int t = 0; t < maxNThreads; ++t )
wfg's avatar
wfg committed
    {
        const size_t initialDestination = stride * t / sizeof(T);
        const size_t initialSource = stride * t / sizeof(U);
wfg's avatar
wfg committed

wfg's avatar
wfg committed
            memcpyThreads.push_back( std::thread( std::memcpy, &destination[initialDestination], &source[initialSource], last ) );
        else
            memcpyThreads.push_back( std::thread( std::memcpy, &destination[initialDestination], &source[initialSource], stride ) );
    }
    //Now join the threads (is this really needed?)
    for( auto& thread : memcpyThreads )
        thread.join( );
}

wfg's avatar
wfg committed
template< class T >
wfg's avatar
wfg committed
void MemcpyToBuffer( std::vector<char>& raw, std::size_t& position, const T* source, std::size_t size ) noexcept
wfg's avatar
wfg committed
{
wfg's avatar
wfg committed
    std::memcpy( &raw[position], source, size );
    position += size;
wfg's avatar
wfg committed

/**
 * Version that pushed to the end of the buffer, updates vec.size() automatically
 * @param raw
 * @param source using pointer notation
 * @param elements
 */
template<class T>
void CopyToBuffer( std::vector<char>& buffer, const T* source, const std::size_t elements = 1 ) noexcept
{
    const char* src = reinterpret_cast<const char*>( source );
    buffer.insert( buffer.end(), src, src + elements*sizeof(T) );
}

/**
 * Overloaded version to copies data to a specific location in the buffer, doesn't update vec.size()
 * @param raw
 * @param position
 * @param source
 * @param elements
 */
wfg's avatar
wfg committed
template<class T>
wfg's avatar
wfg committed
void CopyToBuffer( std::vector<char>& buffer, const std::size_t position, const T* source, const std::size_t elements = 1 ) noexcept
wfg's avatar
wfg committed
{
    const char* src = reinterpret_cast<const char*>( source );
wfg's avatar
wfg committed
    std::copy( src, src + elements*sizeof(T), buffer.begin() + position );
wfg's avatar
wfg committed
template<class T>
void CopyFromBuffer( T* destination, std::size_t elements, const std::vector<char>& raw, std::size_t& position ) noexcept
{
    std::copy( raw.begin() + position, raw.begin() + position + sizeof(T)*elements, reinterpret_cast<char*>(destination) );
    position += elements*sizeof(T);
}


wfg's avatar
wfg committed
template< class T >
wfg's avatar
wfg committed
void PrintValues( const std::string name, const char* buffer, const std::size_t position, const std::size_t elements )
wfg's avatar
wfg committed
{
wfg's avatar
wfg committed
    std::vector<T> values( elements );
    std::memcpy( values.data(), &buffer[position], elements * sizeof(T) );
wfg's avatar
wfg committed

wfg's avatar
wfg committed
    std::cout << "Read " << name << "\n";
    for( const auto value : values )
        std::cout << value << " ";
wfg's avatar
wfg committed

wfg's avatar
wfg committed
    std::cout << "\n";
} //end namespace


#endif /* ADIOSTEMPLATES_H_ */