ENH: add UPstreamTraits support to map data types and opcodes
The front-end traits: - UPstream_dataType trait: This wrapper is unwinds the type to check against base/alias, but also checks if it is a component aggregate of a supported UPstream data type. This will be that main entry point for usage. - UPstream_opType trait: Provides a mapping of OpenFOAM ops to their MPI equivalent. The \c opcode_id is the corresponding internal representation. The lower-level traits (not normally used within coding) - UPstream_base_dataType trait: Tests true/false if the specified data type has an internal MPI equivalent. The \c datatype_id is the corresponding internal enumeration. Even if this tests as false, it will always return \c type_byte as the fallback for general contiguous data - UPstream_alias_dataType trait: Provides mapping for <int/long/long long,...> to the fundamental 32/64 integrals, since <int/long/long long,...> may not otherwise directly map on all systems. NOTE: can use the updates Test-machine-sizes test application to determine if all data types and aliases are properly defined on different systems
This commit is contained in:
parent
bf60a124ab
commit
dccdb263e8
@ -5,7 +5,7 @@
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2018-2022 OpenCFD Ltd.
|
||||
Copyright (C) 2018-2025 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -25,9 +25,12 @@ License
|
||||
|
||||
Description
|
||||
Test the sizeof for basic types.
|
||||
Also tests how the data mapping of OpenFOAM types to UPstream (MPI)
|
||||
type ids are handled.
|
||||
|
||||
Can be compiled and run without any OpenFOAM libraries.
|
||||
|
||||
g++ -std=c++11 -oTest-machine-sizes Test-machine-sizes.cpp
|
||||
g++ -std=c++17 -oTest-machine-sizes Test-machine-sizes.cpp
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
@ -37,6 +40,114 @@ Description
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <typeinfo>
|
||||
#include <type_traits>
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
// Partial copy from UPstream.H
|
||||
|
||||
//- Some MPI data types
|
||||
//
|
||||
//- Mapping of some fundamental and aggregate types to MPI data types
|
||||
enum class dataTypes : int
|
||||
{
|
||||
// Builtin Types [8]:
|
||||
DataTypes_begin, //!< Begin builtin types (internal use)
|
||||
type_byte = DataTypes_begin, // also for char, unsigned char
|
||||
type_int32,
|
||||
type_int64,
|
||||
type_uint32,
|
||||
type_uint64,
|
||||
type_float,
|
||||
type_double,
|
||||
type_long_double,
|
||||
invalid
|
||||
};
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
// Partial copy from UPstreamTraits.H
|
||||
|
||||
//- A supported UPstream data type (intrinsic or user-defined)
|
||||
template<class T>
|
||||
struct UPstream_base_dataType : std::false_type
|
||||
{
|
||||
static constexpr auto datatype_id = dataTypes::invalid;
|
||||
};
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
// Specializations of the above,
|
||||
// each to match the elements of UPstream::dataTypes
|
||||
|
||||
#undef defineUPstreamDataTraits
|
||||
#define defineUPstreamDataTraits(TypeId, Type) \
|
||||
template<> struct UPstream_base_dataType<Type> : std::true_type \
|
||||
{ \
|
||||
static constexpr auto datatype_id = dataTypes::TypeId; \
|
||||
};
|
||||
|
||||
|
||||
defineUPstreamDataTraits(type_byte, char);
|
||||
defineUPstreamDataTraits(type_byte, unsigned char);
|
||||
defineUPstreamDataTraits(type_int32, int32_t);
|
||||
defineUPstreamDataTraits(type_int64, int64_t);
|
||||
defineUPstreamDataTraits(type_uint32, uint32_t);
|
||||
defineUPstreamDataTraits(type_uint64, uint64_t);
|
||||
defineUPstreamDataTraits(type_float, float);
|
||||
defineUPstreamDataTraits(type_double, double);
|
||||
defineUPstreamDataTraits(type_long_double, long double);
|
||||
|
||||
#undef defineUPstreamDataTraits
|
||||
|
||||
|
||||
//- Explicit handling of data type aliases. This is necessary since
|
||||
//- different systems map things like 'unsigned long' differently but we
|
||||
//- restrict ourselves to int32/int64 types
|
||||
template<class T>
|
||||
struct UPstream_alias_dataType
|
||||
:
|
||||
std::bool_constant
|
||||
<
|
||||
// Base type (no alias needed)
|
||||
UPstream_base_dataType<std::remove_cv_t<T>>::value ||
|
||||
(
|
||||
// Or some int 32/64 type to re-map
|
||||
std::is_integral_v<T>
|
||||
&& (sizeof(T) == sizeof(int32_t) || sizeof(T) == sizeof(int64_t))
|
||||
)
|
||||
>
|
||||
{
|
||||
// Is it using the base type? (no alias needed)
|
||||
static constexpr bool is_base =
|
||||
UPstream_base_dataType<std::remove_cv_t<T>>::value;
|
||||
|
||||
using base = std::conditional_t
|
||||
<
|
||||
UPstream_base_dataType<std::remove_cv_t<T>>::value, // is_base
|
||||
std::remove_cv_t<T>,
|
||||
std::conditional_t
|
||||
<
|
||||
(
|
||||
std::is_integral_v<T>
|
||||
&& (sizeof(T) == sizeof(int32_t) || sizeof(T) == sizeof(int64_t))
|
||||
),
|
||||
std::conditional_t
|
||||
<
|
||||
(sizeof(T) == sizeof(int32_t)),
|
||||
std::conditional_t<std::is_signed_v<T>, int32_t, uint32_t>,
|
||||
std::conditional_t<std::is_signed_v<T>, int64_t, uint64_t>
|
||||
>,
|
||||
char // Fallback value (assuming it is contiguous)
|
||||
>
|
||||
>;
|
||||
|
||||
static constexpr auto datatype_id =
|
||||
UPstream_base_dataType<base>::datatype_id;
|
||||
};
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
template<class T>
|
||||
void print(const char* name, bool showLimits = true)
|
||||
@ -47,28 +158,78 @@ void print(const char* name, bool showLimits = true)
|
||||
if (showLimits)
|
||||
{
|
||||
std::cout
|
||||
<< " \"max\"=" << std::numeric_limits<T>::max();
|
||||
<< " max=<";
|
||||
|
||||
if constexpr (sizeof(T) == 1)
|
||||
{
|
||||
std::cout << int(std::numeric_limits<T>::max());
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << std::numeric_limits<T>::max();
|
||||
}
|
||||
std::cout << '>';
|
||||
}
|
||||
|
||||
// A declared or deduced MPI type, or aliased
|
||||
std::cout
|
||||
<< " is_mpi=" << UPstream_base_dataType<T>::value
|
||||
<< " (" << int(UPstream_base_dataType<T>::datatype_id) << ")";
|
||||
|
||||
if (UPstream_alias_dataType<T>::value)
|
||||
{
|
||||
if (UPstream_alias_dataType<T>::is_base)
|
||||
{
|
||||
std::cout<< " is_base";
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout<< " is_alias ("
|
||||
<< int(UPstream_alias_dataType<T>::datatype_id) << ")";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout<< " no_alias";
|
||||
}
|
||||
|
||||
std::cout<< '\n';
|
||||
}
|
||||
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
// Main program:
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
std::cout<< "c++ = " << __cplusplus << '\n';
|
||||
std::cout<< "machine sizes\n---\n\n";
|
||||
std::cout<< "machine sizes (and some MPI traits)\n---\n\n";
|
||||
|
||||
print<int8_t>("int8_t");
|
||||
print<uint8_t>("uint8_t");
|
||||
print<int16_t>("int16_t");
|
||||
print<uint16_t>("uint16_t");
|
||||
print<int32_t>("int32_t");
|
||||
print<uint32_t>("uint32_t");
|
||||
print<int64_t>("int64_t");
|
||||
print<uint64_t>("uint64_t");
|
||||
|
||||
std::cout << '\n';
|
||||
print<char>("char");
|
||||
print<unsigned char>("unsigned char");
|
||||
print<short>("short");
|
||||
print<int>("int");
|
||||
print<unsigned>("unsigned");
|
||||
print<long>("long");
|
||||
print<unsigned long>("unsigned long");
|
||||
print<std::size_t>("std::size_t");
|
||||
print<long long>("long long");
|
||||
|
||||
std::cout << '\n';
|
||||
print<std::size_t>("std::size_t");
|
||||
print<std::streamsize>("std::streamsize");
|
||||
|
||||
std::cout << '\n';
|
||||
print<float>("float");
|
||||
print<double>("double");
|
||||
print<long double>("long double");
|
||||
|
3
applications/test/UPstreamTraits/Make/files
Normal file
3
applications/test/UPstreamTraits/Make/files
Normal file
@ -0,0 +1,3 @@
|
||||
Test-UPstreamTraits.cxx
|
||||
|
||||
EXE = $(FOAM_USER_APPBIN)/Test-UPstreamTraits
|
2
applications/test/UPstreamTraits/Make/options
Normal file
2
applications/test/UPstreamTraits/Make/options
Normal file
@ -0,0 +1,2 @@
|
||||
/* EXE_INC = */
|
||||
/* EXE_LIBS = */
|
267
applications/test/UPstreamTraits/Test-UPstreamTraits.cxx
Normal file
267
applications/test/UPstreamTraits/Test-UPstreamTraits.cxx
Normal file
@ -0,0 +1,267 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2025 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
|
||||
OpenFOAM 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.
|
||||
|
||||
OpenFOAM 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 OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Description
|
||||
Simple compilation tests and access for UPstream types
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "pTraits.H"
|
||||
#include "contiguous.H"
|
||||
#include "FixedList.H"
|
||||
#include "boolVector.H" // A FixedList pretending to be a vector
|
||||
#include "barycentric.H"
|
||||
#include "complex.H"
|
||||
#include "vector.H"
|
||||
#include "tensor.H"
|
||||
#include "uLabel.H"
|
||||
#include "Switch.H"
|
||||
#include "IOstreams.H"
|
||||
#include "UPstream.H"
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
using namespace Foam;
|
||||
|
||||
// Just for debugging
|
||||
const List<std::string> dataType_names
|
||||
({
|
||||
"byte",
|
||||
"int32",
|
||||
"int64",
|
||||
"uint32",
|
||||
"uint64",
|
||||
"float",
|
||||
"double",
|
||||
"long_double",
|
||||
|
||||
"float(2)",
|
||||
"double(2)",
|
||||
"float(3)",
|
||||
"double(3)",
|
||||
"float(6)",
|
||||
"double(6)",
|
||||
"float(9)",
|
||||
"double(9)"
|
||||
});
|
||||
|
||||
//- Test for pTraits typeName member : default is false
|
||||
template<class T, class = void>
|
||||
struct check_has_typeName : std::false_type {};
|
||||
|
||||
//- Test for pTraits zero
|
||||
template<class T>
|
||||
struct check_has_typeName
|
||||
<
|
||||
T,
|
||||
std::void_t<decltype(pTraits<std::remove_cv_t<T>>::typeName)>
|
||||
>
|
||||
:
|
||||
std::true_type
|
||||
{};
|
||||
|
||||
|
||||
// Possible future change...
|
||||
// //- A supported UPstream data type (intrinsic or user-defined)
|
||||
// template<>
|
||||
// struct UPstream_base_dataType<complex> : std::true_type
|
||||
// {
|
||||
// static constexpr auto datatype_id = []()
|
||||
// {
|
||||
// if constexpr (sizeof(complex) == 2*sizeof(float))
|
||||
// return UPstream::dataTypes::type_2float;
|
||||
// else
|
||||
// return UPstream::dataTypes::type_2double;
|
||||
// }();
|
||||
// };
|
||||
|
||||
|
||||
template<class T>
|
||||
void printTypeName(const bool showSize = false)
|
||||
{
|
||||
// Both float and double have pTraits typeName = "scalar"!
|
||||
if constexpr (std::is_same_v<float, std::remove_cv_t<T>>)
|
||||
{
|
||||
Info<< "<float>";
|
||||
}
|
||||
else if constexpr (std::is_same_v<double, std::remove_cv_t<T>>)
|
||||
{
|
||||
Info<< "<double>";
|
||||
}
|
||||
else if constexpr (check_has_typeName<T>::value)
|
||||
{
|
||||
Info<< pTraits<std::remove_cv_t<T>>::typeName;
|
||||
}
|
||||
else
|
||||
{
|
||||
Info<< typeid(T).name();
|
||||
}
|
||||
if (showSize)
|
||||
{
|
||||
Info<< " (" << sizeof(T) << " bytes)";
|
||||
}
|
||||
}
|
||||
|
||||
template<class Type, bool UseTypeName = true>
|
||||
void printPstreamTraits(const std::string_view name = std::string_view())
|
||||
{
|
||||
Info<< "========" << nl;
|
||||
Info<< "type: ";
|
||||
if (!name.empty())
|
||||
{
|
||||
Info<< name << ' ';
|
||||
}
|
||||
if constexpr (UseTypeName)
|
||||
{
|
||||
printTypeName<Type>(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
Info<< typeid(Type).name();
|
||||
Info<< " (" << sizeof(Type) << " bytes)";
|
||||
}
|
||||
|
||||
Info<< ", cmpt:";
|
||||
printTypeName<typename Foam::pTraits_cmptType<Type>::type>(true);
|
||||
|
||||
Info<< nl
|
||||
<< " is_contiguous:"
|
||||
<< is_contiguous<Type>::value
|
||||
<< ", is base:"
|
||||
<< UPstream_base_dataType<Type>::value
|
||||
<< ", is cmpt:"
|
||||
<< UPstream_dataType<Type>::value << nl;
|
||||
|
||||
Info<< "is base:"
|
||||
<< UPstream_base_dataType<Type>::value
|
||||
<< " (type:" << int(UPstream_base_dataType<Type>::datatype_id)
|
||||
<< ") is alias:" << UPstream_alias_dataType<Type>::value
|
||||
<< " (type:" << int(UPstream_alias_dataType<Type>::datatype_id)
|
||||
<< ")" << nl;
|
||||
|
||||
|
||||
{
|
||||
int index = int(UPstream_base_dataType<Type>::datatype_id);
|
||||
Info<< "datatype: " << index;
|
||||
|
||||
if (index < dataType_names.size())
|
||||
{
|
||||
Info<< ' ' << dataType_names[index];
|
||||
}
|
||||
Info<< nl;
|
||||
}
|
||||
|
||||
{
|
||||
// Use element or component type (or byte-wise) for data type
|
||||
using base = typename UPstream_dataType<Type>::base;
|
||||
constexpr auto datatype = UPstream_dataType<Type>::datatype_id;
|
||||
|
||||
Info<< "datatype => ";
|
||||
printTypeName<base>();
|
||||
Info<< " (" << sizeof(Type)/sizeof(base) << " elems)" << nl
|
||||
<< "datatype: " << static_cast<int>(datatype) << nl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class BinaryOp>
|
||||
void printOpCodeTraits(BinaryOp bop, std::string_view name)
|
||||
{
|
||||
Info<< "op: " << name << ' ';
|
||||
if constexpr (UPstream_opType<BinaryOp>::value)
|
||||
{
|
||||
Info<< "supported";
|
||||
}
|
||||
else
|
||||
{
|
||||
Info<< "unknown";
|
||||
}
|
||||
Info<< ": " << int(UPstream_opType<BinaryOp>::opcode_id) << nl;
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
// Main program:
|
||||
|
||||
int main()
|
||||
{
|
||||
printPstreamTraits<bool>();
|
||||
printPstreamTraits<label>();
|
||||
|
||||
printPstreamTraits<int>("<int>");
|
||||
printPstreamTraits<long>("<long>");
|
||||
printPstreamTraits<unsigned>("<unsigned>");
|
||||
printPstreamTraits<unsigned int>("<unsigned int>");
|
||||
printPstreamTraits<unsigned long>("<long long>");
|
||||
|
||||
printPstreamTraits<const float>();
|
||||
printPstreamTraits<floatVector>();
|
||||
|
||||
printPstreamTraits<scalar>();
|
||||
printPstreamTraits<double>();
|
||||
printPstreamTraits<doubleVector>();
|
||||
|
||||
// Avoid typeName for barycentric. It is declared, but not defined
|
||||
printPstreamTraits<barycentric, false>("barycentric");
|
||||
|
||||
printPstreamTraits<complex>(); // Uses specialized pTraits_...
|
||||
|
||||
printPstreamTraits<boolVector>(); // Uses specialized pTraits_...
|
||||
printPstreamTraits<floatVector>();
|
||||
printPstreamTraits<doubleVector>();
|
||||
printPstreamTraits<tensor>();
|
||||
printPstreamTraits<word>();
|
||||
printPstreamTraits<std::string>();
|
||||
|
||||
// This will not identify properly at the moment...
|
||||
printPstreamTraits<FixedList<doubleVector, 4>>();
|
||||
printPstreamTraits<labelPair>();
|
||||
|
||||
Info<< nl
|
||||
<< "========" << nl
|
||||
<< "Mapping of binary reduction ops" << nl;
|
||||
|
||||
printOpCodeTraits(minOp<scalar>{}, "min");
|
||||
printOpCodeTraits(maxOp<vector>{}, "max");
|
||||
printOpCodeTraits(sumOp<vector>{}, "sum");
|
||||
printOpCodeTraits(plusOp<vector>{}, "plus");
|
||||
printOpCodeTraits(multiplyOp<scalar>{}, "multiply");
|
||||
printOpCodeTraits(divideOp<vector>{}, "divide");
|
||||
printOpCodeTraits(minMagSqrOp<vector>{}, "minMagSqr");
|
||||
|
||||
printOpCodeTraits(bitAndOp<vector>{}, "bitAnd<vector>");
|
||||
printOpCodeTraits(bitOrOp<vector>{}, "bitOr<vector>");
|
||||
|
||||
printOpCodeTraits(bitOrOp<float>{}, "bitOr<float>");
|
||||
printOpCodeTraits(bitAndOp<unsigned>{}, "bitAnd<unsigned>");
|
||||
printOpCodeTraits(bitOrOp<unsigned>{}, "bitOr<unsigned>");
|
||||
|
||||
Info<< nl << "End\n" << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
@ -26,7 +26,28 @@ License
|
||||
Description
|
||||
A set of traits associated with UPstream communication
|
||||
|
||||
SourceFiles
|
||||
- UPstream_dataType trait:
|
||||
This wrapper is unwinds the type to check against base/alias, but also
|
||||
checks if it is a component aggregate of a supported UPstream data type.
|
||||
This will be that main entry point for usage.
|
||||
|
||||
- UPstream_opType trait:
|
||||
Provides a mapping of OpenFOAM ops to their MPI equivalent.
|
||||
The \c opcode_id is the corresponding internal representation.
|
||||
|
||||
Note
|
||||
Additional helper traits:
|
||||
|
||||
- UPstream_base_dataType trait:
|
||||
Tests true/false if the specified data type has an internal
|
||||
MPI equivalent. The \c datatype_id is the corresponding
|
||||
internal enumeration. Even if this tests as false, it will
|
||||
always return \c type_byte as the fallback for general contiguous data
|
||||
|
||||
- UPstream_alias_dataType trait:
|
||||
Provides mapping for <int/long/long long,...> to the fundamental
|
||||
32/64 bit integrals, since <int/long/long long,...> may not otherwise
|
||||
directly map on all systems.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
@ -36,9 +57,314 @@ SourceFiles
|
||||
#include "UPstream.H"
|
||||
#include <cstdint>
|
||||
#include <ios> // For streamsize
|
||||
#include <type_traits>
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
|
||||
// Forward Declarations
|
||||
|
||||
// Some vector-space types
|
||||
// -----------------------
|
||||
//! \cond
|
||||
template<class T> class Vector;
|
||||
template<class T> class SymmTensor;
|
||||
template<class T> class Tensor;
|
||||
//! \endcond
|
||||
|
||||
// -------------------------
|
||||
// Some binary operators (as per ops.H), but since ListOps.H is included
|
||||
// by UPstream.H, don't need to forward declare
|
||||
// -------------------------
|
||||
// template<class T> struct minOp;
|
||||
// template<class T> struct maxOp;
|
||||
// template<class T> struct plusOp;
|
||||
// template<class T> struct sumOp;
|
||||
// template<class T> struct multiplyOp;
|
||||
// template<class T> struct bitAndOp;
|
||||
// template<class T> struct bitOrOp;
|
||||
// template<class T> struct bitXorOp;
|
||||
|
||||
//! \cond
|
||||
template<class T> struct UPstream_dataType;
|
||||
template<class T> struct UPstream_opType;
|
||||
//! \endcond
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
// Base traits
|
||||
|
||||
//- A supported UPstream (MPI) reduce/window operation type
|
||||
template<class T>
|
||||
struct UPstream_opType : std::false_type
|
||||
{
|
||||
static constexpr auto opcode_id = UPstream::opCodes::invalid;
|
||||
};
|
||||
|
||||
|
||||
//- A supported UPstream data type (intrinsic or user-defined)
|
||||
template<class T>
|
||||
struct UPstream_base_dataType : std::false_type
|
||||
{
|
||||
static constexpr auto datatype_id = UPstream::dataTypes::invalid;
|
||||
};
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
// Trait specializations (op-codes)
|
||||
|
||||
//- Map minOp\<T\> to \c UPstream::opCodes::op_min
|
||||
template<class T>
|
||||
struct UPstream_opType<Foam::minOp<T>> : std::true_type
|
||||
{
|
||||
static constexpr auto opcode_id = UPstream::opCodes::op_min;
|
||||
};
|
||||
|
||||
//- Map maxOp\<T\> to \c UPstream::opCodes::op_max
|
||||
template<class T>
|
||||
struct UPstream_opType<Foam::maxOp<T>> : std::true_type
|
||||
{
|
||||
static constexpr auto opcode_id = UPstream::opCodes::op_max;
|
||||
};
|
||||
|
||||
//- Map sumOp\<T\> to \c UPstream::opCodes::op_sum
|
||||
template<class T>
|
||||
struct UPstream_opType<Foam::sumOp<T>> : std::true_type
|
||||
{
|
||||
static constexpr auto opcode_id = UPstream::opCodes::op_sum;
|
||||
};
|
||||
|
||||
//- Map plusOp\<T\> to \c UPstream::opCodes::op_sum
|
||||
//- as a recognized alternative to sumOp\<T\>
|
||||
template<class T>
|
||||
struct UPstream_opType<Foam::plusOp<T>> : std::true_type
|
||||
{
|
||||
static constexpr auto opcode_id = UPstream::opCodes::op_sum;
|
||||
};
|
||||
|
||||
//- Map multiplyOp\<T\> to \c UPstream::opCodes::op_prod
|
||||
template<class T>
|
||||
struct UPstream_opType<Foam::multiplyOp<T>> : std::true_type
|
||||
{
|
||||
static constexpr auto opcode_id = UPstream::opCodes::op_prod;
|
||||
};
|
||||
|
||||
// NOTE (2025-02):
|
||||
// currently no mappings provided for
|
||||
// (op_bool_and, op_bool_or, op_bool_xor) until the calling semantics
|
||||
// have been properly defined
|
||||
|
||||
|
||||
// These are only viable for unsigned integral types,
|
||||
// probably not for signed integral types.
|
||||
// Be extra restrictive for now
|
||||
|
||||
//- Map bitAndOp\<T\> to \c UPstream::opCodes::op_bit_and
|
||||
//- (for unsigned integrals)
|
||||
template<class T>
|
||||
struct UPstream_opType<Foam::bitAndOp<T>>
|
||||
:
|
||||
// ie, std::unsigned_integral<T> concept
|
||||
std::bool_constant<std::is_integral_v<T> && !std::is_signed_v<T>>
|
||||
{
|
||||
static constexpr auto opcode_id = []() constexpr noexcept
|
||||
{
|
||||
if constexpr (std::is_integral_v<T> && !std::is_signed_v<T>)
|
||||
return UPstream::opCodes::op_bit_and;
|
||||
else
|
||||
return UPstream::opCodes::invalid;
|
||||
}();
|
||||
};
|
||||
|
||||
//- Map bitOrOp\<T\> to \c UPstream::opCodes::op_bit_or
|
||||
//- (for unsigned integrals)
|
||||
template<class T>
|
||||
struct UPstream_opType<Foam::bitOrOp<T>>
|
||||
:
|
||||
// ie, std::unsigned_integral<T> concept
|
||||
std::bool_constant<std::is_integral_v<T> && !std::is_signed_v<T>>
|
||||
{
|
||||
static constexpr auto opcode_id = []() constexpr noexcept
|
||||
{
|
||||
if constexpr (std::is_integral_v<T> && !std::is_signed_v<T>)
|
||||
return UPstream::opCodes::op_bit_or;
|
||||
else
|
||||
return UPstream::opCodes::invalid;
|
||||
}();
|
||||
};
|
||||
|
||||
//- Map bitXorOp\<T\> to \c UPstream::opCodes::op_bit_xor
|
||||
//- (for unsigned integrals)
|
||||
template<class T>
|
||||
struct UPstream_opType<Foam::bitXorOp<T>>
|
||||
:
|
||||
// ie, std::unsigned_integral<T> concept
|
||||
std::bool_constant<std::is_integral_v<T> && !std::is_signed_v<T>>
|
||||
{
|
||||
static constexpr auto opcode_id = []() constexpr noexcept
|
||||
{
|
||||
if constexpr (std::is_integral_v<T> && !std::is_signed_v<T>)
|
||||
return UPstream::opCodes::op_bit_xor;
|
||||
else
|
||||
return UPstream::opCodes::invalid;
|
||||
}();
|
||||
};
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
// Trait specializations (data types)
|
||||
|
||||
// Specializations to match elements of UPstream::dataTypes
|
||||
#undef defineUPstreamDataTraits
|
||||
#define defineUPstreamDataTraits(TypeId, Type) \
|
||||
\
|
||||
/*! \brief Map \c Type to UPstream::dataTypes::TypeId */ \
|
||||
template<> struct UPstream_base_dataType<Type> : std::true_type \
|
||||
{ \
|
||||
static constexpr auto datatype_id = UPstream::dataTypes::TypeId; \
|
||||
}; \
|
||||
/*! \brief Map \c const \c Type to \c UPstream::dataTypes::TypeId */ \
|
||||
template<> struct UPstream_base_dataType<const Type> : std::true_type \
|
||||
{ \
|
||||
static constexpr auto datatype_id = UPstream::dataTypes::TypeId; \
|
||||
};
|
||||
|
||||
|
||||
// Intrinsic Types [8]:
|
||||
// Note: uses 'int32_t,int64_t,...' instead of 'int,long,...' to minimize
|
||||
// the possibility of duplicates types.
|
||||
// OpenFOAM defines Foam::label as either int32_t,int64_t (not int,long) too.
|
||||
defineUPstreamDataTraits(type_byte, char);
|
||||
defineUPstreamDataTraits(type_byte, unsigned char);
|
||||
defineUPstreamDataTraits(type_int32, int32_t);
|
||||
defineUPstreamDataTraits(type_int64, int64_t);
|
||||
defineUPstreamDataTraits(type_uint32, uint32_t);
|
||||
defineUPstreamDataTraits(type_uint64, uint64_t);
|
||||
defineUPstreamDataTraits(type_float, float);
|
||||
defineUPstreamDataTraits(type_double, double);
|
||||
defineUPstreamDataTraits(type_long_double, long double);
|
||||
|
||||
// User Types [6]:
|
||||
defineUPstreamDataTraits(type_3float, Vector<float>);
|
||||
defineUPstreamDataTraits(type_3double, Vector<double>);
|
||||
defineUPstreamDataTraits(type_6float, SymmTensor<float>);
|
||||
defineUPstreamDataTraits(type_6double, SymmTensor<double>);
|
||||
defineUPstreamDataTraits(type_9float, Tensor<float>);
|
||||
defineUPstreamDataTraits(type_9double, Tensor<double>);
|
||||
|
||||
#undef defineUPstreamDataTraits
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------- //
|
||||
|
||||
//- Explicit handling of data type aliases. This is necessary since
|
||||
//- different systems map things like 'unsigned long' differently but we
|
||||
//- restrict ourselves to int32/int64 types
|
||||
template<class T>
|
||||
struct UPstream_alias_dataType
|
||||
:
|
||||
std::bool_constant
|
||||
<
|
||||
// Base type (no alias needed)
|
||||
UPstream_base_dataType<std::remove_cv_t<T>>::value ||
|
||||
(
|
||||
// Or some int 32/64 type to re-map
|
||||
std::is_integral_v<T>
|
||||
&& (sizeof(T) == sizeof(int32_t) || sizeof(T) == sizeof(int64_t))
|
||||
)
|
||||
>
|
||||
{
|
||||
// Is it using the base type? (no alias needed)
|
||||
static constexpr bool is_base =
|
||||
UPstream_base_dataType<std::remove_cv_t<T>>::value;
|
||||
|
||||
using base = std::conditional_t
|
||||
<
|
||||
UPstream_base_dataType<std::remove_cv_t<T>>::value,
|
||||
std::remove_cv_t<T>, // <- using base
|
||||
std::conditional_t // <- using alias
|
||||
<
|
||||
(
|
||||
std::is_integral_v<T>
|
||||
&& (sizeof(T) == sizeof(int32_t) || sizeof(T) == sizeof(int64_t))
|
||||
),
|
||||
std::conditional_t
|
||||
<
|
||||
(sizeof(T) == sizeof(int32_t)),
|
||||
std::conditional_t<std::is_signed_v<T>, int32_t, uint32_t>,
|
||||
std::conditional_t<std::is_signed_v<T>, int64_t, uint64_t>
|
||||
>,
|
||||
char // Fallback is a byte (eg, arbitrary contiguous data)
|
||||
>
|
||||
>;
|
||||
|
||||
static constexpr auto datatype_id =
|
||||
UPstream_base_dataType<base>::datatype_id;
|
||||
};
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------- //
|
||||
|
||||
//- A supported UPstream data type (fundamental or user-defined)
|
||||
//- or a component aggregate of a supported UPstream data type.
|
||||
//
|
||||
// Is true for the following conditions:
|
||||
// - The \c Type is directly supported
|
||||
// - The \c cmptType (eg, from VectorSpace) exists and is directly supported
|
||||
// - Fallback to byte-wise representation (ie, for contiguous)
|
||||
// .
|
||||
template<class T>
|
||||
struct UPstream_dataType
|
||||
:
|
||||
std::bool_constant
|
||||
<
|
||||
UPstream_alias_dataType<T>::value
|
||||
|| UPstream_alias_dataType<typename pTraits_cmptType<T>::type>::value
|
||||
>
|
||||
{
|
||||
// Is it using the base type? (ie, not using components)
|
||||
static constexpr bool is_base = UPstream_alias_dataType<T>::value;
|
||||
|
||||
//- The underlying data type (if supported) or byte
|
||||
using base = std::conditional_t
|
||||
<
|
||||
UPstream_alias_dataType<T>::value,
|
||||
typename UPstream_alias_dataType<T>::base, // <- using base
|
||||
typename UPstream_alias_dataType
|
||||
<typename pTraits_cmptType<T>::type>::base // <- using components
|
||||
>;
|
||||
|
||||
//- The corresponding UPstream::dataTypes enumeration
|
||||
static constexpr auto datatype_id =
|
||||
UPstream_base_dataType<base>::datatype_id;
|
||||
|
||||
//- The size in terms of the number of underlying data elements
|
||||
static std::streamsize size(std::streamsize count) noexcept
|
||||
{
|
||||
if constexpr (UPstream_alias_dataType<T>::value)
|
||||
{
|
||||
// using base: no multiplier
|
||||
return count;
|
||||
}
|
||||
else
|
||||
{
|
||||
// using components: with multiplier
|
||||
return count*(sizeof(T)/sizeof(base));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
} // End namespace Foam
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user