diff --git a/.clang-format b/.clang-format index e5114ffd062d399b881d114f50e94b45988832dc..4ffb182c0fb8f021a6b1f31aee4b7f1b34608f63 100644 --- a/.clang-format +++ b/.clang-format @@ -62,16 +62,18 @@ IncludeCategories: - Regex: '^"core/' Priority: 4 - Regex: '^"domain_decomposition/' - Priority: 6 + Priority: 5 - Regex: '^"executiontree/' - Priority: 7 + Priority: 6 - Regex: '^"fft/' - Priority: 8 + Priority: 7 - Regex: '^"field/' - Priority: 9 + Priority: 8 - Regex: '^"gather/' - Priority: 10 + Priority: 9 - Regex: '^"geometry/' + Priority: 10 + - Regex: '^"gpu/' Priority: 11 - Regex: '^"gpu/' Priority: 12 @@ -97,16 +99,18 @@ IncludeCategories: Priority: 21 - Regex: '^"simd/' Priority: 22 - - Regex: '^"stencil/' + - Regex: '^"sqlite/' Priority: 23 - - Regex: '^"timeloop/' + - Regex: '^"stencil/' Priority: 24 - - Regex: '^"vtk/' + - Regex: '^"timeloop/' Priority: 25 - - Regex: '^<boost/' + - Regex: '^"vtk/' Priority: 26 - - Regex: '^<' + - Regex: '^<boost/' Priority: 27 + - Regex: '^<' + Priority: 28 IndentCaseLabels: false IndentPPDirectives: AfterHash IndentWidth: 3 diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 47ac8e0266e3ae7ddf305a22c70fb22406304238..1ee46ddc0af7fd8dfd8e859d18ce0bce05e4184d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -57,6 +57,7 @@ stages: -DWALBERLA_BUILD_WITH_CODEGEN=$WALBERLA_BUILD_WITH_CODEGEN -DWALBERLA_STL_BOUNDS_CHECKS=$WALBERLA_STL_BOUNDS_CHECKS -DWALBERLA_LOGLEVEL=$WALBERLA_LOGLEVEL + -DCMAKE_CUDA_ARCHITECTURES=60 - cmake . -LA - make -j $NUM_BUILD_CORES -l $NUM_CORES - ctest -LE $CTEST_EXCLUDE_LABELS -C $CMAKE_BUILD_TYPE --output-on-failure -j $NUM_CORES -T Test diff --git a/apps/benchmarks/CMakeLists.txt b/apps/benchmarks/CMakeLists.txt index f418d434ca38902dc79be8f9b9a4207f9fb90de6..cffa8f427d9fc06e9bdc96090553374eb3e73ba3 100644 --- a/apps/benchmarks/CMakeLists.txt +++ b/apps/benchmarks/CMakeLists.txt @@ -5,9 +5,11 @@ add_subdirectory( DEM ) add_subdirectory( MeshDistance ) add_subdirectory( CouetteFlow ) add_subdirectory( FreeSurfaceAdvection ) +add_subdirectory( FluidizedBed ) add_subdirectory( FluidParticleCoupling ) add_subdirectory( FluidParticleCouplingWithLoadBalancing ) add_subdirectory( ForcesOnSphereNearPlaneInShearFlow ) +add_subdirectory(Percolation) add_subdirectory( GranularGas ) add_subdirectory( IntegratorAccuracy ) add_subdirectory( LennardJones ) diff --git a/apps/benchmarks/FluidParticleCoupling/CMakeLists.txt b/apps/benchmarks/FluidParticleCoupling/CMakeLists.txt index 898352998666621d6bdfec7f0f07f5c6b4de3724..34ffaca075f6ac90be4f9f077f779ec21f7e6603 100644 --- a/apps/benchmarks/FluidParticleCoupling/CMakeLists.txt +++ b/apps/benchmarks/FluidParticleCoupling/CMakeLists.txt @@ -67,7 +67,5 @@ waLBerla_add_executable ( NAME ObliqueWetCollision FILES ObliqueWetCollision.cpp endif() - - waLBerla_add_executable ( NAME ObliqueDryCollision FILES ObliqueDryCollision.cpp - DEPENDS blockforest core mesa_pd postprocessing ) \ No newline at end of file + DEPENDS blockforest core mesa_pd postprocessing ) diff --git a/apps/benchmarks/FluidizedBed/CMakeLists.txt b/apps/benchmarks/FluidizedBed/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..9c33fb523801a7f55935e99661496e38142b412a --- /dev/null +++ b/apps/benchmarks/FluidizedBed/CMakeLists.txt @@ -0,0 +1,6 @@ +waLBerla_link_files_to_builddir("*.prm") + +if (WALBERLA_BUILD_WITH_GPU_SUPPORT AND WALBERLA_BUILD_WITH_CODEGEN AND (CMAKE_CUDA_ARCHITECTURES GREATER_EQUAL 60 OR WALBERLA_BUILD_WITH_HIP)) + waLBerla_add_executable(NAME FluidizedBed_PSM_GPU FILES FluidizedBedGPU.cpp + DEPENDS blockforest boundary core gpu domain_decomposition field lbm lbm_mesapd_coupling mesa_pd timeloop vtk PSMCodegenPython_srt_sc1) +endif () diff --git a/apps/benchmarks/FluidizedBed/FluidizedBedGPU.cpp b/apps/benchmarks/FluidizedBed/FluidizedBedGPU.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cf454243e5c71ce9b8cde90dd73fa92b47d44bff --- /dev/null +++ b/apps/benchmarks/FluidizedBed/FluidizedBedGPU.cpp @@ -0,0 +1,841 @@ +//====================================================================================================================== +// +// This file is part of waLBerla. waLBerla 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. +// +// waLBerla 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 waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file FluidizedBedGPU.cpp +//! \ingroup lbm_mesapd_coupling +//! \author Samuel Kemmler <samuel.kemmler@fau.de> +//! \author Christoph Rettinger <christoph.rettinger@fau.de> +//! \brief Modification of showcases/FluidizedBed/FluidizedBedPSM.cpp +// +//====================================================================================================================== + +#include "blockforest/Initialization.h" + +#include "core/DataTypes.h" +#include "core/Environment.h" +#include "core/debug/Debug.h" +#include "core/grid_generator/SCIterator.h" +#include "core/logging/all.h" +#include "core/math/all.h" +#include "core/mpi/Broadcast.h" +#include "core/timing/RemainingTimeLogger.h" + +#include "field/AddToStorage.h" +#include "field/vtk/all.h" + +#include "geometry/InitBoundaryHandling.h" + +#include "gpu/AddGPUFieldToStorage.h" +#include "gpu/DeviceSelectMPI.h" +#include "gpu/communication/UniformGPUScheme.h" + +#include "lbm/PerformanceLogger.h" +#include "lbm/vtk/all.h" + +#include "lbm_mesapd_coupling/DataTypesCodegen.h" +#include "lbm_mesapd_coupling/partially_saturated_cells_method/codegen/PSMSweepCollection.h" +#include "lbm_mesapd_coupling/utility/AddForceOnParticlesKernel.h" +#include "lbm_mesapd_coupling/utility/AddHydrodynamicInteractionKernel.h" +#include "lbm_mesapd_coupling/utility/AverageHydrodynamicForceTorqueKernel.h" +#include "lbm_mesapd_coupling/utility/InitializeHydrodynamicForceTorqueForAveragingKernel.h" +#include "lbm_mesapd_coupling/utility/LubricationCorrectionKernel.h" +#include "lbm_mesapd_coupling/utility/ParticleSelector.h" +#include "lbm_mesapd_coupling/utility/ResetHydrodynamicForceTorqueKernel.h" + +#include "mesa_pd/collision_detection/AnalyticContactDetection.h" +#include "mesa_pd/data/DataTypes.h" +#include "mesa_pd/data/LinkedCells.h" +#include "mesa_pd/data/ParticleAccessorWithShape.h" +#include "mesa_pd/data/ParticleStorage.h" +#include "mesa_pd/data/ShapeStorage.h" +#include "mesa_pd/data/shape/HalfSpace.h" +#include "mesa_pd/data/shape/Sphere.h" +#include "mesa_pd/domain/BlockForestDataHandling.h" +#include "mesa_pd/domain/BlockForestDomain.h" +#include "mesa_pd/kernel/AssocToBlock.h" +#include "mesa_pd/kernel/DoubleCast.h" +#include "mesa_pd/kernel/InsertParticleIntoLinkedCells.h" +#include "mesa_pd/kernel/LinearSpringDashpot.h" +#include "mesa_pd/kernel/ParticleSelector.h" +#include "mesa_pd/kernel/VelocityVerlet.h" +#include "mesa_pd/mpi/ContactFilter.h" +#include "mesa_pd/mpi/ReduceContactHistory.h" +#include "mesa_pd/mpi/ReduceProperty.h" +#include "mesa_pd/mpi/SyncNextNeighbors.h" +#include "mesa_pd/mpi/notifications/ForceTorqueNotification.h" +#include "mesa_pd/mpi/notifications/HydrodynamicForceTorqueNotification.h" +#include "mesa_pd/vtk/ParticleVtkOutput.h" + +#include "vtk/all.h" + +#include "InitializeDomainForPSM.h" +#include "PSMPackInfo.h" +#include "PSMSweepSplit.h" +#include "PSM_Density.h" +#include "PSM_InfoHeader.h" +#include "PSM_MacroGetter.h" +#include "PSM_NoSlip.h" +#include "PSM_UBB.h" + +namespace fluidized_bed +{ + +/////////// +// USING // +/////////// + +using namespace walberla; +using walberla::uint_t; + +using flag_t = walberla::uint8_t; +using FlagField_T = FlagField< flag_t >; + +using namespace lbm_mesapd_coupling::psm::gpu; +typedef pystencils::PSMPackInfo PackInfo_T; + +/////////// +// FLAGS // +/////////// + +const FlagUID Fluid_Flag("Fluid"); +const FlagUID NoSlip_Flag("NoSlip"); +const FlagUID Inflow_Flag("Inflow"); +const FlagUID Outflow_Flag("Outflow"); + +void createPlane(const shared_ptr< mesa_pd::data::ParticleStorage >& ps, + const shared_ptr< mesa_pd::data::ShapeStorage >& ss, Vector3< real_t > position, + Vector3< real_t > normal) +{ + mesa_pd::data::Particle&& p0 = *ps->create(true); + p0.setPosition(position); + p0.setInteractionRadius(std::numeric_limits< real_t >::infinity()); + p0.setShapeID(ss->create< mesa_pd::data::HalfSpace >(normal)); + p0.setOwner(mpi::MPIManager::instance()->rank()); + p0.setType(0); + mesa_pd::data::particle_flags::set(p0.getFlagsRef(), mesa_pd::data::particle_flags::INFINITE); + mesa_pd::data::particle_flags::set(p0.getFlagsRef(), mesa_pd::data::particle_flags::FIXED); +} + +void createPlaneSetup(const shared_ptr< mesa_pd::data::ParticleStorage >& ps, + const shared_ptr< mesa_pd::data::ShapeStorage >& ss, const math::AABB& simulationDomain, + bool periodicInX, bool periodicInY, real_t offsetAtInflow, real_t offsetAtOutflow) +{ + createPlane(ps, ss, simulationDomain.minCorner() + Vector3< real_t >(0, 0, offsetAtInflow), + Vector3< real_t >(0, 0, 1)); + createPlane(ps, ss, simulationDomain.maxCorner() + Vector3< real_t >(0, 0, offsetAtOutflow), + Vector3< real_t >(0, 0, -1)); + + if (!periodicInX) + { + createPlane(ps, ss, simulationDomain.minCorner(), Vector3< real_t >(1, 0, 0)); + createPlane(ps, ss, simulationDomain.maxCorner(), Vector3< real_t >(-1, 0, 0)); + } + + if (!periodicInY) + { + createPlane(ps, ss, simulationDomain.minCorner(), Vector3< real_t >(0, 1, 0)); + createPlane(ps, ss, simulationDomain.maxCorner(), Vector3< real_t >(0, -1, 0)); + } +} + +struct ParticleInfo +{ + real_t averageVelocity = 0_r; + real_t maximumVelocity = 0_r; + uint_t numParticles = 0; + real_t maximumHeight = 0_r; + real_t particleVolume = 0_r; + real_t heightOfMass = 0_r; + + void allReduce() + { + walberla::mpi::allReduceInplace(numParticles, walberla::mpi::SUM); + walberla::mpi::allReduceInplace(averageVelocity, walberla::mpi::SUM); + walberla::mpi::allReduceInplace(maximumVelocity, walberla::mpi::MAX); + walberla::mpi::allReduceInplace(maximumHeight, walberla::mpi::MAX); + walberla::mpi::allReduceInplace(particleVolume, walberla::mpi::SUM); + walberla::mpi::allReduceInplace(heightOfMass, walberla::mpi::SUM); + + averageVelocity /= real_c(numParticles); + heightOfMass /= particleVolume; + } +}; + +std::ostream& operator<<(std::ostream& os, ParticleInfo const& m) +{ + return os << "Particle Info: uAvg = " << m.averageVelocity << ", uMax = " << m.maximumVelocity + << ", numParticles = " << m.numParticles << ", zMax = " << m.maximumHeight << ", Vp = " << m.particleVolume + << ", zMass = " << m.heightOfMass; +} + +template< typename Accessor_T > +ParticleInfo evaluateParticleInfo(const Accessor_T& ac) +{ + static_assert(std::is_base_of< mesa_pd::data::IAccessor, Accessor_T >::value, "Provide a valid accessor"); + + ParticleInfo info; + for (uint_t i = 0; i < ac.size(); ++i) + { + if (isSet(ac.getFlags(i), mesa_pd::data::particle_flags::GHOST)) continue; + if (isSet(ac.getFlags(i), mesa_pd::data::particle_flags::GLOBAL)) continue; + + ++info.numParticles; + real_t velMagnitude = ac.getLinearVelocity(i).length(); + real_t particleVolume = ac.getShape(i)->getVolume(); + real_t height = ac.getPosition(i)[2]; + info.averageVelocity += velMagnitude; + info.maximumVelocity = std::max(info.maximumVelocity, velMagnitude); + info.maximumHeight = std::max(info.maximumHeight, height); + info.particleVolume += particleVolume; + info.heightOfMass += particleVolume * height; + } + + info.allReduce(); + + return info; +} + +struct FluidInfo +{ + uint_t numFluidCells = 0; + real_t averageVelocity = 0_r; + real_t maximumVelocity = 0_r; + real_t averageDensity = 0_r; + real_t maximumDensity = 0_r; + + void allReduce() + { + walberla::mpi::allReduceInplace(numFluidCells, walberla::mpi::SUM); + walberla::mpi::allReduceInplace(averageVelocity, walberla::mpi::SUM); + walberla::mpi::allReduceInplace(maximumVelocity, walberla::mpi::MAX); + ; + walberla::mpi::allReduceInplace(averageDensity, walberla::mpi::SUM); + walberla::mpi::allReduceInplace(maximumDensity, walberla::mpi::MAX); + + averageVelocity /= real_c(numFluidCells); + averageDensity /= real_c(numFluidCells); + } +}; + +std::ostream& operator<<(std::ostream& os, FluidInfo const& m) +{ + return os << "Fluid Info: numFluidCells = " << m.numFluidCells << ", uAvg = " << m.averageVelocity + << ", uMax = " << m.maximumVelocity << ", densityAvg = " << m.averageDensity + << ", densityMax = " << m.maximumDensity; +} + +FluidInfo evaluateFluidInfo(const shared_ptr< StructuredBlockStorage >& blocks, const BlockDataID& densityFieldID, + const BlockDataID& velocityFieldID) +{ + FluidInfo info; + + for (auto blockIt = blocks->begin(); blockIt != blocks->end(); ++blockIt) + { + auto densityField = blockIt->getData< DensityField_T >(densityFieldID); + auto velocityField = blockIt->getData< VelocityField_T >(velocityFieldID); + + WALBERLA_FOR_ALL_CELLS_XYZ( + densityField, ++info.numFluidCells; Vector3< real_t > velocity( + velocityField->get(x, y, z, 0), velocityField->get(x, y, z, 1), velocityField->get(x, y, z, 2)); + real_t density = densityField->get(x, y, z); real_t velMagnitude = velocity.length(); + info.averageVelocity += velMagnitude; info.maximumVelocity = std::max(info.maximumVelocity, velMagnitude); + info.averageDensity += density; info.maximumDensity = std::max(info.maximumDensity, density);) + } + info.allReduce(); + return info; +} + +////////// +// MAIN // +////////// + +//******************************************************************************************************************* +/*!\brief Basic simulation of a fluidization setup + * + * Initially, the mono-sized sphere are created on a structured grid inside the domain. + * The domain is either periodic or bounded by walls in the horizontal directions (x and y). + * In z-direction, a constant inflow from below is provided + * and a pressure boundary condition is set at the top, resembling an outflow boundary. + * + * The simulation is run for the given number of seconds (runtime). + * + * All parameters should be set via the input file. + * + * For the overall algorithm and the different model parameters, see + * Rettinger, Rüde - An efficient four-way coupled lattice Boltzmann - discrete element method for + * fully resolved simulations of particle-laden flows (2020, preprint: https://arxiv.org/abs/2003.01490) + * + */ +//******************************************************************************************************************* +int main(int argc, char** argv) +{ + Environment env(argc, argv); + gpu::selectDeviceBasedOnMpiRank(); + + auto cfgFile = env.config(); + if (!cfgFile) { WALBERLA_ABORT("Usage: " << argv[0] << " path-to-configuration-file \n"); } + + WALBERLA_LOG_INFO_ON_ROOT("waLBerla revision: " << std::string(WALBERLA_GIT_SHA1).substr(0, 8)); + WALBERLA_LOG_INFO_ON_ROOT("compiler flags: " << std::string(WALBERLA_COMPILER_FLAGS)); + WALBERLA_LOG_INFO_ON_ROOT("build machine: " << std::string(WALBERLA_BUILD_MACHINE)); + WALBERLA_LOG_INFO_ON_ROOT(*cfgFile); + + // read all parameters from the config file + + Config::BlockHandle physicalSetup = cfgFile->getBlock("PhysicalSetup"); + const real_t xSize_SI = physicalSetup.getParameter< real_t >("xSize"); + const real_t ySize_SI = physicalSetup.getParameter< real_t >("ySize"); + const real_t zSize_SI = physicalSetup.getParameter< real_t >("zSize"); + const bool periodicInX = physicalSetup.getParameter< bool >("periodicInX"); + const bool periodicInY = physicalSetup.getParameter< bool >("periodicInY"); + const real_t runtime_SI = physicalSetup.getParameter< real_t >("runtime"); + const real_t uInflow_SI = physicalSetup.getParameter< real_t >("uInflow"); + const real_t gravitationalAcceleration_SI = physicalSetup.getParameter< real_t >("gravitationalAcceleration"); + const real_t kinematicViscosityFluid_SI = physicalSetup.getParameter< real_t >("kinematicViscosityFluid"); + const real_t densityFluid_SI = physicalSetup.getParameter< real_t >("densityFluid"); + const real_t particleDiameter_SI = physicalSetup.getParameter< real_t >("particleDiameter"); + const real_t densityParticle_SI = physicalSetup.getParameter< real_t >("densityParticle"); + const real_t dynamicFrictionCoefficient = physicalSetup.getParameter< real_t >("dynamicFrictionCoefficient"); + const real_t coefficientOfRestitution = physicalSetup.getParameter< real_t >("coefficientOfRestitution"); + const real_t collisionTimeFactor = physicalSetup.getParameter< real_t >("collisionTimeFactor"); + const real_t particleGenerationSpacing_SI = physicalSetup.getParameter< real_t >("particleGenerationSpacing"); + + Config::BlockHandle numericalSetup = cfgFile->getBlock("NumericalSetup"); + const real_t dx_SI = numericalSetup.getParameter< real_t >("dx"); + const real_t uInflow = numericalSetup.getParameter< real_t >("uInflow"); + const uint_t numXBlocks = numericalSetup.getParameter< uint_t >("numXBlocks"); + const uint_t numYBlocks = numericalSetup.getParameter< uint_t >("numYBlocks"); + const uint_t numZBlocks = numericalSetup.getParameter< uint_t >("numZBlocks"); + WALBERLA_CHECK_EQUAL(numXBlocks * numYBlocks * numZBlocks, uint_t(MPIManager::instance()->numProcesses()), + "When using GPUs, the number of blocks (" + << numXBlocks * numYBlocks * numZBlocks << ") has to match the number of MPI processes (" + << uint_t(MPIManager::instance()->numProcesses()) << ")"); + if ((periodicInX && numXBlocks == 1) || (periodicInY && numYBlocks == 1)) + { + WALBERLA_ABORT("The number of blocks must be greater than 1 in periodic dimensions.") + } + const bool useLubricationForces = numericalSetup.getParameter< bool >("useLubricationForces"); + const uint_t numberOfParticleSubCycles = numericalSetup.getParameter< uint_t >("numberOfParticleSubCycles"); + const Vector3< uint_t > particleSubBlockSize = + numericalSetup.getParameter< Vector3< uint_t > >("particleSubBlockSize"); + const real_t linkedCellWidthRation = numericalSetup.getParameter< real_t >("linkedCellWidthRation"); + const bool particleBarriers = numericalSetup.getParameter< bool >("particleBarriers"); + + Config::BlockHandle outputSetup = cfgFile->getBlock("Output"); + const real_t infoSpacing_SI = outputSetup.getParameter< real_t >("infoSpacing"); + const real_t vtkSpacingParticles_SI = outputSetup.getParameter< real_t >("vtkSpacingParticles"); + const real_t vtkSpacingFluid_SI = outputSetup.getParameter< real_t >("vtkSpacingFluid"); + const std::string vtkFolder = outputSetup.getParameter< std::string >("vtkFolder"); + const uint_t performanceLogFrequency = outputSetup.getParameter< uint_t >("performanceLogFrequency"); + + // convert SI units to simulation (LBM) units and check setup + + Vector3< uint_t > domainSize(uint_c(std::ceil(xSize_SI / dx_SI)), uint_c(std::ceil(ySize_SI / dx_SI)), + uint_c(std::ceil(zSize_SI / dx_SI))); + WALBERLA_CHECK_FLOAT_EQUAL(real_t(domainSize[0]) * dx_SI, xSize_SI, "domain size in x is not divisible by given dx"); + WALBERLA_CHECK_FLOAT_EQUAL(real_t(domainSize[1]) * dx_SI, ySize_SI, "domain size in y is not divisible by given dx"); + WALBERLA_CHECK_FLOAT_EQUAL(real_t(domainSize[2]) * dx_SI, zSize_SI, "domain size in z is not divisible by given dx"); + + Vector3< uint_t > cellsPerBlockPerDirection(domainSize[0] / numXBlocks, domainSize[1] / numYBlocks, + domainSize[2] / numZBlocks); + + WALBERLA_CHECK_EQUAL(domainSize[0], cellsPerBlockPerDirection[0] * numXBlocks, + "number of cells in x of " << domainSize[0] + << " is not divisible by given number of blocks in x direction"); + WALBERLA_CHECK_EQUAL(domainSize[1], cellsPerBlockPerDirection[1] * numYBlocks, + "number of cells in y of " << domainSize[1] + << " is not divisible by given number of blocks in y direction"); + WALBERLA_CHECK_EQUAL(domainSize[2], cellsPerBlockPerDirection[2] * numZBlocks, + "number of cells in z of " << domainSize[2] + << " is not divisible by given number of blocks in z direction"); + + WALBERLA_CHECK_GREATER( + particleDiameter_SI / dx_SI, 5_r, + "Your numerical resolution is below 5 cells per diameter and thus too small for such simulations!"); + + const real_t densityRatio = densityParticle_SI / densityFluid_SI; + const real_t ReynoldsNumberParticle = uInflow_SI * particleDiameter_SI / kinematicViscosityFluid_SI; + const real_t GalileiNumber = std::sqrt((densityRatio - 1_r) * particleDiameter_SI * gravitationalAcceleration_SI) * + particleDiameter_SI / kinematicViscosityFluid_SI; + + // in simulation units: dt = 1, dx = 1, densityFluid = 1 + + const real_t dt_SI = uInflow / uInflow_SI * dx_SI; + const real_t diameter = particleDiameter_SI / dx_SI; + const real_t particleGenerationSpacing = particleGenerationSpacing_SI / dx_SI; + const real_t viscosity = kinematicViscosityFluid_SI * dt_SI / (dx_SI * dx_SI); + const real_t omega = lbm::collision_model::omegaFromViscosity(viscosity); + const real_t gravitationalAcceleration = gravitationalAcceleration_SI * dt_SI * dt_SI / dx_SI; + const real_t particleVolume = math::pi / 6_r * diameter * diameter * diameter; + + const real_t densityFluid = real_t(1); + const real_t densityParticle = densityRatio; + const real_t dx = real_t(1); + + const uint_t numTimeSteps = uint_c(std::ceil(runtime_SI / dt_SI)); + const uint_t infoSpacing = uint_c(std::ceil(infoSpacing_SI / dt_SI)); + const uint_t vtkSpacingParticles = uint_c(std::ceil(vtkSpacingParticles_SI / dt_SI)); + const uint_t vtkSpacingFluid = uint_c(std::ceil(vtkSpacingFluid_SI / dt_SI)); + + const Vector3< real_t > inflowVec(0_r, 0_r, uInflow); + + const real_t poissonsRatio = real_t(0.22); + const real_t kappa = real_t(2) * (real_t(1) - poissonsRatio) / (real_t(2) - poissonsRatio); + const real_t particleCollisionTime = collisionTimeFactor * diameter; + + WALBERLA_LOG_INFO_ON_ROOT("Simulation setup:"); + WALBERLA_LOG_INFO_ON_ROOT(" - particles: diameter = " << diameter << ", densityRatio = " << densityRatio); + WALBERLA_LOG_INFO_ON_ROOT(" - fluid: kin. visc = " << viscosity << ", relaxation rate = " << omega); + WALBERLA_LOG_INFO_ON_ROOT(" - grav. acceleration = " << gravitationalAcceleration); + WALBERLA_LOG_INFO_ON_ROOT(" - Galileo number = " << GalileiNumber); + WALBERLA_LOG_INFO_ON_ROOT(" - particle Reynolds number = " << ReynoldsNumberParticle); + WALBERLA_LOG_INFO_ON_ROOT(" - domain size = " << domainSize); + WALBERLA_LOG_INFO_ON_ROOT(" - cells per blocks per direction = " << cellsPerBlockPerDirection); + WALBERLA_LOG_INFO_ON_ROOT(" - dx = " << dx_SI << " m"); + WALBERLA_LOG_INFO_ON_ROOT(" - dt = " << dt_SI << " s"); + WALBERLA_LOG_INFO_ON_ROOT(" - total time steps = " << numTimeSteps); + WALBERLA_LOG_INFO_ON_ROOT(" - particle generation spacing = " << particleGenerationSpacing); + WALBERLA_LOG_INFO_ON_ROOT(" - info spacing = " << infoSpacing); + WALBERLA_LOG_INFO_ON_ROOT(" - vtk spacing particles = " << vtkSpacingParticles + << ", fluid slice = " << vtkSpacingFluid); + + /////////////////////////// + // BLOCK STRUCTURE SETUP // + /////////////////////////// + + const bool periodicInZ = false; + shared_ptr< StructuredBlockForest > blocks = blockforest::createUniformBlockGrid( + numXBlocks, numYBlocks, numZBlocks, cellsPerBlockPerDirection[0], cellsPerBlockPerDirection[1], + cellsPerBlockPerDirection[2], dx, 0, false, false, periodicInX, periodicInY, periodicInZ, // periodicity + false); + + auto simulationDomain = blocks->getDomain(); + + ////////////////// + // RPD COUPLING // + ////////////////// + + auto rpdDomain = std::make_shared< mesa_pd::domain::BlockForestDomain >(blocks->getBlockForestPointer()); + + // init data structures + auto ps = walberla::make_shared< mesa_pd::data::ParticleStorage >(1); + auto ss = walberla::make_shared< mesa_pd::data::ShapeStorage >(); + using ParticleAccessor_T = mesa_pd::data::ParticleAccessorWithShape; + auto accessor = walberla::make_shared< ParticleAccessor_T >(ps, ss); + + // prevent particles from interfering with inflow and outflow by putting the bounding planes slightly in front + const real_t planeOffsetFromInflow = dx; + const real_t planeOffsetFromOutflow = dx; + createPlaneSetup(ps, ss, simulationDomain, periodicInX, periodicInY, planeOffsetFromInflow, planeOffsetFromOutflow); + + auto sphereShape = ss->create< mesa_pd::data::Sphere >(diameter * real_t(0.5)); + ss->shapes[sphereShape]->updateMassAndInertia(densityParticle); + + // create spheres + auto generationDomain = simulationDomain.getExtended(-particleGenerationSpacing * 0.5_r); + for (auto pt : grid_generator::SCGrid(generationDomain, generationDomain.center(), particleGenerationSpacing)) + { + if (rpdDomain->isContainedInProcessSubdomain(uint_c(mpi::MPIManager::instance()->rank()), pt)) + { + mesa_pd::data::Particle&& p = *ps->create(); + p.setPosition(pt); + p.setInteractionRadius(diameter * real_t(0.5)); + p.setOwner(mpi::MPIManager::instance()->rank()); + p.setShapeID(sphereShape); + p.setType(1); + p.setLinearVelocity(0.1_r * Vector3< real_t >(math::realRandom( + -uInflow, uInflow))); // set small initial velocity to break symmetries + } + } + + /////////////////////// + // ADD DATA TO BLOCKS // + //////////////////////// + + // add PDF field + BlockDataID pdfFieldID = + field::addToStorage< PdfField_T >(blocks, "pdf field (fzyx)", real_c(std::nan("")), field::fzyx); + BlockDataID pdfFieldGPUID = gpu::addGPUFieldToStorage< PdfField_T >(blocks, pdfFieldID, "pdf field GPU"); + + BlockDataID densityFieldID = field::addToStorage< DensityField_T >(blocks, "Density", real_t(0), field::fzyx); + BlockDataID velFieldID = field::addToStorage< VelocityField_T >(blocks, "Velocity", real_t(0), field::fzyx); + + BlockDataID BFieldID = + field::addToStorage< lbm_mesapd_coupling::psm::gpu::BField_T >(blocks, "B field", 0, field::fzyx, 1); + + // add flag field + BlockDataID flagFieldID = field::addFlagFieldToStorage< FlagField_T >(blocks, "flag field"); + + // set up RPD functionality + std::function< void(void) > syncCall = [&ps, &rpdDomain]() { + // keep overlap for lubrication + const real_t overlap = real_t(1.5); + mesa_pd::mpi::SyncNextNeighbors syncNextNeighborFunc; + syncNextNeighborFunc(*ps, *rpdDomain, overlap); + }; + + syncCall(); + + real_t timeStepSizeRPD = real_t(1) / real_t(numberOfParticleSubCycles); + mesa_pd::kernel::VelocityVerletPreForceUpdate vvIntegratorPreForce(timeStepSizeRPD); + mesa_pd::kernel::VelocityVerletPostForceUpdate vvIntegratorPostForce(timeStepSizeRPD); + mesa_pd::kernel::LinearSpringDashpot collisionResponse(2); + collisionResponse.setFrictionCoefficientDynamic(0, 1, dynamicFrictionCoefficient); + collisionResponse.setFrictionCoefficientDynamic(1, 1, dynamicFrictionCoefficient); + real_t massSphere = densityParticle * particleVolume; + real_t meffSpherePlane = massSphere; + real_t meffSphereSphere = massSphere * massSphere / (real_t(2) * massSphere); + collisionResponse.setStiffnessAndDamping(0, 1, coefficientOfRestitution, particleCollisionTime, kappa, + meffSpherePlane); + collisionResponse.setStiffnessAndDamping(1, 1, coefficientOfRestitution, particleCollisionTime, kappa, + meffSphereSphere); + mesa_pd::kernel::AssocToBlock assoc(blocks->getBlockForestPointer()); + mesa_pd::mpi::ReduceProperty reduceProperty; + mesa_pd::mpi::ReduceContactHistory reduceAndSwapContactHistory; + + // set up coupling functionality + Vector3< real_t > gravitationalForce(real_t(0), real_t(0), + -(densityParticle - densityFluid) * gravitationalAcceleration * particleVolume); + lbm_mesapd_coupling::AddForceOnParticlesKernel addGravitationalForce(gravitationalForce); + lbm_mesapd_coupling::ResetHydrodynamicForceTorqueKernel resetHydrodynamicForceTorque; + lbm_mesapd_coupling::AverageHydrodynamicForceTorqueKernel averageHydrodynamicForceTorque; + lbm_mesapd_coupling::LubricationCorrectionKernel lubricationCorrectionKernel( + viscosity, [](real_t r) { return (real_t(0.001 + real_t(0.00007) * r)) * r; }); + + // assemble boundary block string + std::string boundariesBlockString = " Boundaries" + "{" + "Border { direction T; walldistance -1; flag Outflow; }" + "Border { direction B; walldistance -1; flag Inflow; }"; + + if (!periodicInX) + { + boundariesBlockString += "Border { direction W; walldistance -1; flag NoSlip; }" + "Border { direction E; walldistance -1; flag NoSlip; }"; + } + + if (!periodicInY) + { + boundariesBlockString += "Border { direction S; walldistance -1; flag NoSlip; }" + "Border { direction N; walldistance -1; flag NoSlip; }"; + } + + boundariesBlockString += "}"; + WALBERLA_ROOT_SECTION() + { + std::ofstream boundariesFile("boundaries.prm"); + boundariesFile << boundariesBlockString; + boundariesFile.close(); + } + WALBERLA_MPI_BARRIER() + + auto boundariesCfgFile = Config(); + boundariesCfgFile.readParameterFile("boundaries.prm"); + auto boundariesConfig = boundariesCfgFile.getBlock("Boundaries"); + + // map boundaries into the LBM simulation + geometry::initBoundaryHandling< FlagField_T >(*blocks, flagFieldID, boundariesConfig); + geometry::setNonBoundaryCellsToDomain< FlagField_T >(*blocks, flagFieldID, Fluid_Flag); + lbm::PSM_NoSlip noSlip(blocks, pdfFieldGPUID); + noSlip.fillFromFlagField< FlagField_T >(blocks, flagFieldID, NoSlip_Flag, Fluid_Flag); + lbm::PSM_UBB ubb(blocks, pdfFieldGPUID, inflowVec[0], inflowVec[1], inflowVec[2]); + ubb.fillFromFlagField< FlagField_T >(blocks, flagFieldID, Inflow_Flag, Fluid_Flag); + lbm::PSM_Density density_bc(blocks, pdfFieldGPUID, real_t(1)); + density_bc.fillFromFlagField< FlagField_T >(blocks, flagFieldID, Outflow_Flag, Fluid_Flag); + + /////////////// + // TIME LOOP // + /////////////// + + // map particles into the LBM simulation + // note: planes are not mapped and are thus only visible to the particles, not to the fluid + // instead, the respective boundary conditions for the fluid are explicitly set, see the boundary handling + ParticleAndVolumeFractionSoA_T< 1 > particleAndVolumeFractionSoA(blocks, omega); + PSMSweepCollection psmSweepCollection(blocks, accessor, lbm_mesapd_coupling::RegularParticlesSelector(), + particleAndVolumeFractionSoA, particleSubBlockSize); + for (auto blockIt = blocks->begin(); blockIt != blocks->end(); ++blockIt) + { + psmSweepCollection.particleMappingSweep(&(*blockIt)); + } + + pystencils::InitializeDomainForPSM pdfSetter( + particleAndVolumeFractionSoA.BsFieldID, particleAndVolumeFractionSoA.BFieldID, + particleAndVolumeFractionSoA.particleVelocitiesFieldID, pdfFieldGPUID, real_t(0), real_t(0), real_t(0), + real_t(1.0), real_t(0), real_t(0), real_t(0)); + + for (auto blockIt = blocks->begin(); blockIt != blocks->end(); ++blockIt) + { + // pdfSetter requires particle velocities at cell centers + psmSweepCollection.setParticleVelocitiesSweep(&(*blockIt)); + pdfSetter(&(*blockIt)); + } + + // setup of the LBM communication for synchronizing the pdf field between neighboring blocks + gpu::communication::UniformGPUScheme< Stencil_T > com(blocks, true, false); + com.addPackInfo(make_shared< PackInfo_T >(pdfFieldGPUID)); + auto communication = std::function< void() >([&]() { com.communicate(); }); + + // create the timeloop + SweepTimeloop commTimeloop(blocks->getBlockStorage(), numTimeSteps); + SweepTimeloop timeloop(blocks->getBlockStorage(), numTimeSteps); + + timeloop.addFuncBeforeTimeStep(RemainingTimeLogger(timeloop.getNrOfTimeSteps()), "Remaining Time Logger"); + + pystencils::PSM_MacroGetter getterSweep(BFieldID, densityFieldID, pdfFieldID, velFieldID, real_t(0.0), real_t(0.0), + real_t(0.0)); + // vtk output + if (vtkSpacingParticles != uint_t(0)) + { + // sphere + auto particleVtkOutput = make_shared< mesa_pd::vtk::ParticleVtkOutput >(ps); + particleVtkOutput->addOutput< mesa_pd::data::SelectParticleUid >("uid"); + particleVtkOutput->addOutput< mesa_pd::data::SelectParticleLinearVelocity >("velocity"); + particleVtkOutput->addOutput< mesa_pd::data::SelectParticleInteractionRadius >("radius"); + // limit output to process-local spheres + particleVtkOutput->setParticleSelector([sphereShape](const mesa_pd::data::ParticleStorage::iterator& pIt) { + return pIt->getShapeID() == sphereShape && + !(mesa_pd::data::particle_flags::isSet(pIt->getFlags(), mesa_pd::data::particle_flags::GHOST)); + }); + auto particleVtkWriter = + vtk::createVTKOutput_PointData(particleVtkOutput, "particles", vtkSpacingParticles, vtkFolder); + timeloop.addFuncBeforeTimeStep(vtk::writeFiles(particleVtkWriter), "VTK (sphere data)"); + } + + if (vtkSpacingFluid != uint_t(0)) + { + // velocity field, only a slice + auto pdfFieldVTK = vtk::createVTKOutput_BlockData(blocks, "fluid", vtkSpacingFluid, 0, false, vtkFolder); + + pdfFieldVTK->addBeforeFunction(communication); + + pdfFieldVTK->addBeforeFunction([&]() { + gpu::fieldCpy< PdfField_T, gpu::GPUField< real_t > >(blocks, pdfFieldID, pdfFieldGPUID); + gpu::fieldCpy< GhostLayerField< real_t, 1 >, BFieldGPU_T >(blocks, BFieldID, + particleAndVolumeFractionSoA.BFieldID); + for (auto& block : *blocks) + getterSweep(&block); + }); + + AABB sliceAABB(real_t(0), real_c(domainSize[1]) * real_t(0.5) - real_t(1), real_t(0), real_c(domainSize[0]), + real_c(domainSize[1]) * real_t(0.5) + real_t(1), real_c(domainSize[2])); + vtk::AABBCellFilter aabbSliceFilter(sliceAABB); + + field::FlagFieldCellFilter< FlagField_T > fluidFilter(flagFieldID); + fluidFilter.addFlag(Fluid_Flag); + + vtk::ChainedFilter combinedSliceFilter; + combinedSliceFilter.addFilter(fluidFilter); + combinedSliceFilter.addFilter(aabbSliceFilter); + + pdfFieldVTK->addCellInclusionFilter(combinedSliceFilter); + + pdfFieldVTK->addCellDataWriter(make_shared< field::VTKWriter< VelocityField_T > >(velFieldID, "Velocity")); + pdfFieldVTK->addCellDataWriter(make_shared< field::VTKWriter< DensityField_T > >(densityFieldID, "Density")); + pdfFieldVTK->addCellDataWriter(make_shared< field::VTKWriter< BField_T > >(BFieldID, "Fraction mapping field B")); + + timeloop.addFuncBeforeTimeStep(vtk::writeFiles(pdfFieldVTK), "VTK (fluid field data)"); + } + + if (vtkSpacingFluid != uint_t(0) || vtkSpacingParticles != uint_t(0)) + { + vtk::writeDomainDecomposition(blocks, "domain_decomposition", vtkFolder); + } + + // add performance logging + const lbm::PerformanceLogger< FlagField_T > performanceLogger(blocks, flagFieldID, Fluid_Flag, + performanceLogFrequency); + timeloop.addFuncAfterTimeStep(performanceLogger, "Evaluate performance logging"); + + // add LBM communication function and boundary handling sweep + timeloop.add() << Sweep(deviceSyncWrapper(ubb.getSweep()), "Boundary Handling (UBB)"); + timeloop.add() << Sweep(deviceSyncWrapper(density_bc.getSweep()), "Boundary Handling (Density)"); + timeloop.add() << Sweep(deviceSyncWrapper(noSlip.getSweep()), "Boundary Handling (NoSlip)"); + + // stream + collide LBM step + pystencils::PSMSweepSplit PSMSweep(particleAndVolumeFractionSoA.BsFieldID, particleAndVolumeFractionSoA.BFieldID, + particleAndVolumeFractionSoA.particleForcesFieldID, + particleAndVolumeFractionSoA.particleVelocitiesFieldID, pdfFieldGPUID, + real_t(0.0), real_t(0.0), real_t(0.0), omega); + addPSMSweepsToTimeloops(commTimeloop, timeloop, com, psmSweepCollection, PSMSweep); + + //////////////////////// + // EXECUTE SIMULATION // + //////////////////////// + + WcTimingPool timeloopTiming; + const bool useOpenMP = true; + + real_t linkedCellWidth = linkedCellWidthRation * diameter; + mesa_pd::data::LinkedCells linkedCells(rpdDomain->getUnionOfLocalAABBs().getExtended(linkedCellWidth), + linkedCellWidth); + mesa_pd::kernel::InsertParticleIntoLinkedCells ipilc; + + // time loop + for (uint_t timeStep = 0; timeStep < numTimeSteps; ++timeStep) + { + // perform a single simulation step -> this contains LBM and setting of the hydrodynamic interactions + commTimeloop.singleStep(timeloopTiming); + timeloop.singleStep(timeloopTiming); + + if (particleBarriers) WALBERLA_MPI_BARRIER(); + timeloopTiming["RPD forEachParticle assoc"].start(); + ps->forEachParticle(useOpenMP, mesa_pd::kernel::SelectLocal(), *accessor, assoc, *accessor); + if (particleBarriers) WALBERLA_MPI_BARRIER(); + timeloopTiming["RPD forEachParticle assoc"].end(); + timeloopTiming["RPD reduceProperty HydrodynamicForceTorqueNotification"].start(); + reduceProperty.operator()< mesa_pd::HydrodynamicForceTorqueNotification >(*ps); + if (particleBarriers) WALBERLA_MPI_BARRIER(); + timeloopTiming["RPD reduceProperty HydrodynamicForceTorqueNotification"].end(); + + if (timeStep == 0) + { + lbm_mesapd_coupling::InitializeHydrodynamicForceTorqueForAveragingKernel + initializeHydrodynamicForceTorqueForAveragingKernel; + timeloopTiming["RPD forEachParticle initializeHydrodynamicForceTorqueForAveragingKernel"].start(); + ps->forEachParticle(useOpenMP, mesa_pd::kernel::SelectLocal(), *accessor, + initializeHydrodynamicForceTorqueForAveragingKernel, *accessor); + if (particleBarriers) WALBERLA_MPI_BARRIER(); + timeloopTiming["RPD forEachParticle initializeHydrodynamicForceTorqueForAveragingKernel"].end(); + } + timeloopTiming["RPD forEachParticle averageHydrodynamicForceTorque"].start(); + ps->forEachParticle(useOpenMP, mesa_pd::kernel::SelectLocal(), *accessor, averageHydrodynamicForceTorque, + *accessor); + if (particleBarriers) WALBERLA_MPI_BARRIER(); + timeloopTiming["RPD forEachParticle averageHydrodynamicForceTorque"].end(); + + for (auto subCycle = uint_t(0); subCycle < numberOfParticleSubCycles; ++subCycle) + { + timeloopTiming["RPD forEachParticle vvIntegratorPreForce"].start(); + ps->forEachParticle(useOpenMP, mesa_pd::kernel::SelectLocal(), *accessor, vvIntegratorPreForce, *accessor); + if (particleBarriers) WALBERLA_MPI_BARRIER(); + timeloopTiming["RPD forEachParticle vvIntegratorPreForce"].end(); + timeloopTiming["RPD syncCall"].start(); + syncCall(); + if (particleBarriers) WALBERLA_MPI_BARRIER(); + timeloopTiming["RPD syncCall"].end(); + + timeloopTiming["RPD linkedCells.clear"].start(); + linkedCells.clear(); + if (particleBarriers) WALBERLA_MPI_BARRIER(); + timeloopTiming["RPD linkedCells.clear"].end(); + timeloopTiming["RPD forEachParticle ipilc"].start(); + ps->forEachParticle(useOpenMP, mesa_pd::kernel::SelectAll(), *accessor, ipilc, *accessor, linkedCells); + if (particleBarriers) WALBERLA_MPI_BARRIER(); + timeloopTiming["RPD forEachParticle ipilc"].end(); + + if (useLubricationForces) + { + // lubrication correction + timeloopTiming["RPD forEachParticlePairHalf lubricationCorrectionKernel"].start(); + linkedCells.forEachParticlePairHalf( + useOpenMP, mesa_pd::kernel::ExcludeInfiniteInfinite(), *accessor, + [&lubricationCorrectionKernel, &rpdDomain](const size_t idx1, const size_t idx2, auto& ac) { + mesa_pd::collision_detection::AnalyticContactDetection acd; + acd.getContactThreshold() = lubricationCorrectionKernel.getNormalCutOffDistance(); + mesa_pd::kernel::DoubleCast double_cast; + mesa_pd::mpi::ContactFilter contact_filter; + if (double_cast(idx1, idx2, ac, acd, ac)) + { + if (contact_filter(acd.getIdx1(), acd.getIdx2(), ac, acd.getContactPoint(), *rpdDomain)) + { + double_cast(acd.getIdx1(), acd.getIdx2(), ac, lubricationCorrectionKernel, ac, + acd.getContactNormal(), acd.getPenetrationDepth()); + } + } + }, + *accessor); + if (particleBarriers) WALBERLA_MPI_BARRIER(); + timeloopTiming["RPD forEachParticlePairHalf lubricationCorrectionKernel"].end(); + } + + // collision response + timeloopTiming["RPD forEachParticlePairHalf collisionResponse"].start(); + linkedCells.forEachParticlePairHalf( + useOpenMP, mesa_pd::kernel::ExcludeInfiniteInfinite(), *accessor, + [&collisionResponse, &rpdDomain, timeStepSizeRPD](const size_t idx1, const size_t idx2, auto& ac) { + mesa_pd::collision_detection::AnalyticContactDetection acd; + mesa_pd::kernel::DoubleCast double_cast; + mesa_pd::mpi::ContactFilter contact_filter; + if (double_cast(idx1, idx2, ac, acd, ac)) + { + if (contact_filter(acd.getIdx1(), acd.getIdx2(), ac, acd.getContactPoint(), *rpdDomain)) + { + collisionResponse(acd.getIdx1(), acd.getIdx2(), ac, acd.getContactPoint(), acd.getContactNormal(), + acd.getPenetrationDepth(), timeStepSizeRPD); + } + } + }, + *accessor); + if (particleBarriers) WALBERLA_MPI_BARRIER(); + timeloopTiming["RPD forEachParticlePairHalf collisionResponse"].end(); + + timeloopTiming["RPD reduceProperty reduceAndSwapContactHistory"].start(); + reduceAndSwapContactHistory(*ps); + if (particleBarriers) WALBERLA_MPI_BARRIER(); + timeloopTiming["RPD reduceProperty reduceAndSwapContactHistory"].end(); + + // add hydrodynamic force + lbm_mesapd_coupling::AddHydrodynamicInteractionKernel addHydrodynamicInteraction; + timeloopTiming["RPD forEachParticle addHydrodynamicInteraction + addGravitationalForce"].start(); + ps->forEachParticle(useOpenMP, mesa_pd::kernel::SelectLocal(), *accessor, addHydrodynamicInteraction, + *accessor); + + ps->forEachParticle(useOpenMP, mesa_pd::kernel::SelectLocal(), *accessor, addGravitationalForce, *accessor); + if (particleBarriers) WALBERLA_MPI_BARRIER(); + timeloopTiming["RPD forEachParticle addHydrodynamicInteraction + addGravitationalForce"].end(); + + timeloopTiming["RPD reduceProperty ForceTorqueNotification"].start(); + reduceProperty.operator()< mesa_pd::ForceTorqueNotification >(*ps); + if (particleBarriers) WALBERLA_MPI_BARRIER(); + timeloopTiming["RPD reduceProperty ForceTorqueNotification"].end(); + + timeloopTiming["RPD forEachParticle vvIntegratorPostForce"].start(); + ps->forEachParticle(useOpenMP, mesa_pd::kernel::SelectLocal(), *accessor, vvIntegratorPostForce, *accessor); + if (particleBarriers) WALBERLA_MPI_BARRIER(); + timeloopTiming["RPD forEachParticle vvIntegratorPostForce"].end(); + } + + timeloopTiming["RPD syncCall"].start(); + syncCall(); + if (particleBarriers) WALBERLA_MPI_BARRIER(); + timeloopTiming["RPD syncCall"].end(); + + timeloopTiming["RPD forEachParticle resetHydrodynamicForceTorque"].start(); + ps->forEachParticle(useOpenMP, mesa_pd::kernel::SelectAll(), *accessor, resetHydrodynamicForceTorque, *accessor); + if (particleBarriers) WALBERLA_MPI_BARRIER(); + timeloopTiming["RPD forEachParticle resetHydrodynamicForceTorque"].end(); + + if (infoSpacing != 0 && timeStep % infoSpacing == 0) + { + timeloopTiming["Evaluate infos"].start(); + + auto particleInfo = evaluateParticleInfo(*accessor); + WALBERLA_LOG_INFO_ON_ROOT(particleInfo); + + auto fluidInfo = evaluateFluidInfo(blocks, densityFieldID, velFieldID); + WALBERLA_LOG_INFO_ON_ROOT(fluidInfo); + if (particleBarriers) WALBERLA_MPI_BARRIER(); + timeloopTiming["Evaluate infos"].end(); + } + } + + timeloopTiming.logResultOnRoot(); + + return EXIT_SUCCESS; +} + +} // namespace fluidized_bed + +int main(int argc, char** argv) { fluidized_bed::main(argc, argv); } diff --git a/apps/benchmarks/FluidizedBed/input.prm b/apps/benchmarks/FluidizedBed/input.prm new file mode 100644 index 0000000000000000000000000000000000000000..aa293e8609c90fa61cf982b5d69d998d5a6e66ec --- /dev/null +++ b/apps/benchmarks/FluidizedBed/input.prm @@ -0,0 +1,54 @@ +PhysicalSetup // all to be specified in SI units! +{ + xSize 0.05; // = width + ySize 0.02; // = depth + zSize 0.08; // = height + + periodicInX false; + periodicInY false; + + runtime 0.1; + + uInflow 0.005; + gravitationalAcceleration 9.81; + + kinematicViscosityFluid 1e-5; + densityFluid 1000.; + + particleDiameter 0.002; + densityParticle 1100.; + dynamicFrictionCoefficient 0.15; + coefficientOfRestitution 0.6; + collisionTimeFactor 1.0; + + particleGenerationSpacing 0.00401; // 0.00401 or 0.00201 +} + +NumericalSetup +{ + dx 0.0001; // in m + uInflow 0.01; // in LBM units, should be smaller than 0.1, this then determines dt + + // product of number of blocks should be equal to number of used processes + numXBlocks 1; + numYBlocks 1; + numZBlocks 1; + + useLubricationForces true; + numberOfParticleSubCycles 10; + + particleSubBlockSize <10, 10, 10>; + linkedCellWidthRation 1.01; + particleBarriers true; +} + +Output +{ + infoSpacing 0.0; // in s + + vtkSpacingParticles 0.0; // in s + vtkSpacingFluid 0.0; // in s + vtkFolder vtk_out; + + performanceLogFrequency 500; +} diff --git a/apps/benchmarks/Percolation/CMakeLists.txt b/apps/benchmarks/Percolation/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..bb8c4f3dc9aa15c71786f4a1bc0a9cc0d28c9664 --- /dev/null +++ b/apps/benchmarks/Percolation/CMakeLists.txt @@ -0,0 +1,9 @@ +waLBerla_link_files_to_builddir("*.prm") + +if (WALBERLA_BUILD_WITH_CODEGEN) + if (NOT WALBERLA_BUILD_WITH_GPU_SUPPORT OR (WALBERLA_BUILD_WITH_GPU_SUPPORT AND (CMAKE_CUDA_ARCHITECTURES GREATER_EQUAL 60 OR WALBERLA_BUILD_WITH_HIP))) + waLBerla_add_executable(NAME Percolation FILES Percolation.cpp + DEPENDS blockforest core field geometry gpu lbm lbm_mesapd_coupling mesa_pd sqlite vtk PSMCodegenPython_trt-smagorinsky_sc1) + target_compile_definitions(Percolation PRIVATE Weighting=2) + endif () +endif () diff --git a/apps/benchmarks/Percolation/Percolation.cpp b/apps/benchmarks/Percolation/Percolation.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f778f7bc951582c2aa5ef04281c66801bd8c0728 --- /dev/null +++ b/apps/benchmarks/Percolation/Percolation.cpp @@ -0,0 +1,507 @@ +//====================================================================================================================== +// +// This file is part of waLBerla. waLBerla 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. +// +// waLBerla 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 waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file Percolation.cpp +//! \ingroup lbm_mesapd_coupling +//! \author Samuel Kemmler <samuel.kemmler@fau.de> +// +//====================================================================================================================== + +#include "blockforest/Initialization.h" +#include "blockforest/communication/UniformBufferedScheme.h" + +#include "core/DataTypes.h" +#include "core/Environment.h" +#include "core/grid_generator/SCIterator.h" +#include "core/logging/all.h" +#include "core/timing/RemainingTimeLogger.h" + +#include "field/AddToStorage.h" +#include "field/vtk/all.h" + +#include "geometry/InitBoundaryHandling.h" + +#include "gpu/AddGPUFieldToStorage.h" +#include "gpu/DeviceSelectMPI.h" +#include "gpu/communication/UniformGPUScheme.h" + +#include "lbm/PerformanceLogger.h" +#include "lbm/vtk/all.h" + +#include "lbm_mesapd_coupling/DataTypesCodegen.h" +#include "lbm_mesapd_coupling/partially_saturated_cells_method/codegen/PSMSweepCollection.h" +#include "lbm_mesapd_coupling/utility/ParticleSelector.h" + +#include "mesa_pd/data/DataTypes.h" +#include "mesa_pd/data/ParticleAccessorWithShape.h" +#include "mesa_pd/data/ParticleStorage.h" +#include "mesa_pd/data/ShapeStorage.h" +#include "mesa_pd/data/shape/Sphere.h" +#include "mesa_pd/domain/BlockForestDomain.h" +#include "mesa_pd/mpi/SyncNextNeighbors.h" +#include "mesa_pd/vtk/ParticleVtkOutput.h" + +#include "sqlite/SQLite.h" + +#include "vtk/all.h" + +#include "LBMSweep.h" +#include "PSMPackInfo.h" +#include "PSMSweep.h" +#include "PSM_Density.h" +#include "PSM_InfoHeader.h" +#include "PSM_MacroGetter.h" + +namespace percolation +{ + +/////////// +// USING // +/////////// + +using namespace walberla; +using namespace lbm_mesapd_coupling::psm::gpu; +typedef pystencils::PSMPackInfo PackInfo_T; + +using flag_t = walberla::uint8_t; +using FlagField_T = FlagField< flag_t >; + +/////////// +// FLAGS // +/////////// + +const FlagUID Fluid_Flag("Fluid"); +const FlagUID Density_Flag("Density"); +const FlagUID NoSlip_Flag("NoSlip"); +const FlagUID Inflow_Flag("Inflow"); + +////////// +// MAIN // +////////// + +//******************************************************************************************************************* +/*!\brief Benchmark of a percolation setup + * + * This code can be used as a percolation (useParticles=true) or as a channel flow (useParticles=false) benchmark. + * A constant inflow from west is applied and a pressure boundary condition is set at the east. + * For the percolation, mono-sized fixed spherical particles are generated on a structured grid with an offset for + * every second particle layer in flow direction to avoid channels in flow direction. The flow is described by Darcy's + * law. For the channel flow, the flow is described by the Hagen–Poiseuille equation. + * + * The domain is either periodic or bounded by (no slip) walls in the vertical directions (y and z). + * + * For the percolation, the PSM is used in combination with a two-way coupling, but no particle dynamics. + * For the channel flow, only the LBM is used. + * + * The parameters can be changed via the input file. + * + */ +//******************************************************************************************************************* +int main(int argc, char** argv) +{ + Environment env(argc, argv); + auto cfgFile = env.config(); + if (!cfgFile) { WALBERLA_ABORT("Usage: " << argv[0] << " path-to-configuration-file \n"); } + +#ifdef WALBERLA_BUILD_WITH_GPU_SUPPORT + gpu::selectDeviceBasedOnMpiRank(); +#endif + + WALBERLA_LOG_INFO_ON_ROOT("waLBerla revision: " << std::string(WALBERLA_GIT_SHA1).substr(0, 8)); + WALBERLA_LOG_INFO_ON_ROOT("compiler flags: " << std::string(WALBERLA_COMPILER_FLAGS)); + WALBERLA_LOG_INFO_ON_ROOT("build machine: " << std::string(WALBERLA_BUILD_MACHINE)); + WALBERLA_LOG_INFO_ON_ROOT(*cfgFile); + + // Read config file + Config::BlockHandle numericalSetup = cfgFile->getBlock("NumericalSetup"); + const uint_t numXBlocks = numericalSetup.getParameter< uint_t >("numXBlocks"); + const uint_t numYBlocks = numericalSetup.getParameter< uint_t >("numYBlocks"); + const uint_t numZBlocks = numericalSetup.getParameter< uint_t >("numZBlocks"); + WALBERLA_CHECK_EQUAL(numXBlocks * numYBlocks * numZBlocks, uint_t(MPIManager::instance()->numProcesses()), + "When using GPUs, the number of blocks (" + << numXBlocks * numYBlocks * numZBlocks << ") has to match the number of MPI processes (" + << uint_t(MPIManager::instance()->numProcesses()) << ")"); + const bool periodicInY = numericalSetup.getParameter< bool >("periodicInY"); + const bool periodicInZ = numericalSetup.getParameter< bool >("periodicInZ"); + const uint_t numXCellsPerBlock = numericalSetup.getParameter< uint_t >("numXCellsPerBlock"); + const uint_t numYCellsPerBlock = numericalSetup.getParameter< uint_t >("numYCellsPerBlock"); + const uint_t numZCellsPerBlock = numericalSetup.getParameter< uint_t >("numZCellsPerBlock"); + const bool sendDirectlyFromGPU = numericalSetup.getParameter< bool >("sendDirectlyFromGPU"); + const bool useCommunicationHiding = numericalSetup.getParameter< bool >("useCommunicationHiding"); + const Vector3< uint_t > frameWidth = numericalSetup.getParameter< Vector3< uint_t > >("frameWidth"); + const uint_t timeSteps = numericalSetup.getParameter< uint_t >("timeSteps"); + const bool useParticles = numericalSetup.getParameter< bool >("useParticles"); + const real_t particleDiameter = numericalSetup.getParameter< real_t >("particleDiameter"); + const real_t particleGenerationSpacing = numericalSetup.getParameter< real_t >("particleGenerationSpacing"); + const Vector3< real_t > generationDomainFraction = + numericalSetup.getParameter< Vector3< real_t > >("generationDomainFraction"); + const Vector3< uint_t > generationPointOfReferenceOffset = + numericalSetup.getParameter< Vector3< uint_t > >("generationPointOfReferenceOffset"); + const bool useParticleOffset = numericalSetup.getParameter< bool >("useParticleOffset"); + const Vector3< uint_t > particleSubBlockSize = + numericalSetup.getParameter< Vector3< uint_t > >("particleSubBlockSize"); + const real_t uInflow = numericalSetup.getParameter< real_t >("uInflow"); + const real_t relaxationRate = numericalSetup.getParameter< real_t >("relaxationRate"); + if ((periodicInY && numYBlocks == 1) || (periodicInZ && numZBlocks == 1)) + { + WALBERLA_LOG_WARNING_ON_ROOT("Using only 1 block in periodic dimensions can lead to unexpected behavior.") + } + const real_t viscosity = lbm::collision_model::viscosityFromOmega(relaxationRate); + WALBERLA_LOG_DEVEL_VAR_ON_ROOT(viscosity) + + Config::BlockHandle outputSetup = cfgFile->getBlock("Output"); + const uint_t vtkSpacing = outputSetup.getParameter< uint_t >("vtkSpacing"); + const std::string vtkFolder = outputSetup.getParameter< std::string >("vtkFolder"); + const uint_t performanceLogFrequency = outputSetup.getParameter< uint_t >("performanceLogFrequency"); + + /////////////////////////// + // BLOCK STRUCTURE SETUP // + /////////////////////////// + + const bool periodicInX = false; + shared_ptr< StructuredBlockForest > blocks = blockforest::createUniformBlockGrid( + numXBlocks, numYBlocks, numZBlocks, numXCellsPerBlock, numYCellsPerBlock, numZCellsPerBlock, real_t(1), uint_t(0), + false, false, periodicInX, periodicInY, periodicInZ, // periodicity + false); + + auto simulationDomain = blocks->getDomain(); + + //////////// + // MesaPD // + //////////// + + auto rpdDomain = std::make_shared< mesa_pd::domain::BlockForestDomain >(blocks->getBlockForestPointer()); + + // Init data structures + auto ps = walberla::make_shared< mesa_pd::data::ParticleStorage >(1); + auto ss = walberla::make_shared< mesa_pd::data::ShapeStorage >(); + using ParticleAccessor_T = mesa_pd::data::ParticleAccessorWithShape; + auto accessor = walberla::make_shared< ParticleAccessor_T >(ps, ss); + auto sphereShape = ss->create< mesa_pd::data::Sphere >(particleDiameter * real_t(0.5)); + + // Create spheres + if (useParticles) + { + // Ensure that generation domain is computed correctly + WALBERLA_CHECK_FLOAT_EQUAL(simulationDomain.xMin(), real_t(0)); + WALBERLA_CHECK_FLOAT_EQUAL(simulationDomain.yMin(), real_t(0)); + WALBERLA_CHECK_FLOAT_EQUAL(simulationDomain.zMin(), real_t(0)); + + auto generationDomain = math::AABB::createFromMinMaxCorner( + math::Vector3< real_t >(simulationDomain.xMax() * (real_t(1) - generationDomainFraction[0]) / real_t(2), + simulationDomain.yMax() * (real_t(1) - generationDomainFraction[1]) / real_t(2), + simulationDomain.zMax() * (real_t(1) - generationDomainFraction[2]) / real_t(2)), + math::Vector3< real_t >(simulationDomain.xMax() * (real_t(1) + generationDomainFraction[0]) / real_t(2), + simulationDomain.yMax() * (real_t(1) + generationDomainFraction[1]) / real_t(2), + simulationDomain.zMax() * (real_t(1) + generationDomainFraction[2]) / real_t(2))); + real_t particleOffset = particleGenerationSpacing / real_t(2); + for (auto pt : + grid_generator::SCGrid(generationDomain, generationDomain.center() + generationPointOfReferenceOffset, + particleGenerationSpacing)) + { + // Offset every second particle layer in flow direction to avoid channels in flow direction + if (useParticleOffset && + uint_t(round(math::abs(generationDomain.center()[0] - pt[0]) / (particleGenerationSpacing))) % uint_t(2) != + uint_t(0)) + { + pt = pt + Vector3(real_t(0), particleOffset, particleOffset); + } + if (rpdDomain->isContainedInProcessSubdomain(uint_c(mpi::MPIManager::instance()->rank()), pt)) + { + mesa_pd::data::Particle&& p = *ps->create(); + p.setPosition(pt); + p.setInteractionRadius(particleDiameter * real_t(0.5)); + p.setOwner(mpi::MPIManager::instance()->rank()); + p.setShapeID(sphereShape); + p.setType(0); + } + } + } + + /////////////////////// + // ADD DATA TO BLOCKS // + //////////////////////// + + // Setting initial PDFs to nan helps to detect bugs in the initialization/BC handling + // Depending on WALBERLA_BUILD_WITH_GPU_SUPPORT, pdfFieldCPUGPUID is either a CPU or a CPU field +#ifdef WALBERLA_BUILD_WITH_GPU_SUPPORT + BlockDataID pdfFieldID = + field::addToStorage< PdfField_T >(blocks, "pdf field (fzyx)", real_c(std::nan("")), field::fzyx); + BlockDataID BFieldID = field::addToStorage< BField_T >(blocks, "B field", 0, field::fzyx, 1); + BlockDataID pdfFieldCPUGPUID = gpu::addGPUFieldToStorage< PdfField_T >(blocks, pdfFieldID, "pdf field GPU"); +#else + BlockDataID pdfFieldCPUGPUID = + field::addToStorage< PdfField_T >(blocks, "pdf field CPU", real_c(std::nan("")), field::fzyx); +#endif + BlockDataID densityFieldID = field::addToStorage< DensityField_T >(blocks, "density field", real_t(0), field::fzyx); + BlockDataID velFieldID = field::addToStorage< VelocityField_T >(blocks, "velocity field", real_t(0), field::fzyx); + BlockDataID flagFieldID = field::addFlagFieldToStorage< FlagField_T >(blocks, "flag field"); + + // Synchronize particles between the blocks for the correct mapping of ghost particles + mesa_pd::mpi::SyncNextNeighbors syncNextNeighborFunc; + syncNextNeighborFunc(*ps, *rpdDomain); + + // Assemble boundary block string + std::string boundariesBlockString = " Boundaries" + "{" + "Border { direction W; walldistance -1; flag Inflow; }" + "Border { direction E; walldistance -1; flag Density; }"; + + if (!periodicInY) + { + boundariesBlockString += "Border { direction S; walldistance -1; flag NoSlip; }" + "Border { direction N; walldistance -1; flag NoSlip; }"; + } + + if (!periodicInZ) + { + boundariesBlockString += "Border { direction T; walldistance -1; flag NoSlip; }" + "Border { direction B; walldistance -1; flag NoSlip; }"; + } + + boundariesBlockString += "}"; + WALBERLA_ROOT_SECTION() + { + std::ofstream boundariesFile("boundaries.prm"); + boundariesFile << boundariesBlockString; + boundariesFile.close(); + } + WALBERLA_MPI_BARRIER() + + auto boundariesCfgFile = Config(); + boundariesCfgFile.readParameterFile("boundaries.prm"); + auto boundariesConfig = boundariesCfgFile.getBlock("Boundaries"); + + // map boundaries into the LBM simulation + geometry::initBoundaryHandling< FlagField_T >(*blocks, flagFieldID, boundariesConfig); + geometry::setNonBoundaryCellsToDomain< FlagField_T >(*blocks, flagFieldID, Fluid_Flag); + lbm::PSM_Density density_bc(blocks, pdfFieldCPUGPUID, real_t(1.0)); + density_bc.fillFromFlagField< FlagField_T >(blocks, flagFieldID, Density_Flag, Fluid_Flag); + lbm::PSM_NoSlip noSlip(blocks, pdfFieldCPUGPUID); + noSlip.fillFromFlagField< FlagField_T >(blocks, flagFieldID, NoSlip_Flag, Fluid_Flag); + lbm::PSM_UBB ubb(blocks, pdfFieldCPUGPUID, uInflow, real_t(0), real_t(0)); + ubb.fillFromFlagField< FlagField_T >(blocks, flagFieldID, Inflow_Flag, Fluid_Flag); + + /////////////// + // TIME LOOP // + /////////////// + + // Map particles into the fluid domain + ParticleAndVolumeFractionSoA_T< Weighting > particleAndVolumeFractionSoA(blocks, relaxationRate); + PSMSweepCollection psmSweepCollection(blocks, accessor, lbm_mesapd_coupling::RegularParticlesSelector(), + particleAndVolumeFractionSoA, particleSubBlockSize); + if (useParticles) + { + for (auto blockIt = blocks->begin(); blockIt != blocks->end(); ++blockIt) + { + psmSweepCollection.particleMappingSweep(&(*blockIt)); + } + } + + // Initialize PDFs + pystencils::InitializeDomainForPSM pdfSetter( + particleAndVolumeFractionSoA.BsFieldID, particleAndVolumeFractionSoA.BFieldID, + particleAndVolumeFractionSoA.particleVelocitiesFieldID, pdfFieldCPUGPUID, real_t(0), real_t(0), real_t(0), + real_t(1.0), real_t(0), real_t(0), real_t(0)); + + for (auto blockIt = blocks->begin(); blockIt != blocks->end(); ++blockIt) + { + // pdfSetter requires particle velocities at cell centers + if (useParticles) { psmSweepCollection.setParticleVelocitiesSweep(&(*blockIt)); } + pdfSetter(&(*blockIt)); + } + + // Setup of the LBM communication for synchronizing the pdf field between neighboring blocks +#ifdef WALBERLA_BUILD_WITH_GPU_SUPPORT + gpu::communication::UniformGPUScheme< Stencil_T > com(blocks, sendDirectlyFromGPU, false); +#else + walberla::blockforest::communication::UniformBufferedScheme< Stencil_T > com(blocks); +#endif + com.addPackInfo(make_shared< PackInfo_T >(pdfFieldCPUGPUID)); + auto communication = std::function< void() >([&]() { com.communicate(); }); + + SweepTimeloop commTimeloop(blocks->getBlockStorage(), timeSteps); + SweepTimeloop timeloop(blocks->getBlockStorage(), timeSteps); + + timeloop.addFuncBeforeTimeStep(RemainingTimeLogger(timeloop.getNrOfTimeSteps()), "Remaining Time Logger"); + +#ifdef WALBERLA_BUILD_WITH_GPU_SUPPORT + pystencils::PSM_MacroGetter getterSweep(BFieldID, densityFieldID, pdfFieldID, velFieldID, real_t(0.0), real_t(0.0), + real_t(0.0)); +#else + pystencils::PSM_MacroGetter getterSweep(particleAndVolumeFractionSoA.BFieldID, densityFieldID, pdfFieldCPUGPUID, + velFieldID, real_t(0.0), real_t(0.0), real_t(0.0)); +#endif + // VTK output + if (vtkSpacing != uint_t(0)) + { + // Spheres + auto particleVtkOutput = make_shared< mesa_pd::vtk::ParticleVtkOutput >(ps); + particleVtkOutput->addOutput< mesa_pd::data::SelectParticleUid >("uid"); + particleVtkOutput->addOutput< mesa_pd::data::SelectParticleLinearVelocity >("velocity"); + particleVtkOutput->addOutput< mesa_pd::data::SelectParticleInteractionRadius >("radius"); + // Limit output to process-local spheres + particleVtkOutput->setParticleSelector([sphereShape](const mesa_pd::data::ParticleStorage::iterator& pIt) { + return pIt->getShapeID() == sphereShape && + !(mesa_pd::data::particle_flags::isSet(pIt->getFlags(), mesa_pd::data::particle_flags::GHOST)); + }); + auto particleVtkWriter = vtk::createVTKOutput_PointData(particleVtkOutput, "particles", vtkSpacing, vtkFolder); + timeloop.addFuncBeforeTimeStep(vtk::writeFiles(particleVtkWriter), "VTK (sphere data)"); + + // Fields + auto pdfFieldVTK = vtk::createVTKOutput_BlockData(blocks, "fluid", vtkSpacing, 0, false, vtkFolder); + + pdfFieldVTK->addBeforeFunction(communication); + + pdfFieldVTK->addBeforeFunction([&]() { +#ifdef WALBERLA_BUILD_WITH_GPU_SUPPORT + gpu::fieldCpy< PdfField_T, gpu::GPUField< real_t > >(blocks, pdfFieldID, pdfFieldCPUGPUID); + gpu::fieldCpy< GhostLayerField< real_t, 1 >, BFieldGPU_T >(blocks, BFieldID, + particleAndVolumeFractionSoA.BFieldID); +#endif + for (auto& block : *blocks) + getterSweep(&block); + }); + + pdfFieldVTK->addCellDataWriter(make_shared< field::VTKWriter< VelocityField_T > >(velFieldID, "Velocity")); + pdfFieldVTK->addCellDataWriter(make_shared< field::VTKWriter< DensityField_T > >(densityFieldID, "Density")); +#ifdef WALBERLA_BUILD_WITH_GPU_SUPPORT + pdfFieldVTK->addCellDataWriter(make_shared< field::VTKWriter< BField_T > >(BFieldID, "OverlapFraction")); +#else + pdfFieldVTK->addCellDataWriter( + make_shared< field::VTKWriter< BField_T > >(particleAndVolumeFractionSoA.BFieldID, "OverlapFraction")); +#endif + pdfFieldVTK->addCellDataWriter(make_shared< field::VTKWriter< FlagField_T > >(flagFieldID, "FlagField")); + + timeloop.addFuncBeforeTimeStep(vtk::writeFiles(pdfFieldVTK), "VTK (fluid field data)"); + } + + if (vtkSpacing != uint_t(0)) { vtk::writeDomainDecomposition(blocks, "domain_decomposition", vtkFolder); } + + // Add performance logging + lbm::PerformanceLogger< FlagField_T > performanceLogger(blocks, flagFieldID, Fluid_Flag, performanceLogFrequency); + if (performanceLogFrequency > 0) + { + timeloop.addFuncAfterTimeStep(performanceLogger, "Evaluate performance logging"); + } + + // Add LBM communication function and boundary handling sweep + if (useCommunicationHiding) + { + timeloop.add() << Sweep(deviceSyncWrapper(density_bc.getSweep()), "Boundary Handling (Density)"); + } + else + { + timeloop.add() << BeforeFunction(communication, "LBM Communication") + << Sweep(deviceSyncWrapper(density_bc.getSweep()), "Boundary Handling (Density)"); + } + timeloop.add() << Sweep(deviceSyncWrapper(ubb.getSweep()), "Boundary Handling (UBB)"); + if (!periodicInY || !periodicInZ) + { + timeloop.add() << Sweep(deviceSyncWrapper(noSlip.getSweep()), "Boundary Handling (NoSlip)"); + } + + // PSM kernel + pystencils::PSMSweep PSMSweep(particleAndVolumeFractionSoA.BsFieldID, particleAndVolumeFractionSoA.BFieldID, + particleAndVolumeFractionSoA.particleForcesFieldID, + particleAndVolumeFractionSoA.particleVelocitiesFieldID, pdfFieldCPUGPUID, real_t(0.0), + real_t(0.0), real_t(0.0), relaxationRate); + pystencils::PSMSweepSplit PSMSplitSweep( + particleAndVolumeFractionSoA.BsFieldID, particleAndVolumeFractionSoA.BFieldID, + particleAndVolumeFractionSoA.particleForcesFieldID, particleAndVolumeFractionSoA.particleVelocitiesFieldID, + pdfFieldCPUGPUID, real_t(0.0), real_t(0.0), real_t(0.0), relaxationRate, frameWidth); + pystencils::LBMSweep LBMSweep(pdfFieldCPUGPUID, real_t(0.0), real_t(0.0), real_t(0.0), relaxationRate); + pystencils::LBMSplitSweep LBMSplitSweep(pdfFieldCPUGPUID, real_t(0.0), real_t(0.0), real_t(0.0), relaxationRate, + frameWidth); + + if (useParticles) + { + if (useCommunicationHiding) + { + addPSMSweepsToTimeloops(commTimeloop, timeloop, com, psmSweepCollection, PSMSplitSweep); + } + else { addPSMSweepsToTimeloop(timeloop, psmSweepCollection, PSMSweep); } + } + else + { + if (useCommunicationHiding) + { + commTimeloop.add() << BeforeFunction([&]() { com.startCommunication(); }, "LBM Communication (start)") + << Sweep(deviceSyncWrapper(LBMSplitSweep.getInnerSweep()), "LBM inner sweep") + << AfterFunction([&]() { com.wait(); }, "LBM Communication (wait)"); + timeloop.add() << Sweep(deviceSyncWrapper(LBMSplitSweep.getOuterSweep()), "LBM outer sweep"); + } + else { timeloop.add() << Sweep(deviceSyncWrapper(LBMSweep), "LBM sweep"); } + } + + WcTimingPool timeloopTiming; + // TODO: maybe add warmup phase + for (uint_t timeStep = 0; timeStep < timeSteps; ++timeStep) + { + if (useCommunicationHiding) { commTimeloop.singleStep(timeloopTiming); } + timeloop.singleStep(timeloopTiming); + } + timeloopTiming.logResultOnRoot(); + auto timeloopTimingReduced = timeloopTiming.getReduced(); + + // Write parameters and performance results in sqlite database + WALBERLA_ROOT_SECTION() + { + // Use DB_FILE environment variable if set + std::string dbFile; + if (std::getenv("DB_FILE") != nullptr) { dbFile = std::getenv("DB_FILE"); } + else + { + if (useParticles) { dbFile = "percolation_benchmark.sqlite3"; } + else { dbFile = "channel_flow_benchmark.sqlite3"; } + } + + std::map< std::string, int > integerProperties; + std::map< std::string, double > realProperties; + std::map< std::string, std::string > stringProperties; + + integerProperties["numXBlocks"] = int(numXBlocks); + integerProperties["numYBlocks"] = int(numYBlocks); + integerProperties["numZBlocks"] = int(numZBlocks); + integerProperties["numXCellsPerBlock"] = int(numXCellsPerBlock); + integerProperties["numYCellsPerBlock"] = int(numYCellsPerBlock); + integerProperties["numZCellsPerBlock"] = int(numZCellsPerBlock); + integerProperties["timeSteps"] = int(timeSteps); + integerProperties["sendDirectlyFromGPU"] = int(sendDirectlyFromGPU); + integerProperties["useCommunicationHiding"] = int(useCommunicationHiding); + integerProperties["communicationHidingXWidth"] = int(frameWidth[0]); + integerProperties["communicationHidingYWidth"] = int(frameWidth[1]); + integerProperties["communicationHidingZWidth"] = int(frameWidth[2]); + integerProperties["useParticles"] = int(useParticles); + integerProperties["numParticles"] = int(ps->size()); + integerProperties["particleSubBlockXSize"] = int(particleSubBlockSize[0]); + integerProperties["particleSubBlockYSize"] = int(particleSubBlockSize[1]); + integerProperties["particleSubBlockZSize"] = int(particleSubBlockSize[2]); + + realProperties["particleDiameter"] = double(particleDiameter); + realProperties["particleGenerationSpacing"] = double(particleGenerationSpacing); + + performanceLogger.getBestResultsForSQLOnRoot(integerProperties, realProperties, stringProperties); + + auto runId = sqlite::storeRunInSqliteDB(dbFile, integerProperties, stringProperties, realProperties); + sqlite::storeTimingPoolInSqliteDB(dbFile, runId, *timeloopTimingReduced, "Timeloop"); + } + + return EXIT_SUCCESS; +} + +} // namespace percolation + +int main(int argc, char** argv) { percolation::main(argc, argv); } diff --git a/apps/benchmarks/Percolation/benchmark.prm b/apps/benchmarks/Percolation/benchmark.prm new file mode 100644 index 0000000000000000000000000000000000000000..f401949b546987d81fd55c052f1aa91973c834ad --- /dev/null +++ b/apps/benchmarks/Percolation/benchmark.prm @@ -0,0 +1,42 @@ + +NumericalSetup +{ + // product of number of blocks should be equal to number of used processes + numXBlocks 1; + numYBlocks 1; + numZBlocks 1; + + periodicInY false; + periodicInZ false; + + numXCellsPerBlock 256; + numYCellsPerBlock 128; + numZCellsPerBlock 128; + + timeSteps 100; + + sendDirectlyFromGPU false; // use GPU-GPU communication + useCommunicationHiding false; + frameWidth <1, 1, 1>; // width of the outer region if splitting the LBM/PSM into inner and outer (only used if useCommunicationHiding is true) + + // particle distribution in LBM units + useParticles true; // if true, PSM/particle mapping/velocity computation/hydrodynamic force reduction is used, else LBM is used + particleDiameter 20.0; + particleGenerationSpacing 21.0; + generationDomainFraction <0.8, 1.0, 1.0>; // fraction of the domain where particles are generated + generationPointOfReferenceOffset <0, 0, 0>; // offset of point of reference from domain center, see SCIterator.h + useParticleOffset true; // offset every second particle layer in flow direction + particleSubBlockSize <8, 8, 8>; + + // fluid quantities in LBM units + uInflow 0.00008; + relaxationRate 0.9; +} + +Output +{ + vtkSpacing 0; + vtkFolder vtk_out; + + performanceLogFrequency 100; +} diff --git a/apps/showcases/CMakeLists.txt b/apps/showcases/CMakeLists.txt index f601fdd24ebb1454ae518db8405be992f9f0be57..d845f5271c267d684793a6c795c49a558b323cd7 100644 --- a/apps/showcases/CMakeLists.txt +++ b/apps/showcases/CMakeLists.txt @@ -7,6 +7,7 @@ add_subdirectory( LightRisingParticleInFluidAMR ) add_subdirectory( Mixer ) add_subdirectory( ParticlePacking ) add_subdirectory( PegIntoSphereBed ) +add_subdirectory( Piping ) if ( WALBERLA_BUILD_WITH_CODEGEN) add_subdirectory( Antidunes ) diff --git a/apps/showcases/Piping/CMakeLists.txt b/apps/showcases/Piping/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..c86a1ee331e80325e60c529c37cc59c9f8871078 --- /dev/null +++ b/apps/showcases/Piping/CMakeLists.txt @@ -0,0 +1,5 @@ +add_subdirectory(setups) + +waLBerla_add_executable(NAME SettlingSpheres + FILES SettlingSpheres.cpp + DEPENDS blockforest core field lbm_mesapd_coupling mesa_pd vtk) diff --git a/apps/showcases/Piping/SettlingSpheres.cpp b/apps/showcases/Piping/SettlingSpheres.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d2477f0fb0716f2521f271c6eb4c309bed166baa --- /dev/null +++ b/apps/showcases/Piping/SettlingSpheres.cpp @@ -0,0 +1,300 @@ +//====================================================================================================================== +// +// This file is part of waLBerla. waLBerla 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. +// +// waLBerla 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 waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file SettlingSpheres.cpp +//! \author Samuel Kemmler <samuel.kemmler@fau.de> +//! \brief Based on showcases/Antidunes/BedGeneration.cpp +// +//====================================================================================================================== + +#include "blockforest/Initialization.h" + +#include "core/Environment.h" +#include "core/grid_generator/SCIterator.h" +#include "core/math/Random.h" +#include "core/mpi/Reduce.h" + +#include "mesa_pd/collision_detection/AnalyticContactDetection.h" +#include "mesa_pd/data/DataTypes.h" +#include "mesa_pd/data/LinkedCells.h" +#include "mesa_pd/data/ParticleAccessorWithBaseShape.h" +#include "mesa_pd/data/ParticleStorage.h" +#include "mesa_pd/data/shape/Sphere.h" +#include "mesa_pd/domain/BlockForestDomain.h" +#include "mesa_pd/kernel/AssocToBlock.h" +#include "mesa_pd/kernel/DoubleCast.h" +#include "mesa_pd/kernel/InsertParticleIntoLinkedCells.h" +#include "mesa_pd/kernel/LinearSpringDashpot.h" +#include "mesa_pd/kernel/ParticleSelector.h" +#include "mesa_pd/kernel/VelocityVerlet.h" +#include "mesa_pd/mpi/ContactFilter.h" +#include "mesa_pd/mpi/ReduceContactHistory.h" +#include "mesa_pd/mpi/ReduceProperty.h" +#include "mesa_pd/mpi/SyncNextNeighbors.h" +#include "mesa_pd/mpi/notifications/ForceTorqueNotification.h" +#include "mesa_pd/vtk/ParticleVtkOutput.h" + +#include "vtk/VTKOutput.h" + +#include "utility/ParticleUtility.h" + +namespace walberla +{ +namespace piping +{ + +using namespace mesa_pd; + +int main(int argc, char** argv) +{ + Environment env(argc, argv); + walberla::mpi::MPIManager::instance()->useWorldComm(); + + // Config + auto cfg = env.config(); + if (cfg == nullptr) WALBERLA_ABORT("No config specified!"); + WALBERLA_LOG_INFO_ON_ROOT(*cfg); + const Config::BlockHandle bedGenerationConf = cfg->getBlock("BedGeneration"); + + const Vec3 domainSize_SI = bedGenerationConf.getParameter< Vec3 >("domainSize_SI"); + const Vector3< int > blocks = bedGenerationConf.getParameter< Vector3< int > >("blocks"); + WALBERLA_CHECK_EQUAL(blocks[0] * blocks[1] * blocks[2], uint_t(MPIManager::instance()->numProcesses()), + "The number of blocks (" << blocks[0] * blocks[1] * blocks[2] + << ") has to match the number of MPI processes (" + << uint_t(MPIManager::instance()->numProcesses()) << ")"); + const bool periodicInX = bedGenerationConf.getParameter< bool >("periodicInX"); + const bool periodicInY = bedGenerationConf.getParameter< bool >("periodicInY"); + if ((periodicInX && blocks[0] == 1) || (periodicInY && blocks[1] == 1)) + { + WALBERLA_ABORT("The number of blocks in periodic dimensions must be greater than 1.") + } + const real_t minDiameter_SI = bedGenerationConf.getParameter< real_t >("minDiameter_SI"); + const real_t maxDiameter_SI = bedGenerationConf.getParameter< real_t >("maxDiameter_SI"); + const real_t gravity_SI = bedGenerationConf.getParameter< real_t >("gravity_SI"); + const real_t densityFluid_SI = bedGenerationConf.getParameter< real_t >("densityFluid_SI"); + const real_t densityParticle_SI = bedGenerationConf.getParameter< real_t >("densityParticle_SI"); + const real_t generationSpacing_SI = bedGenerationConf.getParameter< real_t >("generationSpacing_SI"); + const real_t initialVelocity_SI = bedGenerationConf.getParameter< real_t >("initialVelocity_SI"); + const real_t dt_SI = bedGenerationConf.getParameter< real_t >("dt_SI"); + const real_t frictionCoefficient = bedGenerationConf.getParameter< real_t >("frictionCoefficient"); + const real_t restitutionCoefficient = bedGenerationConf.getParameter< real_t >("restitutionCoefficient"); + const real_t collisionTime_SI = bedGenerationConf.getParameter< real_t >("collisionTime_SI"); + const real_t poissonsRatio = bedGenerationConf.getParameter< real_t >("poissonsRatio"); + const uint_t timeSteps = bedGenerationConf.getParameter< uint_t >("timeSteps"); + const uint_t visSpacing = bedGenerationConf.getParameter< uint_t >("visSpacing"); + const std::string outFileName = bedGenerationConf.getParameter< std::string >("outFileName"); + + bool useOpenMP = false; + + // BlockForest + const math::AABB simulationDomain_SI(real_t(0.0), real_t(0.0), real_t(0.0), domainSize_SI[0], domainSize_SI[1], + domainSize_SI[2]); + const Vector3< bool > isPeriodic{ periodicInX, periodicInY, false }; + + shared_ptr< BlockForest > forest = blockforest::createBlockForest(simulationDomain_SI, blocks, isPeriodic); + auto domain = std::make_shared< mesa_pd::domain::BlockForestDomain >(forest); + + // MesaPD data structures + auto ps = std::make_shared< data::ParticleStorage >(1); + data::ParticleAccessorWithBaseShape accessor(ps); + + // Init spheres + // Use offset to domain boundary to prevent the spheres from touching in the beginning + const real_t domainOffset = maxDiameter_SI / real_t(2); + const math::AABB generationDomain_SI( + simulationDomain_SI.xMin() + domainOffset, simulationDomain_SI.yMin() + domainOffset, + simulationDomain_SI.zMin() + domainOffset, simulationDomain_SI.xMax() - domainOffset, + simulationDomain_SI.yMax() - domainOffset, simulationDomain_SI.zMax() - domainOffset); + math::seedRandomGenerator(42); + + for (auto pt : + grid_generator::SCGrid(generationDomain_SI, Vec3(generationSpacing_SI) * real_c(0.5), generationSpacing_SI)) + { + auto diameter = math::realRandom< real_t >(minDiameter_SI, maxDiameter_SI); + + if (!domain->isContainedInLocalSubdomain(pt, real_t(0))) continue; + auto p = ps->create(); + p->getPositionRef() = pt; + p->getInteractionRadiusRef() = diameter * real_t(0.5); + p->getBaseShapeRef() = std::make_shared< data::Sphere >(p->getInteractionRadius()); + p->getBaseShapeRef()->updateMassAndInertia(densityParticle_SI); + + p->setLinearVelocity(Vec3(real_t(0.1) * math::realRandom(-initialVelocity_SI, initialVelocity_SI), + real_t(0.1) * math::realRandom(-initialVelocity_SI, initialVelocity_SI), + -initialVelocity_SI)); + p->getOwnerRef() = walberla::mpi::MPIManager::instance()->rank(); + p->getTypeRef() = 0; + } + + uint_t numParticles = ps->size(); + walberla::mpi::reduceInplace(numParticles, walberla::mpi::SUM); + + createPlane(*ps, simulationDomain_SI.minCorner(), Vec3(real_t(0), real_t(0), real_t(1))); + createPlane(*ps, simulationDomain_SI.maxCorner(), Vec3(real_t(0), real_t(0), real_t(-1))); + + if (!isPeriodic[0]) + { + createPlane(*ps, simulationDomain_SI.minCorner(), Vector3< real_t >(1, 0, 0)); + createPlane(*ps, simulationDomain_SI.maxCorner(), Vector3< real_t >(-1, 0, 0)); + } + if (!isPeriodic[1]) + { + createPlane(*ps, simulationDomain_SI.minCorner(), Vector3< real_t >(0, 1, 0)); + createPlane(*ps, simulationDomain_SI.maxCorner(), Vector3< real_t >(0, -1, 0)); + } + + // VTK + auto vtkDomainOutput = walberla::vtk::createVTKOutput_DomainDecomposition(forest, "domain_decomposition", 1, + "vtk_settling_spheres", "simulation_step"); + if (visSpacing > 0) { vtkDomainOutput->write(); } + + auto particleVtkOutput = make_shared< mesa_pd::vtk::ParticleVtkOutput >(ps); + particleVtkOutput->addOutput< mesa_pd::data::SelectParticleLinearVelocity >("velocity"); + particleVtkOutput->addOutput< mesa_pd::data::SelectParticleInteractionRadius >("radius"); + particleVtkOutput->setParticleSelector([](const data::ParticleStorage::iterator& pIt) { + using namespace walberla::mesa_pd::data::particle_flags; + return (pIt->getBaseShape()->getShapeType() == data::Sphere::SHAPE_TYPE) && !isSet(pIt->getFlags(), GHOST); + }); + auto vtkWriter = walberla::vtk::createVTKOutput_PointData(particleVtkOutput, "Particles", 1, "vtk_settling_spheres", + "simulation_step", false, false); + + // Init kernels + mesa_pd::kernel::VelocityVerletPreForceUpdate vvIntegratorPreForce(dt_SI); + mesa_pd::kernel::VelocityVerletPostForceUpdate vvIntegratorPostForce(dt_SI); + kernel::LinearSpringDashpot dem(2); + dem.setFrictionCoefficientDynamic(0, 0, frictionCoefficient); + // Use friction between spheres and planes to speed up the settling + dem.setFrictionCoefficientDynamic(0, 1, frictionCoefficient); + real_t kappa = real_t(2) * (real_t(1) - poissonsRatio) / (real_t(2) - poissonsRatio); // from Thornton et al + + kernel::AssocToBlock assoc(forest); + mesa_pd::mpi::ReduceProperty RP; + mesa_pd::mpi::ReduceContactHistory reduceAndSwapContactHistory; + mesa_pd::mpi::SyncNextNeighbors SNN; + + ps->forEachParticle(useOpenMP, kernel::SelectLocal(), accessor, assoc, accessor); + + // initial sync + SNN(*ps, *domain); + + real_t linkedCellWidth = 1.01_r * maxDiameter_SI; + data::LinkedCells linkedCells(domain->getUnionOfLocalAABBs().getExtended(linkedCellWidth), linkedCellWidth); + kernel::InsertParticleIntoLinkedCells ipilc; + + WcTimer timer; + WcTimingPool timeloopTiming; + timer.start(); + for (uint_t i = 0; i < timeSteps; ++i) + { + if (visSpacing > 0 && i % visSpacing == 0) { vtkWriter->write(); } + + timeloopTiming["RPD forEachParticle assoc"].start(); + ps->forEachParticle(useOpenMP, kernel::SelectLocal(), accessor, assoc, accessor); + timeloopTiming["RPD forEachParticle assoc"].end(); + + timeloopTiming["RPD forEachParticle vvIntegratorPreForce"].start(); + ps->forEachParticle(useOpenMP, kernel::SelectLocal(), accessor, vvIntegratorPreForce, accessor); + timeloopTiming["RPD forEachParticle vvIntegratorPreForce"].end(); + + timeloopTiming["SNN"].start(); + SNN(*ps, *domain); + timeloopTiming["SNN"].end(); + + // gravity - buoyancy + timeloopTiming["RPD forEachParticle addGravitationalForce"].start(); + ps->forEachParticle( + useOpenMP, kernel::SelectLocal(), accessor, + [densityParticle_SI, densityFluid_SI, gravity_SI](const size_t idx, auto& ac) { + mesa_pd::addForceAtomic( + idx, ac, Vec3(0, 0, -(densityParticle_SI - densityFluid_SI) * ac.getVolume(idx) * gravity_SI)); + }, + accessor); + timeloopTiming["RPD forEachParticle addGravitationalForce"].end(); + + timeloopTiming["RPD linkedCells.clear"].start(); + linkedCells.clear(); + timeloopTiming["RPD linkedCells.clear"].end(); + timeloopTiming["RPD forEachParticle ipilc"].start(); + ps->forEachParticle(useOpenMP, kernel::SelectAll(), accessor, ipilc, accessor, linkedCells); + timeloopTiming["RPD forEachParticle ipilc"].end(); + timeloopTiming["RPD forEachParticlePairHalf dem"].start(); + linkedCells.forEachParticlePairHalf( + useOpenMP, kernel::ExcludeInfiniteInfinite(), accessor, + [restitutionCoefficient, collisionTime_SI, kappa, domain, &dem, dt_SI](const size_t idx1, const size_t idx2, + auto& ac) { + kernel::DoubleCast double_cast; + mesa_pd::mpi::ContactFilter contact_filter; + collision_detection::AnalyticContactDetection acd; + + if (double_cast(idx1, idx2, ac, acd, ac)) + { + if (contact_filter(acd.getIdx1(), acd.getIdx2(), ac, acd.getContactPoint(), *domain)) + { + auto meff = real_t(1) / (ac.getInvMass(idx1) + ac.getInvMass(idx2)); + dem.setStiffnessAndDamping(ac.getType(idx1), ac.getType(idx2), restitutionCoefficient, + collisionTime_SI, kappa, meff); + dem(acd.getIdx1(), acd.getIdx2(), ac, acd.getContactPoint(), acd.getContactNormal(), + acd.getPenetrationDepth(), dt_SI); + } + } + }, + accessor); + timeloopTiming["RPD forEachParticlePairHalf dem"].end(); + + timeloopTiming["RPD reduceProperty reduceAndSwapContactHistory"].start(); + reduceAndSwapContactHistory(*ps); + timeloopTiming["RPD reduceProperty reduceAndSwapContactHistory"].end(); + + timeloopTiming["RPD reduceProperty ForceTorqueNotification"].start(); + RP.operator()< ForceTorqueNotification >(*ps); + timeloopTiming["RPD reduceProperty ForceTorqueNotification"].end(); + + timeloopTiming["RPD forEachParticle vvIntegratorPostForce"].start(); + ps->forEachParticle(useOpenMP, kernel::SelectLocal(), accessor, vvIntegratorPostForce, accessor); + timeloopTiming["RPD forEachParticle vvIntegratorPostForce"].end(); + + // Log particle velocities every 10% of progress. Turn logging off for benchmark run (i.e., no vtk output). + if (i % (timeSteps / uint_t(10)) == 0 && visSpacing != 0) + { + real_t maxVelocity; + real_t averageVelocity; + uint_t numAveragedParticles; + + getParticleVelocities(accessor, numAveragedParticles, maxVelocity, averageVelocity); + WALBERLA_LOG_INFO_ON_ROOT("Timestep " << i << " / " << timeSteps << ", average velocity = " << averageVelocity + << ", max velocity = " << maxVelocity + << ", #particles = " << numAveragedParticles); + } + } + timer.end(); + + auto timer_reduced = walberla::timing::getReduced(timer, timing::REDUCE_TOTAL, 0); + WALBERLA_ROOT_SECTION() + { + WALBERLA_LOG_INFO_ON_ROOT(*timer_reduced); + real_t PUpS = real_t(numParticles) * real_t(timeSteps) / real_t(timer_reduced->max()); + WALBERLA_LOG_INFO_ON_ROOT("PUpS: " << PUpS); + } + + timeloopTiming.logResultOnRoot(); + + writeSphereInformationToFile(outFileName, *ps, domainSize_SI); + + return EXIT_SUCCESS; +} +} // namespace piping +} // namespace walberla + +int main(int argc, char** argv) { return walberla::piping::main(argc, argv); } diff --git a/apps/showcases/Piping/setups/CMakeLists.txt b/apps/showcases/Piping/setups/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..77d65d222e15d50cbd546143cb68672ae8483946 --- /dev/null +++ b/apps/showcases/Piping/setups/CMakeLists.txt @@ -0,0 +1 @@ +waLBerla_link_files_to_builddir(*.prm) diff --git a/apps/showcases/Piping/setups/SettlingSpheres_Fukumoto.prm b/apps/showcases/Piping/setups/SettlingSpheres_Fukumoto.prm new file mode 100644 index 0000000000000000000000000000000000000000..92a9ac319fd303fa95d4293411a6050a4c6d80ae --- /dev/null +++ b/apps/showcases/Piping/setups/SettlingSpheres_Fukumoto.prm @@ -0,0 +1,21 @@ +BedGeneration{ + domainSize_SI < 0.015, 0.003, 0.015 >; // for Fukumoto: < 0.2, 0.003, 0.133 > (results in bed height of ~0.05) + blocks < 3, 3, 1 >; + periodicInX false; + periodicInY false; + minDiameter_SI 0.0005; + maxDiameter_SI 0.0006; + gravity_SI 9.81; + densityFluid_SI 1000; + densityParticle_SI 2500; + generationSpacing_SI 0.0007; + initialVelocity_SI 0.05; + dt_SI 5e-5; // decrease dt_SI to get lower particle velocity in the end + frictionCoefficient 0.6; + restitutionCoefficient 0.1; // artificial low value to decrease the rebound (increase settling speed) + collisionTime_SI 5e-4; // time to resolve a collision + poissonsRatio 0.22; + timeSteps 10000; + visSpacing 100; + outFileName spheres_out.dat; +} diff --git a/apps/showcases/Piping/utility/ParticleUtility.h b/apps/showcases/Piping/utility/ParticleUtility.h new file mode 100644 index 0000000000000000000000000000000000000000..e9b223efcf8328fa8cef1cb47f24ec647914fbbf --- /dev/null +++ b/apps/showcases/Piping/utility/ParticleUtility.h @@ -0,0 +1,306 @@ +//====================================================================================================================== +// +// This file is part of waLBerla. waLBerla 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. +// +// waLBerla 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 waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file ParticleUtility.h +//! \author Samuel Kemmler <samuel.kemmler@fau.de> +// +//====================================================================================================================== + +#pragma once + +#include "core/mpi/Broadcast.h" +#include "core/mpi/MPITextFile.h" +#include "core/mpi/Reduce.h" + +#include "mesa_pd/data/ParticleStorage.h" +#include "mesa_pd/data/shape/Sphere.h" + +namespace walberla +{ +namespace piping +{ + +// Some functions in this file (as the one below) are based on showcases/Antidunes/Utility.cpp + +void writeSphereInformationToFile(const std::string& filename, walberla::mesa_pd::data::ParticleStorage& ps, + const Vector3< real_t >& domainSize, const int precision = 12) +{ + std::ostringstream ossData; + ossData << std::setprecision(precision); + + WALBERLA_ROOT_SECTION() { ossData << domainSize[0] << " " << domainSize[1] << " " << domainSize[2] << "\n"; } + + for (auto pIt : ps) + { + using namespace walberla::mesa_pd::data; + if (pIt->getBaseShape()->getShapeType() != Sphere::SHAPE_TYPE) continue; + using namespace walberla::mesa_pd::data::particle_flags; + if (isSet(pIt->getFlags(), GHOST)) continue; + auto sp = static_cast< Sphere* >(pIt->getBaseShape().get()); + + auto position = pIt->getPosition(); + + ossData << position[0] << " " << position[1] << " " << position[2] << " " << sp->getRadius() << '\n'; + } + + walberla::mpi::writeMPITextFile(filename, ossData.str()); +} + +bool sphereBoxOverlap(const mesa_pd::Vec3& spherePosition, const real_t sphereRadius, const mesa_pd::Vec3& boxPosition, + const mesa_pd::Vec3& boxEdgeLength) +{ + if ((spherePosition[0] + sphereRadius < boxPosition[0] - boxEdgeLength[0] / real_t(2)) || + (spherePosition[1] + sphereRadius < boxPosition[1] - boxEdgeLength[1] / real_t(2)) || + (spherePosition[2] + sphereRadius < boxPosition[2] - boxEdgeLength[2] / real_t(2)) || + (spherePosition[0] - sphereRadius > boxPosition[0] + boxEdgeLength[0] / real_t(2)) || + (spherePosition[1] - sphereRadius > boxPosition[1] + boxEdgeLength[1] / real_t(2)) || + (spherePosition[2] - sphereRadius > boxPosition[2] + boxEdgeLength[2] / real_t(2))) + { + return false; + } + return true; +} + +void initSpheresFromFile(const std::string& fileName, walberla::mesa_pd::data::ParticleStorage& ps, + const walberla::mesa_pd::domain::IDomain& domain, walberla::real_t particleDensity, + math::AABB& simulationDomain, const Vector3< uint_t >& domainSize, + const mesa_pd::Vec3& boxPosition, const mesa_pd::Vec3& boxEdgeLength, real_t& maxDiameter) +{ + using namespace walberla::mesa_pd::data; + + auto rank = walberla::mpi::MPIManager::instance()->rank(); + + std::string textFile; + + WALBERLA_ROOT_SECTION() + { + std::ifstream t(fileName.c_str()); + if (!t) { WALBERLA_ABORT("Invalid input file " << fileName << "\n"); } + std::stringstream buffer; + buffer << t.rdbuf(); + textFile = buffer.str(); + } + + walberla::mpi::broadcastObject(textFile); + + std::istringstream fileIss(textFile); + std::string line; + + // first line contains generation domain sizes + std::getline(fileIss, line); + Vector3< real_t > generationDomainSize_SI(0_r); + std::istringstream firstLine(line); + firstLine >> generationDomainSize_SI[0] >> generationDomainSize_SI[1] >> generationDomainSize_SI[2]; + real_t scalingFactor = real_t(domainSize[0]) / generationDomainSize_SI[0]; + WALBERLA_LOG_DEVEL_VAR_ON_ROOT(generationDomainSize_SI) + WALBERLA_LOG_DEVEL_VAR_ON_ROOT(scalingFactor) + + real_t minParticleDiameter = std::numeric_limits< real_t >::max(); + real_t maxParticleDiameter = real_t(0); + + while (std::getline(fileIss, line)) + { + std::istringstream iss(line); + + ParticleStorage::position_type position; + real_t radius; + iss >> position[0] >> position[1] >> position[2] >> radius; + position *= scalingFactor; + radius *= scalingFactor; + + WALBERLA_CHECK(simulationDomain.contains(position), + "Particle read from file is not contained in simulation domain"); + + if (!domain.isContainedInProcessSubdomain(uint_c(rank), position)) continue; + if (sphereBoxOverlap(position, radius, boxPosition, boxEdgeLength)) continue; + + auto pIt = ps.create(); + pIt->setPosition(position); + pIt->getBaseShapeRef() = std::make_shared< data::Sphere >(radius); + pIt->getBaseShapeRef()->updateMassAndInertia(particleDensity); + pIt->setInteractionRadius(radius); + pIt->setOwner(rank); + pIt->setType(0); + + minParticleDiameter = std::min(real_t(2) * radius, minParticleDiameter); + maxParticleDiameter = std::max(real_t(2) * radius, maxParticleDiameter); + + WALBERLA_CHECK_EQUAL(iss.tellg(), -1); + } + + WALBERLA_MPI_SECTION() { walberla::mpi::allReduceInplace(minParticleDiameter, walberla::mpi::MIN); } + WALBERLA_MPI_SECTION() { walberla::mpi::allReduceInplace(maxParticleDiameter, walberla::mpi::MAX); } + WALBERLA_LOG_DEVEL_VAR_ON_ROOT(minParticleDiameter) + WALBERLA_LOG_DEVEL_VAR_ON_ROOT(maxParticleDiameter) + // Maximum particle diameter is used for the size of the linked cells + maxDiameter = maxParticleDiameter; +} + +template< typename ParticleAccessor_T > +void getParticleVelocities(const ParticleAccessor_T& ac, uint_t& numParticles, real_t& maxVelocity, + real_t& averageVelocity) +{ + maxVelocity = real_t(0); + averageVelocity = real_t(0); + numParticles = uint_t(0); + + for (uint_t i = 0; i < ac.size(); ++i) + { + if (isSet(ac.getFlags(i), walberla::mesa_pd::data::particle_flags::GHOST)) continue; + if (isSet(ac.getFlags(i), walberla::mesa_pd::data::particle_flags::GLOBAL)) continue; + + ++numParticles; + real_t velMagnitude = ac.getLinearVelocity(i).length(); + maxVelocity = std::max(maxVelocity, velMagnitude); + averageVelocity += velMagnitude; + } + + WALBERLA_MPI_SECTION() + { + walberla::mpi::allReduceInplace(maxVelocity, walberla::mpi::MAX); + walberla::mpi::allReduceInplace(averageVelocity, walberla::mpi::SUM); + walberla::mpi::allReduceInplace(numParticles, walberla::mpi::SUM); + } + + averageVelocity /= real_t(numParticles); +} + +auto createPlane(mesa_pd::data::ParticleStorage& ps, const mesa_pd::Vec3& pos, const mesa_pd::Vec3& normal) +{ + auto p0 = ps.create(true); + p0->setPosition(pos); + p0->setBaseShape(std::make_shared< mesa_pd::data::HalfSpace >(normal)); + // Mass is set to infinity internally for HalfSpace (independent of the density that is set here) + p0->getBaseShapeRef()->updateMassAndInertia(real_t(1)); + p0->setOwner(walberla::mpi::MPIManager::instance()->rank()); + p0->setType(1); + p0->setInteractionRadius(std::numeric_limits< real_t >::infinity()); + mesa_pd::data::particle_flags::set(p0->getFlagsRef(), mesa_pd::data::particle_flags::GLOBAL); + mesa_pd::data::particle_flags::set(p0->getFlagsRef(), mesa_pd::data::particle_flags::INFINITE); + mesa_pd::data::particle_flags::set(p0->getFlagsRef(), mesa_pd::data::particle_flags::FIXED); + mesa_pd::data::particle_flags::set(p0->getFlagsRef(), mesa_pd::data::particle_flags::NON_COMMUNICATING); + return p0; +} + +auto createBox(mesa_pd::data::ParticleStorage& ps, const mesa_pd::Vec3& pos, const mesa_pd::Vec3& edgeLength, + const bool movingBucket) +{ + auto p0 = ps.create(true); + p0->setPosition(pos); + p0->setBaseShape(std::make_shared< mesa_pd::data::Box >(edgeLength)); + if (movingBucket) + { + // TODO: replace the density of 2.0 + p0->getBaseShapeRef()->updateMassAndInertia(real_t(2.0)); + } + else + { + // If the bucket is fixed, its collision behaviour should be the same as for the bounding planes + p0->getBaseShapeRef()->updateMassAndInertia(std::numeric_limits< real_t >::infinity()); + } + p0->setOwner(walberla::mpi::MPIManager::instance()->rank()); + p0->setType(1); + p0->setInteractionRadius(std::numeric_limits< real_t >::infinity()); + mesa_pd::data::particle_flags::set(p0->getFlagsRef(), mesa_pd::data::particle_flags::GLOBAL); + mesa_pd::data::particle_flags::set(p0->getFlagsRef(), mesa_pd::data::particle_flags::INFINITE); + return p0->getUid(); +} + +template< typename ParticleAccessor_T, typename Sync_T, typename CollisionResponse_T > +void settleParticles(const uint_t numTimeSteps, const shared_ptr< ParticleAccessor_T >& accessor, + const shared_ptr< mesa_pd::data::ParticleStorage >& ps, + const walberla::mesa_pd::domain::IDomain& domain, mesa_pd::data::LinkedCells& linkedCells, + Sync_T& syncNextNeighborFunc, CollisionResponse_T& collisionResponse, + const real_t& particleDensityRatio, const real_t& gravitationalAcceleration, const bool& useOpenMP) +{ + // Increase the settling speed + const real_t timeStepSizeParticles = real_t(10); + mesa_pd::kernel::VelocityVerletPreForceUpdate vvIntegratorPreForce(timeStepSizeParticles); + mesa_pd::kernel::VelocityVerletPostForceUpdate vvIntegratorPostForce(timeStepSizeParticles); + mesa_pd::mpi::ReduceProperty reduceProperty; + mesa_pd::mpi::ReduceContactHistory reduceAndSwapContactHistory; + mesa_pd::kernel::InsertParticleIntoLinkedCells ipilc; + + WALBERLA_LOG_INFO_ON_ROOT("Starting initial particle settling...") + + for (uint_t t = uint_t(0); t < numTimeSteps; ++t) + { + ps->forEachParticle(useOpenMP, mesa_pd::kernel::SelectLocal(), *accessor, vvIntegratorPreForce, *accessor); + syncNextNeighborFunc(*ps, domain); + + linkedCells.clear(); + ps->forEachParticle(useOpenMP, mesa_pd::kernel::SelectAll(), *accessor, ipilc, *accessor, linkedCells); + + // collision + linkedCells.forEachParticlePairHalf( + useOpenMP, mesa_pd::kernel::ExcludeInfiniteInfinite(), *accessor, + [&collisionResponse, &domain, &timeStepSizeParticles](const size_t idx1, const size_t idx2, auto& ac) { + mesa_pd::collision_detection::AnalyticContactDetection acd; + mesa_pd::kernel::DoubleCast double_cast; + mesa_pd::mpi::ContactFilter contact_filter; + if (double_cast(idx1, idx2, ac, acd, ac)) + { + if (contact_filter(acd.getIdx1(), acd.getIdx2(), ac, acd.getContactPoint(), domain)) + { + collisionResponse(acd.getIdx1(), acd.getIdx2(), ac, acd.getContactPoint(), acd.getContactNormal(), + acd.getPenetrationDepth(), timeStepSizeParticles); + } + } + }, + *accessor); + reduceAndSwapContactHistory(*ps); + + // gravity - buoyancy + ps->forEachParticle( + useOpenMP, mesa_pd::kernel::SelectLocal(), *accessor, + [particleDensityRatio, gravitationalAcceleration](const size_t idx, auto& ac) { + mesa_pd::addForceAtomic( + idx, ac, + Vector3< real_t >(real_t(0), real_t(0), + -(particleDensityRatio - real_c(1)) * ac.getVolume(idx) * gravitationalAcceleration)); + }, + *accessor); + + reduceProperty.operator()< mesa_pd::ForceTorqueNotification >(*ps); + + ps->forEachParticle(useOpenMP, mesa_pd::kernel::SelectLocal(), *accessor, vvIntegratorPostForce, *accessor); + syncNextNeighborFunc(*ps, domain); + + if (t % (numTimeSteps / uint_t(10)) == 0) + { + real_t maxVelocity; + real_t averageVelocity; + uint_t numAveragedParticles; + + getParticleVelocities(*accessor, numAveragedParticles, maxVelocity, averageVelocity); + WALBERLA_LOG_INFO_ON_ROOT("Timestep " + << t << " / " << numTimeSteps << ", average velocity = " << averageVelocity + << ", max velocity = " << maxVelocity << ", #particles = " << numAveragedParticles); + } + } + + // Velocities should be 0 after settling such that the simulation starts from rest + ps->forEachParticle( + useOpenMP, mesa_pd::kernel::SelectLocal(), *accessor, + [](const size_t idx, auto& ac) { + ac.setLinearVelocity(idx, Vector3(real_t(0))); + ac.setAngularVelocity(idx, Vector3(real_t(0))); + }, + *accessor); + syncNextNeighborFunc(*ps, domain); +} + +} // namespace piping +} // namespace walberla diff --git a/python/mesa_pd.py b/python/mesa_pd.py index adbd847e84d7880afa67fd3006a0405c6c8171f0..18c01edbcefb75dc6994fb0a6f6a67fe74dc8465 100755 --- a/python/mesa_pd.py +++ b/python/mesa_pd.py @@ -23,6 +23,7 @@ if __name__ == '__main__': ps.add_property("invMass", "walberla::real_t", defValue="real_t(1)", syncMode="ON_GHOST_CREATION") ps.add_property("force", "walberla::mesa_pd::Vec3", defValue="real_t(0)", syncMode="NEVER") ps.add_property("oldForce", "walberla::mesa_pd::Vec3", defValue="real_t(0)", syncMode="ON_OWNERSHIP_CHANGE") + ps.add_property("charge", "walberla::real_t", defValue="real_t(0)", syncMode="ALWAYS") # shape definition for cases with small number of different shapes ps.add_property("shapeID", "size_t", defValue="", syncMode="ON_GHOST_CREATION") @@ -70,6 +71,12 @@ if __name__ == '__main__': syncMode="ON_OWNERSHIP_CHANGE") ps.add_property("oldHydrodynamicTorque", "walberla::mesa_pd::Vec3", defValue="real_t(0)", syncMode="ON_OWNERSHIP_CHANGE") + ps.add_property("electrostaticForce", "walberla::mesa_pd::Vec3", defValue="real_t(0)", + syncMode="ON_OWNERSHIP_CHANGE") + + # Properties for evaluation purposes + ps.add_property("totalDisplacement", "walberla::real_t", defValue="real_t(0)", syncMode="ON_OWNERSHIP_CHANGE") + ps.add_property("collisionForceNorm", "walberla::real_t", defValue="real_t(0)", syncMode="ON_OWNERSHIP_CHANGE") # Properties for virtual mass: ps.add_property("virtualMass", "walberla::real_t", defValue="real_t(0)", @@ -150,6 +157,8 @@ if __name__ == '__main__': hftn = mpd.add(mpi.PropertyNotification('HydrodynamicForceTorqueNotification')) hftn.add_property('hydrodynamicForce', 'mesa_pd::Vec3', 'Vec3(real_t(0))') hftn.add_property('hydrodynamicTorque', 'mesa_pd::Vec3', 'Vec3(real_t(0))') + eftn = mpd.add(mpi.PropertyNotification('ElectrostaticForceNotification')) + eftn.add_property('electrostaticForce', 'mesa_pd::Vec3', 'Vec3(real_t(0))') hfn = mpd.add(mpi.PropertyNotification('HeatFluxNotification')) hfn.add_property('heatFlux', 'real_t', 'real_t(0)') ncn = mpd.add(mpi.PropertyNotification('NumContactNotification')) diff --git a/python/mesa_pd/templates/common/ParticleFunctions.templ.h b/python/mesa_pd/templates/common/ParticleFunctions.templ.h index 61629f05909a60069ccb2b91d69bf79c8a034f2f..d90adcf692baa4bf01dc31fee3a9d9d52fcb2b6d 100644 --- a/python/mesa_pd/templates/common/ParticleFunctions.templ.h +++ b/python/mesa_pd/templates/common/ParticleFunctions.templ.h @@ -93,19 +93,19 @@ inline void addForceAtomic(const size_t p_idx, Accessor& ac, const Vec3& f) #ifdef _OPENMP #pragma omp atomic #endif - {%- endif %}; + {%- endif %} ac.getForceRef(p_idx)[0] += f[0]; {%- if module.enableOpenMP %} #ifdef _OPENMP #pragma omp atomic #endif - {%- endif %}; + {%- endif %} ac.getForceRef(p_idx)[1] += f[1]; {%- if module.enableOpenMP %} #ifdef _OPENMP #pragma omp atomic #endif - {%- endif %}; + {%- endif %} ac.getForceRef(p_idx)[2] += f[2]; } @@ -117,19 +117,19 @@ inline void addForceAtWFPosAtomic(const size_t p_idx, Accessor& ac, const Vec3& #ifdef _OPENMP #pragma omp atomic #endif - {%- endif %}; + {%- endif %} ac.getForceRef(p_idx)[0] += f[0]; {%- if module.enableOpenMP %} #ifdef _OPENMP #pragma omp atomic #endif - {%- endif %}; + {%- endif %} ac.getForceRef(p_idx)[1] += f[1]; {%- if module.enableOpenMP %} #ifdef _OPENMP #pragma omp atomic #endif - {%- endif %}; + {%- endif %} ac.getForceRef(p_idx)[2] += f[2]; const auto t = cross(( wf_pt - ac.getPosition(p_idx) ), f); @@ -138,19 +138,19 @@ inline void addForceAtWFPosAtomic(const size_t p_idx, Accessor& ac, const Vec3& #ifdef _OPENMP #pragma omp atomic #endif - {%- endif %}; + {%- endif %} ac.getTorqueRef(p_idx)[0] += t[0]; {%- if module.enableOpenMP %} #ifdef _OPENMP #pragma omp atomic #endif - {%- endif %}; + {%- endif %} ac.getTorqueRef(p_idx)[1] += t[1]; {%- if module.enableOpenMP %} #ifdef _OPENMP #pragma omp atomic #endif - {%- endif %}; + {%- endif %} ac.getTorqueRef(p_idx)[2] += t[2]; } @@ -165,19 +165,19 @@ inline void addTorqueAtomic(const size_t p_idx, Accessor& ac, const Vec3& t) #ifdef _OPENMP #pragma omp atomic #endif - {%- endif %}; + {%- endif %} ac.getTorqueRef(p_idx)[0] += t[0]; {%- if module.enableOpenMP %} #ifdef _OPENMP #pragma omp atomic #endif - {%- endif %}; + {%- endif %} ac.getTorqueRef(p_idx)[1] += t[1]; {%- if module.enableOpenMP %} #ifdef _OPENMP #pragma omp atomic #endif - {%- endif %}; + {%- endif %} ac.getTorqueRef(p_idx)[2] += t[2]; } diff --git a/python/mesa_pd/templates/kernel/LinearSpringDashpot.templ.h b/python/mesa_pd/templates/kernel/LinearSpringDashpot.templ.h index efa4138873bc7c70f41b0ee02a4250fa418e6753..bec0b5bb815243f0e61a6d467d15da904b758488 100644 --- a/python/mesa_pd/templates/kernel/LinearSpringDashpot.templ.h +++ b/python/mesa_pd/templates/kernel/LinearSpringDashpot.templ.h @@ -240,7 +240,14 @@ inline void LinearSpringDashpot::operator()(const size_t p_idx1, const real_t fTabs( std::min( fTLS.length(), fFrictionAbs) ); const Vec3 fT ( fTabs * t ); - //TODO check if tangential spring displacement is same for symmetric case + // TODO check if tangential spring displacement is same for symmetric case + // TODO: check why exactly this critical section is needed + {%- if module.enableOpenMP %} + #ifdef _OPENMP + #pragma omp critical + { + #endif + {%- endif %} auto& ch1 = ac.getNewContactHistoryRef(p_idx1)[ac.getUid(p_idx2)]; ch1.setTangentialSpringDisplacement(newTangentialSpringDisplacement); ch1.setIsSticking(isSticking); @@ -250,6 +257,11 @@ inline void LinearSpringDashpot::operator()(const size_t p_idx1, ch2.setTangentialSpringDisplacement(newTangentialSpringDisplacement); ch2.setIsSticking(isSticking); ch2.setImpactVelocityMagnitude(impactVelocityMagnitude); + {%- if module.enableOpenMP %} + #ifdef _OPENMP + } + #endif + {%- endif %} // Add normal force at contact point addForceAtWFPosAtomic( p_idx1, ac, fN, contactPoint ); diff --git a/src/core/math/extern/exprtk.h b/src/core/math/extern/exprtk.h index aab5062bacc2510e37cf55418eaaa5b46d0005a3..4f14480b9ff5ea09ba74801c7bba4f301c236d8e 100644 --- a/src/core/math/extern/exprtk.h +++ b/src/core/math/extern/exprtk.h @@ -2,14 +2,15 @@ ****************************************************************** * C++ Mathematical Expression Toolkit Library * * * - * Author: Arash Partow (1999-2021) * - * URL: http://www.partow.net/programming/exprtk/index.html * + * Author: Arash Partow (1999-2024) * + * URL: https://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * * Free use of the C++ Mathematical Expression Toolkit Library is * * permitted under the guidelines and in accordance with the most * * current version of the MIT License. * - * http://www.opensource.org/licenses/MIT * + * https://www.opensource.org/licenses/MIT * + * SPDX-License-Identifier: MIT * * * * Example expressions: * * (00) (y + x / y) * (x - y / x) * @@ -17,12 +18,12 @@ * (02) sqrt(1 - (x^2)) * * (03) 1 - sin(2 * x) + cos(pi / y) * * (04) a * exp(2 * t) + c * - * (05) if(((x + 2) == 3) and ((y + 5) <= 9),1 + w, 2 / z) * + * (05) if(((x + 2) == 3) and ((y + 5) <= 9), 1 + w, 2 / z) * * (06) (avg(x,y) <= x + y ? x - y : x * y) + 2 * pi / x * * (07) z := x + sin(2 * pi / y) * * (08) u := 2 * (pi * z) / (w := x + cos(y / pi)) * - * (09) clamp(-1,sin(2 * pi * x) + cos(y / 2 * pi),+1) * - * (10) inrange(-2,m,+2) == if(({-2 <= m} and [m <= +2]),1,0) * + * (09) clamp(-1, sin(2 * pi * x) + cos(y / 2 * pi), +1) * + * (10) inrange(-2, m, +2) == if(({-2 <= m} and [m <= +2]), 1, 0) * * (11) (2sin(x)cos(2y)7 + 1) == (2 * sin(x) * cos(2*y) * 7 + 1) * * (12) (x ilike 's*ri?g') and [y < (3 z^7 + w)] * * * @@ -38,12 +39,10 @@ #include <cassert> #include <cctype> #include <cmath> -#include <complex> #include <cstdio> #include <cstdlib> #include <cstring> #include <deque> -#include <exception> #include <functional> #include <iterator> #include <limits> @@ -56,7 +55,7 @@ #include <utility> #include <vector> -//NOLINTBEGIN(modernize-use-nullptr) +//NOLINTBEGIN(modernize-*,readability-*,performance-no-int-to-ptr,bugprone-empty-catch,bugprone-inc-dec-in-conditions) namespace exprtk { @@ -69,30 +68,40 @@ namespace exprtk #define exprtk_error_location \ "exprtk.hpp:" + details::to_str(__LINE__) \ - #if defined(__GNUC__) && (__GNUC__ >= 7) - - #define exprtk_disable_fallthrough_begin \ - _Pragma ("GCC diagnostic push") \ - _Pragma ("GCC diagnostic ignored \"-Wimplicit-fallthrough\"") \ - - #define exprtk_disable_fallthrough_end \ - _Pragma ("GCC diagnostic pop") \ + #if __cplusplus >= 201103L + #define exprtk_override override + #define exprtk_final final + #define exprtk_delete = delete + #define exprtk_default = default + #else + #define exprtk_override + #define exprtk_final + #define exprtk_delete + #define exprtk_default {} + #endif + #if __cplusplus >= 201603L + #define exprtk_fallthrough [[fallthrough]]; + #elif __cplusplus >= 201103L + #define exprtk_fallthrough [[gnu::fallthrough]]; #else - #define exprtk_disable_fallthrough_begin (void)0; - #define exprtk_disable_fallthrough_end (void)0; + #ifndef _MSC_VER + #define exprtk_fallthrough __attribute__ ((fallthrough)); + #else + #define exprtk_fallthrough + #endif #endif namespace details { - typedef unsigned char uchar_t; - typedef char char_t; - typedef uchar_t* uchar_ptr; - typedef char_t* char_ptr; - typedef uchar_t const* uchar_cptr; + typedef char char_t; + typedef char_t* char_ptr; typedef char_t const* char_cptr; + typedef unsigned char uchar_t; + typedef uchar_t* uchar_ptr; + typedef uchar_t const* uchar_cptr; typedef unsigned long long int _uint64_t; - typedef long long int _int64_t; + typedef long long int _int64_t; inline bool is_whitespace(const char_t c) { @@ -168,7 +177,7 @@ namespace exprtk inline bool is_valid_string_char(const char_t c) { - return std::isprint(static_cast<unsigned char>(c)) || + return std::isprint(static_cast<uchar_t>(c)) || is_whitespace(c); } @@ -210,15 +219,15 @@ namespace exprtk { const std::size_t length = std::min(s1.size(),s2.size()); - for (std::size_t i = 0; i < length; ++i) + for (std::size_t i = 0; i < length; ++i) { - const char_t c1 = static_cast<char>(std::tolower(s1[i])); - const char_t c2 = static_cast<char>(std::tolower(s2[i])); + const char_t c1 = static_cast<char_t>(std::tolower(s1[i])); + const char_t c2 = static_cast<char_t>(std::tolower(s2[i])); - if (c1 > c2) - return false; - else if (c1 < c2) + if (c1 < c2) return true; + else if (c2 < c1) + return false; } return s1.size() < s2.size(); @@ -275,21 +284,16 @@ namespace exprtk std::string result; - if (i < 0) - { - for ( ; i; i /= 10) - { - result += '0' + char(-(i % 10)); - } + const int sign = (i < 0) ? -1 : 1; - result += '-'; + for ( ; i; i /= 10) + { + result += '0' + static_cast<char_t>(sign * (i % 10)); } - else + + if (sign < 0) { - for ( ; i; i /= 10) - { - result += '0' + char(i % 10); - } + result += '-'; } std::reverse(result.begin(), result.end()); @@ -302,7 +306,7 @@ namespace exprtk return to_str(static_cast<int>(i)); } - inline bool is_hex_digit(const std::string::value_type digit) + inline bool is_hex_digit(const uchar_t digit) { return (('0' <= digit) && (digit <= '9')) || (('A' <= digit) && (digit <= 'F')) || @@ -314,12 +318,12 @@ namespace exprtk if (('0' <= h) && (h <= '9')) return (h - '0'); else - return static_cast<unsigned char>(std::toupper(h) - 'A'); + return static_cast<uchar_t>(std::toupper(h) - 'A'); } template <typename Iterator> inline bool parse_hex(Iterator& itr, Iterator end, - std::string::value_type& result) + char_t& result) { if ( (end == (itr )) || @@ -361,9 +365,9 @@ namespace exprtk } else if (parse_hex(itr1, end, *itr2)) { - itr1+= 4; - itr2+= 1; - removal_count +=4; + itr1 += 4; + itr2 += 1; + removal_count += 4; } else if ('a' == (*itr1)) { (*itr2++) = '\a'; ++itr1; ++removal_count; } else if ('b' == (*itr1)) { (*itr2++) = '\b'; ++itr1; ++removal_count; } @@ -378,6 +382,7 @@ namespace exprtk (*itr2++) = (*itr1++); ++removal_count; } + continue; } else @@ -396,7 +401,7 @@ namespace exprtk { public: - build_string(const std::size_t& initial_size = 64) + explicit build_string(const std::size_t& initial_size = 64) { data_.reserve(initial_size); } @@ -429,85 +434,85 @@ namespace exprtk }; static const std::string reserved_words[] = - { - "break", "case", "continue", "default", "false", "for", - "if", "else", "ilike", "in", "like", "and", "nand", "nor", - "not", "null", "or", "repeat", "return", "shl", "shr", - "swap", "switch", "true", "until", "var", "while", "xnor", - "xor", "&", "|" - }; + { + "assert", "break", "case", "continue", "const", "default", + "false", "for", "if", "else", "ilike", "in", "like", "and", + "nand", "nor", "not", "null", "or", "repeat", "return", + "shl", "shr", "swap", "switch", "true", "until", "var", + "while", "xnor", "xor", "&", "|" + }; static const std::size_t reserved_words_size = sizeof(reserved_words) / sizeof(std::string); static const std::string reserved_symbols[] = - { - "abs", "acos", "acosh", "and", "asin", "asinh", "atan", - "atanh", "atan2", "avg", "break", "case", "ceil", "clamp", - "continue", "cos", "cosh", "cot", "csc", "default", - "deg2grad", "deg2rad", "equal", "erf", "erfc", "exp", - "expm1", "false", "floor", "for", "frac", "grad2deg", - "hypot", "iclamp", "if", "else", "ilike", "in", "inrange", - "like", "log", "log10", "log2", "logn", "log1p", "mand", - "max", "min", "mod", "mor", "mul", "ncdf", "nand", "nor", - "not", "not_equal", "null", "or", "pow", "rad2deg", - "repeat", "return", "root", "round", "roundn", "sec", "sgn", - "shl", "shr", "sin", "sinc", "sinh", "sqrt", "sum", "swap", - "switch", "tan", "tanh", "true", "trunc", "until", "var", - "while", "xnor", "xor", "&", "|" - }; + { + "abs", "acos", "acosh", "and", "asin", "asinh", "assert", + "atan", "atanh", "atan2", "avg", "break", "case", "ceil", + "clamp", "continue", "const", "cos", "cosh", "cot", "csc", + "default", "deg2grad", "deg2rad", "equal", "erf", "erfc", + "exp", "expm1", "false", "floor", "for", "frac", "grad2deg", + "hypot", "iclamp", "if", "else", "ilike", "in", "inrange", + "like", "log", "log10", "log2", "logn", "log1p", "mand", + "max", "min", "mod", "mor", "mul", "ncdf", "nand", "nor", + "not", "not_equal", "null", "or", "pow", "rad2deg", + "repeat", "return", "root", "round", "roundn", "sec", "sgn", + "shl", "shr", "sin", "sinc", "sinh", "sqrt", "sum", "swap", + "switch", "tan", "tanh", "true", "trunc", "until", "var", + "while", "xnor", "xor", "&", "|" + }; static const std::size_t reserved_symbols_size = sizeof(reserved_symbols) / sizeof(std::string); static const std::string base_function_list[] = - { - "abs", "acos", "acosh", "asin", "asinh", "atan", "atanh", - "atan2", "avg", "ceil", "clamp", "cos", "cosh", "cot", - "csc", "equal", "erf", "erfc", "exp", "expm1", "floor", - "frac", "hypot", "iclamp", "like", "log", "log10", "log2", - "logn", "log1p", "mand", "max", "min", "mod", "mor", "mul", - "ncdf", "pow", "root", "round", "roundn", "sec", "sgn", - "sin", "sinc", "sinh", "sqrt", "sum", "swap", "tan", "tanh", - "trunc", "not_equal", "inrange", "deg2grad", "deg2rad", - "rad2deg", "grad2deg" - }; + { + "abs", "acos", "acosh", "asin", "asinh", "atan", "atanh", + "atan2", "avg", "ceil", "clamp", "cos", "cosh", "cot", + "csc", "equal", "erf", "erfc", "exp", "expm1", "floor", + "frac", "hypot", "iclamp", "like", "log", "log10", "log2", + "logn", "log1p", "mand", "max", "min", "mod", "mor", "mul", + "ncdf", "pow", "root", "round", "roundn", "sec", "sgn", + "sin", "sinc", "sinh", "sqrt", "sum", "swap", "tan", "tanh", + "trunc", "not_equal", "inrange", "deg2grad", "deg2rad", + "rad2deg", "grad2deg" + }; static const std::size_t base_function_list_size = sizeof(base_function_list) / sizeof(std::string); static const std::string logic_ops_list[] = - { - "and", "nand", "nor", "not", "or", "xnor", "xor", "&", "|" - }; + { + "and", "nand", "nor", "not", "or", "xnor", "xor", "&", "|" + }; static const std::size_t logic_ops_list_size = sizeof(logic_ops_list) / sizeof(std::string); static const std::string cntrl_struct_list[] = - { - "if", "switch", "for", "while", "repeat", "return" - }; + { + "if", "switch", "for", "while", "repeat", "return" + }; static const std::size_t cntrl_struct_list_size = sizeof(cntrl_struct_list) / sizeof(std::string); static const std::string arithmetic_ops_list[] = - { - "+", "-", "*", "/", "%", "^" - }; + { + "+", "-", "*", "/", "%", "^" + }; static const std::size_t arithmetic_ops_list_size = sizeof(arithmetic_ops_list) / sizeof(std::string); static const std::string assignment_ops_list[] = - { - ":=", "+=", "-=", - "*=", "/=", "%=" - }; + { + ":=", "+=", "-=", + "*=", "/=", "%=" + }; static const std::size_t assignment_ops_list_size = sizeof(assignment_ops_list) / sizeof(std::string); static const std::string inequality_ops_list[] = - { - "<", "<=", "==", - "=", "!=", "<>", - ">=", ">" - }; + { + "<", "<=", "==", + "=", "!=", "<>", + ">=", ">" + }; static const std::size_t inequality_ops_list_size = sizeof(inequality_ops_list) / sizeof(std::string); @@ -598,78 +603,87 @@ namespace exprtk const Iterator data_begin , const Iterator data_end , const typename std::iterator_traits<Iterator>::value_type& zero_or_more, - const typename std::iterator_traits<Iterator>::value_type& zero_or_one ) + const typename std::iterator_traits<Iterator>::value_type& exactly_one ) { + typedef typename std::iterator_traits<Iterator>::value_type type; + const Iterator null_itr(0); - Iterator d_itr = data_begin; - Iterator p_itr = pattern_begin; - Iterator tb_p_itr = null_itr; - Iterator tb_d_itr = null_itr; + Iterator p_itr = pattern_begin; + Iterator d_itr = data_begin; + Iterator np_itr = null_itr; + Iterator nd_itr = null_itr; - while (d_itr != data_end) + for ( ; ; ) { - if (zero_or_more == *p_itr) + if (p_itr != pattern_end) { - while ((pattern_end != p_itr) && ((zero_or_more == *p_itr) || (zero_or_one == *p_itr))) - { - ++p_itr; - } - - if (pattern_end == p_itr) - return true; - - const typename std::iterator_traits<Iterator>::value_type c = *(p_itr); + const type c = *(p_itr); - while ((data_end != d_itr) && !Compare::cmp(c,*d_itr)) + if ((data_end != d_itr) && (Compare::cmp(c,*(d_itr)) || (exactly_one == c))) { ++d_itr; + ++p_itr; + continue; } + else if (zero_or_more == c) + { + while ((pattern_end != p_itr) && (zero_or_more == *(p_itr))) + { + ++p_itr; + } - tb_p_itr = p_itr; - tb_d_itr = d_itr; + const type d = *(p_itr); - continue; - } - else if (!Compare::cmp(*p_itr, *d_itr) && (zero_or_one != *p_itr)) - { - if (null_itr == tb_d_itr) - return false; + while ((data_end != d_itr) && !(Compare::cmp(d,*(d_itr)) || (exactly_one == d))) + { + ++d_itr; + } - d_itr = tb_d_itr++; - p_itr = tb_p_itr; + // set backtrack iterators + np_itr = p_itr - 1; + nd_itr = d_itr + 1; - continue; + continue; + } } + else if (data_end == d_itr) + break; - ++p_itr; - ++d_itr; - } + if ((data_end == d_itr) || (null_itr == nd_itr)) + return false; - while ((pattern_end != p_itr) && ((zero_or_more == *p_itr) || (zero_or_one == *p_itr))) - { - ++p_itr; + p_itr = np_itr; + d_itr = nd_itr; } - return (pattern_end == p_itr); + return true; } inline bool wc_match(const std::string& wild_card, const std::string& str) { - return match_impl<char_cptr,cs_match>( - wild_card.data(), wild_card.data() + wild_card.size(), - str.data(), str.data() + str.size(), - '*', '?'); + return match_impl<char_cptr,cs_match> + ( + wild_card.data(), + wild_card.data() + wild_card.size(), + str.data(), + str.data() + str.size(), + '*', '?' + ); } inline bool wc_imatch(const std::string& wild_card, const std::string& str) { - return match_impl<char_cptr,cis_match>( - wild_card.data(), wild_card.data() + wild_card.size(), - str.data(), str.data() + str.size(), - '*', '?'); + return match_impl<char_cptr,cis_match> + ( + wild_card.data(), + wild_card.data() + wild_card.size(), + str.data(), + str.data() + str.size(), + '*', '?' + ); } inline bool sequence_match(const std::string& pattern, @@ -689,19 +703,19 @@ namespace exprtk itr_t p_itr = pattern.begin(); itr_t s_itr = str .begin(); - itr_t p_end = pattern.end(); - itr_t s_end = str .end(); + const itr_t p_end = pattern.end(); + const itr_t s_end = str .end(); while ((s_end != s_itr) && (p_end != p_itr)) { if ('*' == (*p_itr)) { - const char_t target = static_cast<char>(std::toupper(*(p_itr - 1))); + const char_t target = static_cast<char_t>(std::toupper(*(p_itr - 1))); if ('*' == target) { diff_index = static_cast<std::size_t>(std::distance(str.begin(),s_itr)); - diff_value = static_cast<char>(std::toupper(*p_itr)); + diff_value = static_cast<char_t>(std::toupper(*p_itr)); return false; } @@ -724,7 +738,7 @@ namespace exprtk ) { diff_index = static_cast<std::size_t>(std::distance(str.begin(),s_itr)); - diff_value = static_cast<char>(std::toupper(*p_itr)); + diff_value = static_cast<char_t>(std::toupper(*p_itr)); return false; } @@ -742,13 +756,55 @@ namespace exprtk ); } - static const double pow10[] = { - 1.0, - 1.0E+001, 1.0E+002, 1.0E+003, 1.0E+004, - 1.0E+005, 1.0E+006, 1.0E+007, 1.0E+008, - 1.0E+009, 1.0E+010, 1.0E+011, 1.0E+012, - 1.0E+013, 1.0E+014, 1.0E+015, 1.0E+016 - }; + template<typename T> + struct set_zero_value_impl + { + static inline void process(T* base_ptr, const std::size_t size) + { + const T zero = T(0); + for (std::size_t i = 0; i < size; ++i) + { + base_ptr[i] = zero; + } + } + }; + + #define pod_set_zero_value(T) \ + template <> \ + struct set_zero_value_impl<T> \ + { \ + static inline void process(T* base_ptr, const std::size_t size) \ + { std::memset(base_ptr, 0x00, size * sizeof(T)); } \ + }; \ + + pod_set_zero_value(float ) + pod_set_zero_value(double ) + pod_set_zero_value(long double) + + #ifdef pod_set_zero_value + #undef pod_set_zero_value + #endif + + template<typename T> + inline void set_zero_value(T* data, const std::size_t size) + { + set_zero_value_impl<T>::process(data,size); + } + + template<typename T> + inline void set_zero_value(std::vector<T>& v) + { + set_zero_value(v.data(),v.size()); + } + + static const double pow10[] = + { + 1.0, + 1.0E+001, 1.0E+002, 1.0E+003, 1.0E+004, + 1.0E+005, 1.0E+006, 1.0E+007, 1.0E+008, + 1.0E+009, 1.0E+010, 1.0E+011, 1.0E+012, + 1.0E+013, 1.0E+014, 1.0E+015, 1.0E+016 + }; static const std::size_t pow10_size = sizeof(pow10) / sizeof(double); @@ -770,37 +826,28 @@ namespace exprtk namespace details { - struct unknown_type_tag { unknown_type_tag() = default; }; - struct real_type_tag { real_type_tag () = default; }; - struct complex_type_tag { complex_type_tag() = default; }; - struct int_type_tag { int_type_tag () = default; }; + struct unknown_type_tag { unknown_type_tag() exprtk_default; }; + struct real_type_tag { real_type_tag () exprtk_default; }; + struct int_type_tag { int_type_tag () exprtk_default; }; template <typename T> struct number_type { typedef unknown_type_tag type; - number_type() = default; + number_type() exprtk_default; }; - #define exprtk_register_real_type_tag(T) \ - template <> struct number_type<T> \ - { typedef real_type_tag type; number_type() {} }; \ - - #define exprtk_register_complex_type_tag(T) \ - template <> struct number_type<std::complex<T> > \ - { typedef complex_type_tag type; number_type() {} }; \ + #define exprtk_register_real_type_tag(T) \ + template <> struct number_type<T> \ + { typedef real_type_tag type; number_type() {} }; \ - #define exprtk_register_int_type_tag(T) \ - template <> struct number_type<T> \ - { typedef int_type_tag type; number_type() {} }; \ + #define exprtk_register_int_type_tag(T) \ + template <> struct number_type<T> \ + { typedef int_type_tag type; number_type() {} }; \ + exprtk_register_real_type_tag(float ) exprtk_register_real_type_tag(double ) exprtk_register_real_type_tag(long double) - exprtk_register_real_type_tag(float ) - - exprtk_register_complex_type_tag(double ) - exprtk_register_complex_type_tag(long double) - exprtk_register_complex_type_tag(float ) exprtk_register_int_type_tag(short ) exprtk_register_int_type_tag(int ) @@ -813,34 +860,23 @@ namespace exprtk #undef exprtk_register_int_type_tag template <typename T> - struct epsilon_type - { - static inline T value() - { - const T epsilon = T(0.0000000001); - return epsilon; - } - }; + struct epsilon_type {}; - template <> - struct epsilon_type <float> - { - static inline float value() - { - const float epsilon = float(0.000001f); - return epsilon; - } - }; + #define exprtk_define_epsilon_type(Type, Epsilon) \ + template <> struct epsilon_type<Type> \ + { \ + static inline Type value() \ + { \ + const Type epsilon = static_cast<Type>(Epsilon); \ + return epsilon; \ + } \ + }; \ - template <> - struct epsilon_type <long double> - { - static inline long double value() - { - const long double epsilon = static_cast<long double>(0.000000000001); - return epsilon; - } - }; + exprtk_define_epsilon_type(float , 0.00000100000f) + exprtk_define_epsilon_type(double , 0.000000000100) + exprtk_define_epsilon_type(long double, 0.000000000001) + + #undef exprtk_define_epsilon_type template <typename T> inline bool is_nan_impl(const T v, real_type_tag) @@ -860,6 +896,12 @@ namespace exprtk return static_cast<_int64_t>(v); } + template <typename T> + inline _uint64_t to_uint64_impl(const T v, real_type_tag) + { + return static_cast<_uint64_t>(v); + } + template <typename T> inline bool is_true_impl(const T v) { @@ -994,8 +1036,8 @@ namespace exprtk else return (T(-0.5) * v + T(1)) * v; } - else - return std::numeric_limits<T>::quiet_NaN(); + + return std::numeric_limits<T>::quiet_NaN(); } template <typename T> @@ -1005,8 +1047,8 @@ namespace exprtk { return std::log(T(1) + v); } - else - return std::numeric_limits<T>::quiet_NaN(); + + return std::numeric_limits<T>::quiet_NaN(); } template <typename T> @@ -1104,7 +1146,7 @@ namespace exprtk template <typename T> inline T sgn_impl(const T v, real_type_tag) { - if (v > T(0)) return T(+1); + if (v > T(0)) return T(+1); else if (v < T(0)) return T(-1); else return T( 0); } @@ -1112,7 +1154,7 @@ namespace exprtk template <typename T> inline T sgn_impl(const T v, int_type_tag) { - if (v > T(0)) return T(+1); + if (v > T(0)) return T(+1); else if (v < T(0)) return T(-1); else return T( 0); } @@ -1202,36 +1244,37 @@ namespace exprtk } #if (defined(_MSC_VER) && (_MSC_VER >= 1900)) || !defined(_MSC_VER) - #define exprtk_define_erf(TT,impl) \ - inline TT erf_impl(TT v) { return impl(v); } \ + #define exprtk_define_erf(TT, impl) \ + inline TT erf_impl(const TT v) { return impl(v); } \ - exprtk_define_erf( float,::erff) - exprtk_define_erf( double,::erf ) - exprtk_define_erf(long double,::erfl) + exprtk_define_erf(float , ::erff) + exprtk_define_erf(double , ::erf ) + exprtk_define_erf(long double, ::erfl) #undef exprtk_define_erf #endif template <typename T> - inline T erf_impl(T v, real_type_tag) + inline T erf_impl(const T v, real_type_tag) { #if defined(_MSC_VER) && (_MSC_VER < 1900) // Credits: Abramowitz & Stegun Equations 7.1.25-28 - static const T c[] = { - T( 1.26551223), T(1.00002368), - T( 0.37409196), T(0.09678418), - T(-0.18628806), T(0.27886807), - T(-1.13520398), T(1.48851587), - T(-0.82215223), T(0.17087277) - }; + static const T c[] = + { + T( 1.26551223), T(1.00002368), + T( 0.37409196), T(0.09678418), + T(-0.18628806), T(0.27886807), + T(-1.13520398), T(1.48851587), + T(-0.82215223), T(0.17087277) + }; const T t = T(1) / (T(1) + T(0.5) * abs_impl(v,real_type_tag())); - T result = T(1) - t * std::exp((-v * v) - - c[0] + t * (c[1] + t * - (c[2] + t * (c[3] + t * - (c[4] + t * (c[5] + t * - (c[6] + t * (c[7] + t * - (c[8] + t * (c[9])))))))))); + const T result = T(1) - t * std::exp((-v * v) - + c[0] + t * (c[1] + t * + (c[2] + t * (c[3] + t * + (c[4] + t * (c[5] + t * + (c[6] + t * (c[7] + t * + (c[8] + t * (c[9])))))))))); return (v >= T(0)) ? result : -result; #else @@ -1240,23 +1283,23 @@ namespace exprtk } template <typename T> - inline T erf_impl(T v, int_type_tag) + inline T erf_impl(const T v, int_type_tag) { return erf_impl(static_cast<double>(v),real_type_tag()); } #if (defined(_MSC_VER) && (_MSC_VER >= 1900)) || !defined(_MSC_VER) - #define exprtk_define_erfc(TT,impl) \ - inline TT erfc_impl(TT v) { return impl(v); } \ + #define exprtk_define_erfc(TT, impl) \ + inline TT erfc_impl(const TT v) { return impl(v); } \ - exprtk_define_erfc( float,::erfcf) - exprtk_define_erfc( double,::erfc ) + exprtk_define_erfc(float ,::erfcf) + exprtk_define_erfc(double ,::erfc ) exprtk_define_erfc(long double,::erfcl) #undef exprtk_define_erfc #endif template <typename T> - inline T erfc_impl(T v, real_type_tag) + inline T erfc_impl(const T v, real_type_tag) { #if defined(_MSC_VER) && (_MSC_VER < 1900) return T(1) - erf_impl(v,real_type_tag()); @@ -1266,28 +1309,25 @@ namespace exprtk } template <typename T> - inline T erfc_impl(T v, int_type_tag) + inline T erfc_impl(const T v, int_type_tag) { return erfc_impl(static_cast<double>(v),real_type_tag()); } template <typename T> - inline T ncdf_impl(T v, real_type_tag) + inline T ncdf_impl(const T v, real_type_tag) { - T cnd = T(0.5) * (T(1) + erf_impl( - abs_impl(v,real_type_tag()) / - T(numeric::constant::sqrt2),real_type_tag())); - return (v < T(0)) ? (T(1) - cnd) : cnd; + return T(0.5) * erfc_impl(-(v / T(numeric::constant::sqrt2)),real_type_tag()); } template <typename T> - inline T ncdf_impl(T v, int_type_tag) + inline T ncdf_impl(const T v, int_type_tag) { return ncdf_impl(static_cast<double>(v),real_type_tag()); } template <typename T> - inline T sinc_impl(T v, real_type_tag) + inline T sinc_impl(const T v, real_type_tag) { if (std::abs(v) >= std::numeric_limits<T>::epsilon()) return(std::sin(v) / v); @@ -1296,17 +1336,52 @@ namespace exprtk } template <typename T> - inline T sinc_impl(T v, int_type_tag) + inline T sinc_impl(const T v, int_type_tag) { return sinc_impl(static_cast<double>(v),real_type_tag()); } + #if __cplusplus >= 201103L + template <typename T> + inline T acosh_impl(const T v, real_type_tag) + { + return std::acosh(v); + } + + template <typename T> + inline T asinh_impl(const T v, real_type_tag) + { + return std::asinh(v); + } + + template <typename T> + inline T atanh_impl(const T v, real_type_tag) + { + return std::atanh(v); + } + #else + template <typename T> + inline T acosh_impl(const T v, real_type_tag) + { + return std::log(v + std::sqrt((v * v) - T(1))); + } + + template <typename T> + inline T asinh_impl(const T v, real_type_tag) + { + return std::log(v + std::sqrt((v * v) + T(1))); + } + + template <typename T> + inline T atanh_impl(const T v, real_type_tag) + { + return (std::log(T(1) + v) - std::log(T(1) - v)) / T(2); + } + #endif + template <typename T> inline T acos_impl(const T v, real_type_tag) { return std::acos (v); } - template <typename T> inline T acosh_impl(const T v, real_type_tag) { return std::log(v + std::sqrt((v * v) - T(1))); } template <typename T> inline T asin_impl(const T v, real_type_tag) { return std::asin (v); } - template <typename T> inline T asinh_impl(const T v, real_type_tag) { return std::log(v + std::sqrt((v * v) + T(1))); } template <typename T> inline T atan_impl(const T v, real_type_tag) { return std::atan (v); } - template <typename T> inline T atanh_impl(const T v, real_type_tag) { return (std::log(T(1) + v) - std::log(T(1) - v)) / T(2); } template <typename T> inline T ceil_impl(const T v, real_type_tag) { return std::ceil (v); } template <typename T> inline T cos_impl(const T v, real_type_tag) { return std::cos (v); } template <typename T> inline T cosh_impl(const T v, real_type_tag) { return std::cosh (v); } @@ -1327,14 +1402,15 @@ namespace exprtk template <typename T> inline T csc_impl(const T v, real_type_tag) { return T(1) / std::sin(v); } template <typename T> inline T r2d_impl(const T v, real_type_tag) { return (v * T(numeric::constant::_180_pi)); } template <typename T> inline T d2r_impl(const T v, real_type_tag) { return (v * T(numeric::constant::pi_180)); } - template <typename T> inline T d2g_impl(const T v, real_type_tag) { return (v * T(20.0/9.0)); } - template <typename T> inline T g2d_impl(const T v, real_type_tag) { return (v * T(9.0/20.0)); } + template <typename T> inline T d2g_impl(const T v, real_type_tag) { return (v * T(10.0/9.0)); } + template <typename T> inline T g2d_impl(const T v, real_type_tag) { return (v * T(9.0/10.0)); } template <typename T> inline T notl_impl(const T v, real_type_tag) { return (std::not_equal_to<T>()(T(0),v) ? T(0) : T(1)); } template <typename T> inline T frac_impl(const T v, real_type_tag) { return (v - static_cast<long long>(v)); } template <typename T> inline T trunc_impl(const T v, real_type_tag) { return T(static_cast<long long>(v)); } - template <typename T> inline T const_pi_impl(real_type_tag) { return T(numeric::constant::pi); } - template <typename T> inline T const_e_impl (real_type_tag) { return T(numeric::constant::e); } + template <typename T> inline T const_pi_impl(real_type_tag) { return T(numeric::constant::pi); } + template <typename T> inline T const_e_impl(real_type_tag) { return T(numeric::constant::e); } + template <typename T> inline T const_qnan_impl(real_type_tag) { return std::numeric_limits<T>::quiet_NaN(); } template <typename T> inline T abs_impl(const T v, int_type_tag) { return ((v >= T(0)) ? v : -v); } template <typename T> inline T exp_impl(const T v, int_type_tag) { return std::exp (v); } @@ -1382,10 +1458,10 @@ namespace exprtk template <typename Type> struct numeric_info { enum { length = 0, size = 32, bound_length = 0, min_exp = 0, max_exp = 0 }; }; - template <> struct numeric_info<int> { enum { length = 10, size = 16, bound_length = 9}; }; - template <> struct numeric_info<float> { enum { min_exp = -38, max_exp = +38}; }; - template <> struct numeric_info<double> { enum { min_exp = -308, max_exp = +308}; }; - template <> struct numeric_info<long double> { enum { min_exp = -308, max_exp = +308}; }; + template <> struct numeric_info<int > { enum { length = 10, size = 16, bound_length = 9 }; }; + template <> struct numeric_info<float > { enum { min_exp = -38, max_exp = +38 }; }; + template <> struct numeric_info<double > { enum { min_exp = -308, max_exp = +308 }; }; + template <> struct numeric_info<long double> { enum { min_exp = -308, max_exp = +308 }; }; template <typename T> inline int to_int32(const T v) @@ -1401,6 +1477,13 @@ namespace exprtk return to_int64_impl(v, num_type); } + template <typename T> + inline _uint64_t to_uint64(const T v) + { + const typename details::number_type<T>::type num_type; + return to_uint64_impl(v, num_type); + } + template <typename T> inline bool is_nan(const T v) { @@ -1558,31 +1641,31 @@ namespace exprtk while (k) { - if (k & 1) + if (1 == (k % 2)) { l *= v; --k; } v *= v; - k >>= 1; + k /= 2; } return l; } }; - template <typename T> struct fast_exp<T,10> { static inline T result(T v) { T v_5 = fast_exp<T,5>::result(v); return v_5 * v_5; } }; - template <typename T> struct fast_exp<T, 9> { static inline T result(T v) { return fast_exp<T,8>::result(v) * v; } }; - template <typename T> struct fast_exp<T, 8> { static inline T result(T v) { T v_4 = fast_exp<T,4>::result(v); return v_4 * v_4; } }; - template <typename T> struct fast_exp<T, 7> { static inline T result(T v) { return fast_exp<T,6>::result(v) * v; } }; - template <typename T> struct fast_exp<T, 6> { static inline T result(T v) { T v_3 = fast_exp<T,3>::result(v); return v_3 * v_3; } }; - template <typename T> struct fast_exp<T, 5> { static inline T result(T v) { return fast_exp<T,4>::result(v) * v; } }; - template <typename T> struct fast_exp<T, 4> { static inline T result(T v) { T v_2 = v * v; return v_2 * v_2; } }; - template <typename T> struct fast_exp<T, 3> { static inline T result(T v) { return v * v * v; } }; - template <typename T> struct fast_exp<T, 2> { static inline T result(T v) { return v * v; } }; - template <typename T> struct fast_exp<T, 1> { static inline T result(T v) { return v; } }; - template <typename T> struct fast_exp<T, 0> { static inline T result(T ) { return T(1); } }; + template <typename T> struct fast_exp<T,10> { static inline T result(const T v) { T v_5 = fast_exp<T,5>::result(v); return v_5 * v_5; } }; + template <typename T> struct fast_exp<T, 9> { static inline T result(const T v) { return fast_exp<T,8>::result(v) * v; } }; + template <typename T> struct fast_exp<T, 8> { static inline T result(const T v) { T v_4 = fast_exp<T,4>::result(v); return v_4 * v_4; } }; + template <typename T> struct fast_exp<T, 7> { static inline T result(const T v) { return fast_exp<T,6>::result(v) * v; } }; + template <typename T> struct fast_exp<T, 6> { static inline T result(const T v) { T v_3 = fast_exp<T,3>::result(v); return v_3 * v_3; } }; + template <typename T> struct fast_exp<T, 5> { static inline T result(const T v) { return fast_exp<T,4>::result(v) * v; } }; + template <typename T> struct fast_exp<T, 4> { static inline T result(const T v) { T v_2 = v * v; return v_2 * v_2; } }; + template <typename T> struct fast_exp<T, 3> { static inline T result(const T v) { return v * v * v; } }; + template <typename T> struct fast_exp<T, 2> { static inline T result(const T v) { return v * v; } }; + template <typename T> struct fast_exp<T, 1> { static inline T result(const T v) { return v; } }; + template <typename T> struct fast_exp<T, 0> { static inline T result(const T ) { return T(1); } }; #define exprtk_define_unary_function(FunctionName) \ template <typename T> \ @@ -1640,38 +1723,38 @@ namespace exprtk { static const double fract10[] = { - 0.0, - 1.0E+001, 1.0E+002, 1.0E+003, 1.0E+004, 1.0E+005, 1.0E+006, 1.0E+007, 1.0E+008, 1.0E+009, 1.0E+010, - 1.0E+011, 1.0E+012, 1.0E+013, 1.0E+014, 1.0E+015, 1.0E+016, 1.0E+017, 1.0E+018, 1.0E+019, 1.0E+020, - 1.0E+021, 1.0E+022, 1.0E+023, 1.0E+024, 1.0E+025, 1.0E+026, 1.0E+027, 1.0E+028, 1.0E+029, 1.0E+030, - 1.0E+031, 1.0E+032, 1.0E+033, 1.0E+034, 1.0E+035, 1.0E+036, 1.0E+037, 1.0E+038, 1.0E+039, 1.0E+040, - 1.0E+041, 1.0E+042, 1.0E+043, 1.0E+044, 1.0E+045, 1.0E+046, 1.0E+047, 1.0E+048, 1.0E+049, 1.0E+050, - 1.0E+051, 1.0E+052, 1.0E+053, 1.0E+054, 1.0E+055, 1.0E+056, 1.0E+057, 1.0E+058, 1.0E+059, 1.0E+060, - 1.0E+061, 1.0E+062, 1.0E+063, 1.0E+064, 1.0E+065, 1.0E+066, 1.0E+067, 1.0E+068, 1.0E+069, 1.0E+070, - 1.0E+071, 1.0E+072, 1.0E+073, 1.0E+074, 1.0E+075, 1.0E+076, 1.0E+077, 1.0E+078, 1.0E+079, 1.0E+080, - 1.0E+081, 1.0E+082, 1.0E+083, 1.0E+084, 1.0E+085, 1.0E+086, 1.0E+087, 1.0E+088, 1.0E+089, 1.0E+090, - 1.0E+091, 1.0E+092, 1.0E+093, 1.0E+094, 1.0E+095, 1.0E+096, 1.0E+097, 1.0E+098, 1.0E+099, 1.0E+100, - 1.0E+101, 1.0E+102, 1.0E+103, 1.0E+104, 1.0E+105, 1.0E+106, 1.0E+107, 1.0E+108, 1.0E+109, 1.0E+110, - 1.0E+111, 1.0E+112, 1.0E+113, 1.0E+114, 1.0E+115, 1.0E+116, 1.0E+117, 1.0E+118, 1.0E+119, 1.0E+120, - 1.0E+121, 1.0E+122, 1.0E+123, 1.0E+124, 1.0E+125, 1.0E+126, 1.0E+127, 1.0E+128, 1.0E+129, 1.0E+130, - 1.0E+131, 1.0E+132, 1.0E+133, 1.0E+134, 1.0E+135, 1.0E+136, 1.0E+137, 1.0E+138, 1.0E+139, 1.0E+140, - 1.0E+141, 1.0E+142, 1.0E+143, 1.0E+144, 1.0E+145, 1.0E+146, 1.0E+147, 1.0E+148, 1.0E+149, 1.0E+150, - 1.0E+151, 1.0E+152, 1.0E+153, 1.0E+154, 1.0E+155, 1.0E+156, 1.0E+157, 1.0E+158, 1.0E+159, 1.0E+160, - 1.0E+161, 1.0E+162, 1.0E+163, 1.0E+164, 1.0E+165, 1.0E+166, 1.0E+167, 1.0E+168, 1.0E+169, 1.0E+170, - 1.0E+171, 1.0E+172, 1.0E+173, 1.0E+174, 1.0E+175, 1.0E+176, 1.0E+177, 1.0E+178, 1.0E+179, 1.0E+180, - 1.0E+181, 1.0E+182, 1.0E+183, 1.0E+184, 1.0E+185, 1.0E+186, 1.0E+187, 1.0E+188, 1.0E+189, 1.0E+190, - 1.0E+191, 1.0E+192, 1.0E+193, 1.0E+194, 1.0E+195, 1.0E+196, 1.0E+197, 1.0E+198, 1.0E+199, 1.0E+200, - 1.0E+201, 1.0E+202, 1.0E+203, 1.0E+204, 1.0E+205, 1.0E+206, 1.0E+207, 1.0E+208, 1.0E+209, 1.0E+210, - 1.0E+211, 1.0E+212, 1.0E+213, 1.0E+214, 1.0E+215, 1.0E+216, 1.0E+217, 1.0E+218, 1.0E+219, 1.0E+220, - 1.0E+221, 1.0E+222, 1.0E+223, 1.0E+224, 1.0E+225, 1.0E+226, 1.0E+227, 1.0E+228, 1.0E+229, 1.0E+230, - 1.0E+231, 1.0E+232, 1.0E+233, 1.0E+234, 1.0E+235, 1.0E+236, 1.0E+237, 1.0E+238, 1.0E+239, 1.0E+240, - 1.0E+241, 1.0E+242, 1.0E+243, 1.0E+244, 1.0E+245, 1.0E+246, 1.0E+247, 1.0E+248, 1.0E+249, 1.0E+250, - 1.0E+251, 1.0E+252, 1.0E+253, 1.0E+254, 1.0E+255, 1.0E+256, 1.0E+257, 1.0E+258, 1.0E+259, 1.0E+260, - 1.0E+261, 1.0E+262, 1.0E+263, 1.0E+264, 1.0E+265, 1.0E+266, 1.0E+267, 1.0E+268, 1.0E+269, 1.0E+270, - 1.0E+271, 1.0E+272, 1.0E+273, 1.0E+274, 1.0E+275, 1.0E+276, 1.0E+277, 1.0E+278, 1.0E+279, 1.0E+280, - 1.0E+281, 1.0E+282, 1.0E+283, 1.0E+284, 1.0E+285, 1.0E+286, 1.0E+287, 1.0E+288, 1.0E+289, 1.0E+290, - 1.0E+291, 1.0E+292, 1.0E+293, 1.0E+294, 1.0E+295, 1.0E+296, 1.0E+297, 1.0E+298, 1.0E+299, 1.0E+300, - 1.0E+301, 1.0E+302, 1.0E+303, 1.0E+304, 1.0E+305, 1.0E+306, 1.0E+307, 1.0E+308 + 0.0, + 1.0E+001, 1.0E+002, 1.0E+003, 1.0E+004, 1.0E+005, 1.0E+006, 1.0E+007, 1.0E+008, 1.0E+009, 1.0E+010, + 1.0E+011, 1.0E+012, 1.0E+013, 1.0E+014, 1.0E+015, 1.0E+016, 1.0E+017, 1.0E+018, 1.0E+019, 1.0E+020, + 1.0E+021, 1.0E+022, 1.0E+023, 1.0E+024, 1.0E+025, 1.0E+026, 1.0E+027, 1.0E+028, 1.0E+029, 1.0E+030, + 1.0E+031, 1.0E+032, 1.0E+033, 1.0E+034, 1.0E+035, 1.0E+036, 1.0E+037, 1.0E+038, 1.0E+039, 1.0E+040, + 1.0E+041, 1.0E+042, 1.0E+043, 1.0E+044, 1.0E+045, 1.0E+046, 1.0E+047, 1.0E+048, 1.0E+049, 1.0E+050, + 1.0E+051, 1.0E+052, 1.0E+053, 1.0E+054, 1.0E+055, 1.0E+056, 1.0E+057, 1.0E+058, 1.0E+059, 1.0E+060, + 1.0E+061, 1.0E+062, 1.0E+063, 1.0E+064, 1.0E+065, 1.0E+066, 1.0E+067, 1.0E+068, 1.0E+069, 1.0E+070, + 1.0E+071, 1.0E+072, 1.0E+073, 1.0E+074, 1.0E+075, 1.0E+076, 1.0E+077, 1.0E+078, 1.0E+079, 1.0E+080, + 1.0E+081, 1.0E+082, 1.0E+083, 1.0E+084, 1.0E+085, 1.0E+086, 1.0E+087, 1.0E+088, 1.0E+089, 1.0E+090, + 1.0E+091, 1.0E+092, 1.0E+093, 1.0E+094, 1.0E+095, 1.0E+096, 1.0E+097, 1.0E+098, 1.0E+099, 1.0E+100, + 1.0E+101, 1.0E+102, 1.0E+103, 1.0E+104, 1.0E+105, 1.0E+106, 1.0E+107, 1.0E+108, 1.0E+109, 1.0E+110, + 1.0E+111, 1.0E+112, 1.0E+113, 1.0E+114, 1.0E+115, 1.0E+116, 1.0E+117, 1.0E+118, 1.0E+119, 1.0E+120, + 1.0E+121, 1.0E+122, 1.0E+123, 1.0E+124, 1.0E+125, 1.0E+126, 1.0E+127, 1.0E+128, 1.0E+129, 1.0E+130, + 1.0E+131, 1.0E+132, 1.0E+133, 1.0E+134, 1.0E+135, 1.0E+136, 1.0E+137, 1.0E+138, 1.0E+139, 1.0E+140, + 1.0E+141, 1.0E+142, 1.0E+143, 1.0E+144, 1.0E+145, 1.0E+146, 1.0E+147, 1.0E+148, 1.0E+149, 1.0E+150, + 1.0E+151, 1.0E+152, 1.0E+153, 1.0E+154, 1.0E+155, 1.0E+156, 1.0E+157, 1.0E+158, 1.0E+159, 1.0E+160, + 1.0E+161, 1.0E+162, 1.0E+163, 1.0E+164, 1.0E+165, 1.0E+166, 1.0E+167, 1.0E+168, 1.0E+169, 1.0E+170, + 1.0E+171, 1.0E+172, 1.0E+173, 1.0E+174, 1.0E+175, 1.0E+176, 1.0E+177, 1.0E+178, 1.0E+179, 1.0E+180, + 1.0E+181, 1.0E+182, 1.0E+183, 1.0E+184, 1.0E+185, 1.0E+186, 1.0E+187, 1.0E+188, 1.0E+189, 1.0E+190, + 1.0E+191, 1.0E+192, 1.0E+193, 1.0E+194, 1.0E+195, 1.0E+196, 1.0E+197, 1.0E+198, 1.0E+199, 1.0E+200, + 1.0E+201, 1.0E+202, 1.0E+203, 1.0E+204, 1.0E+205, 1.0E+206, 1.0E+207, 1.0E+208, 1.0E+209, 1.0E+210, + 1.0E+211, 1.0E+212, 1.0E+213, 1.0E+214, 1.0E+215, 1.0E+216, 1.0E+217, 1.0E+218, 1.0E+219, 1.0E+220, + 1.0E+221, 1.0E+222, 1.0E+223, 1.0E+224, 1.0E+225, 1.0E+226, 1.0E+227, 1.0E+228, 1.0E+229, 1.0E+230, + 1.0E+231, 1.0E+232, 1.0E+233, 1.0E+234, 1.0E+235, 1.0E+236, 1.0E+237, 1.0E+238, 1.0E+239, 1.0E+240, + 1.0E+241, 1.0E+242, 1.0E+243, 1.0E+244, 1.0E+245, 1.0E+246, 1.0E+247, 1.0E+248, 1.0E+249, 1.0E+250, + 1.0E+251, 1.0E+252, 1.0E+253, 1.0E+254, 1.0E+255, 1.0E+256, 1.0E+257, 1.0E+258, 1.0E+259, 1.0E+260, + 1.0E+261, 1.0E+262, 1.0E+263, 1.0E+264, 1.0E+265, 1.0E+266, 1.0E+267, 1.0E+268, 1.0E+269, 1.0E+270, + 1.0E+271, 1.0E+272, 1.0E+273, 1.0E+274, 1.0E+275, 1.0E+276, 1.0E+277, 1.0E+278, 1.0E+279, 1.0E+280, + 1.0E+281, 1.0E+282, 1.0E+283, 1.0E+284, 1.0E+285, 1.0E+286, 1.0E+287, 1.0E+288, 1.0E+289, 1.0E+290, + 1.0E+291, 1.0E+292, 1.0E+293, 1.0E+294, 1.0E+295, 1.0E+296, 1.0E+297, 1.0E+298, 1.0E+299, 1.0E+300, + 1.0E+301, 1.0E+302, 1.0E+303, 1.0E+304, 1.0E+305, 1.0E+306, 1.0E+307, 1.0E+308 }; static const int fract10_size = static_cast<int>(sizeof(fract10) / sizeof(double)); @@ -1717,11 +1800,10 @@ namespace exprtk bool return_result = true; unsigned int digit = 0; - const std::size_t length = static_cast<std::size_t>(std::distance(itr,end)); + const std::size_t length = static_cast<std::size_t>(std::distance(itr,end)); if (length <= 4) { - exprtk_disable_fallthrough_begin switch (length) { #ifdef exprtk_use_lut @@ -1734,28 +1816,33 @@ namespace exprtk return_result = false; \ break; \ } \ + exprtk_fallthrough \ #else - #define exprtk_process_digit \ - if ((digit = (*itr++ - zero)) < 10) \ - result = result * T(10) + digit; \ - else \ - { \ - return_result = false; \ - break; \ - } \ + #define exprtk_process_digit \ + if ((digit = (*itr++ - zero)) < 10) \ + result = result * T(10) + digit; \ + else \ + { \ + return_result = false; \ + break; \ + } \ + exprtk_fallthrough \ #endif - case 4 : exprtk_process_digit - case 3 : exprtk_process_digit - case 2 : exprtk_process_digit - case 1 : if ((digit = (*itr - zero))>= 10) { digit = 0; return_result = false; } + case 4 : exprtk_process_digit + case 3 : exprtk_process_digit + case 2 : exprtk_process_digit + case 1 : if ((digit = (*itr - zero))>= 10) + { + digit = 0; + return_result = false; + } #undef exprtk_process_digit } - exprtk_disable_fallthrough_end } else return_result = false; @@ -1804,7 +1891,7 @@ namespace exprtk } template <typename Iterator, typename T> - static inline bool parse_inf(Iterator& itr, const Iterator end, T& t, bool negative) + static inline bool parse_inf(Iterator& itr, const Iterator end, T& t, const bool negative) { static const char_t inf_uc[] = "INFINITY"; static const char_t inf_lc[] = "infinity"; @@ -1819,7 +1906,7 @@ namespace exprtk while (end != itr) { - if (*inf_itr == static_cast<char>(*itr)) + if (*inf_itr == static_cast<char_t>(*itr)) { ++itr; ++inf_itr; @@ -1840,8 +1927,8 @@ namespace exprtk template <typename T> inline bool valid_exponent(const int exponent, numeric::details::real_type_tag) { - return (std::numeric_limits<T>::min_exponent10 <= exponent) && - (exponent <= std::numeric_limits<T>::max_exponent10) ; + using namespace details::numeric; + return (numeric_info<T>::min_exp <= exponent) && (exponent <= numeric_info<T>::max_exp); } template <typename Iterator, typename T> @@ -1875,7 +1962,8 @@ namespace exprtk #define parse_digit_2(d) \ if ((digit = (*itr - zero)) < 10) \ { d = d * T(10) + digit; } \ - else { break; } \ + else \ + { break; } \ ++itr; \ if ('.' != (*itr)) @@ -1886,14 +1974,7 @@ namespace exprtk while (end != itr) { - // Note: For 'physical' superscalar architectures it - // is advised that the following loop be: 4xPD1 and 1xPD2 unsigned int digit; - - #ifdef exprtk_enable_superscalar - parse_digit_1(d) - parse_digit_1(d) - #endif parse_digit_1(d) parse_digit_1(d) parse_digit_2(d) @@ -1914,12 +1995,6 @@ namespace exprtk while (end != itr) { unsigned int digit; - - #ifdef exprtk_enable_superscalar - parse_digit_1(tmp_d) - parse_digit_1(tmp_d) - parse_digit_1(tmp_d) - #endif parse_digit_1(tmp_d) parse_digit_1(tmp_d) parse_digit_2(tmp_d) @@ -1929,12 +2004,12 @@ namespace exprtk { instate = true; - const int exponent = static_cast<int>(-std::distance(curr, itr)); + const int frac_exponent = static_cast<int>(-std::distance(curr, itr)); - if (!valid_exponent<T>(exponent, numeric::details::real_type_tag())) + if (!valid_exponent<T>(frac_exponent, numeric::details::real_type_tag())) return false; - d += compute_pow10(tmp_d, exponent); + d += compute_pow10(tmp_d, frac_exponent); } #undef parse_digit_1 @@ -2066,8 +2141,8 @@ namespace exprtk loop_types loop_set; loop_runtime_check() - : loop_set(e_invalid), - max_loop_iterations(0) + : loop_set(e_invalid) + , max_loop_iterations(0) {} details::_uint64_t max_loop_iterations; @@ -2079,16 +2154,77 @@ namespace exprtk details::_uint64_t iteration_count; }; + virtual bool check() + { + return true; + } + virtual void handle_runtime_violation(const violation_context&) { - throw std::runtime_error("ExprTk Loop run-time violation."); + throw std::runtime_error("ExprTk Loop runtime violation."); } - virtual ~loop_runtime_check() = default; + virtual ~loop_runtime_check() exprtk_default; }; typedef loop_runtime_check* loop_runtime_check_ptr; + struct vector_access_runtime_check + { + struct violation_context + { + void* base_ptr; + void* end_ptr; + void* access_ptr; + std::size_t type_size; + }; + + virtual ~vector_access_runtime_check() exprtk_default; + + virtual bool handle_runtime_violation(violation_context& /*context*/) + { + throw std::runtime_error("ExprTk runtime vector access violation."); + #if !defined(_MSC_VER) && !defined(__NVCOMPILER) + return false; + #endif + } + }; + + typedef vector_access_runtime_check* vector_access_runtime_check_ptr; + + struct assert_check + { + struct assert_context + { + std::string condition; + std::string message; + std::string id; + std::size_t offet; + }; + + virtual ~assert_check() exprtk_default; + + virtual void handle_assert(const assert_context& /*context*/) + { + } + }; + + typedef assert_check* assert_check_ptr; + + struct compilation_check + { + struct compilation_context + { + std::string error_message; + }; + + virtual bool continue_compilation(compilation_context& /*context*/) = 0; + + virtual ~compilation_check() exprtk_default; + }; + + typedef compilation_check* compilation_check_ptr; + namespace lexer { struct token @@ -2112,9 +2248,9 @@ namespace exprtk }; token() - : type(e_none), - value(""), - position(std::numeric_limits<std::size_t>::max()) + : type(e_none) + , value("") + , position(std::numeric_limits<std::size_t>::max()) {} void clear() @@ -2247,6 +2383,19 @@ namespace exprtk } } + static inline std::string seperator_to_str(const token_type t) + { + switch (t) + { + case e_comma : return ","; + case e_colon : return ":"; + case e_eof : return ";"; + default : return "UNKNOWN"; + } + + return "UNKNOWN"; + } + inline bool is_error() const { return ( @@ -2273,9 +2422,9 @@ namespace exprtk typedef details::char_t char_t; generator() - : base_itr_(0), - s_itr_ (0), - s_end_ (0) + : base_itr_(0) + , s_itr_ (0) + , s_end_ (0) { clear(); } @@ -2296,7 +2445,7 @@ namespace exprtk s_itr_ = str.data(); s_end_ = str.data() + str.size(); - eof_token_.set_operator(token_t::e_eof,s_end_,s_end_,base_itr_); + eof_token_.set_operator(token_t::e_eof, s_end_, s_end_, base_itr_); token_list_.clear(); while (!is_end(s_itr_)) @@ -2359,7 +2508,9 @@ namespace exprtk inline token_t& operator[](const std::size_t& index) { if (index < token_list_.size()) + { return token_list_[index]; + } else return eof_token_; } @@ -2367,7 +2518,9 @@ namespace exprtk inline token_t operator[](const std::size_t& index) const { if (index < token_list_.size()) + { return token_list_[index]; + } else return eof_token_; } @@ -2391,10 +2544,10 @@ namespace exprtk } } - inline std::string substr(const std::size_t& begin, const std::size_t& end) + inline std::string substr(const std::size_t& begin, const std::size_t& end) const { const details::char_cptr begin_itr = ((base_itr_ + begin) < s_end_) ? (base_itr_ + begin) : s_end_; - const details::char_cptr end_itr = ((base_itr_ + end) < s_end_) ? (base_itr_ + end) : s_end_; + const details::char_cptr end_itr = ((base_itr_ + end ) < s_end_) ? (base_itr_ + end ) : s_end_; return std::string(begin_itr,end_itr); } @@ -2411,13 +2564,13 @@ namespace exprtk private: - inline bool is_end(details::char_cptr itr) + inline bool is_end(details::char_cptr itr) const { return (s_end_ == itr); } #ifndef exprtk_disable_comments - inline bool is_comment_start(details::char_cptr itr) + inline bool is_comment_start(details::char_cptr itr) const { const char_t c0 = *(itr + 0); const char_t c1 = *(itr + 1); @@ -2432,7 +2585,7 @@ namespace exprtk return false; } #else - inline bool is_comment_start(details::char_cptr) + inline bool is_comment_start(details::char_cptr) const { return false; } @@ -2458,10 +2611,10 @@ namespace exprtk static inline bool comment_start(const char_t c0, const char_t c1, int& mode, int& incr) { mode = 0; - if ('#' == c0) { mode = 1; incr = 1; } + if ('#' == c0) { mode = 1; incr = 1; } else if ('/' == c0) { - if ('/' == c1) { mode = 1; incr = 2; } + if ('/' == c1) { mode = 1; incr = 2; } else if ('*' == c1) { mode = 2; incr = 2; } } return (0 != mode); @@ -2511,7 +2664,7 @@ namespace exprtk } } - ++s_itr_; + ++s_itr_; } if (2 == mode) @@ -2523,9 +2676,17 @@ namespace exprtk #endif } + inline bool next_is_digit(const details::char_cptr itr) const + { + return ((itr + 1) != s_end_) && + details::is_digit(*(itr + 1)); + } + inline void scan_token() { - if (details::is_whitespace(*s_itr_)) + const char_t c = *s_itr_; + + if (details::is_whitespace(c)) { skip_whitespace(); return; @@ -2535,34 +2696,39 @@ namespace exprtk skip_comments(); return; } - else if (details::is_operator_char(*s_itr_)) + else if (details::is_operator_char(c)) { scan_operator(); return; } - else if (details::is_letter(*s_itr_)) + else if (details::is_letter(c)) { scan_symbol(); return; } - else if (details::is_digit((*s_itr_)) || ('.' == (*s_itr_))) + else if (('.' == c) && !next_is_digit(s_itr_)) + { + scan_operator(); + return; + } + else if (details::is_digit(c) || ('.' == c)) { scan_number(); return; } - else if ('$' == (*s_itr_)) + else if ('$' == c) { scan_special_function(); return; } #ifndef exprtk_disable_string_capabilities - else if ('\'' == (*s_itr_)) + else if ('\'' == c) { scan_string(); return; } #endif - else if ('~' == (*s_itr_)) + else if ('~' == c) { token_t t; t.set_symbol(s_itr_, s_itr_ + 1, base_itr_); @@ -2604,7 +2770,7 @@ namespace exprtk token_t::token_type ttype = token_t::e_none; - if ((c0 == '<') && (c1 == '=')) ttype = token_t::e_lte; + if ((c0 == '<') && (c1 == '=')) ttype = token_t::e_lte; else if ((c0 == '>') && (c1 == '=')) ttype = token_t::e_gte; else if ((c0 == '<') && (c1 == '>')) ttype = token_t::e_ne; else if ((c0 == '!') && (c1 == '=')) ttype = token_t::e_ne; @@ -2672,7 +2838,7 @@ namespace exprtk } token_t t; - t.set_symbol(initial_itr,s_itr_,base_itr_); + t.set_symbol(initial_itr, s_itr_, base_itr_); token_list_.push_back(t); } @@ -2872,12 +3038,12 @@ namespace exprtk ((s_itr_ + 4) <= s_end_) ) { - const bool x_seperator = ('X' == std::toupper(*(s_itr_ + 1))); + const bool x_separator = ('X' == std::toupper(*(s_itr_ + 1))); const bool both_digits = details::is_hex_digit(*(s_itr_ + 2)) && details::is_hex_digit(*(s_itr_ + 3)) ; - if (!(x_seperator && both_digits)) + if (!(x_separator && both_digits)) { t.set_error(token::e_err_string, initial_itr, s_itr_, base_itr_); token_list_.push_back(t); @@ -2917,8 +3083,8 @@ namespace exprtk } t.set_string( - parsed_string, - static_cast<std::size_t>(std::distance(base_itr_,initial_itr))); + parsed_string, + static_cast<std::size_t>(std::distance(base_itr_,initial_itr))); } token_list_.push_back(t); @@ -2942,7 +3108,7 @@ namespace exprtk friend class token_modifier; friend class token_inserter; friend class token_joiner; - }; + }; // class generator class helper_interface { @@ -2952,14 +3118,14 @@ namespace exprtk virtual void reset() { } virtual bool result() { return true; } virtual std::size_t process(generator&) { return 0; } - virtual ~helper_interface() = default; + virtual ~helper_interface() exprtk_default; }; class token_scanner : public helper_interface { public: - ~token_scanner() override = default; + ~token_scanner() exprtk_override exprtk_default; explicit token_scanner(const std::size_t& stride) : stride_(stride) @@ -2970,7 +3136,7 @@ namespace exprtk } } - inline std::size_t process(generator& g) override + inline std::size_t process(generator& g) exprtk_override { if (g.token_list_.size() >= stride_) { @@ -2986,7 +3152,7 @@ namespace exprtk if (!operator()(t0)) { - return i; + return 0; } } break; @@ -2998,7 +3164,7 @@ namespace exprtk if (!operator()(t0, t1)) { - return i; + return 0; } } break; @@ -3011,7 +3177,7 @@ namespace exprtk if (!operator()(t0, t1, t2)) { - return i; + return 0; } } break; @@ -3025,7 +3191,7 @@ namespace exprtk if (!operator()(t0, t1, t2, t3)) { - return i; + return 0; } } break; @@ -3033,7 +3199,7 @@ namespace exprtk } } - return (g.token_list_.size() - stride_ + 1); + return 0; } virtual bool operator() (const token&) @@ -3059,13 +3225,13 @@ namespace exprtk private: const std::size_t stride_; - }; + }; // class token_scanner class token_modifier : public helper_interface { public: - inline std::size_t process(generator& g) override + inline std::size_t process(generator& g) exprtk_override { std::size_t changes = 0; @@ -3093,7 +3259,7 @@ namespace exprtk } } - inline std::size_t process(generator& g) override + inline std::size_t process(generator& g) exprtk_override { if (g.token_list_.empty()) return 0; @@ -3197,7 +3363,7 @@ namespace exprtk : stride_(stride) {} - inline std::size_t process(generator& g) override + inline std::size_t process(generator& g) exprtk_override { if (g.token_list_.empty()) return 0; @@ -3225,7 +3391,7 @@ namespace exprtk generator::token_list_t token_list; token_list.reserve(10000); - for (int i = 0; i < static_cast<int>(g.token_list_.size() - 1); ++i) + for (int i = 0; i < static_cast<int>(g.token_list_.size() - 1); ++i) { token t; @@ -3241,15 +3407,17 @@ namespace exprtk ++changes; - i+=2; + i += 2; - if (static_cast<std::size_t>(i) >= g.token_list_.size()) + if (static_cast<std::size_t>(i) >= (g.token_list_.size() - 1)) break; } } token_list.push_back(g.token_list_.back()); + assert(token_list.size() <= g.token_list_.size()); + std::swap(token_list, g.token_list_); return changes; @@ -3265,7 +3433,7 @@ namespace exprtk generator::token_list_t token_list; token_list.reserve(10000); - for (int i = 0; i < static_cast<int>(g.token_list_.size() - 2); ++i) + for (int i = 0; i < static_cast<int>(g.token_list_.size() - 2); ++i) { token t; @@ -3281,9 +3449,9 @@ namespace exprtk ++changes; - i+=3; + i += 3; - if (static_cast<std::size_t>(i) >= g.token_list_.size()) + if (static_cast<std::size_t>(i) >= (g.token_list_.size() - 2)) break; } } @@ -3291,6 +3459,8 @@ namespace exprtk token_list.push_back(*(g.token_list_.begin() + g.token_list_.size() - 2)); token_list.push_back(*(g.token_list_.begin() + g.token_list_.size() - 1)); + assert(token_list.size() <= g.token_list_.size()); + std::swap(token_list, g.token_list_); return changes; @@ -3330,7 +3500,7 @@ namespace exprtk ignore_set_.insert(symbol); } - inline int insert(const lexer::token& t0, const lexer::token& t1, lexer::token& new_token) override + inline int insert(const lexer::token& t0, const lexer::token& t1, lexer::token& new_token) exprtk_override { bool match = false; new_token.type = lexer::token::e_mul; @@ -3356,7 +3526,7 @@ namespace exprtk return -1; } } - if ((t0.type == lexer::token::e_number ) && (t1.type == lexer::token::e_symbol )) match = true; + if ((t0.type == lexer::token::e_number ) && (t1.type == lexer::token::e_symbol )) match = true; else if ((t0.type == lexer::token::e_number ) && (t1.type == lexer::token::e_lbracket )) match = true; else if ((t0.type == lexer::token::e_number ) && (t1.type == lexer::token::e_lcrlbracket)) match = true; else if ((t0.type == lexer::token::e_number ) && (t1.type == lexer::token::e_lsqrbracket)) match = true; @@ -3377,7 +3547,7 @@ namespace exprtk std::set<std::string,details::ilesscompare> ignore_set_; }; - class operator_joiner : public token_joiner + class operator_joiner exprtk_final : public token_joiner { public: @@ -3385,7 +3555,7 @@ namespace exprtk : token_joiner(stride) {} - inline bool join(const lexer::token& t0, const lexer::token& t1, lexer::token& t) override + inline bool join(const lexer::token& t0, const lexer::token& t1, lexer::token& t) exprtk_override { // ': =' --> ':=' if ((t0.type == lexer::token::e_colon) && (t1.type == lexer::token::e_eq)) @@ -3469,7 +3639,7 @@ namespace exprtk return true; } // '! =' --> '!=' - else if ((static_cast<char>(t0.type) == '!') && (t1.type == lexer::token::e_eq)) + else if ((static_cast<details::char_t>(t0.type) == '!') && (t1.type == lexer::token::e_eq)) { t.type = lexer::token::e_ne; t.value = "!="; @@ -3530,7 +3700,10 @@ namespace exprtk return false; } - inline bool join(const lexer::token& t0, const lexer::token& t1, const lexer::token& t2, lexer::token& t) override + inline bool join(const lexer::token& t0, + const lexer::token& t1, + const lexer::token& t2, + lexer::token& t) exprtk_override { // '[ * ]' --> '[*]' if ( @@ -3550,18 +3723,18 @@ namespace exprtk } }; - class bracket_checker : public lexer::token_scanner + class bracket_checker exprtk_final : public lexer::token_scanner { public: using lexer::token_scanner::operator(); bracket_checker() - : token_scanner(1), - state_(true) + : token_scanner(1) + , state_(true) {} - bool result() override + bool result() exprtk_override { if (!stack_.empty()) { @@ -3582,7 +3755,7 @@ namespace exprtk return error_token_; } - void reset() override + void reset() exprtk_override { // Why? because msvc doesn't support swap properly. stack_ = std::stack<std::pair<char,std::size_t> >(); @@ -3590,7 +3763,7 @@ namespace exprtk error_token_.clear(); } - bool operator() (const lexer::token& t) override + bool operator() (const lexer::token& t) exprtk_override { if ( !t.value.empty() && @@ -3601,7 +3774,7 @@ namespace exprtk { details::char_t c = t.value[0]; - if (t.type == lexer::token::e_lbracket ) stack_.push(std::make_pair(')',t.position)); + if (t.type == lexer::token::e_lbracket ) stack_.push(std::make_pair(')',t.position)); else if (t.type == lexer::token::e_lcrlbracket) stack_.push(std::make_pair('}',t.position)); else if (t.type == lexer::token::e_lsqrbracket) stack_.push(std::make_pair(']',t.position)); else if (exprtk::details::is_right_bracket(c)) @@ -3635,33 +3808,34 @@ namespace exprtk lexer::token error_token_; }; - class numeric_checker : public lexer::token_scanner + template <typename T> + class numeric_checker exprtk_final : public lexer::token_scanner { public: using lexer::token_scanner::operator(); numeric_checker() - : token_scanner (1), - current_index_(0) + : token_scanner (1) + , current_index_(0) {} - bool result() override + bool result() exprtk_override { return error_list_.empty(); } - void reset() override + void reset() exprtk_override { error_list_.clear(); current_index_ = 0; } - bool operator() (const lexer::token& t) override + bool operator() (const lexer::token& t) exprtk_override { if (token::e_number == t.type) { - double v; + T v; if (!exprtk::details::string_to_real(t.value,v)) { @@ -3698,7 +3872,7 @@ namespace exprtk std::vector<std::size_t> error_list_; }; - class symbol_replacer : public lexer::token_modifier + class symbol_replacer exprtk_final : public lexer::token_modifier { private: @@ -3741,7 +3915,7 @@ namespace exprtk private: - bool modify(lexer::token& t) override + bool modify(lexer::token& t) exprtk_override { if (lexer::token::e_symbol == t.type) { @@ -3765,7 +3939,7 @@ namespace exprtk replace_map_t replace_map_; }; - class sequence_validator : public lexer::token_scanner + class sequence_validator exprtk_final : public lexer::token_scanner { private: @@ -3804,12 +3978,12 @@ namespace exprtk add_invalid_set1(lexer::token::e_ternary); } - bool result() override + bool result() exprtk_override { return error_list_.empty(); } - bool operator() (const lexer::token& t0, const lexer::token& t1) override + bool operator() (const lexer::token& t0, const lexer::token& t1) exprtk_override { const set_t::value_type p = std::make_pair(t0.type,t1.type); @@ -3850,12 +4024,12 @@ namespace exprtk private: - void add_invalid(lexer::token::token_type base, lexer::token::token_type t) + void add_invalid(const lexer::token::token_type base, const lexer::token::token_type t) { invalid_comb_.insert(std::make_pair(base,t)); } - void add_invalid_set1(lexer::token::token_type t) + void add_invalid_set1(const lexer::token::token_type t) { add_invalid(t, lexer::token::e_assign); add_invalid(t, lexer::token::e_shr ); @@ -3874,9 +4048,9 @@ namespace exprtk add_invalid(t, lexer::token::e_colon ); } - bool invalid_bracket_check(lexer::token::token_type base, lexer::token::token_type t) + bool invalid_bracket_check(const lexer::token::token_type base, const lexer::token::token_type t) { - if (details::is_right_bracket(static_cast<char>(base))) + if (details::is_right_bracket(static_cast<details::char_t>(base))) { switch (t) { @@ -3885,11 +4059,11 @@ namespace exprtk default : return false; } } - else if (details::is_left_bracket(static_cast<char>(base))) + else if (details::is_left_bracket(static_cast<details::char_t>(base))) { - if (details::is_right_bracket(static_cast<char>(t))) + if (details::is_right_bracket(static_cast<details::char_t>(t))) return false; - else if (details::is_left_bracket(static_cast<char>(t))) + else if (details::is_left_bracket(static_cast<details::char_t>(t))) return false; else { @@ -3906,7 +4080,7 @@ namespace exprtk } } } - else if (details::is_right_bracket(static_cast<char>(t))) + else if (details::is_right_bracket(static_cast<details::char_t>(t))) { switch (base) { @@ -3919,7 +4093,7 @@ namespace exprtk default : return true ; } } - else if (details::is_left_bracket(static_cast<char>(t))) + else if (details::is_left_bracket(static_cast<details::char_t>(t))) { switch (base) { @@ -3937,7 +4111,7 @@ namespace exprtk std::vector<std::pair<lexer::token,lexer::token> > error_list_; }; - class sequence_validator_3tokens : public lexer::token_scanner + class sequence_validator_3tokens exprtk_final : public lexer::token_scanner { private: @@ -3952,31 +4126,31 @@ namespace exprtk sequence_validator_3tokens() : lexer::token_scanner(3) { - add_invalid(lexer::token::e_number, lexer::token::e_number, lexer::token::e_number); - add_invalid(lexer::token::e_string, lexer::token::e_string, lexer::token::e_string); - add_invalid(lexer::token::e_comma , lexer::token::e_comma , lexer::token::e_comma ); + add_invalid(lexer::token::e_number , lexer::token::e_number , lexer::token::e_number); + add_invalid(lexer::token::e_string , lexer::token::e_string , lexer::token::e_string); + add_invalid(lexer::token::e_comma , lexer::token::e_comma , lexer::token::e_comma ); - add_invalid(lexer::token::e_add , lexer::token::e_add , lexer::token::e_add ); - add_invalid(lexer::token::e_sub , lexer::token::e_sub , lexer::token::e_sub ); - add_invalid(lexer::token::e_div , lexer::token::e_div , lexer::token::e_div ); - add_invalid(lexer::token::e_mul , lexer::token::e_mul , lexer::token::e_mul ); - add_invalid(lexer::token::e_mod , lexer::token::e_mod , lexer::token::e_mod ); - add_invalid(lexer::token::e_pow , lexer::token::e_pow , lexer::token::e_pow ); + add_invalid(lexer::token::e_add , lexer::token::e_add , lexer::token::e_add ); + add_invalid(lexer::token::e_sub , lexer::token::e_sub , lexer::token::e_sub ); + add_invalid(lexer::token::e_div , lexer::token::e_div , lexer::token::e_div ); + add_invalid(lexer::token::e_mul , lexer::token::e_mul , lexer::token::e_mul ); + add_invalid(lexer::token::e_mod , lexer::token::e_mod , lexer::token::e_mod ); + add_invalid(lexer::token::e_pow , lexer::token::e_pow , lexer::token::e_pow ); - add_invalid(lexer::token::e_add , lexer::token::e_sub , lexer::token::e_add ); - add_invalid(lexer::token::e_sub , lexer::token::e_add , lexer::token::e_sub ); - add_invalid(lexer::token::e_div , lexer::token::e_mul , lexer::token::e_div ); - add_invalid(lexer::token::e_mul , lexer::token::e_div , lexer::token::e_mul ); - add_invalid(lexer::token::e_mod , lexer::token::e_pow , lexer::token::e_mod ); - add_invalid(lexer::token::e_pow , lexer::token::e_mod , lexer::token::e_pow ); + add_invalid(lexer::token::e_add , lexer::token::e_sub , lexer::token::e_add ); + add_invalid(lexer::token::e_sub , lexer::token::e_add , lexer::token::e_sub ); + add_invalid(lexer::token::e_div , lexer::token::e_mul , lexer::token::e_div ); + add_invalid(lexer::token::e_mul , lexer::token::e_div , lexer::token::e_mul ); + add_invalid(lexer::token::e_mod , lexer::token::e_pow , lexer::token::e_mod ); + add_invalid(lexer::token::e_pow , lexer::token::e_mod , lexer::token::e_pow ); } - bool result() override + bool result() exprtk_override { return error_list_.empty(); } - bool operator() (const lexer::token& t0, const lexer::token& t1, const lexer::token& t2) override + bool operator() (const lexer::token& t0, const lexer::token& t1, const lexer::token& t2) exprtk_override { const set_t::value_type p = std::make_pair(t0.type,std::make_pair(t1.type,t2.type)); @@ -4013,7 +4187,7 @@ namespace exprtk private: - void add_invalid(token_t t0, token_t t1, token_t t2) + void add_invalid(const token_t t0, const token_t t1, const token_t t2) { invalid_comb_.insert(std::make_pair(t0,std::make_pair(t1,t2))); } @@ -4184,7 +4358,7 @@ namespace exprtk { public: - typedef token token_t; + typedef token token_t; typedef generator generator_t; inline bool init(const std::string& str) @@ -4233,6 +4407,11 @@ namespace exprtk return current_token_; } + inline const token_t& peek_next_token() + { + return lexer_.peek_next_token(); + } + enum token_advance_mode { e_hold = 0, @@ -4276,6 +4455,110 @@ namespace exprtk return true; } + inline bool token_is(const std::string& value, + const token_advance_mode mode = e_advance) + { + if (!exprtk::details::imatch(value,current_token().value)) + { + return false; + } + + advance_token(mode); + + return true; + } + + inline bool token_is_arithmetic_opr(const token_advance_mode mode = e_advance) + { + switch (current_token().type) + { + case token_t::e_add : + case token_t::e_sub : + case token_t::e_div : + case token_t::e_mul : + case token_t::e_mod : + case token_t::e_pow : break; + default : return false; + } + + advance_token(mode); + + return true; + } + + inline bool token_is_ineq_opr(const token_advance_mode mode = e_advance) + { + switch (current_token().type) + { + case token_t::e_eq : + case token_t::e_lte : + case token_t::e_ne : + case token_t::e_gte : + case token_t::e_lt : + case token_t::e_gt : break; + default : return false; + } + + advance_token(mode); + + return true; + } + + inline bool token_is_left_bracket(const token_advance_mode mode = e_advance) + { + switch (current_token().type) + { + case token_t::e_lbracket : + case token_t::e_lcrlbracket : + case token_t::e_lsqrbracket : break; + default : return false; + } + + advance_token(mode); + + return true; + } + + inline bool token_is_right_bracket(const token_advance_mode mode = e_advance) + { + switch (current_token().type) + { + case token_t::e_rbracket : + case token_t::e_rcrlbracket : + case token_t::e_rsqrbracket : break; + default : return false; + } + + advance_token(mode); + + return true; + } + + inline bool token_is_bracket(const token_advance_mode mode = e_advance) + { + switch (current_token().type) + { + case token_t::e_rbracket : + case token_t::e_rcrlbracket : + case token_t::e_rsqrbracket : + case token_t::e_lbracket : + case token_t::e_lcrlbracket : + case token_t::e_lsqrbracket : break; + default : return false; + } + + advance_token(mode); + + return true; + } + + inline bool token_is_loop(const token_advance_mode mode = e_advance) + { + return token_is("for" , mode) || + token_is("while" , mode) || + token_is("repeat", mode) ; + } + inline bool peek_token_is(const token_t::token_type& ttype) { return (lexer_.peek_next_token().type == ttype); @@ -4302,16 +4585,22 @@ namespace exprtk typedef T* data_ptr_t; vector_view(data_ptr_t data, const std::size_t& size) - : size_(size), - data_(data), - data_ref_(0) - {} + : base_size_(size) + , size_(size) + , data_(data) + , data_ref_(0) + { + assert(size_ > 0); + } vector_view(const vector_view<T>& vv) - : size_(vv.size_), - data_(vv.data_), - data_ref_(0) - {} + : base_size_(vv.base_size_) + , size_(vv.size_) + , data_(vv.data_) + , data_ref_(0) + { + assert(size_ > 0); + } inline void rebase(data_ptr_t data) { @@ -4331,6 +4620,11 @@ namespace exprtk return data_; } + inline std::size_t base_size() const + { + return base_size_; + } + inline std::size_t size() const { return size_; @@ -4338,22 +4632,55 @@ namespace exprtk inline const T& operator[](const std::size_t index) const { + assert(index < size_); return data_[index]; } inline T& operator[](const std::size_t index) { + assert(index < size_); return data_[index]; } void set_ref(data_ptr_t* data_ref) { data_ref_.push_back(data_ref); + exprtk_debug(("vector_view::set_ref() - data_ref: %p data_ref_.size(): %d\n", + reinterpret_cast<void*>(data_ref), + static_cast<int>(data_ref_.size()))); + } + + void remove_ref(data_ptr_t* data_ref) + { + data_ref_.erase( + std::remove(data_ref_.begin(), data_ref_.end(), data_ref), + data_ref_.end()); + exprtk_debug(("vector_view::remove_ref() - data_ref: %p data_ref_.size(): %d\n", + reinterpret_cast<void*>(data_ref), + static_cast<int>(data_ref_.size()))); + } + + bool set_size(const std::size_t new_size) + { + if ((new_size > 0) && (new_size <= base_size_)) + { + size_ = new_size; + exprtk_debug(("vector_view::set_size() - data_: %p size: %lu\n", + reinterpret_cast<void*>(data_), + size_)); + return true; + } + + exprtk_debug(("vector_view::set_size() - error invalid new_size: %lu base_size: %lu\n", + new_size, + base_size_)); + return false; } private: - const std::size_t size_; + const std::size_t base_size_; + std::size_t size_; data_ptr_t data_; std::vector<data_ptr_t*> data_ref_; }; @@ -4386,15 +4713,15 @@ namespace exprtk }; type_store() - : data(0), - size(0), - type(e_unknown) + : data(0) + , size(0) + , type(e_unknown) {} union { - void* data; - T* vec_data; + void* data; + T* vec_data; }; std::size_t size; @@ -4462,13 +4789,13 @@ namespace exprtk typedef ViewType value_t; explicit type_view(type_store_t& ts) - : ts_(ts), - data_(reinterpret_cast<value_t*>(ts_.data)) + : ts_(ts) + , data_(reinterpret_cast<value_t*>(ts_.data)) {} explicit type_view(const type_store_t& ts) - : ts_(const_cast<type_store_t&>(ts)), - data_(reinterpret_cast<value_t*>(ts_.data)) + : ts_(const_cast<type_store_t&>(ts)) + , data_(reinterpret_cast<value_t*>(ts_.data)) {} inline std::size_t size() const @@ -4529,6 +4856,16 @@ namespace exprtk return v_; } + inline operator value_t() const + { + return v_; + } + + inline operator value_t() + { + return v_; + } + template <typename IntType> inline bool to_int(IntType& i) const { @@ -4577,6 +4914,9 @@ namespace exprtk public: typedef type_store<T> type_store_t; + typedef typename type_store_t::scalar_view scalar_t; + typedef typename type_store_t::vector_view vector_t; + typedef typename type_store_t::string_view string_t; results_context() : results_available_(false) @@ -4600,6 +4940,61 @@ namespace exprtk return parameter_list_[index]; } + inline bool get_scalar(const std::size_t& index, T& out) const + { + if ( + (index < parameter_list_.size()) && + (parameter_list_[index].type == type_store_t::e_scalar) + ) + { + const scalar_t scalar(parameter_list_[index]); + out = scalar(); + return true; + } + + return false; + } + + template <typename OutputIterator> + inline bool get_vector(const std::size_t& index, OutputIterator out_itr) const + { + if ( + (index < parameter_list_.size()) && + (parameter_list_[index].type == type_store_t::e_vector) + ) + { + const vector_t vector(parameter_list_[index]); + for (std::size_t i = 0; i < vector.size(); ++i) + { + *(out_itr++) = vector[i]; + } + + return true; + } + + return false; + } + + inline bool get_vector(const std::size_t& index, std::vector<T>& out) const + { + return get_vector(index,std::back_inserter(out)); + } + + inline bool get_string(const std::size_t& index, std::string& out) const + { + if ( + (index < parameter_list_.size()) && + (parameter_list_[index].type == type_store_t::e_string) + ) + { + const string_t str(parameter_list_[index]); + out.assign(str.begin(),str.size()); + return true; + } + + return false; + } + private: inline void clear() @@ -4736,8 +5131,8 @@ namespace exprtk struct base_operation_t { base_operation_t(const operator_type t, const unsigned int& np) - : type(t), - num_params(np) + : type(t) + , num_params(np) {} operator_type type; @@ -4746,23 +5141,24 @@ namespace exprtk namespace loop_unroll { + const unsigned int global_loop_batch_size = #ifndef exprtk_disable_superscalar_unroll - const unsigned int global_loop_batch_size = 16; + 16; #else - const unsigned int global_loop_batch_size = 4; + 4; #endif struct details { explicit details(const std::size_t& vsize, const unsigned int loop_batch_size = global_loop_batch_size) - : batch_size(loop_batch_size ), - remainder (vsize % batch_size), - upper_bound(static_cast<int>(vsize - (remainder ? loop_batch_size : 0))) + : batch_size(loop_batch_size ) + , remainder (vsize % batch_size) + , upper_bound(static_cast<int>(vsize - (remainder ? loop_batch_size : 0))) {} unsigned int batch_size; - int remainder; + int remainder; int upper_bound; }; } @@ -4771,16 +5167,33 @@ namespace exprtk inline void dump_ptr(const std::string& s, const void* ptr, const std::size_t size = 0) { if (size) - exprtk_debug(("%s - addr: %p\n",s.c_str(),ptr)); - else exprtk_debug(("%s - addr: %p size: %d\n", s.c_str(), ptr, static_cast<unsigned int>(size))); + else + exprtk_debug(("%s - addr: %p\n", s.c_str(), ptr)); + } + + template <typename T> + inline void dump_vector(const std::string& vec_name, const T* data, const std::size_t size) + { + printf("----- %s (%p) -----\n", + vec_name.c_str(), + static_cast<const void*>(data)); + printf("[ "); + for (std::size_t i = 0; i < size; ++i) + { + printf("%8.3f\t", data[i]); + } + printf(" ]\n"); + printf("---------------------\n"); } #else inline void dump_ptr(const std::string&, const void*) {} inline void dump_ptr(const std::string&, const void*, const std::size_t) {} + template <typename T> + inline void dump_vector(const std::string&, const T*, const std::size_t) {} #endif template <typename T> @@ -4796,31 +5209,31 @@ namespace exprtk struct control_block { control_block() - : ref_count(1), - size (0), - data (0), - destruct (true) + : ref_count(1) + , size (0) + , data (0) + , destruct (true) {} explicit control_block(const std::size_t& dsize) - : ref_count(1 ), - size (dsize), - data (0 ), - destruct (true ) + : ref_count(1 ) + , size (dsize) + , data (0 ) + , destruct (true ) { create_data(); } control_block(const std::size_t& dsize, data_t dptr, bool dstrct = false) - : ref_count(1 ), - size (dsize ), - data (dptr ), - destruct (dstrct) + : ref_count(1 ) + , size (dsize ) + , data (dptr ) + , destruct (dstrct) {} ~control_block() { if (data && destruct && (0 == ref_count)) { - dump_ptr("~control_block() data",data); + dump_ptr("~vec_data_store::control_block() data",data); delete[] data; data = reinterpret_cast<data_t>(0); } @@ -4862,15 +5275,15 @@ namespace exprtk private: - control_block(const control_block&); - control_block& operator=(const control_block&); + control_block(const control_block&) exprtk_delete; + control_block& operator=(const control_block&) exprtk_delete; inline void create_data() { destruct = true; data = new T[size]; std::fill_n(data, size, T(0)); - dump_ptr("control_block::create_data() - data",data,size); + dump_ptr("control_block::create_data() - data", data, size); } }; @@ -4903,7 +5316,7 @@ namespace exprtk { if (this != &vds) { - std::size_t final_size = min_size(control_block_, vds.control_block_); + const std::size_t final_size = min_size(control_block_, vds.control_block_); vds.control_block_->size = final_size; control_block_->size = final_size; @@ -4930,11 +5343,6 @@ namespace exprtk return control_block_->data; } - inline std::size_t size() - { - return control_block_->size; - } - inline std::size_t size() const { return control_block_->size; @@ -4958,7 +5366,7 @@ namespace exprtk if (5 == i) exprtk_debug(("\n")); - exprtk_debug(("%15.10f ",data()[i])); + exprtk_debug(("%15.10f ", data()[i])); } exprtk_debug(("\n")); #endif @@ -4973,7 +5381,7 @@ namespace exprtk private: - static inline std::size_t min_size(control_block* cb0, control_block* cb1) + static inline std::size_t min_size(const control_block* cb0, const control_block* cb1) { const std::size_t size0 = cb0->size; const std::size_t size1 = cb1->size; @@ -5071,8 +5479,8 @@ namespace exprtk case e_xnor : return xnor_opr<T>(arg0,arg1); case e_root : return root <T>(arg0,arg1); case e_roundn : return roundn <T>(arg0,arg1); - case e_equal : return equal (arg0,arg1); - case e_nequal : return nequal (arg0,arg1); + case e_equal : return equal <T>(arg0,arg1); + case e_nequal : return nequal <T>(arg0,arg1); case e_hypot : return hypot <T>(arg0,arg1); case e_shr : return shr <T>(arg0,arg1); case e_shl : return shl <T>(arg0,arg1); @@ -5141,17 +5549,18 @@ namespace exprtk typedef Node** node_pp_t; typedef std::vector<node_pp_t> noderef_list_t; - virtual ~node_collector_interface() = default; + virtual ~node_collector_interface() exprtk_default; - virtual void collect_nodes(noderef_list_t&) {} + virtual void collect_nodes(noderef_list_t&) + {} }; template <typename Node> struct node_depth_base; template <typename T> - class expression_node : public node_collector_interface<expression_node<T> >, - public node_depth_base<expression_node<T> > + class expression_node : public node_collector_interface<expression_node<T> > + , public node_depth_base<expression_node<T> > { public: @@ -5188,12 +5597,14 @@ namespace exprtk e_vovovoc , e_vovocov , e_vocovov , e_covovov , e_covocov , e_vocovoc , e_covovoc , e_vococov , e_sf3ext , e_sf4ext , e_nulleq , e_strass , - e_vector , e_vecelem , e_rbvecelem , e_rbveccelem , - e_vecdefass , e_vecvalass , e_vecvecass , e_vecopvalass , - e_vecopvecass , e_vecfunc , e_vecvecswap , e_vecvecineq , - e_vecvalineq , e_valvecineq , e_vecvecarith , e_vecvalarith , - e_valvecarith , e_vecunaryop , e_break , e_continue , - e_swap + e_vector , e_vecsize , e_vecelem , e_veccelem , + e_vecelemrtc , e_veccelemrtc , e_rbvecelem , e_rbvecelemrtc , + e_rbveccelem , e_rbveccelemrtc , e_vecinit , e_vecvalass , + e_vecvecass , e_vecopvalass , e_vecopvecass , e_vecfunc , + e_vecvecswap , e_vecvecineq , e_vecvalineq , e_valvecineq , + e_vecvecarith , e_vecvalarith , e_valvecarith , e_vecunaryop , + e_vecondition , e_break , e_continue , e_swap , + e_assert }; typedef T value_type; @@ -5202,7 +5613,7 @@ namespace exprtk typedef typename nci_t::noderef_list_t noderef_list_t; typedef node_depth_base<expression_node<T> > ndb_t; - ~expression_node() override = default; + ~expression_node() exprtk_override exprtk_default; inline virtual T value() const { @@ -5218,7 +5629,12 @@ namespace exprtk { return e_none; } - }; + + inline virtual bool valid() const + { + return true; + } + }; // class expression_node template <typename T> inline bool is_generally_string_node(const expression_node<T>* node); @@ -5238,12 +5654,6 @@ namespace exprtk return std::not_equal_to<float>()(0.0f,v); } - template <typename T> - inline bool is_true(const std::complex<T>& v) - { - return std::not_equal_to<std::complex<T> >()(std::complex<T>(0),v); - } - template <typename T> inline bool is_true(const expression_node<T>* node) { @@ -5268,6 +5678,12 @@ namespace exprtk return std::equal_to<T>()(T(0),node.first->value()); } + template <typename T> + inline bool is_literal_node(const expression_node<T>* node) + { + return node && (details::expression_node<T>::e_constant == node->type()); + } + template <typename T> inline bool is_unary_node(const expression_node<T>* node) { @@ -5297,10 +5713,15 @@ namespace exprtk { return node && ( - details::expression_node<T>::e_variable == node->type() || - details::expression_node<T>::e_vecelem == node->type() || - details::expression_node<T>::e_rbvecelem == node->type() || - details::expression_node<T>::e_rbveccelem == node->type() + details::expression_node<T>::e_variable == node->type() || + details::expression_node<T>::e_vecelem == node->type() || + details::expression_node<T>::e_veccelem == node->type() || + details::expression_node<T>::e_vecelemrtc == node->type() || + details::expression_node<T>::e_veccelemrtc == node->type() || + details::expression_node<T>::e_rbvecelem == node->type() || + details::expression_node<T>::e_rbveccelem == node->type() || + details::expression_node<T>::e_rbvecelemrtc == node->type() || + details::expression_node<T>::e_rbveccelemrtc == node->type() ); } @@ -5310,12 +5731,42 @@ namespace exprtk return node && (details::expression_node<T>::e_vecelem == node->type()); } + template <typename T> + inline bool is_vector_celem_node(const expression_node<T>* node) + { + return node && (details::expression_node<T>::e_veccelem == node->type()); + } + + template <typename T> + inline bool is_vector_elem_rtc_node(const expression_node<T>* node) + { + return node && (details::expression_node<T>::e_vecelemrtc == node->type()); + } + + template <typename T> + inline bool is_vector_celem_rtc_node(const expression_node<T>* node) + { + return node && (details::expression_node<T>::e_veccelemrtc == node->type()); + } + template <typename T> inline bool is_rebasevector_elem_node(const expression_node<T>* node) { return node && (details::expression_node<T>::e_rbvecelem == node->type()); } + template <typename T> + inline bool is_rebasevector_elem_rtc_node(const expression_node<T>* node) + { + return node && (details::expression_node<T>::e_rbvecelemrtc == node->type()); + } + + template <typename T> + inline bool is_rebasevector_celem_rtc_node(const expression_node<T>* node) + { + return node && (details::expression_node<T>::e_rbveccelemrtc == node->type()); + } + template <typename T> inline bool is_rebasevector_celem_node(const expression_node<T>* node) { @@ -5344,7 +5795,8 @@ namespace exprtk case details::expression_node<T>::e_vecvecarith : case details::expression_node<T>::e_vecvalarith : case details::expression_node<T>::e_valvecarith : - case details::expression_node<T>::e_vecunaryop : return true; + case details::expression_node<T>::e_vecunaryop : + case details::expression_node<T>::e_vecondition : return true; default : return false; } } @@ -5355,7 +5807,11 @@ namespace exprtk template <typename T> inline bool is_constant_node(const expression_node<T>* node) { - return node && (details::expression_node<T>::e_constant == node->type()); + return node && + ( + details::expression_node<T>::e_constant == node->type() || + details::expression_node<T>::e_stringconst == node->type() + ); } template <typename T> @@ -5388,6 +5844,12 @@ namespace exprtk return node && (details::expression_node<T>::e_function == node->type()); } + template <typename T> + inline bool is_vararg_node(const expression_node<T>* node) + { + return node && (details::expression_node<T>::e_vararg == node->type()); + } + template <typename T> inline bool is_return_node(const expression_node<T>* node) { @@ -5408,7 +5870,13 @@ namespace exprtk } template <typename T> - inline bool branch_deletable(expression_node<T>* node) + inline bool is_assert_node(const expression_node<T>* node) + { + return node && (details::expression_node<T>::e_assert == node->type()); + } + + template <typename T> + inline bool branch_deletable(const expression_node<T>* node) { return (0 != node) && !is_variable_node(node) && @@ -5416,7 +5884,7 @@ namespace exprtk } template <std::size_t N, typename T> - inline bool all_nodes_valid(expression_node<T>* (&b)[N]) + inline bool all_nodes_valid(expression_node<T>* const (&b)[N]) { for (std::size_t i = 0; i < N; ++i) { @@ -5440,7 +5908,7 @@ namespace exprtk } template <std::size_t N, typename T> - inline bool all_nodes_variables(expression_node<T>* (&b)[N]) + inline bool all_nodes_variables(expression_node<T>* const (&b)[N]) { for (std::size_t i = 0; i < N; ++i) { @@ -5456,7 +5924,7 @@ namespace exprtk template <typename T, typename Allocator, template <typename, typename> class Sequence> - inline bool all_nodes_variables(Sequence<expression_node<T>*,Allocator>& b) + inline bool all_nodes_variables(const Sequence<expression_node<T>*,Allocator>& b) { for (std::size_t i = 0; i < b.size(); ++i) { @@ -5490,7 +5958,7 @@ namespace exprtk for (std::size_t i = 0; i < node_delete_list.size(); ++i) { node_ptr_t& node = *node_delete_list[i]; - exprtk_debug(("ncd::delete_nodes() - deleting: %p\n", static_cast<void*>(node))); + exprtk_debug(("ncd::delete_nodes() - deleting: %p\n", reinterpret_cast<void*>(node))); delete node; node = reinterpret_cast<node_ptr_t>(0); } @@ -5587,12 +6055,15 @@ namespace exprtk template <typename Node> struct node_depth_base { + typedef Node* node_ptr_t; + typedef std::pair<node_ptr_t,bool> nb_pair_t; + node_depth_base() - : depth_set(false), - depth(0) + : depth_set(false) + , depth(0) {} - virtual ~node_depth_base() = default; + virtual ~node_depth_base() exprtk_default; virtual std::size_t node_depth() const { return 1; } @@ -5607,7 +6078,7 @@ namespace exprtk return depth; } - std::size_t compute_node_depth(const std::pair<Node*,bool>& branch) const + std::size_t compute_node_depth(const nb_pair_t& branch) const { if (!depth_set) { @@ -5619,11 +6090,12 @@ namespace exprtk } template <std::size_t N> - std::size_t compute_node_depth(const std::pair<Node*,bool> (&branch)[N]) const + std::size_t compute_node_depth(const nb_pair_t (&branch)[N]) const { if (!depth_set) { depth = 0; + for (std::size_t i = 0; i < N; ++i) { if (branch[i].first) @@ -5631,6 +6103,7 @@ namespace exprtk depth = std::max(depth,branch[i].first->node_depth()); } } + depth += 1; depth_set = true; } @@ -5638,12 +6111,34 @@ namespace exprtk return depth; } + template <typename BranchType> + std::size_t max_node_depth(const BranchType& n0, const BranchType& n1) const + { + return std::max(compute_node_depth(n0), compute_node_depth(n1)); + } + + template <typename BranchType> + std::size_t max_node_depth(const BranchType& n0, const BranchType& n1, const BranchType& n2) const + { + return std::max(compute_node_depth(n0), + std::max(compute_node_depth(n1), compute_node_depth(n2))); + } + + template <typename BranchType> + std::size_t max_node_depth(const BranchType& n0, const BranchType& n1, + const BranchType& n2, const BranchType& n3) const + { + return std::max( + std::max(compute_node_depth(n0), compute_node_depth(n1)), + std::max(compute_node_depth(n2), compute_node_depth(n3))); + } + template <typename BranchType> std::size_t compute_node_depth(const BranchType& n0, const BranchType& n1) const { if (!depth_set) { - depth = 1 + std::max(compute_node_depth(n0), compute_node_depth(n1)); + depth = 1 + max_node_depth(n0, n1); depth_set = true; } @@ -5656,9 +6151,7 @@ namespace exprtk { if (!depth_set) { - depth = 1 + std::max( - std::max(compute_node_depth(n0), compute_node_depth(n1)), - compute_node_depth(n2)); + depth = 1 + max_node_depth(n0, n1, n2); depth_set = true; } @@ -5671,9 +6164,7 @@ namespace exprtk { if (!depth_set) { - depth = 1 + std::max( - std::max(compute_node_depth(n0), compute_node_depth(n1)), - std::max(compute_node_depth(n2), compute_node_depth(n3))); + depth = 1 + max_node_depth(n0, n1, n2, n3); depth_set = true; } @@ -5682,7 +6173,7 @@ namespace exprtk template <typename Allocator, template <typename, typename> class Sequence> - std::size_t compute_node_depth(const Sequence<Node*, Allocator>& branch_list) const + std::size_t compute_node_depth(const Sequence<node_ptr_t, Allocator>& branch_list) const { if (!depth_set) { @@ -5693,6 +6184,7 @@ namespace exprtk depth = std::max(depth, compute_node_depth(branch_list[i])); } } + depth_set = true; } @@ -5701,7 +6193,7 @@ namespace exprtk template <typename Allocator, template <typename, typename> class Sequence> - std::size_t compute_node_depth(const Sequence<std::pair<Node*,bool>,Allocator>& branch_list) const + std::size_t compute_node_depth(const Sequence<nb_pair_t,Allocator>& branch_list) const { if (!depth_set) { @@ -5712,6 +6204,7 @@ namespace exprtk depth = std::max(depth, compute_node_depth(branch_list[i].first)); } } + depth_set = true; } @@ -5722,18 +6215,18 @@ namespace exprtk mutable std::size_t depth; template <typename NodeSequence> - void collect(Node*const& node, + void collect(node_ptr_t const& node, const bool deletable, NodeSequence& delete_node_list) const { if ((0 != node) && deletable) { - delete_node_list.push_back(const_cast<Node**>(&node)); + delete_node_list.push_back(const_cast<node_ptr_t*>(&node)); } } template <typename NodeSequence> - void collect(const std::pair<Node*, bool>& branch, + void collect(const nb_pair_t& branch, NodeSequence& delete_node_list) const { collect(branch.first, branch.second, delete_node_list); @@ -5747,7 +6240,7 @@ namespace exprtk } template <std::size_t N, typename NodeSequence> - void collect(const std::pair<Node*, bool>(&branch)[N], + void collect(const nb_pair_t(&branch)[N], NodeSequence& delete_node_list) const { for (std::size_t i = 0; i < N; ++i) @@ -5759,7 +6252,7 @@ namespace exprtk template <typename Allocator, template <typename, typename> class Sequence, typename NodeSequence> - void collect(const Sequence<std::pair<Node*, bool>, Allocator>& branch, + void collect(const Sequence<nb_pair_t, Allocator>& branch, NodeSequence& delete_node_list) const { for (std::size_t i = 0; i < branch.size(); ++i) @@ -5771,7 +6264,7 @@ namespace exprtk template <typename Allocator, template <typename, typename> class Sequence, typename NodeSequence> - void collect(const Sequence<Node*, Allocator>& branch_list, + void collect(const Sequence<node_ptr_t, Allocator>& branch_list, NodeSequence& delete_node_list) const { for (std::size_t i = 0; i < branch_list.size(); ++i) @@ -5785,7 +6278,7 @@ namespace exprtk typename AllocatorB, template <typename, typename> class Sequence, typename NodeSequence> - void collect(const Sequence<Node*, AllocatorT>& branch_list, + void collect(const Sequence<node_ptr_t, AllocatorT>& branch_list, const Sequence<Boolean, AllocatorB>& branch_deletable_list, NodeSequence& delete_node_list) const { @@ -5804,12 +6297,13 @@ namespace exprtk typedef Type value_type; typedef value_type* value_ptr; typedef const value_ptr const_value_ptr; + typedef vector_holder<Type> vector_holder_t; class vector_holder_base { public: - virtual ~vector_holder_base() = default; + virtual ~vector_holder_base() exprtk_default; inline value_ptr operator[](const std::size_t& index) const { @@ -5821,6 +6315,11 @@ namespace exprtk return vector_size(); } + inline std::size_t base_size() const + { + return vector_base_size(); + } + inline value_ptr data() const { return value_at(0); @@ -5831,41 +6330,57 @@ namespace exprtk return false; } - virtual void set_ref(value_ptr*) {} + virtual void set_ref(value_ptr*) + {} + + virtual void remove_ref(value_ptr*) + {} + + virtual vector_view<Type>* rebaseable_instance() + { + return reinterpret_cast<vector_view<Type>*>(0); + } protected: virtual value_ptr value_at(const std::size_t&) const = 0; virtual std::size_t vector_size() const = 0; + virtual std::size_t vector_base_size() const = 0; }; - class array_vector_impl : public vector_holder_base + class array_vector_impl exprtk_final : public vector_holder_base { public: array_vector_impl(const Type* vec, const std::size_t& vec_size) - : vec_(vec), - size_(vec_size) + : vec_(vec) + , size_(vec_size) {} + ~array_vector_impl() exprtk_override exprtk_default; + protected: - value_ptr value_at(const std::size_t& index) const override + value_ptr value_at(const std::size_t& index) const exprtk_override { - if (index < size_) - return const_cast<const_value_ptr>(vec_ + index); - else - return const_value_ptr(0); + assert(index < size_); + return const_cast<const_value_ptr>(vec_ + index); } - std::size_t vector_size() const override + std::size_t vector_size() const exprtk_override { return size_; } + std::size_t vector_base_size() const exprtk_override + { + return vector_size(); + } + private: - array_vector_impl operator=(const array_vector_impl&); + array_vector_impl(const array_vector_impl&) exprtk_delete; + array_vector_impl& operator=(const array_vector_impl&) exprtk_delete; const Type* vec_; const std::size_t size_; @@ -5873,36 +6388,45 @@ namespace exprtk template <typename Allocator, template <typename, typename> class Sequence> - class sequence_vector_impl : public vector_holder_base + class sequence_vector_impl exprtk_final : public vector_holder_base { public: typedef Sequence<Type,Allocator> sequence_t; - sequence_vector_impl(sequence_t& seq) + explicit sequence_vector_impl(sequence_t& seq) : sequence_(seq) {} + ~sequence_vector_impl() exprtk_override exprtk_default; + protected: - value_ptr value_at(const std::size_t& index) const override + value_ptr value_at(const std::size_t& index) const exprtk_override { - return (index < sequence_.size()) ? (&sequence_[index]) : const_value_ptr(0); + assert(index < sequence_.size()); + return (&sequence_[index]); } - std::size_t vector_size() const override + std::size_t vector_size() const exprtk_override { return sequence_.size(); } + std::size_t vector_base_size() const exprtk_override + { + return vector_size(); + } + private: - sequence_vector_impl operator=(const sequence_vector_impl&); + sequence_vector_impl(const sequence_vector_impl&) exprtk_delete; + sequence_vector_impl& operator=(const sequence_vector_impl&) exprtk_delete; sequence_t& sequence_; }; - class vector_view_impl : public vector_holder_base + class vector_view_impl exprtk_final : public vector_holder_base { public: @@ -5910,37 +6434,113 @@ namespace exprtk vector_view_impl(vector_view_t& vec_view) : vec_view_(vec_view) - {} + { + assert(vec_view_.size() > 0); + } - void set_ref(value_ptr* ref) override + void set_ref(value_ptr* ref) exprtk_override { vec_view_.set_ref(ref); } - inline bool rebaseable() const override + void remove_ref(value_ptr* ref) exprtk_override + { + vec_view_.remove_ref(ref); + } + + bool rebaseable() const exprtk_override { return true; } + vector_view<Type>* rebaseable_instance() exprtk_override + { + return &vec_view_; + } + protected: - value_ptr value_at(const std::size_t& index) const override + value_ptr value_at(const std::size_t& index) const exprtk_override { - return (index < vec_view_.size()) ? (&vec_view_[index]) : const_value_ptr(0); + assert(index < vec_view_.size()); + return (&vec_view_[index]); } - std::size_t vector_size() const override + std::size_t vector_size() const exprtk_override { return vec_view_.size(); } + std::size_t vector_base_size() const exprtk_override + { + return vec_view_.base_size(); + } + + ~vector_view_impl() exprtk_override exprtk_default; + private: - vector_view_impl operator=(const vector_view_impl&); + vector_view_impl(const vector_view_impl&) exprtk_delete; + vector_view_impl& operator=(const vector_view_impl&) exprtk_delete; vector_view_t& vec_view_; }; + class resizable_vector_impl exprtk_final : public vector_holder_base + { + public: + + resizable_vector_impl(vector_holder& vec_view_holder, + const Type* vec, + const std::size_t& vec_size) + : vec_(vec) + , size_(vec_size) + , vec_view_holder_(*vec_view_holder.rebaseable_instance()) + { + assert(vec_view_holder.rebaseable_instance()); + assert(size_ <= vector_base_size()); + } + + ~resizable_vector_impl() exprtk_override exprtk_default; + + protected: + + value_ptr value_at(const std::size_t& index) const exprtk_override + { + assert(index < vector_size()); + return const_cast<const_value_ptr>(vec_ + index); + } + + std::size_t vector_size() const exprtk_override + { + return vec_view_holder_.size(); + } + + std::size_t vector_base_size() const exprtk_override + { + return vec_view_holder_.base_size(); + } + + bool rebaseable() const exprtk_override + { + return true; + } + + vector_view<Type>* rebaseable_instance() exprtk_override + { + return &vec_view_holder_; + } + + private: + + resizable_vector_impl(const resizable_vector_impl&) exprtk_delete; + resizable_vector_impl& operator=(const resizable_vector_impl&) exprtk_delete; + + const Type* vec_; + const std::size_t size_; + vector_view<Type>& vec_view_holder_; + }; + public: typedef typename details::vec_data_store<Type> vds_t; @@ -5949,19 +6549,23 @@ namespace exprtk : vector_holder_base_(new(buffer)array_vector_impl(vec,vec_size)) {} - vector_holder(const vds_t& vds) + explicit vector_holder(const vds_t& vds) : vector_holder_base_(new(buffer)array_vector_impl(vds.data(),vds.size())) {} template <typename Allocator> - vector_holder(std::vector<Type,Allocator>& vec) + explicit vector_holder(std::vector<Type,Allocator>& vec) : vector_holder_base_(new(buffer)sequence_vector_impl<Allocator,std::vector>(vec)) {} - vector_holder(exprtk::vector_view<Type>& vec) + explicit vector_holder(exprtk::vector_view<Type>& vec) : vector_holder_base_(new(buffer)vector_view_impl(vec)) {} + explicit vector_holder(vector_holder_t& vec_holder, const vds_t& vds) + : vector_holder_base_(new(buffer)resizable_vector_impl(vec_holder, vds.data(), vds.size())) + {} + inline value_ptr operator[](const std::size_t& index) const { return (*vector_holder_base_)[index]; @@ -5972,6 +6576,11 @@ namespace exprtk return vector_holder_base_->size(); } + inline std::size_t base_size() const + { + return vector_holder_base_->base_size(); + } + inline value_ptr data() const { return vector_holder_base_->data(); @@ -5979,7 +6588,18 @@ namespace exprtk void set_ref(value_ptr* ref) { - vector_holder_base_->set_ref(ref); + if (rebaseable()) + { + vector_holder_base_->set_ref(ref); + } + } + + void remove_ref(value_ptr* ref) + { + if (rebaseable()) + { + vector_holder_base_->remove_ref(ref); + } } bool rebaseable() const @@ -5987,23 +6607,31 @@ namespace exprtk return vector_holder_base_->rebaseable(); } + vector_view<Type>* rebaseable_instance() + { + return vector_holder_base_->rebaseable_instance(); + } + private: + vector_holder(const vector_holder<Type>&) exprtk_delete; + vector_holder<Type>& operator=(const vector_holder<Type>&) exprtk_delete; + mutable vector_holder_base* vector_holder_base_; uchar_t buffer[64]; }; template <typename T> - class null_node : public expression_node<T> + class null_node exprtk_final : public expression_node<T> { public: - inline T value() const override + inline T value() const exprtk_override { return std::numeric_limits<T>::quiet_NaN(); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_null; } @@ -6055,7 +6683,7 @@ namespace exprtk } template <typename T> - class null_eq_node : public expression_node<T> + class null_eq_node exprtk_final : public expression_node<T> { public: @@ -6066,42 +6694,41 @@ namespace exprtk : equality_(equality) { construct_branch_pair(branch_, branch); + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { - assert(branch_.first); - const T v = branch_.first->value(); const bool result = details::numeric::is_nan(v); if (result) - return (equality_) ? T(1) : T(0); + return equality_ ? T(1) : T(0); else - return (equality_) ? T(0) : T(1); + return equality_ ? T(0) : T(1); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_nulleq; } - inline operator_type operation() const + inline expression_node<T>* branch(const std::size_t&) const exprtk_override { - return details::e_eq; + return branch_.first; } - inline expression_node<T>* branch(const std::size_t&) const override + inline bool valid() const exprtk_override { return branch_.first; } - void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) override + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override { - expression_node<T>::ndb_t::collect(branch_,node_delete_list); + expression_node<T>::ndb_t::collect(branch_, node_delete_list); } - std::size_t node_depth() const override + std::size_t node_depth() const exprtk_override { return expression_node<T>::ndb_t::compute_node_depth(branch_); } @@ -6113,7 +6740,7 @@ namespace exprtk }; template <typename T> - class literal_node : public expression_node<T> + class literal_node exprtk_final : public expression_node<T> { public: @@ -6121,25 +6748,25 @@ namespace exprtk : value_(v) {} - inline T value() const override + inline T value() const exprtk_override { return value_; } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_constant; } - inline expression_node<T>* branch(const std::size_t&) const override + inline expression_node<T>* branch(const std::size_t&) const exprtk_override { return reinterpret_cast<expression_node<T>*>(0); } private: - literal_node(literal_node<T>&) {} - literal_node<T>& operator=(literal_node<T>&) { return (*this); } + literal_node(const literal_node<T>&) exprtk_delete; + literal_node<T>& operator=(const literal_node<T>&) exprtk_delete; const T value_; }; @@ -6157,7 +6784,7 @@ namespace exprtk typedef range_pack<T> range_t; - virtual ~range_interface() = default; + virtual ~range_interface() exprtk_default; virtual range_t& range_ref() = 0; @@ -6172,7 +6799,7 @@ namespace exprtk typedef range_data_type<T> range_data_type_t; - virtual ~string_base_node() = default; + virtual ~string_base_node() exprtk_default; virtual std::string str () const = 0; @@ -6182,9 +6809,10 @@ namespace exprtk }; template <typename T> - class string_literal_node : public expression_node <T>, - public string_base_node<T>, - public range_interface <T> + class string_literal_node exprtk_final + : public expression_node <T> + , public string_base_node<T> + , public range_interface <T> { public: @@ -6193,56 +6821,56 @@ namespace exprtk explicit string_literal_node(const std::string& v) : value_(v) { - rp_.n0_c = std::make_pair<bool,std::size_t>(true,0); - rp_.n1_c = std::make_pair<bool,std::size_t>(true,v.size() - 1); + rp_.n0_c = std::make_pair<bool,std::size_t>(true, 0); + rp_.n1_c = std::make_pair<bool,std::size_t>(true, v.size()); rp_.cache.first = rp_.n0_c.second; rp_.cache.second = rp_.n1_c.second; } - inline T value() const override + inline T value() const exprtk_override { return std::numeric_limits<T>::quiet_NaN(); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_stringconst; } - inline expression_node<T>* branch(const std::size_t&) const override + inline expression_node<T>* branch(const std::size_t&) const exprtk_override { return reinterpret_cast<expression_node<T>*>(0); } - std::string str() const override + std::string str() const exprtk_override { return value_; } - char_cptr base() const override + char_cptr base() const exprtk_override { return value_.data(); } - std::size_t size() const override + std::size_t size() const exprtk_override { return value_.size(); } - range_t& range_ref() override + range_t& range_ref() exprtk_override { return rp_; } - const range_t& range_ref() const override + const range_t& range_ref() const exprtk_override { return rp_; } private: - string_literal_node(const string_literal_node<T>&); - string_literal_node<T>& operator=(const string_literal_node<T>&); + string_literal_node(const string_literal_node<T>&) exprtk_delete; + string_literal_node<T>& operator=(const string_literal_node<T>&) exprtk_delete; const std::string value_; range_t rp_; @@ -6261,48 +6889,51 @@ namespace exprtk : operation_(opr) { construct_branch_pair(branch_,branch); + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { - assert(branch_.first); - - const T arg = branch_.first->value(); - - return numeric::process<T>(operation_,arg); + return numeric::process<T> + (operation_,branch_.first->value()); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_unary; } - inline operator_type operation() const + inline operator_type operation() { return operation_; } - inline expression_node<T>* branch(const std::size_t&) const override + inline expression_node<T>* branch(const std::size_t&) const exprtk_override { return branch_.first; } + inline bool valid() const exprtk_override + { + return branch_.first && branch_.first->valid(); + } + inline void release() { branch_.second = false; } - void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) override + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override { expression_node<T>::ndb_t::collect(branch_, node_delete_list); } - std::size_t node_depth() const override + std::size_t node_depth() const exprtk_final { return expression_node<T>::ndb_t::compute_node_depth(branch_); } - protected: + private: operator_type operation_; branch_t branch_; @@ -6322,20 +6953,20 @@ namespace exprtk : operation_(opr) { init_branches<2>(branch_, branch0, branch1); + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { - assert(branch_[0].first); - assert(branch_[1].first); - - const T arg0 = branch_[0].first->value(); - const T arg1 = branch_[1].first->value(); - - return numeric::process<T>(operation_,arg0,arg1); + return numeric::process<T> + ( + operation_, + branch_[0].first->value(), + branch_[1].first->value() + ); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_binary; } @@ -6345,34 +6976,37 @@ namespace exprtk return operation_; } - inline expression_node<T>* branch(const std::size_t& index = 0) const override + inline expression_node<T>* branch(const std::size_t& index = 0) const exprtk_override { - if (0 == index) - return branch_[0].first; - else if (1 == index) - return branch_[1].first; - else - return reinterpret_cast<expression_ptr>(0); + assert(index < 2); + return branch_[index].first; + } + + inline bool valid() const exprtk_override + { + return + branch_[0].first && branch_[0].first->valid() && + branch_[1].first && branch_[1].first->valid() ; } - void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) override + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override { - expression_node<T>::ndb_t::template collect<>(branch_, node_delete_list); + expression_node<T>::ndb_t::collect(branch_, node_delete_list); } - std::size_t node_depth() const override + std::size_t node_depth() const exprtk_final { return expression_node<T>::ndb_t::template compute_node_depth<2>(branch_); } - protected: + private: operator_type operation_; branch_t branch_[2]; }; template <typename T, typename Operation> - class binary_ext_node : public expression_node<T> + class binary_ext_node exprtk_final : public expression_node<T> { public: @@ -6382,20 +7016,17 @@ namespace exprtk binary_ext_node(expression_ptr branch0, expression_ptr branch1) { init_branches<2>(branch_, branch0, branch1); + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { - assert(branch_[0].first); - assert(branch_[1].first); - const T arg0 = branch_[0].first->value(); const T arg1 = branch_[1].first->value(); - return Operation::process(arg0,arg1); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_binary_ext; } @@ -6405,22 +7036,25 @@ namespace exprtk return Operation::operation(); } - inline expression_node<T>* branch(const std::size_t& index = 0) const override + inline expression_node<T>* branch(const std::size_t& index = 0) const exprtk_override { - if (0 == index) - return branch_[0].first; - else if (1 == index) - return branch_[1].first; - else - return reinterpret_cast<expression_ptr>(0); + assert(index < 2); + return branch_[index].first; + } + + inline bool valid() const exprtk_override + { + return + branch_[0].first && branch_[0].first->valid() && + branch_[1].first && branch_[1].first->valid() ; } - void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) override + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override { - expression_node<T>::ndb_t::template collect<>(branch_, node_delete_list); + expression_node<T>::ndb_t::collect(branch_, node_delete_list); } - std::size_t node_depth() const override + std::size_t node_depth() const exprtk_override { return expression_node<T>::ndb_t::template compute_node_depth<2>(branch_); } @@ -6445,14 +7079,11 @@ namespace exprtk : operation_(opr) { init_branches<3>(branch_, branch0, branch1, branch2); + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { - assert(branch_[0].first); - assert(branch_[1].first); - assert(branch_[2].first); - const T arg0 = branch_[0].first->value(); const T arg1 = branch_[1].first->value(); const T arg2 = branch_[2].first->value(); @@ -6473,17 +7104,25 @@ namespace exprtk } } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_trinary; } - void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) override + inline bool valid() const exprtk_override { - expression_node<T>::ndb_t::template collect<>(branch_, node_delete_list); + return + branch_[0].first && branch_[0].first->valid() && + branch_[1].first && branch_[1].first->valid() && + branch_[2].first && branch_[2].first->valid() ; + } + + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override + { + expression_node<T>::ndb_t::collect(branch_, node_delete_list); } - std::size_t node_depth() const override + std::size_t node_depth() const exprtk_final { return expression_node<T>::ndb_t::template compute_node_depth<3>(branch_); } @@ -6512,26 +7151,35 @@ namespace exprtk init_branches<4>(branch_, branch0, branch1, branch2, branch3); } - inline T value() const override + inline T value() const exprtk_override { return std::numeric_limits<T>::quiet_NaN(); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_quaternary; } - void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) override + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override { - expression_node<T>::ndb_t::template collect<>(branch_, node_delete_list); + expression_node<T>::ndb_t::collect(branch_, node_delete_list); } - std::size_t node_depth() const override + std::size_t node_depth() const exprtk_final { return expression_node<T>::ndb_t::template compute_node_depth<4>(branch_); } + inline bool valid() const exprtk_override + { + return + branch_[0].first && branch_[0].first->valid() && + branch_[1].first && branch_[1].first->valid() && + branch_[2].first && branch_[2].first->valid() && + branch_[3].first && branch_[3].first->valid() ; + } + protected: operator_type operation_; @@ -6539,7 +7187,7 @@ namespace exprtk }; template <typename T> - class conditional_node : public expression_node<T> + class conditional_node exprtk_final : public expression_node<T> { public: @@ -6553,33 +7201,38 @@ namespace exprtk construct_branch_pair(condition_ , condition ); construct_branch_pair(consequent_ , consequent ); construct_branch_pair(alternative_, alternative); + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { - assert(condition_ .first); - assert(consequent_ .first); - assert(alternative_.first); - if (is_true(condition_)) return consequent_.first->value(); else return alternative_.first->value(); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_conditional; } - void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) override + inline bool valid() const exprtk_override { - expression_node<T>::ndb_t::collect(condition_ , node_delete_list); - expression_node<T>::ndb_t::collect(consequent_ , node_delete_list); - expression_node<T>::ndb_t::collect(alternative_, node_delete_list); + return + condition_ .first && condition_ .first->valid() && + consequent_ .first && consequent_ .first->valid() && + alternative_.first && alternative_.first->valid() ; + } + + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override + { + expression_node<T>::ndb_t::collect(condition_ , node_delete_list); + expression_node<T>::ndb_t::collect(consequent_ , node_delete_list); + expression_node<T>::ndb_t::collect(alternative_ , node_delete_list); } - std::size_t node_depth() const override + std::size_t node_depth() const exprtk_override { return expression_node<T>::ndb_t::compute_node_depth (condition_, consequent_, alternative_); @@ -6593,7 +7246,7 @@ namespace exprtk }; template <typename T> - class cons_conditional_node : public expression_node<T> + class cons_conditional_node exprtk_final : public expression_node<T> { public: @@ -6606,31 +7259,36 @@ namespace exprtk { construct_branch_pair(condition_ , condition ); construct_branch_pair(consequent_, consequent); + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { - assert(condition_ .first); - assert(consequent_.first); - if (is_true(condition_)) return consequent_.first->value(); else return std::numeric_limits<T>::quiet_NaN(); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_conditional; } - void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) override + inline bool valid() const exprtk_override { - expression_node<T>::ndb_t::collect(condition_ , node_delete_list); - expression_node<T>::ndb_t::collect(consequent_, node_delete_list); + return + condition_ .first && condition_ .first->valid() && + consequent_.first && consequent_.first->valid() ; + } + + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override + { + expression_node<T>::ndb_t::collect(condition_ , node_delete_list); + expression_node<T>::ndb_t::collect(consequent_ , node_delete_list); } - std::size_t node_depth() const override + std::size_t node_depth() const exprtk_override { return expression_node<T>::ndb_t:: compute_node_depth(condition_, consequent_); @@ -6655,41 +7313,45 @@ namespace exprtk T value; }; - class continue_exception - {}; + class continue_exception {}; template <typename T> - class break_node : public expression_node<T> + class break_node exprtk_final : public expression_node<T> { public: typedef expression_node<T>* expression_ptr; typedef std::pair<expression_ptr,bool> branch_t; - break_node(expression_ptr ret = expression_ptr(0)) + explicit break_node(expression_ptr ret = expression_ptr(0)) { construct_branch_pair(return_, ret); } - inline T value() const override + inline T value() const exprtk_override { - throw break_exception<T>(return_.first ? return_.first->value() : std::numeric_limits<T>::quiet_NaN()); - #ifndef _MSC_VER + const T result = return_.first ? + return_.first->value() : + std::numeric_limits<T>::quiet_NaN(); + + throw break_exception<T>(result); + + #if !defined(_MSC_VER) && !defined(__NVCOMPILER) return std::numeric_limits<T>::quiet_NaN(); #endif } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_break; } - void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) override + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override { expression_node<T>::ndb_t::collect(return_, node_delete_list); } - std::size_t node_depth() const override + std::size_t node_depth() const exprtk_override { return expression_node<T>::ndb_t::compute_node_depth(return_); } @@ -6700,34 +7362,36 @@ namespace exprtk }; template <typename T> - class continue_node : public expression_node<T> + class continue_node exprtk_final : public expression_node<T> { public: - inline T value() const override + inline T value() const exprtk_override { throw continue_exception(); - #ifndef _MSC_VER + #if !defined(_MSC_VER) && !defined(__NVCOMPILER) return std::numeric_limits<T>::quiet_NaN(); #endif } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_break; } }; #endif - #ifdef exprtk_enable_runtime_checks struct loop_runtime_checker { - loop_runtime_checker(loop_runtime_check_ptr loop_rt_chk = loop_runtime_check_ptr(0), + loop_runtime_checker(loop_runtime_check_ptr loop_runtime_check, loop_runtime_check::loop_types lp_typ = loop_runtime_check::e_invalid) - : iteration_count_(0), - loop_runtime_check_(loop_rt_chk), - loop_type(lp_typ) - {} + : iteration_count_(0) + , loop_runtime_check_(loop_runtime_check) + , max_loop_iterations_(loop_runtime_check_->max_loop_iterations) + , loop_type_(lp_typ) + { + assert(loop_runtime_check_); + } inline void reset(const _uint64_t initial_value = 0) const { @@ -6736,16 +7400,18 @@ namespace exprtk inline bool check() const { + assert(loop_runtime_check_); + if ( - (0 == loop_runtime_check_) || - (++iteration_count_ <= loop_runtime_check_->max_loop_iterations) + (++iteration_count_ <= max_loop_iterations_) && + loop_runtime_check_->check() ) { return true; } loop_runtime_check::violation_context ctxt; - ctxt.loop = loop_type; + ctxt.loop = loop_type_; ctxt.violation = loop_runtime_check::e_iteration_count; loop_runtime_check_->handle_runtime_violation(ctxt); @@ -6753,29 +7419,19 @@ namespace exprtk return false; } - mutable _uint64_t iteration_count_; - mutable loop_runtime_check_ptr loop_runtime_check_; - loop_runtime_check::loop_types loop_type; - }; - #else - struct loop_runtime_checker - { - loop_runtime_checker(loop_runtime_check_ptr, loop_runtime_check::loop_types) - {} - - inline void reset(const _uint64_t = 0) const - {} - - inline bool check() const + bool valid() const { - return true; + return 0 != loop_runtime_check_; } + + mutable _uint64_t iteration_count_; + mutable loop_runtime_check_ptr loop_runtime_check_; + const details::_uint64_t& max_loop_iterations_; + loop_runtime_check::loop_types loop_type_; }; - #endif template <typename T> - class while_loop_node : public expression_node<T>, - public loop_runtime_checker + class while_loop_node : public expression_node<T> { public: @@ -6783,24 +7439,18 @@ namespace exprtk typedef std::pair<expression_ptr,bool> branch_t; while_loop_node(expression_ptr condition, - expression_ptr loop_body, - loop_runtime_check_ptr loop_rt_chk = loop_runtime_check_ptr(0)) - : loop_runtime_checker(loop_rt_chk,loop_runtime_check::e_while_loop) + expression_ptr loop_body) { construct_branch_pair(condition_, condition); construct_branch_pair(loop_body_, loop_body); + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { - assert(condition_.first); - assert(loop_body_.first); - T result = T(0); - loop_runtime_checker::reset(); - - while (is_true(condition_) && loop_runtime_checker::check()) + while (is_true(condition_)) { result = loop_body_.first->value(); } @@ -6808,31 +7458,80 @@ namespace exprtk return result; } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_while; } - void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) override + inline bool valid() const exprtk_override + { + return + condition_.first && condition_.first->valid() && + loop_body_.first && loop_body_.first->valid() ; + } + + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override { - expression_node<T>::ndb_t::collect(condition_, node_delete_list); - expression_node<T>::ndb_t::collect(loop_body_, node_delete_list); + expression_node<T>::ndb_t::collect(condition_ , node_delete_list); + expression_node<T>::ndb_t::collect(loop_body_ , node_delete_list); } - std::size_t node_depth() const override + std::size_t node_depth() const exprtk_override { return expression_node<T>::ndb_t::compute_node_depth(condition_, loop_body_); } - private: + protected: branch_t condition_; branch_t loop_body_; }; template <typename T> - class repeat_until_loop_node : public expression_node<T>, - public loop_runtime_checker + class while_loop_rtc_node exprtk_final + : public while_loop_node<T> + , public loop_runtime_checker + { + public: + + typedef while_loop_node<T> parent_t; + typedef expression_node<T>* expression_ptr; + + while_loop_rtc_node(expression_ptr condition, + expression_ptr loop_body, + loop_runtime_check_ptr loop_rt_chk) + : parent_t(condition, loop_body) + , loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_while_loop) + { + assert(valid()); + } + + inline T value() const exprtk_override + { + + T result = T(0); + + loop_runtime_checker::reset(); + + while (is_true(parent_t::condition_) && loop_runtime_checker::check()) + { + result = parent_t::loop_body_.first->value(); + } + + return result; + } + + using parent_t::valid; + + bool valid() const exprtk_final + { + return parent_t::valid() && + loop_runtime_checker::valid(); + } + }; + + template <typename T> + class repeat_until_loop_node : public expression_node<T> { public: @@ -6840,57 +7539,100 @@ namespace exprtk typedef std::pair<expression_ptr,bool> branch_t; repeat_until_loop_node(expression_ptr condition, - expression_ptr loop_body, - loop_runtime_check_ptr loop_rt_chk = loop_runtime_check_ptr(0)) - : loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_repeat_until_loop) + expression_ptr loop_body) { construct_branch_pair(condition_, condition); construct_branch_pair(loop_body_, loop_body); + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { - assert(condition_.first); - assert(loop_body_.first); - T result = T(0); - loop_runtime_checker::reset(1); - do { result = loop_body_.first->value(); } - while (is_false(condition_.first) && loop_runtime_checker::check()); + while (is_false(condition_.first)); return result; } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_repeat; } - void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) override + inline bool valid() const exprtk_override { - expression_node<T>::ndb_t::collect(condition_, node_delete_list); - expression_node<T>::ndb_t::collect(loop_body_, node_delete_list); + return + condition_.first && condition_.first->valid() && + loop_body_.first && loop_body_.first->valid() ; } - std::size_t node_depth() const override + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override + { + expression_node<T>::ndb_t::collect(condition_ , node_delete_list); + expression_node<T>::ndb_t::collect(loop_body_ , node_delete_list); + } + + std::size_t node_depth() const exprtk_override { return expression_node<T>::ndb_t::compute_node_depth(condition_, loop_body_); } - private: + protected: branch_t condition_; branch_t loop_body_; }; template <typename T> - class for_loop_node : public expression_node<T>, - public loop_runtime_checker + class repeat_until_loop_rtc_node exprtk_final + : public repeat_until_loop_node<T> + , public loop_runtime_checker + { + public: + + typedef repeat_until_loop_node<T> parent_t; + typedef expression_node<T>* expression_ptr; + + repeat_until_loop_rtc_node(expression_ptr condition, + expression_ptr loop_body, + loop_runtime_check_ptr loop_rt_chk) + : parent_t(condition, loop_body) + , loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_repeat_until_loop) + { + assert(valid()); + } + + inline T value() const exprtk_override + { + T result = T(0); + + loop_runtime_checker::reset(1); + + do + { + result = parent_t::loop_body_.first->value(); + } + while (is_false(parent_t::condition_.first) && loop_runtime_checker::check()); + + return result; + } + + using parent_t::valid; + + inline bool valid() const exprtk_final + { + return parent_t::valid() && + loop_runtime_checker::valid(); + } + }; + + template <typename T> + class for_loop_node : public expression_node<T> { public: @@ -6900,31 +7642,25 @@ namespace exprtk for_loop_node(expression_ptr initialiser, expression_ptr condition, expression_ptr incrementor, - expression_ptr loop_body, - loop_runtime_check_ptr loop_rt_chk = loop_runtime_check_ptr(0)) - : loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_for_loop) + expression_ptr loop_body) { construct_branch_pair(initialiser_, initialiser); construct_branch_pair(condition_ , condition ); construct_branch_pair(incrementor_, incrementor); construct_branch_pair(loop_body_ , loop_body ); + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { - assert(condition_.first); - assert(loop_body_.first); - T result = T(0); - loop_runtime_checker::reset(); - if (initialiser_.first) initialiser_.first->value(); if (incrementor_.first) { - while (is_true(condition_) && loop_runtime_checker::check()) + while (is_true(condition_)) { result = loop_body_.first->value(); incrementor_.first->value(); @@ -6932,7 +7668,7 @@ namespace exprtk } else { - while (is_true(condition_) && loop_runtime_checker::check()) + while (is_true(condition_)) { result = loop_body_.first->value(); } @@ -6941,26 +7677,31 @@ namespace exprtk return result; } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_for; } - void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) override + inline bool valid() const exprtk_override { - expression_node<T>::ndb_t::collect(initialiser_, node_delete_list); - expression_node<T>::ndb_t::collect(condition_ , node_delete_list); - expression_node<T>::ndb_t::collect(incrementor_, node_delete_list); - expression_node<T>::ndb_t::collect(loop_body_ , node_delete_list); + return condition_.first && loop_body_.first; } - std::size_t node_depth() const override + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override + { + expression_node<T>::ndb_t::collect(initialiser_ , node_delete_list); + expression_node<T>::ndb_t::collect(condition_ , node_delete_list); + expression_node<T>::ndb_t::collect(incrementor_ , node_delete_list); + expression_node<T>::ndb_t::collect(loop_body_ , node_delete_list); + } + + std::size_t node_depth() const exprtk_override { return expression_node<T>::ndb_t::compute_node_depth (initialiser_, condition_, incrementor_, loop_body_); } - private: + protected: branch_t initialiser_; branch_t condition_ ; @@ -6968,39 +7709,89 @@ namespace exprtk branch_t loop_body_ ; }; - #ifndef exprtk_disable_break_continue template <typename T> - class while_loop_bc_node : public expression_node<T>, - public loop_runtime_checker + class for_loop_rtc_node exprtk_final + : public for_loop_node<T> + , public loop_runtime_checker { public: + typedef for_loop_node<T> parent_t; typedef expression_node<T>* expression_ptr; - typedef std::pair<expression_ptr,bool> branch_t; - while_loop_bc_node(expression_ptr condition, - expression_ptr loop_body, - loop_runtime_check_ptr loop_rt_chk = loop_runtime_check_ptr(0)) - : loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_while_loop) + for_loop_rtc_node(expression_ptr initialiser, + expression_ptr condition, + expression_ptr incrementor, + expression_ptr loop_body, + loop_runtime_check_ptr loop_rt_chk) + : parent_t(initialiser, condition, incrementor, loop_body) + , loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_for_loop) { - construct_branch_pair(condition_, condition); - construct_branch_pair(loop_body_, loop_body); + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { - assert(condition_.first); - assert(loop_body_.first); - T result = T(0); loop_runtime_checker::reset(); - while (is_true(condition_) && loop_runtime_checker::check()) + if (parent_t::initialiser_.first) + parent_t::initialiser_.first->value(); + + if (parent_t::incrementor_.first) + { + while (is_true(parent_t::condition_) && loop_runtime_checker::check()) + { + result = parent_t::loop_body_.first->value(); + parent_t::incrementor_.first->value(); + } + } + else + { + while (is_true(parent_t::condition_) && loop_runtime_checker::check()) + { + result = parent_t::loop_body_.first->value(); + } + } + + return result; + } + + using parent_t::valid; + + inline bool valid() const exprtk_final + { + return parent_t::valid() && + loop_runtime_checker::valid(); + } + }; + + #ifndef exprtk_disable_break_continue + template <typename T> + class while_loop_bc_node : public while_loop_node<T> + { + public: + + typedef while_loop_node<T> parent_t; + typedef expression_node<T>* expression_ptr; + + while_loop_bc_node(expression_ptr condition, + expression_ptr loop_body) + : parent_t(condition, loop_body) + { + assert(parent_t::valid()); + } + + inline T value() const exprtk_override + { + T result = T(0); + + while (is_true(parent_t::condition_)) { try { - result = loop_body_.first->value(); + result = parent_t::loop_body_.first->value(); } catch(const break_exception<T>& e) { @@ -7012,61 +7803,83 @@ namespace exprtk return result; } + }; - inline typename expression_node<T>::node_type type() const override - { - return expression_node<T>::e_while; - } + template <typename T> + class while_loop_bc_rtc_node exprtk_final + : public while_loop_bc_node<T> + , public loop_runtime_checker + { + public: - void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) override + typedef while_loop_bc_node<T> parent_t; + typedef expression_node<T>* expression_ptr; + + while_loop_bc_rtc_node(expression_ptr condition, + expression_ptr loop_body, + loop_runtime_check_ptr loop_rt_chk) + : parent_t(condition, loop_body) + , loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_while_loop) { - expression_node<T>::ndb_t::collect(condition_, node_delete_list); - expression_node<T>::ndb_t::collect(loop_body_, node_delete_list); + assert(valid()); } - std::size_t node_depth() const override + inline T value() const exprtk_override { - return expression_node<T>::ndb_t::compute_node_depth(condition_, loop_body_); + T result = T(0); + + loop_runtime_checker::reset(); + + while (is_true(parent_t::condition_) && loop_runtime_checker::check()) + { + try + { + result = parent_t::loop_body_.first->value(); + } + catch(const break_exception<T>& e) + { + return e.value; + } + catch(const continue_exception&) + {} + } + + return result; } - private: + using parent_t::valid; - branch_t condition_; - branch_t loop_body_; + inline bool valid() const exprtk_final + { + return parent_t::valid() && + loop_runtime_checker::valid(); + } }; template <typename T> - class repeat_until_loop_bc_node : public expression_node<T>, - public loop_runtime_checker + class repeat_until_loop_bc_node : public repeat_until_loop_node<T> { public: - typedef expression_node<T>* expression_ptr; - typedef std::pair<expression_ptr,bool> branch_t; + typedef repeat_until_loop_node<T> parent_t; + typedef expression_node<T>* expression_ptr; repeat_until_loop_bc_node(expression_ptr condition, - expression_ptr loop_body, - loop_runtime_check_ptr loop_rt_chk = loop_runtime_check_ptr(0)) - : loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_repeat_until_loop) + expression_ptr loop_body) + : parent_t(condition, loop_body) { - construct_branch_pair(condition_, condition); - construct_branch_pair(loop_body_, loop_body); + assert(parent_t::valid()); } - inline T value() const override + inline T value() const exprtk_override { - assert(condition_.first); - assert(loop_body_.first); - T result = T(0); - loop_runtime_checker::reset(); - do { try { - result = loop_body_.first->value(); + result = parent_t::loop_body_.first->value(); } catch(const break_exception<T>& e) { @@ -7075,74 +7888,95 @@ namespace exprtk catch(const continue_exception&) {} } - while (is_false(condition_.first) && loop_runtime_checker::check()); + while (is_false(parent_t::condition_.first)); return result; } + }; - inline typename expression_node<T>::node_type type() const override - { - return expression_node<T>::e_repeat; - } + template <typename T> + class repeat_until_loop_bc_rtc_node exprtk_final + : public repeat_until_loop_bc_node<T> + , public loop_runtime_checker + { + public: - void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) override + typedef repeat_until_loop_bc_node<T> parent_t; + typedef expression_node<T>* expression_ptr; + + repeat_until_loop_bc_rtc_node(expression_ptr condition, + expression_ptr loop_body, + loop_runtime_check_ptr loop_rt_chk) + : parent_t(condition, loop_body) + , loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_repeat_until_loop) { - expression_node<T>::ndb_t::collect(condition_, node_delete_list); - expression_node<T>::ndb_t::collect(loop_body_, node_delete_list); + assert(valid()); } - std::size_t node_depth() const override + inline T value() const exprtk_override { - return expression_node<T>::ndb_t::compute_node_depth(condition_, loop_body_); + T result = T(0); + + loop_runtime_checker::reset(); + + do + { + try + { + result = parent_t::loop_body_.first->value(); + } + catch(const break_exception<T>& e) + { + return e.value; + } + catch(const continue_exception&) + {} + } + while (is_false(parent_t::condition_.first) && loop_runtime_checker::check()); + + return result; } - private: + using parent_t::valid; - branch_t condition_; - branch_t loop_body_; + inline bool valid() const exprtk_final + { + return parent_t::valid() && + loop_runtime_checker::valid(); + } }; template <typename T> - class for_loop_bc_node : public expression_node<T>, - public loop_runtime_checker + class for_loop_bc_node : public for_loop_node<T> { public: + typedef for_loop_node<T> parent_t; typedef expression_node<T>* expression_ptr; - typedef std::pair<expression_ptr,bool> branch_t; for_loop_bc_node(expression_ptr initialiser, expression_ptr condition, expression_ptr incrementor, - expression_ptr loop_body, - loop_runtime_check_ptr loop_rt_chk = loop_runtime_check_ptr(0)) - : loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_for_loop) + expression_ptr loop_body) + : parent_t(initialiser, condition, incrementor, loop_body) { - construct_branch_pair(initialiser_, initialiser); - construct_branch_pair(condition_ , condition ); - construct_branch_pair(incrementor_, incrementor); - construct_branch_pair(loop_body_ , loop_body ); + assert(parent_t::valid()); } - inline T value() const override + inline T value() const exprtk_override { - assert(condition_.first); - assert(loop_body_.first); - T result = T(0); - loop_runtime_checker::reset(); + if (parent_t::initialiser_.first) + parent_t::initialiser_.first->value(); - if (initialiser_.first) - initialiser_.first->value(); - - if (incrementor_.first) + if (parent_t::incrementor_.first) { - while (is_true(condition_) && loop_runtime_checker::check()) + while (is_true(parent_t::condition_)) { try { - result = loop_body_.first->value(); + result = parent_t::loop_body_.first->value(); } catch(const break_exception<T>& e) { @@ -7151,16 +7985,16 @@ namespace exprtk catch(const continue_exception&) {} - incrementor_.first->value(); + parent_t::incrementor_.first->value(); } } else { - while (is_true(condition_) && loop_runtime_checker::check()) + while (is_true(parent_t::condition_)) { try { - result = loop_body_.first->value(); + result = parent_t::loop_body_.first->value(); } catch(const break_exception<T>& e) { @@ -7173,32 +8007,83 @@ namespace exprtk return result; } + }; - inline typename expression_node<T>::node_type type() const override - { - return expression_node<T>::e_for; - } + template <typename T> + class for_loop_bc_rtc_node exprtk_final + : public for_loop_bc_node<T> + , public loop_runtime_checker + { + public: + + typedef for_loop_bc_node<T> parent_t; + typedef expression_node<T>* expression_ptr; - void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) override + for_loop_bc_rtc_node(expression_ptr initialiser, + expression_ptr condition, + expression_ptr incrementor, + expression_ptr loop_body, + loop_runtime_check_ptr loop_rt_chk) + : parent_t(initialiser, condition, incrementor, loop_body) + , loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_for_loop) { - expression_node<T>::ndb_t::collect(initialiser_, node_delete_list); - expression_node<T>::ndb_t::collect(condition_ , node_delete_list); - expression_node<T>::ndb_t::collect(incrementor_, node_delete_list); - expression_node<T>::ndb_t::collect(loop_body_ , node_delete_list); + assert(valid()); } - std::size_t node_depth() const override + inline T value() const exprtk_override { - return expression_node<T>::ndb_t::compute_node_depth - (initialiser_, condition_, incrementor_, loop_body_); + T result = T(0); + + loop_runtime_checker::reset(); + + if (parent_t::initialiser_.first) + parent_t::initialiser_.first->value(); + + if (parent_t::incrementor_.first) + { + while (is_true(parent_t::condition_) && loop_runtime_checker::check()) + { + try + { + result = parent_t::loop_body_.first->value(); + } + catch(const break_exception<T>& e) + { + return e.value; + } + catch(const continue_exception&) + {} + + parent_t::incrementor_.first->value(); + } + } + else + { + while (is_true(parent_t::condition_) && loop_runtime_checker::check()) + { + try + { + result = parent_t::loop_body_.first->value(); + } + catch(const break_exception<T>& e) + { + return e.value; + } + catch(const continue_exception&) + {} + } + } + + return result; } - private: + using parent_t::valid; - branch_t initialiser_; - branch_t condition_ ; - branch_t incrementor_; - branch_t loop_body_ ; + inline bool valid() const exprtk_final + { + return parent_t::valid() && + loop_runtime_checker::valid(); + } }; #endif @@ -7221,7 +8106,7 @@ namespace exprtk for (std::size_t i = 0; i < arg_list.size(); ++i) { - if (arg_list[i]) + if (arg_list[i] && arg_list[i]->valid()) { construct_branch_pair(arg_list_[i], arg_list[i]); } @@ -7231,42 +8116,44 @@ namespace exprtk return; } } + + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { - if (!arg_list_.empty()) + const std::size_t upper_bound = (arg_list_.size() - 1); + + for (std::size_t i = 0; i < upper_bound; i += 2) { - const std::size_t upper_bound = (arg_list_.size() - 1); + expression_ptr condition = arg_list_[i ].first; + expression_ptr consequent = arg_list_[i + 1].first; - for (std::size_t i = 0; i < upper_bound; i += 2) + if (is_true(condition)) { - expression_ptr condition = arg_list_[i ].first; - expression_ptr consequent = arg_list_[i + 1].first; - - if (is_true(condition)) - { - return consequent->value(); - } + return consequent->value(); } - - return arg_list_[upper_bound].first->value(); } - else - return std::numeric_limits<T>::quiet_NaN(); + + return arg_list_[upper_bound].first->value(); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_final { return expression_node<T>::e_switch; } - void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) override + inline bool valid() const exprtk_override + { + return !arg_list_.empty(); + } + + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override { expression_node<T>::ndb_t::collect(arg_list_, node_delete_list); } - std::size_t node_depth() const override + std::size_t node_depth() const exprtk_final { return expression_node<T>::ndb_t::compute_node_depth(arg_list_); } @@ -7277,7 +8164,7 @@ namespace exprtk }; template <typename T, typename Switch_N> - class switch_n_node : public switch_node<T> + class switch_n_node exprtk_final : public switch_node<T> { public: @@ -7289,14 +8176,14 @@ namespace exprtk : switch_node<T>(arg_list) {} - inline T value() const override + inline T value() const exprtk_override { return Switch_N::process(switch_node<T>::arg_list_); } }; template <typename T> - class multi_switch_node : public expression_node<T> + class multi_switch_node exprtk_final : public expression_node<T> { public: @@ -7314,7 +8201,7 @@ namespace exprtk for (std::size_t i = 0; i < arg_list.size(); ++i) { - if (arg_list[i]) + if (arg_list[i] && arg_list[i]->valid()) { construct_branch_pair(arg_list_[i], arg_list[i]); } @@ -7324,19 +8211,16 @@ namespace exprtk return; } } + + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { - T result = T(0); - - if (arg_list_.empty()) - { - return std::numeric_limits<T>::quiet_NaN(); - } - const std::size_t upper_bound = (arg_list_.size() - 1); + T result = T(0); + for (std::size_t i = 0; i < upper_bound; i += 2) { expression_ptr condition = arg_list_[i ].first; @@ -7351,17 +8235,22 @@ namespace exprtk return result; } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_mswitch; } - void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) override + inline bool valid() const exprtk_override + { + return !arg_list_.empty() && (0 == (arg_list_.size() % 2)); + } + + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override { expression_node<T>::ndb_t::collect(arg_list_, node_delete_list); } - std::size_t node_depth() const override + std::size_t node_depth() const exprtk_final { return expression_node<T>::ndb_t::compute_node_depth(arg_list_); } @@ -7376,15 +8265,16 @@ namespace exprtk { public: - virtual ~ivariable() = default; + virtual ~ivariable() exprtk_default; virtual T& ref() = 0; virtual const T& ref() const = 0; }; template <typename T> - class variable_node : public expression_node<T>, - public ivariable <T> + class variable_node exprtk_final + : public expression_node<T> + , public ivariable <T> { public: @@ -7403,22 +8293,22 @@ namespace exprtk return this < (&v); } - inline T value() const override + inline T value() const exprtk_override { return (*value_); } - inline T& ref() override + inline T& ref() exprtk_override { return (*value_); } - inline const T& ref() const override + inline const T& ref() const exprtk_override { return (*value_); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_variable; } @@ -7438,11 +8328,11 @@ namespace exprtk typedef std::pair<std::size_t,std::size_t> cached_range_t; range_pack() - : n0_e (std::make_pair(false,expression_node_ptr(0))), - n1_e (std::make_pair(false,expression_node_ptr(0))), - n0_c (std::make_pair(false,0)), - n1_c (std::make_pair(false,0)), - cache(std::make_pair(0,0)) + : n0_e (std::make_pair(false,expression_node_ptr(0))) + , n1_e (std::make_pair(false,expression_node_ptr(0))) + , n0_c (std::make_pair(false,0)) + , n1_c (std::make_pair(false,0)) + , cache(std::make_pair(0,0)) {} void clear() @@ -7521,13 +8411,13 @@ namespace exprtk (std::numeric_limits<std::size_t>::max() == r1 ) ) { - r1 = size - 1; + r1 = size; } cache.first = r0; cache.second = r1; - #ifndef exprtk_enable_runtime_checks + #ifndef exprtk_enable_range_runtime_checks return (r0 <= r1); #else return range_runtime_check(r0, r1, size); @@ -7536,12 +8426,12 @@ namespace exprtk inline std::size_t const_size() const { - return (n1_c.second - n0_c.second + 1); + return (n1_c.second - n0_c.second); } inline std::size_t cache_size() const { - return (cache.second - cache.first + 1); + return (cache.second - cache.first); } std::pair<bool,expression_node_ptr> n0_e; @@ -7550,21 +8440,25 @@ namespace exprtk std::pair<bool,std::size_t > n1_c; mutable cached_range_t cache; - #ifdef exprtk_enable_runtime_checks + #ifdef exprtk_enable_range_runtime_checks bool range_runtime_check(const std::size_t r0, const std::size_t r1, const std::size_t size) const { - if ((r0 < 0) || (r0 >= size)) + if (r0 > size) { - throw std::runtime_error("range error: (r0 < 0) || (r0 >= size)"); + throw std::runtime_error("range error: (r0 < 0) || (r0 > size)"); + #if !defined(_MSC_VER) && !defined(__NVCOMPILER) return false; + #endif } - if ((r1 < 0) || (r1 >= size)) + if (r1 > size) { - throw std::runtime_error("range error: (r1 < 0) || (r1 >= size)"); + throw std::runtime_error("range error: (r1 < 0) || (r1 > size)"); + #if !defined(_MSC_VER) && !defined(__NVCOMPILER) return false; + #endif } return (r0 <= r1); @@ -7582,11 +8476,11 @@ namespace exprtk typedef string_base_node<T>* strbase_ptr_t; range_data_type() - : range(0), - data (0), - size (0), - type_size(0), - str_node (0) + : range(0) + , data (0) + , size (0) + , type_size(0) + , str_node (0) {} range_t* range; @@ -7604,77 +8498,96 @@ namespace exprtk public: typedef vector_node<T>* vector_node_ptr; - typedef vec_data_store<T> vds_t; + typedef vec_data_store<T> vds_t; - virtual ~vector_interface() = default; + virtual ~vector_interface() exprtk_default; - virtual std::size_t size () const = 0; + virtual std::size_t size () const = 0; - virtual vector_node_ptr vec() const = 0; + virtual std::size_t base_size() const = 0; - virtual vector_node_ptr vec() = 0; + virtual vector_node_ptr vec () const = 0; - virtual vds_t& vds () = 0; + virtual vector_node_ptr vec () = 0; - virtual const vds_t& vds () const = 0; + virtual vds_t& vds () = 0; - virtual bool side_effect () const { return false; } + virtual const vds_t& vds () const = 0; + + virtual bool side_effect () const { return false; } }; template <typename T> - class vector_node : public expression_node <T>, - public vector_interface<T> + class vector_node exprtk_final + : public expression_node <T> + , public vector_interface<T> { public: - typedef expression_node<T>* expression_ptr; + typedef expression_node<T>* expression_ptr; typedef vector_holder<T> vector_holder_t; typedef vector_node<T>* vector_node_ptr; - typedef vec_data_store<T> vds_t; + typedef vec_data_store<T> vds_t; explicit vector_node(vector_holder_t* vh) - : vector_holder_(vh), - vds_((*vector_holder_).size(),(*vector_holder_)[0]) + : vector_holder_(vh) + , vds_((*vector_holder_).size(),(*vector_holder_)[0]) { vector_holder_->set_ref(&vds_.ref()); } vector_node(const vds_t& vds, vector_holder_t* vh) - : vector_holder_(vh), - vds_(vds) + : vector_holder_(vh) + , vds_(vds) {} - inline T value() const override + ~vector_node() exprtk_override + { + assert(valid()); + vector_holder_->remove_ref(&vds_.ref()); + } + + inline T value() const exprtk_override { return vds().data()[0]; } - vector_node_ptr vec() const override + vector_node_ptr vec() const exprtk_override { return const_cast<vector_node_ptr>(this); } - vector_node_ptr vec() override + vector_node_ptr vec() exprtk_override { return this; } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_vector; } - std::size_t size() const override + inline bool valid() const exprtk_override + { + return vector_holder_; + } + + std::size_t size() const exprtk_override + { + return vec_holder().size(); + } + + std::size_t base_size() const exprtk_override { - return vds().size(); + return vec_holder().base_size(); } - vds_t& vds() override + vds_t& vds() exprtk_override { return vds_; } - const vds_t& vds() const override + const vds_t& vds() const exprtk_override { return vds_; } @@ -7684,6 +8597,11 @@ namespace exprtk return (*vector_holder_); } + inline vector_holder_t& vec_holder() const + { + return (*vector_holder_); + } + private: vector_holder_t* vector_holder_; @@ -7691,103 +8609,100 @@ namespace exprtk }; template <typename T> - class vector_elem_node : public expression_node<T>, - public ivariable <T> + class vector_size_node exprtk_final + : public expression_node <T> { public: - typedef expression_node<T>* expression_ptr; - typedef vector_holder<T> vector_holder_t; - typedef vector_holder_t* vector_holder_ptr; - typedef std::pair<expression_ptr,bool> branch_t; - - vector_elem_node(expression_ptr index, vector_holder_ptr vec_holder) - : vec_holder_(vec_holder), - vector_base_((*vec_holder)[0]) - { - construct_branch_pair(index_, index); - } - - inline T value() const override - { - return *(vector_base_ + static_cast<std::size_t>(details::numeric::to_int64(index_.first->value()))); - } + typedef expression_node<T>* expression_ptr; + typedef vector_holder<T> vector_holder_t; - inline T& ref() override - { - return *(vector_base_ + static_cast<std::size_t>(details::numeric::to_int64(index_.first->value()))); - } + explicit vector_size_node(vector_holder_t* vh) + : vector_holder_(vh) + {} - inline const T& ref() const override + ~vector_size_node() exprtk_override { - return *(vector_base_ + static_cast<std::size_t>(details::numeric::to_int64(index_.first->value()))); + assert(valid()); } - inline typename expression_node<T>::node_type type() const override + inline T value() const exprtk_override { - return expression_node<T>::e_vecelem; + assert(vector_holder_); + return static_cast<T>(vector_holder_->size()); } - inline vector_holder_t& vec_holder() + inline typename expression_node<T>::node_type type() const exprtk_override { - return (*vec_holder_); + return expression_node<T>::e_vecsize; } - void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) override + inline bool valid() const exprtk_override { - expression_node<T>::ndb_t::collect(index_, node_delete_list); + return vector_holder_ && vector_holder_->size(); } - std::size_t node_depth() const override + inline vector_holder_t* vec_holder() { - return expression_node<T>::ndb_t::compute_node_depth(index_); + return vector_holder_; } private: - vector_holder_ptr vec_holder_; - T* vector_base_; - branch_t index_; + vector_holder_t* vector_holder_; }; template <typename T> - class rebasevector_elem_node : public expression_node<T>, - public ivariable <T> + class vector_elem_node exprtk_final + : public expression_node<T> + , public ivariable <T> { public: typedef expression_node<T>* expression_ptr; typedef vector_holder<T> vector_holder_t; typedef vector_holder_t* vector_holder_ptr; - typedef vec_data_store<T> vds_t; typedef std::pair<expression_ptr,bool> branch_t; - rebasevector_elem_node(expression_ptr index, vector_holder_ptr vec_holder) - : vector_holder_(vec_holder), - vds_((*vector_holder_).size(),(*vector_holder_)[0]) + vector_elem_node(expression_ptr vec_node, + expression_ptr index, + vector_holder_ptr vec_holder) + : vector_holder_(vec_holder) + , vector_base_((*vec_holder)[0]) { - vector_holder_->set_ref(&vds_.ref()); - construct_branch_pair(index_, index); + construct_branch_pair(vector_node_, vec_node); + construct_branch_pair(index_ , index ); + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { - return *(vds_.data() + static_cast<std::size_t>(details::numeric::to_int64(index_.first->value()))); + return *access_vector(); } - inline T& ref() override + inline T& ref() exprtk_override { - return *(vds_.data() + static_cast<std::size_t>(details::numeric::to_int64(index_.first->value()))); + return *access_vector(); } - inline const T& ref() const override + inline const T& ref() const exprtk_override { - return *(vds_.data() + static_cast<std::size_t>(details::numeric::to_int64(index_.first->value()))); + return *access_vector(); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { - return expression_node<T>::e_rbvecelem; + return expression_node<T>::e_vecelem; + } + + inline bool valid() const exprtk_override + { + return + vector_holder_ && + index_.first && + vector_node_.first && + index_.first->valid() && + vector_node_.first->valid(); } inline vector_holder_t& vec_holder() @@ -7795,60 +8710,81 @@ namespace exprtk return (*vector_holder_); } - void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) override + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override { - expression_node<T>::ndb_t::template collect<>(index_, node_delete_list); + expression_node<T>::ndb_t::collect(vector_node_, node_delete_list); + expression_node<T>::ndb_t::collect(index_ , node_delete_list); } - std::size_t node_depth() const override + std::size_t node_depth() const exprtk_override { - return expression_node<T>::ndb_t::compute_node_depth(index_); + return expression_node<T>::ndb_t::compute_node_depth + (vector_node_, index_); } private: + inline T* access_vector() const + { + vector_node_.first->value(); + return (vector_base_ + details::numeric::to_uint64(index_.first->value())); + } + vector_holder_ptr vector_holder_; - vds_t vds_; - branch_t index_; + T* vector_base_; + branch_t vector_node_; + branch_t index_; }; template <typename T> - class rebasevector_celem_node : public expression_node<T>, - public ivariable <T> + class vector_celem_node exprtk_final + : public expression_node<T> + , public ivariable <T> { public: - typedef expression_node<T>* expression_ptr; - typedef vector_holder<T> vector_holder_t; - typedef vector_holder_t* vector_holder_ptr; - typedef vec_data_store<T> vds_t; + typedef expression_node<T>* expression_ptr; + typedef vector_holder<T> vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; + typedef std::pair<expression_ptr,bool> branch_t; - rebasevector_celem_node(const std::size_t index, vector_holder_ptr vec_holder) - : index_(index), - vector_holder_(vec_holder), - vds_((*vector_holder_).size(),(*vector_holder_)[0]) + vector_celem_node(expression_ptr vec_node, + const std::size_t index, + vector_holder_ptr vec_holder) + : index_(index) + , vector_holder_(vec_holder) + , vector_base_((*vec_holder)[0]) { - vector_holder_->set_ref(&vds_.ref()); + construct_branch_pair(vector_node_, vec_node); + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { - return *(vds_.data() + index_); + return *access_vector(); } - inline T& ref() override + inline T& ref() exprtk_override { - return *(vds_.data() + index_); + return *access_vector(); } - inline const T& ref() const override + inline const T& ref() const exprtk_override { - return *(vds_.data() + index_); + return *access_vector(); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { - return expression_node<T>::e_rbveccelem; + return expression_node<T>::e_veccelem; + } + + inline bool valid() const exprtk_override + { + return + vector_holder_ && + vector_node_.first && + vector_node_.first->valid(); } inline vector_holder_t& vec_holder() @@ -7856,684 +8792,1773 @@ namespace exprtk return (*vector_holder_); } + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override + { + expression_node<T>::ndb_t::collect(vector_node_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node<T>::ndb_t::compute_node_depth(vector_node_); + } + private: + inline T* access_vector() const + { + vector_node_.first->value(); + return (vector_base_ + index_); + } + const std::size_t index_; vector_holder_ptr vector_holder_; - vds_t vds_; + T* vector_base_; + branch_t vector_node_; }; template <typename T> - class vector_assignment_node : public expression_node<T> + class vector_elem_rtc_node exprtk_final + : public expression_node<T> + , public ivariable <T> { public: - typedef expression_node<T>* expression_ptr; + typedef expression_node<T>* expression_ptr; + typedef vector_holder<T> vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; + typedef std::pair<expression_ptr,bool> branch_t; - vector_assignment_node(T* vector_base, - const std::size_t& size, - const std::vector<expression_ptr>& initialiser_list, - const bool single_value_initialse) - : vector_base_(vector_base), - initialiser_list_(initialiser_list), - size_(size), - single_value_initialse_(single_value_initialse) - {} + vector_elem_rtc_node(expression_ptr vec_node, + expression_ptr index, + vector_holder_ptr vec_holder, + vector_access_runtime_check_ptr vec_rt_chk) + : vector_holder_(vec_holder) + , vector_base_((*vec_holder)[0]) + , vec_rt_chk_(vec_rt_chk) + , max_vector_index_(vector_holder_->size() - 1) + { + construct_branch_pair(vector_node_, vec_node); + construct_branch_pair(index_ , index ); + assert(valid()); + } - inline T value() const override + inline T value() const exprtk_override { - if (single_value_initialse_) - { - for (std::size_t i = 0; i < size_; ++i) - { - *(vector_base_ + i) = initialiser_list_[0]->value(); - } - } - else - { - std::size_t il_size = initialiser_list_.size(); + return *access_vector(); + } - for (std::size_t i = 0; i < il_size; ++i) - { - *(vector_base_ + i) = initialiser_list_[i]->value(); - } + inline T& ref() exprtk_override + { + return *access_vector(); + } - if (il_size < size_) - { - for (std::size_t i = il_size; i < size_; ++i) - { - *(vector_base_ + i) = T(0); - } - } - } + inline const T& ref() const exprtk_override + { + return *access_vector(); + } - return *(vector_base_); + inline typename expression_node<T>::node_type type() const exprtk_override + { + return expression_node<T>::e_vecelemrtc; } - inline typename expression_node<T>::node_type type() const override + inline bool valid() const exprtk_override { - return expression_node<T>::e_vecdefass; + return + vector_holder_ && + index_.first && + vector_node_.first && + index_.first->valid() && + vector_node_.first->valid(); } - void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) override + inline vector_holder_t& vec_holder() { - expression_node<T>::ndb_t::collect(initialiser_list_, node_delete_list); + return (*vector_holder_); } - std::size_t node_depth() const override + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override { - return expression_node<T>::ndb_t::compute_node_depth(initialiser_list_); + expression_node<T>::ndb_t::collect(vector_node_, node_delete_list); + expression_node<T>::ndb_t::collect(index_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node<T>::ndb_t::compute_node_depth + (vector_node_, index_); } private: - vector_assignment_node<T>& operator=(const vector_assignment_node<T>&); + inline T* access_vector() const + { + const _uint64_t index = details::numeric::to_uint64(index_.first->value()); + vector_node_.first->value(); - mutable T* vector_base_; - std::vector<expression_ptr> initialiser_list_; - const std::size_t size_; - const bool single_value_initialse_; + if (index <= max_vector_index_) + { + return (vector_holder_->data() + index); + } + + assert(vec_rt_chk_); + + vector_access_runtime_check::violation_context context; + context.base_ptr = reinterpret_cast<void*>(vector_base_); + context.end_ptr = reinterpret_cast<void*>(vector_base_ + vector_holder_->size()); + context.access_ptr = reinterpret_cast<void*>(vector_base_ + index); + context.type_size = sizeof(T); + + return vec_rt_chk_->handle_runtime_violation(context) ? + reinterpret_cast<T*>(context.access_ptr) : + vector_base_ ; + } + + vector_holder_ptr vector_holder_; + T* vector_base_; + branch_t vector_node_; + branch_t index_; + vector_access_runtime_check_ptr vec_rt_chk_; + const std::size_t max_vector_index_; }; template <typename T> - class swap_node : public expression_node<T> + class vector_celem_rtc_node exprtk_final + : public expression_node<T> + , public ivariable <T> { public: - typedef expression_node<T>* expression_ptr; - typedef variable_node<T>* variable_node_ptr; - - swap_node(variable_node_ptr var0, variable_node_ptr var1) - : var0_(var0), - var1_(var1) - {} + typedef expression_node<T>* expression_ptr; + typedef vector_holder<T> vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; + typedef std::pair<expression_ptr,bool> branch_t; - inline T value() const override + vector_celem_rtc_node(expression_ptr vec_node, + const std::size_t index, + vector_holder_ptr vec_holder, + vector_access_runtime_check_ptr vec_rt_chk) + : index_(index) + , max_vector_index_(vec_holder->size() - 1) + , vector_holder_(vec_holder) + , vector_base_((*vec_holder)[0]) + , vec_rt_chk_(vec_rt_chk) { - std::swap(var0_->ref(),var1_->ref()); - return var1_->ref(); + construct_branch_pair(vector_node_, vec_node); + assert(valid()); } - inline typename expression_node<T>::node_type type() const override + inline T value() const exprtk_override { - return expression_node<T>::e_swap; + return *access_vector(); } - private: + inline T& ref() exprtk_override + { + return *access_vector(); + } - variable_node_ptr var0_; - variable_node_ptr var1_; - }; + inline const T& ref() const exprtk_override + { + return *access_vector(); + } - template <typename T> - class swap_generic_node : public binary_node<T> - { - public: + inline typename expression_node<T>::node_type type() const exprtk_override + { + return expression_node<T>::e_veccelemrtc; + } - typedef expression_node<T>* expression_ptr; - typedef ivariable<T>* ivariable_ptr; + inline bool valid() const exprtk_override + { + return + vector_holder_ && + vector_node_.first && + vector_node_.first->valid(); + } - swap_generic_node(expression_ptr var0, expression_ptr var1) - : binary_node<T>(details::e_swap, var0, var1), - var0_(dynamic_cast<ivariable_ptr>(var0)), - var1_(dynamic_cast<ivariable_ptr>(var1)) - {} + inline vector_holder_t& vec_holder() + { + return (*vector_holder_); + } - inline T value() const override + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override { - std::swap(var0_->ref(),var1_->ref()); - return var1_->ref(); + expression_node<T>::ndb_t::collect(vector_node_, node_delete_list); } - inline typename expression_node<T>::node_type type() const override + std::size_t node_depth() const exprtk_override { - return expression_node<T>::e_swap; + return expression_node<T>::ndb_t::compute_node_depth(vector_node_); } private: - ivariable_ptr var0_; - ivariable_ptr var1_; - }; - - template <typename T> - class swap_vecvec_node : public binary_node <T>, - public vector_interface<T> - { - public: - - typedef expression_node<T>* expression_ptr; - typedef vector_node<T>* vector_node_ptr; - typedef vec_data_store<T> vds_t; - - swap_vecvec_node(expression_ptr branch0, - expression_ptr branch1) - : binary_node<T>(details::e_swap, branch0, branch1), - vec0_node_ptr_(0), - vec1_node_ptr_(0), - vec_size_ (0), - initialised_ (false) + inline T* access_vector() const { - if (is_ivector_node(binary_node<T>::branch_[0].first)) - { - vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0); - - if (0 != (vi = dynamic_cast<vector_interface<T>*>(binary_node<T>::branch_[0].first))) - { - vec0_node_ptr_ = vi->vec(); - vds() = vi->vds(); - } - } + vector_node_.first->value(); - if (is_ivector_node(binary_node<T>::branch_[1].first)) + if (index_ <= max_vector_index_) { - vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0); - - if (0 != (vi = dynamic_cast<vector_interface<T>*>(binary_node<T>::branch_[1].first))) - { - vec1_node_ptr_ = vi->vec(); - } + return (vector_holder_->data() + index_); } - if (vec0_node_ptr_ && vec1_node_ptr_) - { - vec_size_ = std::min(vec0_node_ptr_->vds().size(), - vec1_node_ptr_->vds().size()); + assert(vec_rt_chk_); - initialised_ = true; - } + vector_access_runtime_check::violation_context context; + context.base_ptr = reinterpret_cast<void*>(vector_base_); + context.end_ptr = reinterpret_cast<void*>(vector_base_ + vector_holder_->size()); + context.access_ptr = reinterpret_cast<void*>(vector_base_ + index_); + context.type_size = sizeof(T); + + return vec_rt_chk_->handle_runtime_violation(context) ? + reinterpret_cast<T*>(context.access_ptr) : + vector_base_ ; } - inline T value() const override - { - assert(binary_node<T>::branch_[0].first); - assert(binary_node<T>::branch_[1].first); + const std::size_t index_; + const std::size_t max_vector_index_; + vector_holder_ptr vector_holder_; + T* vector_base_; + branch_t vector_node_; + vector_access_runtime_check_ptr vec_rt_chk_; + }; - if (initialised_) - { - binary_node<T>::branch_[0].first->value(); - binary_node<T>::branch_[1].first->value(); + template <typename T> + class rebasevector_elem_node exprtk_final + : public expression_node<T> + , public ivariable <T> + { + public: - T* vec0 = vec0_node_ptr_->vds().data(); - T* vec1 = vec1_node_ptr_->vds().data(); + typedef expression_node<T>* expression_ptr; + typedef vector_holder<T> vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; + typedef vec_data_store<T> vds_t; + typedef std::pair<expression_ptr,bool> branch_t; - for (std::size_t i = 0; i < vec_size_; ++i) - { - std::swap(vec0[i],vec1[i]); - } + rebasevector_elem_node(expression_ptr vec_node, + expression_ptr index, + vector_holder_ptr vec_holder) + : vector_holder_(vec_holder) + { + construct_branch_pair(vector_node_, vec_node); + construct_branch_pair(index_ , index ); + assert(valid()); + } - return vec1_node_ptr_->value(); - } - else - return std::numeric_limits<T>::quiet_NaN(); + inline T value() const exprtk_override + { + return *access_vector(); } - vector_node_ptr vec() const override + inline T& ref() exprtk_override { - return vec0_node_ptr_; + return *access_vector(); } - vector_node_ptr vec() override + inline const T& ref() const exprtk_override { - return vec0_node_ptr_; + return *access_vector(); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { - return expression_node<T>::e_vecvecswap; + return expression_node<T>::e_rbvecelem; } - std::size_t size() const override + inline bool valid() const exprtk_override { - return vec_size_; + return + vector_holder_ && + index_.first && + vector_node_.first && + index_.first->valid() && + vector_node_.first->valid(); } - vds_t& vds() override + inline vector_holder_t& vec_holder() { - return vds_; + return (*vector_holder_); } - const vds_t& vds() const override + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override { - return vds_; + expression_node<T>::ndb_t::collect(vector_node_, node_delete_list); + expression_node<T>::ndb_t::collect(index_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node<T>::ndb_t::compute_node_depth + (vector_node_, index_); } private: - vector_node<T>* vec0_node_ptr_; - vector_node<T>* vec1_node_ptr_; - std::size_t vec_size_; - bool initialised_; - vds_t vds_; + inline T* access_vector() const + { + vector_node_.first->value(); + return (vector_holder_->data() + details::numeric::to_uint64(index_.first->value())); + } + + vector_holder_ptr vector_holder_; + branch_t vector_node_; + branch_t index_; }; - #ifndef exprtk_disable_string_capabilities template <typename T> - class stringvar_node : public expression_node <T>, - public string_base_node<T>, - public range_interface <T> + class rebasevector_celem_node exprtk_final + : public expression_node<T> + , public ivariable <T> { public: - typedef range_pack<T> range_t; - - static std::string null_value; - - explicit stringvar_node() - : value_(&null_value) - {} - - explicit stringvar_node(std::string& v) - : value_(&v) - { - rp_.n0_c = std::make_pair<bool,std::size_t>(true,0); - rp_.n1_c = std::make_pair<bool,std::size_t>(true,v.size() - 1); - rp_.cache.first = rp_.n0_c.second; - rp_.cache.second = rp_.n1_c.second; - } - - inline bool operator <(const stringvar_node<T>& v) const - { - return this < (&v); - } + typedef expression_node<T>* expression_ptr; + typedef vector_holder<T> vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; + typedef std::pair<expression_ptr,bool> branch_t; - inline T value() const override + rebasevector_celem_node(expression_ptr vec_node, + const std::size_t index, + vector_holder_ptr vec_holder) + : index_(index) + , vector_holder_(vec_holder) { - rp_.n1_c.second = (*value_).size() - 1; - rp_.cache.second = rp_.n1_c.second; - - return std::numeric_limits<T>::quiet_NaN(); + construct_branch_pair(vector_node_, vec_node); + assert(valid()); } - std::string str() const override + inline T value() const exprtk_override { - return ref(); + vector_node_.first->value(); + return ref();; } - char_cptr base() const override + inline T& ref() exprtk_override { - return &(*value_)[0]; + return *(vector_holder_->data() + index_); } - std::size_t size() const override + inline const T& ref() const exprtk_override { - return ref().size(); + return *(vector_holder_->data() + index_); } - std::string& ref() + inline typename expression_node<T>::node_type type() const exprtk_override { - return (*value_); + return expression_node<T>::e_rbveccelem; } - const std::string& ref() const + inline bool valid() const exprtk_override { - return (*value_); + return + vector_holder_ && + vector_node_.first && + vector_node_.first->valid(); } - range_t& range_ref() override + inline vector_holder_t& vec_holder() { - return rp_; + return (*vector_holder_); } - const range_t& range_ref() const override + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override { - return rp_; + expression_node<T>::ndb_t::collect(vector_node_, node_delete_list); } - inline typename expression_node<T>::node_type type() const override + std::size_t node_depth() const exprtk_override { - return expression_node<T>::e_stringvar; + return expression_node<T>::ndb_t::compute_node_depth(vector_node_); } private: - std::string* value_; - mutable range_t rp_; + const std::size_t index_; + vector_holder_ptr vector_holder_; + branch_t vector_node_; }; template <typename T> - std::string stringvar_node<T>::null_value = std::string(""); - - template <typename T> - class string_range_node : public expression_node <T>, - public string_base_node<T>, - public range_interface <T> + class rebasevector_elem_rtc_node exprtk_final + : public expression_node<T> + , public ivariable <T> { public: - typedef range_pack<T> range_t; - - static std::string null_value; - - explicit string_range_node(std::string& v, const range_t& rp) - : value_(&v), - rp_(rp) - {} + typedef expression_node<T>* expression_ptr; + typedef vector_holder<T> vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; + typedef std::pair<expression_ptr,bool> branch_t; - ~string_range_node() override + rebasevector_elem_rtc_node(expression_ptr vec_node, + expression_ptr index, + vector_holder_ptr vec_holder, + vector_access_runtime_check_ptr vec_rt_chk) + : vector_holder_(vec_holder) + , vec_rt_chk_(vec_rt_chk) { - rp_.free(); + construct_branch_pair(vector_node_, vec_node); + construct_branch_pair(index_ , index ); + assert(valid()); } - inline bool operator <(const string_range_node<T>& v) const + inline T value() const exprtk_override { - return this < (&v); + return *access_vector(); } - inline T value() const override + inline T& ref() exprtk_override { - return std::numeric_limits<T>::quiet_NaN(); + return *access_vector(); } - inline std::string str() const override + inline const T& ref() const exprtk_override { - return (*value_); + return *access_vector(); } - char_cptr base() const override + inline typename expression_node<T>::node_type type() const exprtk_override { - return &(*value_)[0]; + return expression_node<T>::e_rbvecelemrtc; } - std::size_t size() const override + inline bool valid() const exprtk_override { - return ref().size(); + return + vector_holder_ && + index_.first && + vector_node_.first && + index_.first->valid() && + vector_node_.first->valid(); } - inline range_t range() const + inline vector_holder_t& vec_holder() { - return rp_; + return (*vector_holder_); } - inline virtual std::string& ref() + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override { - return (*value_); + expression_node<T>::ndb_t::collect(vector_node_, node_delete_list); + expression_node<T>::ndb_t::collect(index_ , node_delete_list); } - inline virtual const std::string& ref() const + std::size_t node_depth() const exprtk_override { - return (*value_); + return expression_node<T>::ndb_t::compute_node_depth + (vector_node_, index_); } - inline range_t& range_ref() override - { - return rp_; - } + private: - inline const range_t& range_ref() const override + inline T* access_vector() const { - return rp_; - } + vector_node_.first->value(); + const _uint64_t index = details::numeric::to_uint64(index_.first->value()); - inline typename expression_node<T>::node_type type() const override - { - return expression_node<T>::e_stringvarrng; - } + if (index <= (vector_holder_->size() - 1)) + { + return (vector_holder_->data() + index); + } - private: + assert(vec_rt_chk_); - std::string* value_; - range_t rp_; - }; + vector_access_runtime_check::violation_context context; + context.base_ptr = reinterpret_cast<void*>(vector_holder_->data()); + context.end_ptr = reinterpret_cast<void*>(vector_holder_->data() + vector_holder_->size()); + context.access_ptr = reinterpret_cast<void*>(vector_holder_->data() + index); + context.type_size = sizeof(T); - template <typename T> - std::string string_range_node<T>::null_value = std::string(""); + return vec_rt_chk_->handle_runtime_violation(context) ? + reinterpret_cast<T*>(context.access_ptr) : + vector_holder_->data() ; + } + + vector_holder_ptr vector_holder_; + branch_t vector_node_; + branch_t index_; + vector_access_runtime_check_ptr vec_rt_chk_; + }; template <typename T> - class const_string_range_node : public expression_node <T>, - public string_base_node<T>, - public range_interface <T> + class rebasevector_celem_rtc_node exprtk_final + : public expression_node<T> + , public ivariable <T> { public: - typedef range_pack<T> range_t; - - explicit const_string_range_node(const std::string& v, const range_t& rp) - : value_(v), - rp_(rp) - {} + typedef expression_node<T>* expression_ptr; + typedef vector_holder<T> vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; + typedef std::pair<expression_ptr,bool> branch_t; - ~const_string_range_node() override + rebasevector_celem_rtc_node(expression_ptr vec_node, + const std::size_t index, + vector_holder_ptr vec_holder, + vector_access_runtime_check_ptr vec_rt_chk) + : index_(index) + , vector_holder_(vec_holder) + , vector_base_((*vec_holder)[0]) + , vec_rt_chk_(vec_rt_chk) { - rp_.free(); + construct_branch_pair(vector_node_, vec_node); + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { - return std::numeric_limits<T>::quiet_NaN(); + return *access_vector(); } - std::string str() const override + inline T& ref() exprtk_override { - return value_; + return *access_vector(); } - char_cptr base() const override + inline const T& ref() const exprtk_override { - return value_.data(); + return *access_vector(); } - std::size_t size() const override + inline typename expression_node<T>::node_type type() const exprtk_override { - return value_.size(); + return expression_node<T>::e_rbveccelemrtc; } - range_t range() const + inline bool valid() const exprtk_override { - return rp_; + return + vector_holder_ && + vector_node_.first && + vector_node_.first->valid(); } - range_t& range_ref() override + inline vector_holder_t& vec_holder() { - return rp_; + return (*vector_holder_); } - const range_t& range_ref() const override + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override { - return rp_; + expression_node<T>::ndb_t::collect(vector_node_, node_delete_list); } - inline typename expression_node<T>::node_type type() const override + std::size_t node_depth() const exprtk_override { - return expression_node<T>::e_cstringvarrng; + return expression_node<T>::ndb_t::compute_node_depth(vector_node_); } private: - const_string_range_node<T>& operator=(const const_string_range_node<T>&); + inline T* access_vector() const + { + vector_node_.first->value(); - const std::string value_; - range_t rp_; + if (index_ <= vector_holder_->size() - 1) + { + return (vector_holder_->data() + index_); + } + + assert(vec_rt_chk_); + + vector_access_runtime_check::violation_context context; + context.base_ptr = reinterpret_cast<void*>(vector_base_); + context.end_ptr = reinterpret_cast<void*>(vector_base_ + vector_holder_->size()); + context.access_ptr = reinterpret_cast<void*>(vector_base_ + index_); + context.type_size = sizeof(T); + + return vec_rt_chk_->handle_runtime_violation(context) ? + reinterpret_cast<T*>(context.access_ptr) : + vector_base_ ; + } + + const std::size_t index_; + vector_holder_ptr vector_holder_; + T* vector_base_; + branch_t vector_node_; + vector_access_runtime_check_ptr vec_rt_chk_; }; template <typename T> - class generic_string_range_node : public expression_node <T>, - public string_base_node<T>, - public range_interface <T> + class vector_initialisation_node exprtk_final : public expression_node<T> { public: - typedef expression_node <T>* expression_ptr; - typedef stringvar_node <T>* strvar_node_ptr; - typedef string_base_node<T>* str_base_ptr; - typedef range_pack <T> range_t; - typedef range_t* range_ptr; - typedef range_interface<T> irange_t; - typedef irange_t* irange_ptr; - typedef std::pair<expression_ptr,bool> branch_t; - + typedef expression_node<T>* expression_ptr; - generic_string_range_node(expression_ptr str_branch, const range_t& brange) - : initialised_(false), - str_base_ptr_ (0), - str_range_ptr_(0), - base_range_(brange) + vector_initialisation_node(T* vector_base, + const std::size_t& size, + const std::vector<expression_ptr>& initialiser_list, + const bool single_value_initialse) + : vector_base_(vector_base) + , initialiser_list_(initialiser_list) + , size_(size) + , single_value_initialse_(single_value_initialse) + , zero_value_initialse_(false) + , const_nonzero_literal_value_initialse_(false) + , single_initialiser_value_(T(0)) { - range_.n0_c = std::make_pair<bool,std::size_t>(true,0); - range_.n1_c = std::make_pair<bool,std::size_t>(true,0); - range_.cache.first = range_.n0_c.second; - range_.cache.second = range_.n1_c.second; + if (single_value_initialse_) + { + if (initialiser_list_.empty()) + zero_value_initialse_ = true; + else if ( + (initialiser_list_.size() == 1) && + details::is_constant_node(initialiser_list_[0]) && + (T(0) == initialiser_list_[0]->value()) + ) + { + zero_value_initialse_ = true; + } + else + { + assert(initialiser_list_.size() == 1); - construct_branch_pair(branch_, str_branch); + if (details::is_constant_node(initialiser_list_[0])) + { + const_nonzero_literal_value_initialse_ = true; + single_initialiser_value_ = initialiser_list_[0]->value(); + assert(T(0) != single_initialiser_value_); + } + } + } + } - if (is_generally_string_node(branch_.first)) + inline T value() const exprtk_override + { + if (single_value_initialse_) { - str_base_ptr_ = dynamic_cast<str_base_ptr>(branch_.first); - - if (0 == str_base_ptr_) - return; + if (zero_value_initialse_) + { + details::set_zero_value(vector_base_, size_); + } + else if (const_nonzero_literal_value_initialse_) + { + for (std::size_t i = 0; i < size_; ++i) + { + *(vector_base_ + i) = single_initialiser_value_; + } + } + else + { + for (std::size_t i = 0; i < size_; ++i) + { + *(vector_base_ + i) = initialiser_list_[0]->value(); + } + } + } + else + { + const std::size_t initialiser_list_size = initialiser_list_.size(); - str_range_ptr_ = dynamic_cast<irange_ptr>(branch_.first); + for (std::size_t i = 0; i < initialiser_list_size; ++i) + { + *(vector_base_ + i) = initialiser_list_[i]->value(); + } - if (0 == str_range_ptr_) - return; + if (initialiser_list_size < size_) + { + details::set_zero_value( + vector_base_ + initialiser_list_size, + (size_ - initialiser_list_size)); + } } - initialised_ = (str_base_ptr_ && str_range_ptr_); + return *(vector_base_); } - ~generic_string_range_node() override + inline typename expression_node<T>::node_type type() const exprtk_override { - base_range_.free(); + return expression_node<T>::e_vecinit; } - inline T value() const override + inline bool valid() const exprtk_override { - if (initialised_) - { - assert(branch_.first); + return vector_base_; + } - branch_.first->value(); + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override + { + expression_node<T>::ndb_t::collect(initialiser_list_, node_delete_list); + } - std::size_t str_r0 = 0; - std::size_t str_r1 = 0; + std::size_t node_depth() const exprtk_override + { + return expression_node<T>::ndb_t::compute_node_depth(initialiser_list_); + } - std::size_t r0 = 0; - std::size_t r1 = 0; + private: - const range_t& range = str_range_ptr_->range_ref(); + vector_initialisation_node(const vector_initialisation_node<T>&) exprtk_delete; + vector_initialisation_node<T>& operator=(const vector_initialisation_node<T>&) exprtk_delete; - const std::size_t base_str_size = str_base_ptr_->size(); + mutable T* vector_base_; + std::vector<expression_ptr> initialiser_list_; + const std::size_t size_; + const bool single_value_initialse_; + bool zero_value_initialse_; + bool const_nonzero_literal_value_initialse_; + T single_initialiser_value_; + }; - if ( - range (str_r0, str_r1, base_str_size) && - base_range_( r0, r1, base_str_size) - ) - { - const std::size_t size = (r1 - r0) + 1; + template <typename T> + class vector_init_zero_value_node exprtk_final : public expression_node<T> + { + public: - range_.n1_c.second = size - 1; - range_.cache.second = range_.n1_c.second; + typedef expression_node<T>* expression_ptr; - value_.assign(str_base_ptr_->base() + str_r0 + r0, size); - } - } + vector_init_zero_value_node(T* vector_base, + const std::size_t& size, + const std::vector<expression_ptr>& initialiser_list) + : vector_base_(vector_base) + , size_(size) + , initialiser_list_(initialiser_list) + {} - return std::numeric_limits<T>::quiet_NaN(); + inline T value() const exprtk_override + { + details::set_zero_value(vector_base_, size_); + return *(vector_base_); } - std::string str() const override + inline typename expression_node<T>::node_type type() const exprtk_override { - return value_; + return expression_node<T>::e_vecinit; } - char_cptr base() const override + inline bool valid() const exprtk_override { - return &value_[0]; + return vector_base_; } - std::size_t size() const override + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override { - return value_.size(); + expression_node<T>::ndb_t::collect(initialiser_list_, node_delete_list); } - range_t& range_ref() override + std::size_t node_depth() const exprtk_override { - return range_; + return expression_node<T>::ndb_t::compute_node_depth(initialiser_list_); + } + + private: + + vector_init_zero_value_node(const vector_init_zero_value_node<T>&) exprtk_delete; + vector_init_zero_value_node<T>& operator=(const vector_init_zero_value_node<T>&) exprtk_delete; + + mutable T* vector_base_; + const std::size_t size_; + std::vector<expression_ptr> initialiser_list_; + }; + + template <typename T> + class vector_init_single_constvalue_node exprtk_final : public expression_node<T> + { + public: + + typedef expression_node<T>* expression_ptr; + + vector_init_single_constvalue_node(T* vector_base, + const std::size_t& size, + const std::vector<expression_ptr>& initialiser_list) + : vector_base_(vector_base) + , size_(size) + , initialiser_list_(initialiser_list) + { + single_initialiser_value_ = initialiser_list_[0]->value(); + assert(valid()); } - const range_t& range_ref() const override + inline T value() const exprtk_override { - return range_; + for (std::size_t i = 0; i < size_; ++i) + { + *(vector_base_ + i) = single_initialiser_value_; + } + + return *(vector_base_); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { - return expression_node<T>::e_strgenrange; + return expression_node<T>::e_vecinit; } - void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) override + inline bool valid() const exprtk_override { - expression_node<T>::ndb_t::collect(branch_, node_delete_list); + return vector_base_ && + (initialiser_list_.size() == 1) && + (details::is_constant_node(initialiser_list_[0])) && + (single_initialiser_value_ != T(0)); } - std::size_t node_depth() const override + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override { - return expression_node<T>::ndb_t::compute_node_depth(branch_); + expression_node<T>::ndb_t::collect(initialiser_list_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node<T>::ndb_t::compute_node_depth(initialiser_list_); } private: - bool initialised_; - branch_t branch_; - str_base_ptr str_base_ptr_; - irange_ptr str_range_ptr_; - mutable range_t base_range_; - mutable range_t range_; - mutable std::string value_; + vector_init_single_constvalue_node(const vector_init_single_constvalue_node<T>&) exprtk_delete; + vector_init_single_constvalue_node<T>& operator=(const vector_init_single_constvalue_node<T>&) exprtk_delete; + + mutable T* vector_base_; + const std::size_t size_; + std::vector<expression_ptr> initialiser_list_; + T single_initialiser_value_; }; template <typename T> - class string_concat_node : public binary_node <T>, - public string_base_node<T>, - public range_interface <T> + class vector_init_single_value_node exprtk_final : public expression_node<T> { public: - typedef expression_node <T>* expression_ptr; - typedef string_base_node<T>* str_base_ptr; - typedef range_pack <T> range_t; - typedef range_t* range_ptr; - typedef range_interface<T> irange_t; - typedef irange_t* irange_ptr; + typedef expression_node<T>* expression_ptr; - string_concat_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node<T>(opr, branch0, branch1), - initialised_(false), - str0_base_ptr_ (0), - str1_base_ptr_ (0), - str0_range_ptr_(0), - str1_range_ptr_(0) + vector_init_single_value_node(T* vector_base, + const std::size_t& size, + const std::vector<expression_ptr>& initialiser_list) + : vector_base_(vector_base) + , size_(size) + , initialiser_list_(initialiser_list) { - range_.n0_c = std::make_pair<bool,std::size_t>(true,0); - range_.n1_c = std::make_pair<bool,std::size_t>(true,0); + assert(valid()); + } - range_.cache.first = range_.n0_c.second; - range_.cache.second = range_.n1_c.second; + inline T value() const exprtk_override + { + expression_node<T>& node = *initialiser_list_[0]; - if (is_generally_string_node(binary_node<T>::branch_[0].first)) + for (std::size_t i = 0; i < size_; ++i) { - str0_base_ptr_ = dynamic_cast<str_base_ptr>(binary_node<T>::branch_[0].first); + *(vector_base_ + i) = node.value(); + } + + return *(vector_base_); + } + + inline typename expression_node<T>::node_type type() const exprtk_override + { + return expression_node<T>::e_vecinit; + } + + inline bool valid() const exprtk_override + { + return vector_base_ && + (initialiser_list_.size() == 1) && + !details::is_constant_node(initialiser_list_[0]); + } + + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override + { + expression_node<T>::ndb_t::collect(initialiser_list_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node<T>::ndb_t::compute_node_depth(initialiser_list_); + } + + private: + + vector_init_single_value_node(const vector_init_single_value_node<T>&) exprtk_delete; + vector_init_single_value_node<T>& operator=(const vector_init_single_value_node<T>&) exprtk_delete; + + mutable T* vector_base_; + const std::size_t size_; + std::vector<expression_ptr> initialiser_list_; + }; + + template <typename T> + class vector_init_iota_constconst_node exprtk_final : public expression_node<T> + { + public: + + typedef expression_node<T>* expression_ptr; + + vector_init_iota_constconst_node(T* vector_base, + const std::size_t& size, + const std::vector<expression_ptr>& initialiser_list) + : vector_base_(vector_base) + , size_(size) + , initialiser_list_(initialiser_list) + { + base_value_ = initialiser_list_[0]->value(); + increment_value_ = initialiser_list_[1]->value(); + + assert(valid()); + } + + inline T value() const exprtk_override + { + T value = base_value_; + + for (std::size_t i = 0; i < size_; ++i, value += increment_value_) + { + *(vector_base_ + i) = value; + } + + return *(vector_base_); + } + + inline typename expression_node<T>::node_type type() const exprtk_override + { + return expression_node<T>::e_vecinit; + } + + inline bool valid() const exprtk_override + { + return vector_base_ && + (initialiser_list_.size() == 2) && + (details::is_constant_node(initialiser_list_[0])) && + (details::is_constant_node(initialiser_list_[1])) ; + } + + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override + { + expression_node<T>::ndb_t::collect(initialiser_list_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node<T>::ndb_t::compute_node_depth(initialiser_list_); + } + + private: + + vector_init_iota_constconst_node(const vector_init_iota_constconst_node<T>&) exprtk_delete; + vector_init_iota_constconst_node<T>& operator=(const vector_init_iota_constconst_node<T>&) exprtk_delete; + + mutable T* vector_base_; + const std::size_t size_; + std::vector<expression_ptr> initialiser_list_; + T base_value_; + T increment_value_; + }; + + template <typename T> + class vector_init_iota_constnconst_node exprtk_final : public expression_node<T> + { + public: + + typedef expression_node<T>* expression_ptr; + + vector_init_iota_constnconst_node(T* vector_base, + const std::size_t& size, + const std::vector<expression_ptr>& initialiser_list) + : vector_base_(vector_base) + , size_(size) + , initialiser_list_(initialiser_list) + { + assert(valid()); + base_value_ = initialiser_list_[0]->value(); + } + + inline T value() const exprtk_override + { + T value = base_value_; + expression_node<T>& increment = *initialiser_list_[1]; + + for (std::size_t i = 0; i < size_; ++i, value += increment.value()) + { + *(vector_base_ + i) = value; + } + + return *(vector_base_); + } + + inline typename expression_node<T>::node_type type() const exprtk_override + { + return expression_node<T>::e_vecinit; + } + + inline bool valid() const exprtk_override + { + return vector_base_ && + (initialiser_list_.size() == 2) && + ( details::is_constant_node(initialiser_list_[0])) && + (!details::is_constant_node(initialiser_list_[1])); + } + + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override + { + expression_node<T>::ndb_t::collect(initialiser_list_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node<T>::ndb_t::compute_node_depth(initialiser_list_); + } + + private: + + vector_init_iota_constnconst_node(const vector_init_iota_constnconst_node<T>&) exprtk_delete; + vector_init_iota_constnconst_node<T>& operator=(const vector_init_iota_constnconst_node<T>&) exprtk_delete; + + mutable T* vector_base_; + const std::size_t size_; + std::vector<expression_ptr> initialiser_list_; + T base_value_; + }; + + template <typename T> + class vector_init_iota_nconstconst_node exprtk_final : public expression_node<T> + { + public: + + typedef expression_node<T>* expression_ptr; + + vector_init_iota_nconstconst_node(T* vector_base, + const std::size_t& size, + const std::vector<expression_ptr>& initialiser_list) + : vector_base_(vector_base) + , size_(size) + , initialiser_list_(initialiser_list) + { + assert(valid()); + } + + inline T value() const exprtk_override + { + T value = initialiser_list_[0]->value(); + const T increment = initialiser_list_[1]->value(); + + for (std::size_t i = 0; i < size_; ++i, value += increment) + { + *(vector_base_ + i) = value; + } + + return *(vector_base_); + } + + inline typename expression_node<T>::node_type type() const exprtk_override + { + return expression_node<T>::e_vecinit; + } + + inline bool valid() const exprtk_override + { + return vector_base_ && + (initialiser_list_.size() == 2) && + (!details::is_constant_node(initialiser_list_[0])) && + (details::is_constant_node(initialiser_list_[1])); + } + + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override + { + expression_node<T>::ndb_t::collect(initialiser_list_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node<T>::ndb_t::compute_node_depth(initialiser_list_); + } + + private: + + vector_init_iota_nconstconst_node(const vector_init_iota_nconstconst_node<T>&) exprtk_delete; + vector_init_iota_nconstconst_node<T>& operator=(const vector_init_iota_nconstconst_node<T>&) exprtk_delete; + + mutable T* vector_base_; + const std::size_t size_; + std::vector<expression_ptr> initialiser_list_; + }; + + template <typename T> + class vector_init_iota_nconstnconst_node exprtk_final : public expression_node<T> + { + public: + + typedef expression_node<T>* expression_ptr; + + vector_init_iota_nconstnconst_node(T* vector_base, + const std::size_t& size, + const std::vector<expression_ptr>& initialiser_list) + : vector_base_(vector_base) + , size_(size) + , initialiser_list_(initialiser_list) + { + assert(valid()); + } + + inline T value() const exprtk_override + { + T value = initialiser_list_[0]->value(); + expression_node<T>& increment = *initialiser_list_[1]; + + for (std::size_t i = 0; i < size_; ++i, value += increment.value()) + { + *(vector_base_ + i) = value; + } + + return *(vector_base_); + } + + inline typename expression_node<T>::node_type type() const exprtk_override + { + return expression_node<T>::e_vecinit; + } + + inline bool valid() const exprtk_override + { + return vector_base_ && + (initialiser_list_.size() == 2) && + (!details::is_constant_node(initialiser_list_[0])) && + (!details::is_constant_node(initialiser_list_[1])); + } + + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override + { + expression_node<T>::ndb_t::collect(initialiser_list_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node<T>::ndb_t::compute_node_depth(initialiser_list_); + } + + private: + + vector_init_iota_nconstnconst_node(const vector_init_iota_nconstnconst_node<T>&) exprtk_delete; + vector_init_iota_nconstnconst_node<T>& operator=(const vector_init_iota_nconstnconst_node<T>&) exprtk_delete; + + mutable T* vector_base_; + const std::size_t size_; + std::vector<expression_ptr> initialiser_list_; + }; + + template <typename T> + class swap_node exprtk_final : public expression_node<T> + { + public: + + typedef expression_node<T>* expression_ptr; + typedef variable_node<T>* variable_node_ptr; + + swap_node(variable_node_ptr var0, variable_node_ptr var1) + : var0_(var0) + , var1_(var1) + {} + + inline T value() const exprtk_override + { + std::swap(var0_->ref(),var1_->ref()); + return var1_->ref(); + } + + inline typename expression_node<T>::node_type type() const exprtk_override + { + return expression_node<T>::e_swap; + } + + private: + + variable_node_ptr var0_; + variable_node_ptr var1_; + }; + + template <typename T> + class swap_generic_node exprtk_final : public binary_node<T> + { + public: + + typedef expression_node<T>* expression_ptr; + typedef ivariable<T>* ivariable_ptr; + + swap_generic_node(expression_ptr var0, expression_ptr var1) + : binary_node<T>(details::e_swap, var0, var1) + , var0_(dynamic_cast<ivariable_ptr>(var0)) + , var1_(dynamic_cast<ivariable_ptr>(var1)) + {} + + inline T value() const exprtk_override + { + std::swap(var0_->ref(),var1_->ref()); + return var1_->ref(); + } + + inline typename expression_node<T>::node_type type() const exprtk_override + { + return expression_node<T>::e_swap; + } + + private: + + ivariable_ptr var0_; + ivariable_ptr var1_; + }; + + template <typename T> + class swap_vecvec_node exprtk_final + : public binary_node <T> + , public vector_interface<T> + { + public: + + typedef expression_node<T>* expression_ptr; + typedef vector_node <T>* vector_node_ptr; + typedef vec_data_store <T> vds_t; + + using binary_node<T>::branch; + + swap_vecvec_node(expression_ptr branch0, + expression_ptr branch1) + : binary_node<T>(details::e_swap, branch0, branch1) + , vec0_node_ptr_(0) + , vec1_node_ptr_(0) + , initialised_ (false) + { + if (is_ivector_node(branch(0))) + { + vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0); + + if (0 != (vi = dynamic_cast<vector_interface<T>*>(branch(0)))) + { + vec0_node_ptr_ = vi->vec(); + vds() = vi->vds(); + } + } + + if (is_ivector_node(branch(1))) + { + vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0); + + if (0 != (vi = dynamic_cast<vector_interface<T>*>(branch(1)))) + { + vec1_node_ptr_ = vi->vec(); + } + } + + if (vec0_node_ptr_ && vec1_node_ptr_) + { + initialised_ = size() <= base_size(); + } + + assert(valid()); + } + + inline T value() const exprtk_override + { + binary_node<T>::branch(0)->value(); + binary_node<T>::branch(1)->value(); + + T* vec0 = vec0_node_ptr_->vds().data(); + T* vec1 = vec1_node_ptr_->vds().data(); + + assert(size() <= base_size()); + const std::size_t n = size(); + + for (std::size_t i = 0; i < n; ++i) + { + std::swap(vec0[i],vec1[i]); + } + + return vec1_node_ptr_->value(); + } + + vector_node_ptr vec() const exprtk_override + { + return vec0_node_ptr_; + } + + vector_node_ptr vec() exprtk_override + { + return vec0_node_ptr_; + } + + inline typename expression_node<T>::node_type type() const exprtk_override + { + return expression_node<T>::e_vecvecswap; + } + + inline bool valid() const exprtk_override + { + return initialised_ && binary_node<T>::valid(); + } + + std::size_t size() const exprtk_override + { + return std::min( + vec0_node_ptr_->vec_holder().size(), + vec1_node_ptr_->vec_holder().size()); + } + + std::size_t base_size() const exprtk_override + { + return std::min( + vec0_node_ptr_->vec_holder().base_size(), + vec1_node_ptr_->vec_holder().base_size()); + } + + vds_t& vds() exprtk_override + { + return vds_; + } + + const vds_t& vds() const exprtk_override + { + return vds_; + } + + private: + + vector_node<T>* vec0_node_ptr_; + vector_node<T>* vec1_node_ptr_; + bool initialised_; + vds_t vds_; + }; + + #ifndef exprtk_disable_string_capabilities + template <typename T> + class stringvar_node exprtk_final + : public expression_node <T> + , public string_base_node<T> + , public range_interface <T> + { + public: + + typedef typename range_interface<T>::range_t range_t; + + static std::string null_value; + + explicit stringvar_node() + : value_(&null_value) + {} + + explicit stringvar_node(std::string& v) + : value_(&v) + { + rp_.n0_c = std::make_pair<bool,std::size_t>(true,0); + rp_.n1_c = std::make_pair<bool,std::size_t>(true,v.size()); + rp_.cache.first = rp_.n0_c.second; + rp_.cache.second = rp_.n1_c.second; + } + + inline bool operator <(const stringvar_node<T>& v) const + { + return this < (&v); + } + + inline T value() const exprtk_override + { + rp_.n1_c.second = (*value_).size(); + rp_.cache.second = rp_.n1_c.second; + + return std::numeric_limits<T>::quiet_NaN(); + } + + std::string str() const exprtk_override + { + return ref(); + } + + char_cptr base() const exprtk_override + { + return &(*value_)[0]; + } + + std::size_t size() const exprtk_override + { + return ref().size(); + } + + std::string& ref() + { + return (*value_); + } + + const std::string& ref() const + { + return (*value_); + } + + range_t& range_ref() exprtk_override + { + return rp_; + } + + const range_t& range_ref() const exprtk_override + { + return rp_; + } + + inline typename expression_node<T>::node_type type() const exprtk_override + { + return expression_node<T>::e_stringvar; + } + + void rebase(std::string& s) + { + value_ = &s; + rp_.n0_c = std::make_pair<bool,std::size_t>(true,0); + rp_.n1_c = std::make_pair<bool,std::size_t>(true,value_->size() - 1); + rp_.cache.first = rp_.n0_c.second; + rp_.cache.second = rp_.n1_c.second; + } + + private: + + std::string* value_; + mutable range_t rp_; + }; + + template <typename T> + std::string stringvar_node<T>::null_value = std::string(""); + + template <typename T> + class string_range_node exprtk_final + : public expression_node <T> + , public string_base_node<T> + , public range_interface <T> + { + public: + + typedef typename range_interface<T>::range_t range_t; + + static std::string null_value; + + explicit string_range_node(std::string& v, const range_t& rp) + : value_(&v) + , rp_(rp) + {} + + ~string_range_node() exprtk_override + { + rp_.free(); + } + + inline bool operator <(const string_range_node<T>& v) const + { + return this < (&v); + } + + inline T value() const exprtk_override + { + return std::numeric_limits<T>::quiet_NaN(); + } + + inline std::string str() const exprtk_override + { + return (*value_); + } + + char_cptr base() const exprtk_override + { + return &(*value_)[0]; + } + + std::size_t size() const exprtk_override + { + return ref().size(); + } + + inline range_t range() const + { + return rp_; + } + + inline virtual std::string& ref() + { + return (*value_); + } + + inline virtual const std::string& ref() const + { + return (*value_); + } + + inline range_t& range_ref() exprtk_override + { + return rp_; + } + + inline const range_t& range_ref() const exprtk_override + { + return rp_; + } + + inline typename expression_node<T>::node_type type() const exprtk_override + { + return expression_node<T>::e_stringvarrng; + } + + private: + + std::string* value_; + range_t rp_; + }; + + template <typename T> + std::string string_range_node<T>::null_value = std::string(""); + + template <typename T> + class const_string_range_node exprtk_final + : public expression_node <T> + , public string_base_node<T> + , public range_interface <T> + { + public: + + typedef typename range_interface<T>::range_t range_t; + + explicit const_string_range_node(const std::string& v, const range_t& rp) + : value_(v) + , rp_(rp) + {} + + ~const_string_range_node() exprtk_override + { + rp_.free(); + } + + inline T value() const exprtk_override + { + return std::numeric_limits<T>::quiet_NaN(); + } + + std::string str() const exprtk_override + { + return value_; + } + + char_cptr base() const exprtk_override + { + return value_.data(); + } + + std::size_t size() const exprtk_override + { + return value_.size(); + } + + range_t range() const + { + return rp_; + } + + range_t& range_ref() exprtk_override + { + return rp_; + } + + const range_t& range_ref() const exprtk_override + { + return rp_; + } + + inline typename expression_node<T>::node_type type() const exprtk_override + { + return expression_node<T>::e_cstringvarrng; + } + + private: + + const_string_range_node(const const_string_range_node<T>&) exprtk_delete; + const_string_range_node<T>& operator=(const const_string_range_node<T>&) exprtk_delete; + + const std::string value_; + range_t rp_; + }; + + template <typename T> + class generic_string_range_node exprtk_final + : public expression_node <T> + , public string_base_node<T> + , public range_interface <T> + { + public: + + typedef expression_node <T>* expression_ptr; + typedef stringvar_node <T>* strvar_node_ptr; + typedef string_base_node<T>* str_base_ptr; + typedef typename range_interface<T>::range_t range_t; + typedef range_t* range_ptr; + typedef range_interface<T> irange_t; + typedef irange_t* irange_ptr; + typedef std::pair<expression_ptr,bool> branch_t; + + generic_string_range_node(expression_ptr str_branch, const range_t& brange) + : initialised_(false) + , str_base_ptr_ (0) + , str_range_ptr_(0) + , base_range_(brange) + { + range_.n0_c = std::make_pair<bool,std::size_t>(true,0); + range_.n1_c = std::make_pair<bool,std::size_t>(true,0); + range_.cache.first = range_.n0_c.second; + range_.cache.second = range_.n1_c.second; + + construct_branch_pair(branch_, str_branch); + + if (is_generally_string_node(branch_.first)) + { + str_base_ptr_ = dynamic_cast<str_base_ptr>(branch_.first); + + if (0 == str_base_ptr_) + return; + + str_range_ptr_ = dynamic_cast<irange_ptr>(branch_.first); + + if (0 == str_range_ptr_) + return; + } + + initialised_ = (str_base_ptr_ && str_range_ptr_); + assert(valid()); + } + + ~generic_string_range_node() exprtk_override + { + base_range_.free(); + } + + inline T value() const exprtk_override + { + branch_.first->value(); + + std::size_t str_r0 = 0; + std::size_t str_r1 = 0; + + std::size_t r0 = 0; + std::size_t r1 = 0; + + const range_t& range = str_range_ptr_->range_ref(); + + const std::size_t base_str_size = str_base_ptr_->size(); + + if ( + range (str_r0, str_r1, base_str_size ) && + base_range_(r0 , r1 , base_str_size - str_r0) + ) + { + const std::size_t size = r1 - r0; + + range_.n1_c.second = size; + range_.cache.second = range_.n1_c.second; + + value_.assign(str_base_ptr_->base() + str_r0 + r0, size); + } + + return std::numeric_limits<T>::quiet_NaN(); + } + + std::string str() const exprtk_override + { + return value_; + } + + char_cptr base() const exprtk_override + { + return &value_[0]; + } + + std::size_t size() const exprtk_override + { + return value_.size(); + } + + range_t& range_ref() exprtk_override + { + return range_; + } + + const range_t& range_ref() const exprtk_override + { + return range_; + } + + inline typename expression_node<T>::node_type type() const exprtk_override + { + return expression_node<T>::e_strgenrange; + } + + inline bool valid() const exprtk_override + { + return initialised_ && branch_.first; + } + + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override + { + expression_node<T>::ndb_t::collect(branch_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node<T>::ndb_t::compute_node_depth(branch_); + } + + private: + + bool initialised_; + branch_t branch_; + str_base_ptr str_base_ptr_; + irange_ptr str_range_ptr_; + mutable range_t base_range_; + mutable range_t range_; + mutable std::string value_; + }; + + template <typename T> + class string_concat_node exprtk_final + : public binary_node <T> + , public string_base_node<T> + , public range_interface <T> + { + public: + + typedef typename range_interface<T>::range_t range_t; + typedef range_interface<T> irange_t; + typedef irange_t* irange_ptr; + typedef range_t* range_ptr; + typedef expression_node <T>* expression_ptr; + typedef string_base_node<T>* str_base_ptr; + + using binary_node<T>::branch; + + string_concat_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node<T>(opr, branch0, branch1) + , initialised_(false) + , str0_base_ptr_ (0) + , str1_base_ptr_ (0) + , str0_range_ptr_(0) + , str1_range_ptr_(0) + { + range_.n0_c = std::make_pair<bool,std::size_t>(true,0); + range_.n1_c = std::make_pair<bool,std::size_t>(true,0); + + range_.cache.first = range_.n0_c.second; + range_.cache.second = range_.n1_c.second; + + if (is_generally_string_node(branch(0))) + { + str0_base_ptr_ = dynamic_cast<str_base_ptr>(branch(0)); if (0 == str0_base_ptr_) return; - str0_range_ptr_ = dynamic_cast<irange_ptr>(binary_node<T>::branch_[0].first); + str0_range_ptr_ = dynamic_cast<irange_ptr>(branch(0)); if (0 == str0_range_ptr_) return; } - if (is_generally_string_node(binary_node<T>::branch_[1].first)) + if (is_generally_string_node(branch(1))) { - str1_base_ptr_ = dynamic_cast<str_base_ptr>(binary_node<T>::branch_[1].first); + str1_base_ptr_ = dynamic_cast<str_base_ptr>(branch(1)); if (0 == str1_base_ptr_) return; - str1_range_ptr_ = dynamic_cast<irange_ptr>(binary_node<T>::branch_[1].first); + str1_range_ptr_ = dynamic_cast<irange_ptr>(branch(1)); if (0 == str1_range_ptr_) return; @@ -8543,167 +10568,171 @@ namespace exprtk str1_base_ptr_ && str0_range_ptr_ && str1_range_ptr_ ; + + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { - if (initialised_) - { - assert(binary_node<T>::branch_[0].first); - assert(binary_node<T>::branch_[1].first); - - binary_node<T>::branch_[0].first->value(); - binary_node<T>::branch_[1].first->value(); + branch(0)->value(); + branch(1)->value(); - std::size_t str0_r0 = 0; - std::size_t str0_r1 = 0; + std::size_t str0_r0 = 0; + std::size_t str0_r1 = 0; - std::size_t str1_r0 = 0; - std::size_t str1_r1 = 0; + std::size_t str1_r0 = 0; + std::size_t str1_r1 = 0; - const range_t& range0 = str0_range_ptr_->range_ref(); - const range_t& range1 = str1_range_ptr_->range_ref(); + const range_t& range0 = str0_range_ptr_->range_ref(); + const range_t& range1 = str1_range_ptr_->range_ref(); - if ( - range0(str0_r0, str0_r1, str0_base_ptr_->size()) && - range1(str1_r0, str1_r1, str1_base_ptr_->size()) - ) - { - const std::size_t size0 = (str0_r1 - str0_r0) + 1; - const std::size_t size1 = (str1_r1 - str1_r0) + 1; + if ( + range0(str0_r0, str0_r1, str0_base_ptr_->size()) && + range1(str1_r0, str1_r1, str1_base_ptr_->size()) + ) + { + const std::size_t size0 = (str0_r1 - str0_r0); + const std::size_t size1 = (str1_r1 - str1_r0); - value_.assign(str0_base_ptr_->base() + str0_r0, size0); - value_.append(str1_base_ptr_->base() + str1_r0, size1); + value_.assign(str0_base_ptr_->base() + str0_r0, size0); + value_.append(str1_base_ptr_->base() + str1_r0, size1); - range_.n1_c.second = value_.size() - 1; - range_.cache.second = range_.n1_c.second; - } + range_.n1_c.second = value_.size(); + range_.cache.second = range_.n1_c.second; } return std::numeric_limits<T>::quiet_NaN(); } - std::string str() const override + std::string str() const exprtk_override { return value_; } - char_cptr base() const override + char_cptr base() const exprtk_override { return &value_[0]; } - std::size_t size() const override + std::size_t size() const exprtk_override { return value_.size(); } - range_t& range_ref() override + range_t& range_ref() exprtk_override { return range_; } - const range_t& range_ref() const override + const range_t& range_ref() const exprtk_override { return range_; } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_strconcat; } + inline bool valid() const exprtk_override + { + return initialised_ && binary_node<T>::valid(); + } + private: - bool initialised_; - str_base_ptr str0_base_ptr_; - str_base_ptr str1_base_ptr_; - irange_ptr str0_range_ptr_; - irange_ptr str1_range_ptr_; + bool initialised_; + str_base_ptr str0_base_ptr_; + str_base_ptr str1_base_ptr_; + irange_ptr str0_range_ptr_; + irange_ptr str1_range_ptr_; mutable range_t range_; mutable std::string value_; }; template <typename T> - class swap_string_node : public binary_node <T>, - public string_base_node<T>, - public range_interface <T> + class swap_string_node exprtk_final + : public binary_node <T> + , public string_base_node<T> + , public range_interface <T> { public: - typedef expression_node <T>* expression_ptr; + typedef typename range_interface<T>::range_t range_t; + typedef range_t* range_ptr; + typedef range_interface<T> irange_t; + typedef irange_t* irange_ptr; + typedef expression_node <T>* expression_ptr; typedef stringvar_node <T>* strvar_node_ptr; - typedef string_base_node<T>* str_base_ptr; - typedef range_pack <T> range_t; - typedef range_t* range_ptr; - typedef range_interface<T> irange_t; - typedef irange_t* irange_ptr; + typedef string_base_node<T>* str_base_ptr; + + using binary_node<T>::branch; swap_string_node(expression_ptr branch0, expression_ptr branch1) - : binary_node<T>(details::e_swap, branch0, branch1), - initialised_(false), - str0_node_ptr_(0), - str1_node_ptr_(0) + : binary_node<T>(details::e_swap, branch0, branch1) + , initialised_(false) + , str0_node_ptr_(0) + , str1_node_ptr_(0) { - if (is_string_node(binary_node<T>::branch_[0].first)) + if (is_string_node(branch(0))) { - str0_node_ptr_ = static_cast<strvar_node_ptr>(binary_node<T>::branch_[0].first); + str0_node_ptr_ = static_cast<strvar_node_ptr>(branch(0)); } - if (is_string_node(binary_node<T>::branch_[1].first)) + if (is_string_node(branch(1))) { - str1_node_ptr_ = static_cast<strvar_node_ptr>(binary_node<T>::branch_[1].first); + str1_node_ptr_ = static_cast<strvar_node_ptr>(branch(1)); } initialised_ = (str0_node_ptr_ && str1_node_ptr_); + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { - if (initialised_) - { - assert(binary_node<T>::branch_[0].first); - assert(binary_node<T>::branch_[1].first); + branch(0)->value(); + branch(1)->value(); - binary_node<T>::branch_[0].first->value(); - binary_node<T>::branch_[1].first->value(); - - std::swap(str0_node_ptr_->ref(), str1_node_ptr_->ref()); - } + std::swap(str0_node_ptr_->ref(), str1_node_ptr_->ref()); return std::numeric_limits<T>::quiet_NaN(); } - std::string str() const override + std::string str() const exprtk_override { return str0_node_ptr_->str(); } - char_cptr base() const override + char_cptr base() const exprtk_override { return str0_node_ptr_->base(); } - std::size_t size() const override + std::size_t size() const exprtk_override { return str0_node_ptr_->size(); } - range_t& range_ref() override + range_t& range_ref() exprtk_override { return str0_node_ptr_->range_ref(); } - const range_t& range_ref() const override + const range_t& range_ref() const exprtk_override { return str0_node_ptr_->range_ref(); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_strswap; } + inline bool valid() const exprtk_override + { + return initialised_ && binary_node<T>::valid(); + } + private: bool initialised_; @@ -8712,34 +10741,36 @@ namespace exprtk }; template <typename T> - class swap_genstrings_node : public binary_node<T> + class swap_genstrings_node exprtk_final : public binary_node<T> { public: + typedef typename range_interface<T>::range_t range_t; + typedef range_t* range_ptr; + typedef range_interface<T> irange_t; + typedef irange_t* irange_ptr; typedef expression_node <T>* expression_ptr; - typedef string_base_node<T>* str_base_ptr; - typedef range_pack <T> range_t; - typedef range_t* range_ptr; - typedef range_interface<T> irange_t; - typedef irange_t* irange_ptr; + typedef string_base_node<T>* str_base_ptr; + + using binary_node<T>::branch; swap_genstrings_node(expression_ptr branch0, expression_ptr branch1) - : binary_node<T>(details::e_default, branch0, branch1), - str0_base_ptr_ (0), - str1_base_ptr_ (0), - str0_range_ptr_(0), - str1_range_ptr_(0), - initialised_(false) + : binary_node<T>(details::e_default, branch0, branch1) + , str0_base_ptr_ (0) + , str1_base_ptr_ (0) + , str0_range_ptr_(0) + , str1_range_ptr_(0) + , initialised_(false) { - if (is_generally_string_node(binary_node<T>::branch_[0].first)) + if (is_generally_string_node(branch(0))) { - str0_base_ptr_ = dynamic_cast<str_base_ptr>(binary_node<T>::branch_[0].first); + str0_base_ptr_ = dynamic_cast<str_base_ptr>(branch(0)); if (0 == str0_base_ptr_) return; - irange_ptr range = dynamic_cast<irange_ptr>(binary_node<T>::branch_[0].first); + irange_ptr range = dynamic_cast<irange_ptr>(branch(0)); if (0 == range) return; @@ -8747,14 +10778,14 @@ namespace exprtk str0_range_ptr_ = &(range->range_ref()); } - if (is_generally_string_node(binary_node<T>::branch_[1].first)) + if (is_generally_string_node(branch(1))) { - str1_base_ptr_ = dynamic_cast<str_base_ptr>(binary_node<T>::branch_[1].first); + str1_base_ptr_ = dynamic_cast<str_base_ptr>(branch(1)); if (0 == str1_base_ptr_) return; - irange_ptr range = dynamic_cast<irange_ptr>(binary_node<T>::branch_[1].first); + irange_ptr range = dynamic_cast<irange_ptr>(branch(1)); if (0 == range) return; @@ -8766,100 +10797,101 @@ namespace exprtk str1_base_ptr_ && str0_range_ptr_ && str1_range_ptr_ ; + + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { - if (initialised_) - { - assert(binary_node<T>::branch_[0].first); - assert(binary_node<T>::branch_[1].first); + branch(0)->value(); + branch(1)->value(); - binary_node<T>::branch_[0].first->value(); - binary_node<T>::branch_[1].first->value(); + std::size_t str0_r0 = 0; + std::size_t str0_r1 = 0; - std::size_t str0_r0 = 0; - std::size_t str0_r1 = 0; + std::size_t str1_r0 = 0; + std::size_t str1_r1 = 0; - std::size_t str1_r0 = 0; - std::size_t str1_r1 = 0; + const range_t& range0 = (*str0_range_ptr_); + const range_t& range1 = (*str1_range_ptr_); - const range_t& range0 = (*str0_range_ptr_); - const range_t& range1 = (*str1_range_ptr_); + if ( + range0(str0_r0, str0_r1, str0_base_ptr_->size()) && + range1(str1_r0, str1_r1, str1_base_ptr_->size()) + ) + { + const std::size_t size0 = range0.cache_size(); + const std::size_t size1 = range1.cache_size(); + const std::size_t max_size = std::min(size0,size1); - if ( - range0(str0_r0, str0_r1, str0_base_ptr_->size()) && - range1(str1_r0, str1_r1, str1_base_ptr_->size()) - ) - { - const std::size_t size0 = range0.cache_size(); - const std::size_t size1 = range1.cache_size(); - const std::size_t max_size = std::min(size0,size1); + char_ptr s0 = const_cast<char_ptr>(str0_base_ptr_->base() + str0_r0); + char_ptr s1 = const_cast<char_ptr>(str1_base_ptr_->base() + str1_r0); - char_ptr s0 = const_cast<char_ptr>(str0_base_ptr_->base() + str0_r0); - char_ptr s1 = const_cast<char_ptr>(str1_base_ptr_->base() + str1_r0); + loop_unroll::details lud(max_size); + char_cptr upper_bound = s0 + lud.upper_bound; - loop_unroll::details lud(max_size); - char_cptr upper_bound = s0 + lud.upper_bound; + while (s0 < upper_bound) + { + #define exprtk_loop(N) \ + std::swap(s0[N], s1[N]); \ - while (s0 < upper_bound) - { - #define exprtk_loop(N) \ - std::swap(s0[N], s1[N]); \ - - exprtk_loop( 0) exprtk_loop( 1) - exprtk_loop( 2) exprtk_loop( 3) - #ifndef exprtk_disable_superscalar_unroll - exprtk_loop( 4) exprtk_loop( 5) - exprtk_loop( 6) exprtk_loop( 7) - exprtk_loop( 8) exprtk_loop( 9) - exprtk_loop(10) exprtk_loop(11) - exprtk_loop(12) exprtk_loop(13) - exprtk_loop(14) exprtk_loop(15) - #endif - - s0 += lud.batch_size; - s1 += lud.batch_size; - } + exprtk_loop( 0) exprtk_loop( 1) + exprtk_loop( 2) exprtk_loop( 3) + #ifndef exprtk_disable_superscalar_unroll + exprtk_loop( 4) exprtk_loop( 5) + exprtk_loop( 6) exprtk_loop( 7) + exprtk_loop( 8) exprtk_loop( 9) + exprtk_loop(10) exprtk_loop(11) + exprtk_loop(12) exprtk_loop(13) + exprtk_loop(14) exprtk_loop(15) + #endif - int i = 0; + s0 += lud.batch_size; + s1 += lud.batch_size; + } - exprtk_disable_fallthrough_begin - switch (lud.remainder) - { - #define case_stmt(N) \ - case N : { std::swap(s0[i], s1[i]); ++i; } \ - - #ifndef exprtk_disable_superscalar_unroll - case_stmt(15) case_stmt(14) - case_stmt(13) case_stmt(12) - case_stmt(11) case_stmt(10) - case_stmt( 9) case_stmt( 8) - case_stmt( 7) case_stmt( 6) - case_stmt( 5) case_stmt( 4) - #endif - case_stmt( 3) case_stmt( 2) - case_stmt( 1) - } - exprtk_disable_fallthrough_end + int i = 0; - #undef exprtk_loop - #undef case_stmt + switch (lud.remainder) + { + #define case_stmt(N) \ + case N : { std::swap(s0[i], s1[i]); ++i; } \ + exprtk_fallthrough \ + + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15) case_stmt(14) + case_stmt(13) case_stmt(12) + case_stmt(11) case_stmt(10) + case_stmt( 9) case_stmt( 8) + case_stmt( 7) case_stmt( 6) + case_stmt( 5) case_stmt( 4) + #endif + case_stmt( 3) case_stmt( 2) + case_stmt( 1) + default: break; } + + #undef exprtk_loop + #undef case_stmt } return std::numeric_limits<T>::quiet_NaN(); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_strswap; } + inline bool valid() const exprtk_override + { + return initialised_ && binary_node<T>::valid(); + } + private: - swap_genstrings_node(swap_genstrings_node<T>&); - swap_genstrings_node<T>& operator=(swap_genstrings_node<T>&); + swap_genstrings_node(const swap_genstrings_node<T>&) exprtk_delete; + swap_genstrings_node<T>& operator=(const swap_genstrings_node<T>&) exprtk_delete; str_base_ptr str0_base_ptr_; str_base_ptr str1_base_ptr_; @@ -8869,11 +10901,11 @@ namespace exprtk }; template <typename T> - class stringvar_size_node : public expression_node<T> + class stringvar_size_node exprtk_final : public expression_node<T> { public: - static std::string null_value; + static const std::string null_value; explicit stringvar_size_node() : value_(&null_value) @@ -8883,34 +10915,33 @@ namespace exprtk : value_(&v) {} - inline T value() const override + inline T value() const exprtk_override { return T((*value_).size()); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_stringvarsize; } private: - std::string* value_; + const std::string* value_; }; template <typename T> - std::string stringvar_size_node<T>::null_value = std::string(""); + const std::string stringvar_size_node<T>::null_value = std::string(""); template <typename T> - class string_size_node : public expression_node<T> + class string_size_node exprtk_final : public expression_node<T> { public: - typedef expression_node <T>* expression_ptr; - typedef string_base_node<T>* str_base_ptr; + typedef expression_node <T>* expression_ptr; + typedef string_base_node<T>* str_base_ptr; typedef std::pair<expression_ptr,bool> branch_t; - explicit string_size_node(expression_ptr branch) : str_base_ptr_(0) { @@ -8919,43 +10950,40 @@ namespace exprtk if (is_generally_string_node(branch_.first)) { str_base_ptr_ = dynamic_cast<str_base_ptr>(branch_.first); - - if (0 == str_base_ptr_) - return; } + + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { - T result = std::numeric_limits<T>::quiet_NaN(); - - if (str_base_ptr_) - { - branch_.first->value(); - result = T(str_base_ptr_->size()); - } - - return result; + branch_.first->value(); + return T(str_base_ptr_->size()); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_stringsize; } - void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) override + inline bool valid() const exprtk_override + { + return str_base_ptr_; + } + + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override { expression_node<T>::ndb_t::collect(branch_, node_delete_list); } - std::size_t node_depth() const override + std::size_t node_depth() const exprtk_override { return expression_node<T>::ndb_t::compute_node_depth(branch_); } private: - branch_t branch_; + branch_t branch_; str_base_ptr str_base_ptr_; }; @@ -8972,45 +11000,47 @@ namespace exprtk }; template <typename T, typename AssignmentProcess = asn_assignment> - class assignment_string_node : public binary_node <T>, - public string_base_node<T>, - public range_interface <T> + class assignment_string_node exprtk_final + : public binary_node <T> + , public string_base_node<T> + , public range_interface <T> { public: - typedef expression_node <T>* expression_ptr; + typedef typename range_interface<T>::range_t range_t; + typedef range_t* range_ptr; + typedef range_interface <T> irange_t; + typedef irange_t* irange_ptr; + typedef expression_node <T>* expression_ptr; typedef stringvar_node <T>* strvar_node_ptr; - typedef string_base_node<T>* str_base_ptr; - typedef range_pack <T> range_t; - typedef range_t* range_ptr; - typedef range_interface<T> irange_t; - typedef irange_t* irange_ptr; + typedef string_base_node<T>* str_base_ptr; + + using binary_node<T>::branch; assignment_string_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) - : binary_node<T>(opr, branch0, branch1), - initialised_(false), - str0_base_ptr_ (0), - str1_base_ptr_ (0), - str0_node_ptr_ (0), - str1_range_ptr_(0) + : binary_node<T>(opr, branch0, branch1) + , initialised_(false) + , str0_base_ptr_ (0) + , str1_base_ptr_ (0) + , str0_node_ptr_ (0) + , str1_range_ptr_(0) { - if (is_string_node(binary_node<T>::branch_[0].first)) + if (is_string_node(branch(0))) { - str0_node_ptr_ = static_cast<strvar_node_ptr>(binary_node<T>::branch_[0].first); - - str0_base_ptr_ = dynamic_cast<str_base_ptr>(binary_node<T>::branch_[0].first); + str0_node_ptr_ = static_cast<strvar_node_ptr>(branch(0)); + str0_base_ptr_ = dynamic_cast<str_base_ptr>(branch(0)); } - if (is_generally_string_node(binary_node<T>::branch_[1].first)) + if (is_generally_string_node(branch(1))) { - str1_base_ptr_ = dynamic_cast<str_base_ptr>(binary_node<T>::branch_[1].first); + str1_base_ptr_ = dynamic_cast<str_base_ptr>(branch(1)); if (0 == str1_base_ptr_) return; - irange_ptr range = dynamic_cast<irange_ptr>(binary_node<T>::branch_[1].first); + irange_ptr range = dynamic_cast<irange_ptr>(branch(1)); if (0 == range) return; @@ -9022,65 +11052,66 @@ namespace exprtk str1_base_ptr_ && str0_node_ptr_ && str1_range_ptr_ ; + + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { - if (initialised_) - { - assert(binary_node<T>::branch_[0].first); - assert(binary_node<T>::branch_[1].first); - - binary_node<T>::branch_[1].first->value(); + branch(1)->value(); - std::size_t r0 = 0; - std::size_t r1 = 0; + std::size_t r0 = 0; + std::size_t r1 = 0; - const range_t& range = (*str1_range_ptr_); + const range_t& range = (*str1_range_ptr_); - if (range(r0, r1, str1_base_ptr_->size())) - { - AssignmentProcess::execute(str0_node_ptr_->ref(), - str1_base_ptr_->base() + r0, - (r1 - r0) + 1); + if (range(r0, r1, str1_base_ptr_->size())) + { + AssignmentProcess::execute( + str0_node_ptr_->ref(), + str1_base_ptr_->base() + r0, (r1 - r0)); - binary_node<T>::branch_[0].first->value(); - } + branch(0)->value(); } return std::numeric_limits<T>::quiet_NaN(); } - std::string str() const override + std::string str() const exprtk_override { return str0_node_ptr_->str(); } - char_cptr base() const override + char_cptr base() const exprtk_override { return str0_node_ptr_->base(); } - std::size_t size() const override + std::size_t size() const exprtk_override { return str0_node_ptr_->size(); } - range_t& range_ref() override + range_t& range_ref() exprtk_override { return str0_node_ptr_->range_ref(); } - const range_t& range_ref() const override + const range_t& range_ref() const exprtk_override { return str0_node_ptr_->range_ref(); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_strass; } + inline bool valid() const exprtk_override + { + return initialised_ && binary_node<T>::valid(); + } + private: bool initialised_; @@ -9091,39 +11122,40 @@ namespace exprtk }; template <typename T, typename AssignmentProcess = asn_assignment> - class assignment_string_range_node : public binary_node <T>, - public string_base_node<T>, - public range_interface <T> + class assignment_string_range_node exprtk_final + : public binary_node <T> + , public string_base_node<T> + , public range_interface <T> { public: - typedef expression_node <T>* expression_ptr; - typedef stringvar_node <T>* strvar_node_ptr; + typedef typename range_interface<T>::range_t range_t; + typedef range_t* range_ptr; + typedef range_interface <T> irange_t; + typedef irange_t* irange_ptr; + typedef expression_node <T>* expression_ptr; + typedef stringvar_node <T>* strvar_node_ptr; typedef string_range_node<T>* str_rng_node_ptr; - typedef string_base_node <T>* str_base_ptr; - typedef range_pack <T> range_t; - typedef range_t* range_ptr; - typedef range_interface<T> irange_t; - typedef irange_t* irange_ptr; + typedef string_base_node <T>* str_base_ptr; + + using binary_node<T>::branch; assignment_string_range_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) - : binary_node<T>(opr, branch0, branch1), - initialised_(false), - str0_base_ptr_ (0), - str1_base_ptr_ (0), - str0_rng_node_ptr_ (0), - str0_range_ptr_ (0), - str1_range_ptr_ (0) + : binary_node<T>(opr, branch0, branch1) + , initialised_(false) + , str0_base_ptr_ (0) + , str1_base_ptr_ (0) + , str0_rng_node_ptr_(0) + , str0_range_ptr_ (0) + , str1_range_ptr_ (0) { - if (is_string_range_node(binary_node<T>::branch_[0].first)) + if (is_string_range_node(branch(0))) { - str0_rng_node_ptr_ = static_cast<str_rng_node_ptr>(binary_node<T>::branch_[0].first); - - str0_base_ptr_ = dynamic_cast<str_base_ptr>(binary_node<T>::branch_[0].first); - - irange_ptr range = dynamic_cast<irange_ptr>(binary_node<T>::branch_[0].first); + str0_rng_node_ptr_ = static_cast<str_rng_node_ptr>(branch(0)); + str0_base_ptr_ = dynamic_cast<str_base_ptr>(branch(0)); + irange_ptr range = dynamic_cast<irange_ptr>(branch(0)); if (0 == range) return; @@ -9131,14 +11163,14 @@ namespace exprtk str0_range_ptr_ = &(range->range_ref()); } - if (is_generally_string_node(binary_node<T>::branch_[1].first)) + if (is_generally_string_node(branch(1))) { - str1_base_ptr_ = dynamic_cast<str_base_ptr>(binary_node<T>::branch_[1].first); + str1_base_ptr_ = dynamic_cast<str_base_ptr>(branch(1)); if (0 == str1_base_ptr_) return; - irange_ptr range = dynamic_cast<irange_ptr>(binary_node<T>::branch_[1].first); + irange_ptr range = dynamic_cast<irange_ptr>(branch(1)); if (0 == range) return; @@ -9151,73 +11183,75 @@ namespace exprtk str0_rng_node_ptr_ && str0_range_ptr_ && str1_range_ptr_ ; + + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { - if (initialised_) - { - assert(binary_node<T>::branch_[0].first); - assert(binary_node<T>::branch_[1].first); - - binary_node<T>::branch_[0].first->value(); - binary_node<T>::branch_[1].first->value(); + branch(0)->value(); + branch(1)->value(); - std::size_t s0_r0 = 0; - std::size_t s0_r1 = 0; + std::size_t s0_r0 = 0; + std::size_t s0_r1 = 0; - std::size_t s1_r0 = 0; - std::size_t s1_r1 = 0; + std::size_t s1_r0 = 0; + std::size_t s1_r1 = 0; - const range_t& range0 = (*str0_range_ptr_); - const range_t& range1 = (*str1_range_ptr_); + const range_t& range0 = (*str0_range_ptr_); + const range_t& range1 = (*str1_range_ptr_); - if ( - range0(s0_r0, s0_r1, str0_base_ptr_->size()) && - range1(s1_r0, s1_r1, str1_base_ptr_->size()) - ) - { - const std::size_t size = std::min((s0_r1 - s0_r0), (s1_r1 - s1_r0)) + 1; + if ( + range0(s0_r0, s0_r1, str0_base_ptr_->size()) && + range1(s1_r0, s1_r1, str1_base_ptr_->size()) + ) + { + const std::size_t size = std::min((s0_r1 - s0_r0), (s1_r1 - s1_r0)); - std::copy(str1_base_ptr_->base() + s1_r0, - str1_base_ptr_->base() + s1_r0 + size, - const_cast<char_ptr>(base() + s0_r0)); - } + std::copy( + str1_base_ptr_->base() + s1_r0, + str1_base_ptr_->base() + s1_r0 + size, + const_cast<char_ptr>(base() + s0_r0)); } return std::numeric_limits<T>::quiet_NaN(); } - std::string str() const override + std::string str() const exprtk_override { return str0_base_ptr_->str(); } - char_cptr base() const override + char_cptr base() const exprtk_override { return str0_base_ptr_->base(); } - std::size_t size() const override + std::size_t size() const exprtk_override { return str0_base_ptr_->size(); } - range_t& range_ref() override + range_t& range_ref() exprtk_override { return str0_rng_node_ptr_->range_ref(); } - const range_t& range_ref() const override + const range_t& range_ref() const exprtk_override { return str0_rng_node_ptr_->range_ref(); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_strass; } + inline bool valid() const exprtk_override + { + return initialised_ && binary_node<T>::valid(); + } + private: bool initialised_; @@ -9229,31 +11263,32 @@ namespace exprtk }; template <typename T> - class conditional_string_node : public trinary_node <T>, - public string_base_node<T>, - public range_interface <T> + class conditional_string_node exprtk_final + : public trinary_node <T> + , public string_base_node<T> + , public range_interface <T> { public: + typedef typename range_interface<T>::range_t range_t; + typedef range_t* range_ptr; + typedef range_interface <T> irange_t; + typedef irange_t* irange_ptr; typedef expression_node <T>* expression_ptr; - typedef string_base_node<T>* str_base_ptr; - typedef range_pack <T> range_t; - typedef range_t* range_ptr; - typedef range_interface<T> irange_t; - typedef irange_t* irange_ptr; + typedef string_base_node<T>* str_base_ptr; conditional_string_node(expression_ptr condition, expression_ptr consequent, expression_ptr alternative) - : trinary_node<T>(details::e_default,consequent,alternative,condition), - initialised_(false), - str0_base_ptr_ (0), - str1_base_ptr_ (0), - str0_range_ptr_(0), - str1_range_ptr_(0), - condition_ (condition), - consequent_ (consequent), - alternative_(alternative) + : trinary_node<T>(details::e_default, consequent, alternative, condition) + , initialised_(false) + , str0_base_ptr_ (0) + , str1_base_ptr_ (0) + , str0_range_ptr_(0) + , str1_range_ptr_(0) + , condition_ (condition ) + , consequent_ (consequent ) + , alternative_(alternative) { range_.n0_c = std::make_pair<bool,std::size_t>(true,0); range_.n1_c = std::make_pair<bool,std::size_t>(true,0); @@ -9292,90 +11327,93 @@ namespace exprtk str0_range_ptr_ && str1_range_ptr_ ; + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { - if (initialised_) + std::size_t r0 = 0; + std::size_t r1 = 0; + + if (is_true(condition_)) { - assert(condition_ ); - assert(consequent_ ); - assert(alternative_); + consequent_->value(); - std::size_t r0 = 0; - std::size_t r1 = 0; + const range_t& range = str0_range_ptr_->range_ref(); - if (is_true(condition_)) + if (range(r0, r1, str0_base_ptr_->size())) { - consequent_->value(); - - const range_t& range = str0_range_ptr_->range_ref(); + const std::size_t size = (r1 - r0); - if (range(r0, r1, str0_base_ptr_->size())) - { - const std::size_t size = (r1 - r0) + 1; + value_.assign(str0_base_ptr_->base() + r0, size); - value_.assign(str0_base_ptr_->base() + r0, size); - - range_.n1_c.second = value_.size() - 1; - range_.cache.second = range_.n1_c.second; + range_.n1_c.second = value_.size(); + range_.cache.second = range_.n1_c.second; - return T(1); - } + return T(1); } - else - { - alternative_->value(); + } + else + { + alternative_->value(); - const range_t& range = str1_range_ptr_->range_ref(); + const range_t& range = str1_range_ptr_->range_ref(); - if (range(r0, r1, str1_base_ptr_->size())) - { - const std::size_t size = (r1 - r0) + 1; + if (range(r0, r1, str1_base_ptr_->size())) + { + const std::size_t size = (r1 - r0); - value_.assign(str1_base_ptr_->base() + r0, size); + value_.assign(str1_base_ptr_->base() + r0, size); - range_.n1_c.second = value_.size() - 1; - range_.cache.second = range_.n1_c.second; + range_.n1_c.second = value_.size(); + range_.cache.second = range_.n1_c.second; - return T(0); - } + return T(0); } } return std::numeric_limits<T>::quiet_NaN(); } - std::string str() const override + std::string str() const exprtk_override { return value_; } - char_cptr base() const override + char_cptr base() const exprtk_override { return &value_[0]; } - std::size_t size() const override + std::size_t size() const exprtk_override { return value_.size(); } - range_t& range_ref() override + range_t& range_ref() exprtk_override { return range_; } - const range_t& range_ref() const override + const range_t& range_ref() const exprtk_override { return range_; } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_strcondition; } + inline bool valid() const exprtk_override + { + return + initialised_ && + condition_ && condition_ ->valid() && + consequent_ && consequent_ ->valid() && + alternative_&& alternative_->valid() ; + } + private: bool initialised_; @@ -9392,27 +11430,30 @@ namespace exprtk }; template <typename T> - class cons_conditional_str_node : public binary_node <T>, - public string_base_node<T>, - public range_interface <T> + class cons_conditional_str_node exprtk_final + : public binary_node <T> + , public string_base_node<T> + , public range_interface <T> { public: + typedef typename range_interface<T>::range_t range_t; + typedef range_t* range_ptr; + typedef range_interface <T> irange_t; + typedef irange_t* irange_ptr; typedef expression_node <T>* expression_ptr; - typedef string_base_node<T>* str_base_ptr; - typedef range_pack <T> range_t; - typedef range_t* range_ptr; - typedef range_interface<T> irange_t; - typedef irange_t* irange_ptr; + typedef string_base_node<T>* str_base_ptr; + + using binary_node<T>::branch; cons_conditional_str_node(expression_ptr condition, expression_ptr consequent) - : binary_node<T>(details::e_default, consequent, condition), - initialised_(false), - str0_base_ptr_ (0), - str0_range_ptr_(0), - condition_ (condition), - consequent_(consequent) + : binary_node<T>(details::e_default, consequent, condition) + , initialised_(false) + , str0_base_ptr_ (0) + , str0_range_ptr_(0) + , condition_ (condition ) + , consequent_(consequent) { range_.n0_c = std::make_pair<bool,std::size_t>(true,0); range_.n1_c = std::make_pair<bool,std::size_t>(true,0); @@ -9420,85 +11461,88 @@ namespace exprtk range_.cache.first = range_.n0_c.second; range_.cache.second = range_.n1_c.second; - if (is_generally_string_node(binary_node<T>::branch_[0].first)) + if (is_generally_string_node(branch(0))) { - str0_base_ptr_ = dynamic_cast<str_base_ptr>(binary_node<T>::branch_[0].first); + str0_base_ptr_ = dynamic_cast<str_base_ptr>(branch(0)); if (0 == str0_base_ptr_) return; - str0_range_ptr_ = dynamic_cast<irange_ptr>(binary_node<T>::branch_[0].first); + str0_range_ptr_ = dynamic_cast<irange_ptr>(branch(0)); if (0 == str0_range_ptr_) return; } initialised_ = str0_base_ptr_ && str0_range_ptr_ ; + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { - if (initialised_) + if (is_true(condition_)) { - assert(condition_ ); - assert(consequent_); + consequent_->value(); - if (is_true(condition_)) - { - consequent_->value(); - - const range_t& range = str0_range_ptr_->range_ref(); + const range_t& range = str0_range_ptr_->range_ref(); - std::size_t r0 = 0; - std::size_t r1 = 0; + std::size_t r0 = 0; + std::size_t r1 = 0; - if (range(r0, r1, str0_base_ptr_->size())) - { - const std::size_t size = (r1 - r0) + 1; + if (range(r0, r1, str0_base_ptr_->size())) + { + const std::size_t size = (r1 - r0); - value_.assign(str0_base_ptr_->base() + r0, size); + value_.assign(str0_base_ptr_->base() + r0, size); - range_.n1_c.second = value_.size() - 1; - range_.cache.second = range_.n1_c.second; + range_.n1_c.second = value_.size(); + range_.cache.second = range_.n1_c.second; - return T(1); - } + return T(1); } } return std::numeric_limits<T>::quiet_NaN(); } - std::string str() const override + std::string str() const exprtk_override { return value_; } - char_cptr base() const override + char_cptr base() const exprtk_override { return &value_[0]; } - std::size_t size() const override + std::size_t size() const exprtk_override { return value_.size(); } - range_t& range_ref() override + range_t& range_ref() exprtk_override { return range_; } - const range_t& range_ref() const override + const range_t& range_ref() const exprtk_override { return range_; } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_strccondition; } + inline bool valid() const exprtk_override + { + return + initialised_ && + condition_ && condition_ ->valid() && + consequent_ && consequent_ ->valid() ; + } + private: bool initialised_; @@ -9512,26 +11556,27 @@ namespace exprtk }; template <typename T, typename VarArgFunction> - class str_vararg_node : public expression_node <T>, - public string_base_node<T>, - public range_interface <T> + class str_vararg_node exprtk_final + : public expression_node <T> + , public string_base_node<T> + , public range_interface <T> { public: - typedef expression_node <T>* expression_ptr; - typedef string_base_node<T>* str_base_ptr; - typedef range_pack <T> range_t; - typedef range_t* range_ptr; - typedef range_interface<T> irange_t; - typedef irange_t* irange_ptr; + typedef typename range_interface<T>::range_t range_t; + typedef range_t* range_ptr; + typedef range_interface <T> irange_t; + typedef irange_t* irange_ptr; + typedef expression_node <T>* expression_ptr; + typedef string_base_node<T>* str_base_ptr; typedef std::pair<expression_ptr,bool> branch_t; template <typename Allocator, template <typename, typename> class Sequence> explicit str_vararg_node(const Sequence<expression_ptr,Allocator>& arg_list) - : initialised_(false), - str_base_ptr_ (0), - str_range_ptr_(0) + : initialised_(false) + , str_base_ptr_ (0) + , str_range_ptr_(0) { construct_branch_pair(final_node_, const_cast<expression_ptr>(arg_list.back())); @@ -9550,8 +11595,6 @@ namespace exprtk if (0 == str_range_ptr_) return; - initialised_ = str_base_ptr_ && str_range_ptr_; - if (arg_list.size() > 1) { const std::size_t arg_list_size = arg_list.size() - 1; @@ -9560,7 +11603,7 @@ namespace exprtk for (std::size_t i = 0; i < arg_list_size; ++i) { - if (arg_list[i]) + if (arg_list[i] && arg_list[i]->valid()) { construct_branch_pair(arg_list_[i], arg_list[i]); } @@ -9570,10 +11613,15 @@ namespace exprtk return; } } + + initialised_ = true; } + + initialised_ &= str_base_ptr_ && str_range_ptr_; + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { if (!arg_list_.empty()) { @@ -9585,43 +11633,50 @@ namespace exprtk return std::numeric_limits<T>::quiet_NaN(); } - std::string str() const override + std::string str() const exprtk_override { return str_base_ptr_->str(); } - char_cptr base() const override + char_cptr base() const exprtk_override { return str_base_ptr_->base(); } - std::size_t size() const override + std::size_t size() const exprtk_override { return str_base_ptr_->size(); } - range_t& range_ref() override + range_t& range_ref() exprtk_override { return str_range_ptr_->range_ref(); } - const range_t& range_ref() const override + const range_t& range_ref() const exprtk_override { return str_range_ptr_->range_ref(); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_stringvararg; } - void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) override + inline bool valid() const exprtk_override + { + return + initialised_ && + final_node_.first && final_node_.first->valid(); + } + + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override { - expression_node<T>::ndb_t::collect(final_node_, node_delete_list); - expression_node<T>::ndb_t::collect(arg_list_ , node_delete_list); + expression_node<T>::ndb_t::collect(final_node_ , node_delete_list); + expression_node<T>::ndb_t::collect(arg_list_ , node_delete_list); } - std::size_t node_depth() const override + std::size_t node_depth() const exprtk_override { return std::max( expression_node<T>::ndb_t::compute_node_depth(final_node_), @@ -9638,15 +11693,113 @@ namespace exprtk }; #endif + template <typename T> + class assert_node exprtk_final : public expression_node<T> + { + public: + + typedef expression_node<T>* expression_ptr; + typedef std::pair<expression_ptr,bool> branch_t; + typedef string_base_node<T>* str_base_ptr; + typedef assert_check::assert_context assert_context_t; + + assert_node(expression_ptr assert_condition_node, + expression_ptr assert_message_node, + assert_check_ptr assert_check, + assert_context_t context) + : assert_message_str_base_(0) + , assert_check_(assert_check) + , context_(context) + { + construct_branch_pair(assert_condition_node_, assert_condition_node); + construct_branch_pair(assert_message_node_ , assert_message_node ); + + #ifndef exprtk_disable_string_capabilities + if ( + assert_message_node_.first && + details::is_generally_string_node(assert_message_node_.first) + ) + { + assert_message_str_base_ = dynamic_cast<str_base_ptr>(assert_message_node_.first); + } + #endif + + assert(valid()); + } + + inline T value() const exprtk_override + { + if (details::is_true(assert_condition_node_.first->value())) + { + return T(1); + } + + #ifndef exprtk_disable_string_capabilities + if (assert_message_node_.first) + { + assert_message_node_.first->value(); + assert(assert_message_str_base_); + context_.message = assert_message_str_base_->str(); + } + #endif + + assert_check_->handle_assert(context_); + return T(0); + } + + inline typename expression_node<T>::node_type type() const exprtk_override + { + return expression_node<T>::e_assert; + } + + inline bool valid() const exprtk_override + { + return ( + assert_check_ && + assert_condition_node_.first && + assert_condition_node_.first->valid() + ) && + ( + (0 == assert_message_node_.first) || + ( + assert_message_node_.first && + assert_message_str_base_ && + assert_message_node_.first->valid() && + details::is_generally_string_node(assert_message_node_.first) + ) + ); + } + + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override + { + expression_node<T>::ndb_t::collect(assert_condition_node_, node_delete_list); + expression_node<T>::ndb_t::collect(assert_message_node_ , node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node<T>::ndb_t::compute_node_depth + (assert_condition_node_, assert_message_node_); + } + + private: + + branch_t assert_condition_node_; + branch_t assert_message_node_; + str_base_ptr assert_message_str_base_; + assert_check_ptr assert_check_; + mutable assert_context_t context_; + }; + template <typename T, std::size_t N> - inline T axn(T a, T x) + inline T axn(const T a, const T x) { // a*x^n return a * exprtk::details::numeric::fast_exp<T,N>::result(x); } template <typename T, std::size_t N> - inline T axnb(T a, T x, T b) + inline T axnb(const T a, const T x, const T b) { // a*x^n+b return a * exprtk::details::numeric::fast_exp<T,N>::result(x) + b; @@ -9658,12 +11811,12 @@ namespace exprtk typedef typename details::functor_t<T>::Type Type; typedef typename details::functor_t<T> functor_t; typedef typename functor_t::qfunc_t quaternary_functor_t; - typedef typename functor_t::tfunc_t trinary_functor_t; - typedef typename functor_t::bfunc_t binary_functor_t; - typedef typename functor_t::ufunc_t unary_functor_t; + typedef typename functor_t::tfunc_t trinary_functor_t; + typedef typename functor_t::bfunc_t binary_functor_t; + typedef typename functor_t::ufunc_t unary_functor_t; }; - #define define_sfop3(NN,OP0,OP1) \ + #define define_sfop3(NN, OP0, OP1) \ template <typename T> \ struct sf##NN##_op : public sf_base<T> \ { \ @@ -9727,7 +11880,7 @@ namespace exprtk define_sfop3(46,x * numeric::cos(y) - z ,"") define_sfop3(47,details::is_true(x) ? y : z,"") - #define define_sfop4(NN,OP0,OP1) \ + #define define_sfop4(NN, OP0, OP1) \ template <typename T> \ struct sf##NN##_op : public sf_base<T> \ { \ @@ -9863,7 +12016,7 @@ namespace exprtk #undef define_sfop4 template <typename T, typename SpecialFunction> - class sf3_node : public trinary_node<T> + class sf3_node exprtk_final : public trinary_node<T> { public: @@ -9876,12 +12029,8 @@ namespace exprtk : trinary_node<T>(opr, branch0, branch1, branch2) {} - inline T value() const override + inline T value() const exprtk_override { - assert(trinary_node<T>::branch_[0].first); - assert(trinary_node<T>::branch_[1].first); - assert(trinary_node<T>::branch_[2].first); - const T x = trinary_node<T>::branch_[0].first->value(); const T y = trinary_node<T>::branch_[1].first->value(); const T z = trinary_node<T>::branch_[2].first->value(); @@ -9891,7 +12040,7 @@ namespace exprtk }; template <typename T, typename SpecialFunction> - class sf4_node : public quaternary_node<T> + class sf4_node exprtk_final : public quaternary_node<T> { public: @@ -9905,13 +12054,8 @@ namespace exprtk : quaternary_node<T>(opr, branch0, branch1, branch2, branch3) {} - inline T value() const override + inline T value() const exprtk_override { - assert(quaternary_node<T>::branch_[0].first); - assert(quaternary_node<T>::branch_[1].first); - assert(quaternary_node<T>::branch_[2].first); - assert(quaternary_node<T>::branch_[3].first); - const T x = quaternary_node<T>::branch_[0].first->value(); const T y = quaternary_node<T>::branch_[1].first->value(); const T z = quaternary_node<T>::branch_[2].first->value(); @@ -9922,32 +12066,32 @@ namespace exprtk }; template <typename T, typename SpecialFunction> - class sf3_var_node : public expression_node<T> + class sf3_var_node exprtk_final : public expression_node<T> { public: typedef expression_node<T>* expression_ptr; sf3_var_node(const T& v0, const T& v1, const T& v2) - : v0_(v0), - v1_(v1), - v2_(v2) + : v0_(v0) + , v1_(v1) + , v2_(v2) {} - inline T value() const override + inline T value() const exprtk_override { return SpecialFunction::process(v0_, v1_, v2_); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_trinary; } private: - sf3_var_node(sf3_var_node<T,SpecialFunction>&); - sf3_var_node<T,SpecialFunction>& operator=(sf3_var_node<T,SpecialFunction>&); + sf3_var_node(const sf3_var_node<T,SpecialFunction>&) exprtk_delete; + sf3_var_node<T,SpecialFunction>& operator=(const sf3_var_node<T,SpecialFunction>&) exprtk_delete; const T& v0_; const T& v1_; @@ -9955,33 +12099,33 @@ namespace exprtk }; template <typename T, typename SpecialFunction> - class sf4_var_node : public expression_node<T> + class sf4_var_node exprtk_final : public expression_node<T> { public: typedef expression_node<T>* expression_ptr; sf4_var_node(const T& v0, const T& v1, const T& v2, const T& v3) - : v0_(v0), - v1_(v1), - v2_(v2), - v3_(v3) + : v0_(v0) + , v1_(v1) + , v2_(v2) + , v3_(v3) {} - inline T value() const override + inline T value() const exprtk_override { return SpecialFunction::process(v0_, v1_, v2_, v3_); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_trinary; } private: - sf4_var_node(sf4_var_node<T,SpecialFunction>&); - sf4_var_node<T,SpecialFunction>& operator=(sf4_var_node<T,SpecialFunction>&); + sf4_var_node(const sf4_var_node<T,SpecialFunction>&) exprtk_delete; + sf4_var_node<T,SpecialFunction>& operator=(const sf4_var_node<T,SpecialFunction>&) exprtk_delete; const T& v0_; const T& v1_; @@ -9990,7 +12134,7 @@ namespace exprtk }; template <typename T, typename VarArgFunction> - class vararg_node : public expression_node<T> + class vararg_node exprtk_final : public expression_node<T> { public: @@ -10000,12 +12144,13 @@ namespace exprtk template <typename Allocator, template <typename, typename> class Sequence> explicit vararg_node(const Sequence<expression_ptr,Allocator>& arg_list) + : initialised_(false) { arg_list_.resize(arg_list.size()); for (std::size_t i = 0; i < arg_list.size(); ++i) { - if (arg_list[i]) + if (arg_list[i] && arg_list[i]->valid()) { construct_branch_pair(arg_list_[i],arg_list[i]); } @@ -10015,35 +12160,54 @@ namespace exprtk return; } } + + initialised_ = (arg_list_.size() == arg_list.size()); + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { return VarArgFunction::process(arg_list_); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_vararg; } - void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) override + inline bool valid() const exprtk_override + { + return initialised_; + } + + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override { expression_node<T>::ndb_t::collect(arg_list_, node_delete_list); } - std::size_t node_depth() const override + std::size_t node_depth() const exprtk_override { return expression_node<T>::ndb_t::compute_node_depth(arg_list_); } + std::size_t size() const + { + return arg_list_.size(); + } + + expression_ptr operator[](const std::size_t& index) const + { + return arg_list_[index].first; + } + private: std::vector<branch_t> arg_list_; + bool initialised_; }; template <typename T, typename VarArgFunction> - class vararg_varnode : public expression_node<T> + class vararg_varnode exprtk_final : public expression_node<T> { public: @@ -10052,12 +12216,13 @@ namespace exprtk template <typename Allocator, template <typename, typename> class Sequence> explicit vararg_varnode(const Sequence<expression_ptr,Allocator>& arg_list) + : initialised_(false) { arg_list_.resize(arg_list.size()); for (std::size_t i = 0; i < arg_list.size(); ++i) { - if (arg_list[i] && is_variable_node(arg_list[i])) + if (arg_list[i] && arg_list[i]->valid() && is_variable_node(arg_list[i])) { variable_node<T>* var_node_ptr = static_cast<variable_node<T>*>(arg_list[i]); arg_list_[i] = (&var_node_ptr->ref()); @@ -10068,28 +12233,34 @@ namespace exprtk return; } } + + initialised_ = (arg_list.size() == arg_list_.size()); + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { - if (!arg_list_.empty()) - return VarArgFunction::process(arg_list_); - else - return std::numeric_limits<T>::quiet_NaN(); + return VarArgFunction::process(arg_list_); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_vararg; } + inline bool valid() const exprtk_override + { + return initialised_; + } + private: std::vector<const T*> arg_list_; + bool initialised_; }; template <typename T, typename VecFunction> - class vectorize_node : public expression_node<T> + class vectorize_node exprtk_final : public expression_node<T> { public: @@ -10105,35 +12276,30 @@ namespace exprtk { ivec_ptr_ = dynamic_cast<vector_interface<T>*>(v_.first); } - else - ivec_ptr_ = 0; } - inline T value() const override + inline T value() const exprtk_override { - if (ivec_ptr_) - { - assert(v_.first); - - v_.first->value(); - - return VecFunction::process(ivec_ptr_); - } - else - return std::numeric_limits<T>::quiet_NaN(); + v_.first->value(); + return VecFunction::process(ivec_ptr_); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_vecfunc; } - void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) override + inline bool valid() const exprtk_override + { + return ivec_ptr_ && v_.first && v_.first->valid(); + } + + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override { expression_node<T>::ndb_t::collect(v_, node_delete_list); } - std::size_t node_depth() const override + std::size_t node_depth() const exprtk_override { return expression_node<T>::ndb_t::compute_node_depth(v_); } @@ -10145,38 +12311,36 @@ namespace exprtk }; template <typename T> - class assignment_node : public binary_node<T> + class assignment_node exprtk_final : public binary_node<T> { public: typedef expression_node<T>* expression_ptr; + using binary_node<T>::branch; assignment_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) - : binary_node<T>(opr, branch0, branch1), - var_node_ptr_(0) + : binary_node<T>(opr, branch0, branch1) + , var_node_ptr_(0) { - if (is_variable_node(binary_node<T>::branch_[0].first)) + if (is_variable_node(branch(0))) { - var_node_ptr_ = static_cast<variable_node<T>*>(binary_node<T>::branch_[0].first); + var_node_ptr_ = static_cast<variable_node<T>*>(branch(0)); } } - inline T value() const override + inline T value() const exprtk_override { - if (var_node_ptr_) - { - assert(binary_node<T>::branch_[1].first); - - T& result = var_node_ptr_->ref(); + T& result = var_node_ptr_->ref(); + result = branch(1)->value(); - result = binary_node<T>::branch_[1].first->value(); + return result; + } - return result; - } - else - return std::numeric_limits<T>::quiet_NaN(); + inline bool valid() const exprtk_override + { + return var_node_ptr_ && binary_node<T>::valid(); } private: @@ -10185,118 +12349,198 @@ namespace exprtk }; template <typename T> - class assignment_vec_elem_node : public binary_node<T> + class assignment_vec_elem_node exprtk_final : public binary_node<T> { public: typedef expression_node<T>* expression_ptr; + using binary_node<T>::branch; assignment_vec_elem_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) - : binary_node<T>(opr, branch0, branch1), - vec_node_ptr_(0) + : binary_node<T>(opr, branch0, branch1) + , vec_node_ptr_(0) { - if (is_vector_elem_node(binary_node<T>::branch_[0].first)) + if (is_vector_elem_node(branch(0))) { - vec_node_ptr_ = static_cast<vector_elem_node<T>*>(binary_node<T>::branch_[0].first); + vec_node_ptr_ = static_cast<vector_elem_node<T>*>(branch(0)); } + + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { - if (vec_node_ptr_) - { - assert(binary_node<T>::branch_[1].first); + T& result = vec_node_ptr_->ref(); + result = branch(1)->value(); - T& result = vec_node_ptr_->ref(); + return result; + } - result = binary_node<T>::branch_[1].first->value(); + inline bool valid() const exprtk_override + { + return vec_node_ptr_ && binary_node<T>::valid(); + } - return result; + private: + + vector_elem_node<T>* vec_node_ptr_; + }; + + template <typename T> + class assignment_vec_elem_rtc_node exprtk_final : public binary_node<T> + { + public: + + typedef expression_node<T>* expression_ptr; + using binary_node<T>::branch; + + assignment_vec_elem_rtc_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node<T>(opr, branch0, branch1) + , vec_node_ptr_(0) + { + if (is_vector_elem_rtc_node(branch(0))) + { + vec_node_ptr_ = static_cast<vector_elem_rtc_node<T>*>(branch(0)); } - else - return std::numeric_limits<T>::quiet_NaN(); + + assert(valid()); + } + + inline T value() const exprtk_override + { + T& result = vec_node_ptr_->ref(); + result = branch(1)->value(); + + return result; + } + + inline bool valid() const exprtk_override + { + return vec_node_ptr_ && binary_node<T>::valid(); } private: - vector_elem_node<T>* vec_node_ptr_; + vector_elem_rtc_node<T>* vec_node_ptr_; }; template <typename T> - class assignment_rebasevec_elem_node : public binary_node<T> + class assignment_rebasevec_elem_node exprtk_final : public binary_node<T> { public: typedef expression_node<T>* expression_ptr; + using expression_node<T>::branch; assignment_rebasevec_elem_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) - : binary_node<T>(opr, branch0, branch1), - rbvec_node_ptr_(0) + : binary_node<T>(opr, branch0, branch1) + , rbvec_node_ptr_(0) { - if (is_rebasevector_elem_node(binary_node<T>::branch_[0].first)) + if (is_rebasevector_elem_node(branch(0))) { - rbvec_node_ptr_ = static_cast<rebasevector_elem_node<T>*>(binary_node<T>::branch_[0].first); + rbvec_node_ptr_ = static_cast<rebasevector_elem_node<T>*>(branch(0)); } + + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { - if (rbvec_node_ptr_) - { - assert(binary_node<T>::branch_[1].first); + T& result = rbvec_node_ptr_->ref(); + result = branch(1)->value(); - T& result = rbvec_node_ptr_->ref(); + return result; + } - result = binary_node<T>::branch_[1].first->value(); + inline bool valid() const exprtk_override + { + return rbvec_node_ptr_ && binary_node<T>::valid(); + } - return result; + private: + + rebasevector_elem_node<T>* rbvec_node_ptr_; + }; + + template <typename T> + class assignment_rebasevec_elem_rtc_node exprtk_final : public binary_node<T> + { + public: + + typedef expression_node<T>* expression_ptr; + using expression_node<T>::branch; + + assignment_rebasevec_elem_rtc_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node<T>(opr, branch0, branch1) + , rbvec_node_ptr_(0) + { + if (is_rebasevector_elem_rtc_node(branch(0))) + { + rbvec_node_ptr_ = static_cast<rebasevector_elem_rtc_node<T>*>(branch(0)); } - else - return std::numeric_limits<T>::quiet_NaN(); + + assert(valid()); + } + + inline T value() const exprtk_override + { + T& result = rbvec_node_ptr_->ref(); + result = branch(1)->value(); + + return result; + } + + inline bool valid() const exprtk_override + { + return rbvec_node_ptr_ && binary_node<T>::valid(); } private: - rebasevector_elem_node<T>* rbvec_node_ptr_; + rebasevector_elem_rtc_node<T>* rbvec_node_ptr_; }; template <typename T> - class assignment_rebasevec_celem_node : public binary_node<T> + class assignment_rebasevec_celem_node exprtk_final : public binary_node<T> { public: typedef expression_node<T>* expression_ptr; + using binary_node<T>::branch; assignment_rebasevec_celem_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) - : binary_node<T>(opr, branch0, branch1), - rbvec_node_ptr_(0) + : binary_node<T>(opr, branch0, branch1) + , rbvec_node_ptr_(0) { - if (is_rebasevector_celem_node(binary_node<T>::branch_[0].first)) + if (is_rebasevector_celem_node(branch(0))) { - rbvec_node_ptr_ = static_cast<rebasevector_celem_node<T>*>(binary_node<T>::branch_[0].first); + rbvec_node_ptr_ = static_cast<rebasevector_celem_node<T>*>(branch(0)); } + + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { - if (rbvec_node_ptr_) - { - assert(binary_node<T>::branch_[1].first); + T& result = rbvec_node_ptr_->ref(); + result = branch(1)->value(); - T& result = rbvec_node_ptr_->ref(); - - result = binary_node<T>::branch_[1].first->value(); + return result; + } - return result; - } - else - return std::numeric_limits<T>::quiet_NaN(); + inline bool valid() const exprtk_override + { + return rbvec_node_ptr_ && binary_node<T>::valid(); } private: @@ -10305,114 +12549,124 @@ namespace exprtk }; template <typename T> - class assignment_vec_node : public binary_node <T>, - public vector_interface<T> + class assignment_vec_node exprtk_final + : public binary_node <T> + , public vector_interface<T> { public: typedef expression_node<T>* expression_ptr; - typedef vector_node<T>* vector_node_ptr; - typedef vec_data_store<T> vds_t; + typedef vector_node<T>* vector_node_ptr; + typedef vec_data_store<T> vds_t; + + using binary_node<T>::branch; assignment_vec_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) - : binary_node<T>(opr, branch0, branch1), - vec_node_ptr_(0) + : binary_node<T>(opr, branch0, branch1) + , vec_node_ptr_(0) { - if (is_vector_node(binary_node<T>::branch_[0].first)) + if (is_vector_node(branch(0))) { - vec_node_ptr_ = static_cast<vector_node<T>*>(binary_node<T>::branch_[0].first); + vec_node_ptr_ = static_cast<vector_node<T>*>(branch(0)); vds() = vec_node_ptr_->vds(); } + + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { - if (vec_node_ptr_) - { - assert(binary_node<T>::branch_[1].first); - - const T v = binary_node<T>::branch_[1].first->value(); + const T v = branch(1)->value(); - T* vec = vds().data(); + T* vec = vds().data(); - loop_unroll::details lud(size()); - const T* upper_bound = vec + lud.upper_bound; + loop_unroll::details lud(size()); + const T* upper_bound = vec + lud.upper_bound; - while (vec < upper_bound) - { - #define exprtk_loop(N) \ - vec[N] = v; \ + while (vec < upper_bound) + { + #define exprtk_loop(N) \ + vec[N] = v; \ - exprtk_loop( 0) exprtk_loop( 1) - exprtk_loop( 2) exprtk_loop( 3) - #ifndef exprtk_disable_superscalar_unroll - exprtk_loop( 4) exprtk_loop( 5) - exprtk_loop( 6) exprtk_loop( 7) - exprtk_loop( 8) exprtk_loop( 9) - exprtk_loop(10) exprtk_loop(11) - exprtk_loop(12) exprtk_loop(13) - exprtk_loop(14) exprtk_loop(15) - #endif + exprtk_loop( 0) exprtk_loop( 1) + exprtk_loop( 2) exprtk_loop( 3) + #ifndef exprtk_disable_superscalar_unroll + exprtk_loop( 4) exprtk_loop( 5) + exprtk_loop( 6) exprtk_loop( 7) + exprtk_loop( 8) exprtk_loop( 9) + exprtk_loop(10) exprtk_loop(11) + exprtk_loop(12) exprtk_loop(13) + exprtk_loop(14) exprtk_loop(15) + #endif - vec += lud.batch_size; - } + vec += lud.batch_size; + } - exprtk_disable_fallthrough_begin - switch (lud.remainder) - { - #define case_stmt(N) \ - case N : *vec++ = v; \ + switch (lud.remainder) + { + #define case_stmt(N) \ + case N : *vec++ = v; \ + exprtk_fallthrough \ - #ifndef exprtk_disable_superscalar_unroll - case_stmt(15) case_stmt(14) - case_stmt(13) case_stmt(12) - case_stmt(11) case_stmt(10) - case_stmt( 9) case_stmt( 8) - case_stmt( 7) case_stmt( 6) - case_stmt( 5) case_stmt( 4) - #endif - case_stmt( 3) case_stmt( 2) - case_stmt( 1) - } - exprtk_disable_fallthrough_end + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15) case_stmt(14) + case_stmt(13) case_stmt(12) + case_stmt(11) case_stmt(10) + case_stmt( 9) case_stmt( 8) + case_stmt( 7) case_stmt( 6) + case_stmt( 5) case_stmt( 4) + #endif + case_stmt( 3) case_stmt( 2) + case 1 : *vec++ = v; + } - #undef exprtk_loop - #undef case_stmt + #undef exprtk_loop + #undef case_stmt - return vec_node_ptr_->value(); - } - else - return std::numeric_limits<T>::quiet_NaN(); + return vec_node_ptr_->value(); } - vector_node_ptr vec() const override + vector_node_ptr vec() const exprtk_override { return vec_node_ptr_; } - vector_node_ptr vec() override + vector_node_ptr vec() exprtk_override { return vec_node_ptr_; } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_vecvalass; } - std::size_t size() const override + inline bool valid() const exprtk_override + { + return + vec_node_ptr_ && + (vds().size() <= vec_node_ptr_->vec_holder().base_size()) && + binary_node<T>::valid(); + } + + std::size_t size() const exprtk_override + { + return vec_node_ptr_->vec_holder().size(); + } + + std::size_t base_size() const exprtk_override { - return vds().size(); + return vec_node_ptr_->vec_holder().base_size(); } - vds_t& vds() override + vds_t& vds() exprtk_override { return vds_; } - const vds_t& vds() const override + const vds_t& vds() const exprtk_override { return vds_; } @@ -10424,40 +12678,43 @@ namespace exprtk }; template <typename T> - class assignment_vecvec_node : public binary_node <T>, - public vector_interface<T> + class assignment_vecvec_node exprtk_final + : public binary_node <T> + , public vector_interface<T> { public: - typedef expression_node<T>* expression_ptr; + typedef expression_node<T>* expression_ptr; typedef vector_node<T>* vector_node_ptr; - typedef vec_data_store<T> vds_t; + typedef vec_data_store<T> vds_t; + + using binary_node<T>::branch; assignment_vecvec_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) - : binary_node<T>(opr, branch0, branch1), - vec0_node_ptr_(0), - vec1_node_ptr_(0), - initialised_(false), - src_is_ivec_(false) + : binary_node<T>(opr, branch0, branch1) + , vec0_node_ptr_(0) + , vec1_node_ptr_(0) + , initialised_(false) + , src_is_ivec_(false) { - if (is_vector_node(binary_node<T>::branch_[0].first)) + if (is_vector_node(branch(0))) { - vec0_node_ptr_ = static_cast<vector_node<T>*>(binary_node<T>::branch_[0].first); + vec0_node_ptr_ = static_cast<vector_node<T>*>(branch(0)); vds() = vec0_node_ptr_->vds(); } - if (is_vector_node(binary_node<T>::branch_[1].first)) + if (is_vector_node(branch(1))) { - vec1_node_ptr_ = static_cast<vector_node<T>*>(binary_node<T>::branch_[1].first); + vec1_node_ptr_ = static_cast<vector_node<T>*>(branch(1)); vds_t::match_sizes(vds(),vec1_node_ptr_->vds()); } - else if (is_ivector_node(binary_node<T>::branch_[1].first)) + else if (is_ivector_node(branch(1))) { vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0); - if (0 != (vi = dynamic_cast<vector_interface<T>*>(binary_node<T>::branch_[1].first))) + if (0 != (vi = dynamic_cast<vector_interface<T>*>(branch(1)))) { vec1_node_ptr_ = vi->vec(); @@ -10471,384 +12728,570 @@ namespace exprtk } } - initialised_ = (vec0_node_ptr_ && vec1_node_ptr_); + initialised_ = + vec0_node_ptr_ && + vec1_node_ptr_ && + (size() <= base_size()) && + (vds_.size() <= base_size()) && + binary_node<T>::valid(); + + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { - if (initialised_) + branch(1)->value(); + + if (src_is_ivec_) + return vec0_node_ptr_->value(); + + T* vec0 = vec0_node_ptr_->vds().data(); + T* vec1 = vec1_node_ptr_->vds().data(); + + loop_unroll::details lud(size()); + const T* upper_bound = vec0 + lud.upper_bound; + + while (vec0 < upper_bound) { - assert(binary_node<T>::branch_[1].first); + #define exprtk_loop(N) \ + vec0[N] = vec1[N]; \ - binary_node<T>::branch_[1].first->value(); + exprtk_loop( 0) exprtk_loop( 1) + exprtk_loop( 2) exprtk_loop( 3) + #ifndef exprtk_disable_superscalar_unroll + exprtk_loop( 4) exprtk_loop( 5) + exprtk_loop( 6) exprtk_loop( 7) + exprtk_loop( 8) exprtk_loop( 9) + exprtk_loop(10) exprtk_loop(11) + exprtk_loop(12) exprtk_loop(13) + exprtk_loop(14) exprtk_loop(15) + #endif - if (src_is_ivec_) - return vec0_node_ptr_->value(); + vec0 += lud.batch_size; + vec1 += lud.batch_size; + } - T* vec0 = vec0_node_ptr_->vds().data(); - T* vec1 = vec1_node_ptr_->vds().data(); + switch (lud.remainder) + { + #define case_stmt(N,fall_through) \ + case N : *vec0++ = *vec1++; \ + fall_through \ - loop_unroll::details lud(size()); - const T* upper_bound = vec0 + lud.upper_bound; + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15, exprtk_fallthrough) case_stmt(14, exprtk_fallthrough) + case_stmt(13, exprtk_fallthrough) case_stmt(12, exprtk_fallthrough) + case_stmt(11, exprtk_fallthrough) case_stmt(10, exprtk_fallthrough) + case_stmt( 9, exprtk_fallthrough) case_stmt( 8, exprtk_fallthrough) + case_stmt( 7, exprtk_fallthrough) case_stmt( 6, exprtk_fallthrough) + case_stmt( 5, exprtk_fallthrough) case_stmt( 4, exprtk_fallthrough) + #endif + case_stmt( 3, exprtk_fallthrough) case_stmt( 2, exprtk_fallthrough) + case_stmt( 1, (void)0;) + } - while (vec0 < upper_bound) - { - #define exprtk_loop(N) \ - vec0[N] = vec1[N]; \ + #undef exprtk_loop + #undef case_stmt - exprtk_loop( 0) exprtk_loop( 1) - exprtk_loop( 2) exprtk_loop( 3) - #ifndef exprtk_disable_superscalar_unroll - exprtk_loop( 4) exprtk_loop( 5) - exprtk_loop( 6) exprtk_loop( 7) - exprtk_loop( 8) exprtk_loop( 9) - exprtk_loop(10) exprtk_loop(11) - exprtk_loop(12) exprtk_loop(13) - exprtk_loop(14) exprtk_loop(15) - #endif + return vec0_node_ptr_->value(); + } - vec0 += lud.batch_size; - vec1 += lud.batch_size; - } + vector_node_ptr vec() exprtk_override + { + return vec0_node_ptr_; + } + + vector_node_ptr vec() const exprtk_override + { + return vec0_node_ptr_; + } + + inline typename expression_node<T>::node_type type() const exprtk_override + { + return expression_node<T>::e_vecvecass; + } + + inline bool valid() const exprtk_override + { + return initialised_; + } + + std::size_t size() const exprtk_override + { + return std::min( + vec0_node_ptr_->vec_holder().size(), + vec1_node_ptr_->vec_holder().size()); + } + + std::size_t base_size() const exprtk_override + { + return std::min( + vec0_node_ptr_->vec_holder().base_size(), + vec1_node_ptr_->vec_holder().base_size()); + } + + vds_t& vds() exprtk_override + { + return vds_; + } + + const vds_t& vds() const exprtk_override + { + return vds_; + } + + private: + + vector_node<T>* vec0_node_ptr_; + vector_node<T>* vec1_node_ptr_; + bool initialised_; + bool src_is_ivec_; + vds_t vds_; + }; + + template <typename T, typename Operation> + class assignment_op_node exprtk_final : public binary_node<T> + { + public: + + typedef expression_node<T>* expression_ptr; + using binary_node<T>::branch; + + assignment_op_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node<T>(opr, branch0, branch1) + , var_node_ptr_(0) + { + if (is_variable_node(branch(0))) + { + var_node_ptr_ = static_cast<variable_node<T>*>(branch(0)); + } + + assert(valid()); + } + + inline T value() const exprtk_override + { + T& v = var_node_ptr_->ref(); + v = Operation::process(v,branch(1)->value()); + + return v; + } + + inline bool valid() const exprtk_override + { + return var_node_ptr_ && binary_node<T>::valid(); + } + + private: + + variable_node<T>* var_node_ptr_; + }; + + template <typename T, typename Operation> + class assignment_vec_elem_op_node exprtk_final : public binary_node<T> + { + public: + + typedef expression_node<T>* expression_ptr; + using binary_node<T>::branch; + + assignment_vec_elem_op_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node<T>(opr, branch0, branch1) + , vec_node_ptr_(0) + { + if (is_vector_elem_node(branch(0))) + { + vec_node_ptr_ = static_cast<vector_elem_node<T>*>(branch(0)); + } + + assert(valid()); + } + + inline T value() const exprtk_override + { + T& v = vec_node_ptr_->ref(); + v = Operation::process(v,branch(1)->value()); + + return v; + } + + inline bool valid() const exprtk_override + { + return vec_node_ptr_ && binary_node<T>::valid(); + } + + private: - exprtk_disable_fallthrough_begin - switch (lud.remainder) - { - #define case_stmt(N) \ - case N : *vec0++ = *vec1++; \ + vector_elem_node<T>* vec_node_ptr_; + }; - #ifndef exprtk_disable_superscalar_unroll - case_stmt(15) case_stmt(14) - case_stmt(13) case_stmt(12) - case_stmt(11) case_stmt(10) - case_stmt( 9) case_stmt( 8) - case_stmt( 7) case_stmt( 6) - case_stmt( 5) case_stmt( 4) - #endif - case_stmt( 3) case_stmt( 2) - case_stmt( 1) - } - exprtk_disable_fallthrough_end + template <typename T, typename Operation> + class assignment_vec_elem_op_rtc_node exprtk_final : public binary_node<T> + { + public: - #undef exprtk_loop - #undef case_stmt + typedef expression_node<T>* expression_ptr; + using binary_node<T>::branch; - return vec0_node_ptr_->value(); + assignment_vec_elem_op_rtc_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node<T>(opr, branch0, branch1) + , vec_node_ptr_(0) + { + if (is_vector_elem_rtc_node(branch(0))) + { + vec_node_ptr_ = static_cast<vector_elem_rtc_node<T>*>(branch(0)); } - else - return std::numeric_limits<T>::quiet_NaN(); - } - vector_node_ptr vec() const override - { - return vec0_node_ptr_; + assert(valid()); } - vector_node_ptr vec() override + inline T value() const exprtk_override { - return vec0_node_ptr_; + T& v = vec_node_ptr_->ref(); + v = Operation::process(v,branch(1)->value()); + + return v; } - inline typename expression_node<T>::node_type type() const override + inline bool valid() const exprtk_override { - return expression_node<T>::e_vecvecass; + return vec_node_ptr_ && binary_node<T>::valid(); } - std::size_t size() const override + private: + + vector_elem_rtc_node<T>* vec_node_ptr_; + }; + + template <typename T, typename Operation> + class assignment_vec_celem_op_rtc_node exprtk_final : public binary_node<T> + { + public: + + typedef expression_node<T>* expression_ptr; + using binary_node<T>::branch; + + assignment_vec_celem_op_rtc_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node<T>(opr, branch0, branch1) + , vec_node_ptr_(0) { - return vds().size(); + if (is_vector_celem_rtc_node(branch(0))) + { + vec_node_ptr_ = static_cast<vector_celem_rtc_node<T>*>(branch(0)); + } + + assert(valid()); } - vds_t& vds() override + inline T value() const exprtk_override { - return vds_; + T& v = vec_node_ptr_->ref(); + v = Operation::process(v,branch(1)->value()); + + return v; } - const vds_t& vds() const override + inline bool valid() const exprtk_override { - return vds_; + return vec_node_ptr_ && binary_node<T>::valid(); } private: - vector_node<T>* vec0_node_ptr_; - vector_node<T>* vec1_node_ptr_; - bool initialised_; - bool src_is_ivec_; - vds_t vds_; + vector_celem_rtc_node<T>* vec_node_ptr_; }; template <typename T, typename Operation> - class assignment_op_node : public binary_node<T> + class assignment_rebasevec_elem_op_node exprtk_final : public binary_node<T> { public: typedef expression_node<T>* expression_ptr; + using binary_node<T>::branch; - assignment_op_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node<T>(opr, branch0, branch1), - var_node_ptr_(0) + assignment_rebasevec_elem_op_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node<T>(opr, branch0, branch1) + , rbvec_node_ptr_(0) { - if (is_variable_node(binary_node<T>::branch_[0].first)) + if (is_rebasevector_elem_node(branch(0))) { - var_node_ptr_ = static_cast<variable_node<T>*>(binary_node<T>::branch_[0].first); + rbvec_node_ptr_ = static_cast<rebasevector_elem_node<T>*>(branch(0)); } + + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { - if (var_node_ptr_) - { - assert(binary_node<T>::branch_[1].first); + T& v = rbvec_node_ptr_->ref(); + v = Operation::process(v,branch(1)->value()); - T& v = var_node_ptr_->ref(); - v = Operation::process(v,binary_node<T>::branch_[1].first->value()); + return v; + } - return v; - } - else - return std::numeric_limits<T>::quiet_NaN(); + inline bool valid() const exprtk_override + { + return rbvec_node_ptr_ && binary_node<T>::valid(); } private: - variable_node<T>* var_node_ptr_; + rebasevector_elem_node<T>* rbvec_node_ptr_; }; template <typename T, typename Operation> - class assignment_vec_elem_op_node : public binary_node<T> + class assignment_rebasevec_celem_op_node exprtk_final : public binary_node<T> { public: typedef expression_node<T>* expression_ptr; + using binary_node<T>::branch; - assignment_vec_elem_op_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node<T>(opr, branch0, branch1), - vec_node_ptr_(0) + assignment_rebasevec_celem_op_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node<T>(opr, branch0, branch1) + , rbvec_node_ptr_(0) { - if (is_vector_elem_node(binary_node<T>::branch_[0].first)) + if (is_rebasevector_celem_node(branch(0))) { - vec_node_ptr_ = static_cast<vector_elem_node<T>*>(binary_node<T>::branch_[0].first); + rbvec_node_ptr_ = static_cast<rebasevector_celem_node<T>*>(branch(0)); } + + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { - if (vec_node_ptr_) - { - assert(binary_node<T>::branch_[1].first); + T& v = rbvec_node_ptr_->ref(); + v = Operation::process(v,branch(1)->value()); - T& v = vec_node_ptr_->ref(); - v = Operation::process(v,binary_node<T>::branch_[1].first->value()); + return v; + } - return v; - } - else - return std::numeric_limits<T>::quiet_NaN(); + inline bool valid() const exprtk_override + { + return rbvec_node_ptr_ && binary_node<T>::valid(); } private: - vector_elem_node<T>* vec_node_ptr_; + rebasevector_celem_node<T>* rbvec_node_ptr_; }; template <typename T, typename Operation> - class assignment_rebasevec_elem_op_node : public binary_node<T> + class assignment_rebasevec_elem_op_rtc_node exprtk_final : public binary_node<T> { public: typedef expression_node<T>* expression_ptr; + using binary_node<T>::branch; - assignment_rebasevec_elem_op_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node<T>(opr, branch0, branch1), - rbvec_node_ptr_(0) + assignment_rebasevec_elem_op_rtc_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node<T>(opr, branch0, branch1) + , rbvec_node_ptr_(0) { - if (is_rebasevector_elem_node(binary_node<T>::branch_[0].first)) + if (is_rebasevector_elem_rtc_node(branch(0))) { - rbvec_node_ptr_ = static_cast<rebasevector_elem_node<T>*>(binary_node<T>::branch_[0].first); + rbvec_node_ptr_ = static_cast<rebasevector_elem_rtc_node<T>*>(branch(0)); } + + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { - if (rbvec_node_ptr_) - { - assert(binary_node<T>::branch_[1].first); + T& v = rbvec_node_ptr_->ref(); + v = Operation::process(v,branch(1)->value()); - T& v = rbvec_node_ptr_->ref(); - v = Operation::process(v,binary_node<T>::branch_[1].first->value()); + return v; + } - return v; - } - else - return std::numeric_limits<T>::quiet_NaN(); + inline bool valid() const exprtk_override + { + return rbvec_node_ptr_ && binary_node<T>::valid(); } private: - rebasevector_elem_node<T>* rbvec_node_ptr_; + rebasevector_elem_rtc_node<T>* rbvec_node_ptr_; }; template <typename T, typename Operation> - class assignment_rebasevec_celem_op_node : public binary_node<T> + class assignment_rebasevec_celem_op_rtc_node exprtk_final : public binary_node<T> { public: typedef expression_node<T>* expression_ptr; + using binary_node<T>::branch; - assignment_rebasevec_celem_op_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node<T>(opr, branch0, branch1), - rbvec_node_ptr_(0) + assignment_rebasevec_celem_op_rtc_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node<T>(opr, branch0, branch1) + , rbvec_node_ptr_(0) { - if (is_rebasevector_celem_node(binary_node<T>::branch_[0].first)) + if (is_rebasevector_celem_rtc_node(branch(0))) { - rbvec_node_ptr_ = static_cast<rebasevector_celem_node<T>*>(binary_node<T>::branch_[0].first); + rbvec_node_ptr_ = static_cast<rebasevector_celem_rtc_node<T>*>(branch(0)); } + + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { - if (rbvec_node_ptr_) - { - assert(binary_node<T>::branch_[1].first); + T& v = rbvec_node_ptr_->ref(); + v = Operation::process(v,branch(1)->value()); - T& v = rbvec_node_ptr_->ref(); - v = Operation::process(v,binary_node<T>::branch_[1].first->value()); + return v; + } - return v; - } - else - return std::numeric_limits<T>::quiet_NaN(); + inline bool valid() const exprtk_override + { + return rbvec_node_ptr_ && binary_node<T>::valid(); } private: - rebasevector_celem_node<T>* rbvec_node_ptr_; + rebasevector_celem_rtc_node<T>* rbvec_node_ptr_; }; template <typename T, typename Operation> - class assignment_vec_op_node : public binary_node <T>, - public vector_interface<T> + class assignment_vec_op_node exprtk_final + : public binary_node <T> + , public vector_interface<T> { public: - typedef expression_node<T>* expression_ptr; + typedef expression_node<T>* expression_ptr; typedef vector_node<T>* vector_node_ptr; - typedef vec_data_store<T> vds_t; + typedef vec_data_store<T> vds_t; + + using binary_node<T>::branch; assignment_vec_op_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) - : binary_node<T>(opr, branch0, branch1), - vec_node_ptr_(0) + : binary_node<T>(opr, branch0, branch1) + , vec_node_ptr_(0) { - if (is_vector_node(binary_node<T>::branch_[0].first)) + if (is_vector_node(branch(0))) { - vec_node_ptr_ = static_cast<vector_node<T>*>(binary_node<T>::branch_[0].first); + vec_node_ptr_ = static_cast<vector_node<T>*>(branch(0)); vds() = vec_node_ptr_->vds(); } + + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { - if (vec_node_ptr_) - { - assert(binary_node<T>::branch_[1].first); + const T v = branch(1)->value(); - const T v = binary_node<T>::branch_[1].first->value(); + T* vec = vds().data(); - T* vec = vds().data(); - - loop_unroll::details lud(size()); - const T* upper_bound = vec + lud.upper_bound; - - while (vec < upper_bound) - { - #define exprtk_loop(N) \ - Operation::assign(vec[N],v); \ + loop_unroll::details lud(size()); + const T* upper_bound = vec + lud.upper_bound; - exprtk_loop( 0) exprtk_loop( 1) - exprtk_loop( 2) exprtk_loop( 3) - #ifndef exprtk_disable_superscalar_unroll - exprtk_loop( 4) exprtk_loop( 5) - exprtk_loop( 6) exprtk_loop( 7) - exprtk_loop( 8) exprtk_loop( 9) - exprtk_loop(10) exprtk_loop(11) - exprtk_loop(12) exprtk_loop(13) - exprtk_loop(14) exprtk_loop(15) - #endif + while (vec < upper_bound) + { + #define exprtk_loop(N) \ + Operation::assign(vec[N],v); \ - vec += lud.batch_size; - } + exprtk_loop( 0) exprtk_loop( 1) + exprtk_loop( 2) exprtk_loop( 3) + #ifndef exprtk_disable_superscalar_unroll + exprtk_loop( 4) exprtk_loop( 5) + exprtk_loop( 6) exprtk_loop( 7) + exprtk_loop( 8) exprtk_loop( 9) + exprtk_loop(10) exprtk_loop(11) + exprtk_loop(12) exprtk_loop(13) + exprtk_loop(14) exprtk_loop(15) + #endif - exprtk_disable_fallthrough_begin - switch (lud.remainder) - { - #define case_stmt(N) \ - case N : Operation::assign(*vec++,v); \ + vec += lud.batch_size; + } - #ifndef exprtk_disable_superscalar_unroll - case_stmt(15) case_stmt(14) - case_stmt(13) case_stmt(12) - case_stmt(11) case_stmt(10) - case_stmt( 9) case_stmt( 8) - case_stmt( 7) case_stmt( 6) - case_stmt( 5) case_stmt( 4) - #endif - case_stmt( 3) case_stmt( 2) - case_stmt( 1) - } - exprtk_disable_fallthrough_end + switch (lud.remainder) + { + #define case_stmt(N,fall_through) \ + case N : Operation::assign(*vec++,v); \ + fall_through \ + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15, exprtk_fallthrough) case_stmt(14, exprtk_fallthrough) + case_stmt(13, exprtk_fallthrough) case_stmt(12, exprtk_fallthrough) + case_stmt(11, exprtk_fallthrough) case_stmt(10, exprtk_fallthrough) + case_stmt( 9, exprtk_fallthrough) case_stmt( 8, exprtk_fallthrough) + case_stmt( 7, exprtk_fallthrough) case_stmt( 6, exprtk_fallthrough) + case_stmt( 5, exprtk_fallthrough) case_stmt( 4, exprtk_fallthrough) + #endif + case_stmt( 3, exprtk_fallthrough) case_stmt( 2, exprtk_fallthrough) + case_stmt( 1, (void)0;) + } - #undef exprtk_loop - #undef case_stmt + #undef exprtk_loop + #undef case_stmt - return vec_node_ptr_->value(); - } - else - return std::numeric_limits<T>::quiet_NaN(); + return vec_node_ptr_->value(); } - vector_node_ptr vec() const override + vector_node_ptr vec() const exprtk_override { return vec_node_ptr_; } - vector_node_ptr vec() override + vector_node_ptr vec() exprtk_override { return vec_node_ptr_; } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_vecopvalass; } - std::size_t size() const override + inline bool valid() const exprtk_override + { + return + vec_node_ptr_ && + (size() <= base_size()) && + binary_node<T>::valid() ; + } + + std::size_t size() const exprtk_override + { + return vec_node_ptr_->vec_holder().size(); + } + + std::size_t base_size() const exprtk_override { - return vds().size(); + return vec_node_ptr_->vec_holder().base_size(); } - vds_t& vds() override + vds_t& vds() exprtk_override { return vds_; } - const vds_t& vds() const override + const vds_t& vds() const exprtk_override { return vds_; } - bool side_effect() const override + bool side_effect() const exprtk_override { return true; } @@ -10860,147 +13303,161 @@ namespace exprtk }; template <typename T, typename Operation> - class assignment_vecvec_op_node : public binary_node <T>, - public vector_interface<T> + class assignment_vecvec_op_node exprtk_final + : public binary_node <T> + , public vector_interface<T> { public: - typedef expression_node<T>* expression_ptr; + typedef expression_node<T>* expression_ptr; typedef vector_node<T>* vector_node_ptr; - typedef vec_data_store<T> vds_t; + typedef vec_data_store<T> vds_t; + + using binary_node<T>::branch; assignment_vecvec_op_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) - : binary_node<T>(opr, branch0, branch1), - vec0_node_ptr_(0), - vec1_node_ptr_(0), - initialised_(false) + : binary_node<T>(opr, branch0, branch1) + , vec0_node_ptr_(0) + , vec1_node_ptr_(0) + , initialised_(false) { - if (is_vector_node(binary_node<T>::branch_[0].first)) + if (is_vector_node(branch(0))) { - vec0_node_ptr_ = static_cast<vector_node<T>*>(binary_node<T>::branch_[0].first); + vec0_node_ptr_ = static_cast<vector_node<T>*>(branch(0)); vds() = vec0_node_ptr_->vds(); } - if (is_vector_node(binary_node<T>::branch_[1].first)) + if (is_vector_node(branch(1))) { - vec1_node_ptr_ = static_cast<vector_node<T>*>(binary_node<T>::branch_[1].first); + vec1_node_ptr_ = static_cast<vector_node<T>*>(branch(1)); vec1_node_ptr_->vds() = vds(); } - else if (is_ivector_node(binary_node<T>::branch_[1].first)) + else if (is_ivector_node(branch(1))) { vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0); - if (0 != (vi = dynamic_cast<vector_interface<T>*>(binary_node<T>::branch_[1].first))) + if (0 != (vi = dynamic_cast<vector_interface<T>*>(branch(1)))) { vec1_node_ptr_ = vi->vec(); - vec1_node_ptr_->vds() = vds(); + vec1_node_ptr_->vds() = vi->vds(); } else vds_t::match_sizes(vds(),vec1_node_ptr_->vds()); } - initialised_ = (vec0_node_ptr_ && vec1_node_ptr_); + initialised_ = + vec0_node_ptr_ && + vec1_node_ptr_ && + (size() <= base_size()) && + binary_node<T>::valid(); + + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { - if (initialised_) - { - assert(binary_node<T>::branch_[0].first); - assert(binary_node<T>::branch_[1].first); + branch(0)->value(); + branch(1)->value(); - binary_node<T>::branch_[0].first->value(); - binary_node<T>::branch_[1].first->value(); + T* vec0 = vec0_node_ptr_->vds().data(); + const T* vec1 = vec1_node_ptr_->vds().data(); - T* vec0 = vec0_node_ptr_->vds().data(); - const T* vec1 = vec1_node_ptr_->vds().data(); + loop_unroll::details lud(size()); + const T* upper_bound = vec0 + lud.upper_bound; - loop_unroll::details lud(size()); - const T* upper_bound = vec0 + lud.upper_bound; - - while (vec0 < upper_bound) - { - #define exprtk_loop(N) \ - vec0[N] = Operation::process(vec0[N], vec1[N]); \ + while (vec0 < upper_bound) + { + #define exprtk_loop(N) \ + vec0[N] = Operation::process(vec0[N], vec1[N]); \ - exprtk_loop( 0) exprtk_loop( 1) - exprtk_loop( 2) exprtk_loop( 3) - #ifndef exprtk_disable_superscalar_unroll - exprtk_loop( 4) exprtk_loop( 5) - exprtk_loop( 6) exprtk_loop( 7) - exprtk_loop( 8) exprtk_loop( 9) - exprtk_loop(10) exprtk_loop(11) - exprtk_loop(12) exprtk_loop(13) - exprtk_loop(14) exprtk_loop(15) - #endif + exprtk_loop( 0) exprtk_loop( 1) + exprtk_loop( 2) exprtk_loop( 3) + #ifndef exprtk_disable_superscalar_unroll + exprtk_loop( 4) exprtk_loop( 5) + exprtk_loop( 6) exprtk_loop( 7) + exprtk_loop( 8) exprtk_loop( 9) + exprtk_loop(10) exprtk_loop(11) + exprtk_loop(12) exprtk_loop(13) + exprtk_loop(14) exprtk_loop(15) + #endif - vec0 += lud.batch_size; - vec1 += lud.batch_size; - } + vec0 += lud.batch_size; + vec1 += lud.batch_size; + } - int i = 0; + int i = 0; - exprtk_disable_fallthrough_begin - switch (lud.remainder) - { - #define case_stmt(N) \ - case N : { vec0[i] = Operation::process(vec0[i], vec1[i]); ++i; } \ + switch (lud.remainder) + { + #define case_stmt(N,fall_through) \ + case N : { vec0[i] = Operation::process(vec0[i], vec1[i]); ++i; } \ + fall_through \ - #ifndef exprtk_disable_superscalar_unroll - case_stmt(15) case_stmt(14) - case_stmt(13) case_stmt(12) - case_stmt(11) case_stmt(10) - case_stmt( 9) case_stmt( 8) - case_stmt( 7) case_stmt( 6) - case_stmt( 5) case_stmt( 4) - #endif - case_stmt( 3) case_stmt( 2) - case_stmt( 1) - } - exprtk_disable_fallthrough_end + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15, exprtk_fallthrough) case_stmt(14, exprtk_fallthrough) + case_stmt(13, exprtk_fallthrough) case_stmt(12, exprtk_fallthrough) + case_stmt(11, exprtk_fallthrough) case_stmt(10, exprtk_fallthrough) + case_stmt( 9, exprtk_fallthrough) case_stmt( 8, exprtk_fallthrough) + case_stmt( 7, exprtk_fallthrough) case_stmt( 6, exprtk_fallthrough) + case_stmt( 5, exprtk_fallthrough) case_stmt( 4, exprtk_fallthrough) + #endif + case_stmt( 3, exprtk_fallthrough) case_stmt( 2, exprtk_fallthrough) + case_stmt( 1, (void)0;) + } - #undef exprtk_loop - #undef case_stmt + #undef exprtk_loop + #undef case_stmt - return vec0_node_ptr_->value(); - } - else - return std::numeric_limits<T>::quiet_NaN(); + return vec0_node_ptr_->value(); } - vector_node_ptr vec() const override + vector_node_ptr vec() const exprtk_override { return vec0_node_ptr_; } - vector_node_ptr vec() override + vector_node_ptr vec() exprtk_override { return vec0_node_ptr_; } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_vecopvecass; } - std::size_t size() const override + inline bool valid() const exprtk_override + { + return initialised_; + } + + std::size_t size() const exprtk_override + { + return std::min( + vec0_node_ptr_->vec_holder().size(), + vec1_node_ptr_->vec_holder().size()); + } + + std::size_t base_size() const exprtk_override { - return vds().size(); + return std::min( + vec0_node_ptr_->vec_holder().base_size(), + vec1_node_ptr_->vec_holder().base_size()); } - vds_t& vds() override + vds_t& vds() exprtk_override { return vds_; } - const vds_t& vds() const override + const vds_t& vds() const exprtk_override { return vds_; } - bool side_effect() const override + bool side_effect() const exprtk_override { return true; } @@ -11013,54 +13470,115 @@ namespace exprtk vds_t vds_; }; + template <typename T> + struct memory_context_t + { + typedef vector_node<T>* vector_node_ptr; + typedef vector_holder<T> vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; + + memory_context_t() + : temp_(0) + , temp_vec_node_(0) + {} + + void clear() + { + delete temp_vec_node_; + delete temp_; + } + + vector_holder_ptr temp_; + vector_node_ptr temp_vec_node_; + }; + + template <typename T> + inline memory_context_t<T> make_memory_context(vector_holder<T>& vec_holder, + vec_data_store<T>& vds) + { + memory_context_t<T> result_ctxt; + result_ctxt.temp_ = (vec_holder.rebaseable()) ? + new vector_holder<T>(vec_holder,vds) : + new vector_holder<T>(vds) ; + result_ctxt.temp_vec_node_ = new vector_node <T>(vds,result_ctxt.temp_); + return result_ctxt; + } + + template <typename T> + inline memory_context_t<T> make_memory_context(vector_holder<T>& vec_holder0, + vector_holder<T>& vec_holder1, + vec_data_store<T>& vds) + { + memory_context_t<T> result_ctxt; + + if (!vec_holder0.rebaseable() && !vec_holder1.rebaseable()) + result_ctxt.temp_ = new vector_holder<T>(vds); + else if (vec_holder0.rebaseable() && !vec_holder1.rebaseable()) + result_ctxt.temp_ = new vector_holder<T>(vec_holder0,vds); + else if (!vec_holder0.rebaseable() && vec_holder1.rebaseable()) + result_ctxt.temp_ = new vector_holder<T>(vec_holder1,vds); + else + { + result_ctxt.temp_ = (vec_holder0.base_size() >= vec_holder1.base_size()) ? + new vector_holder<T>(vec_holder0, vds) : + new vector_holder<T>(vec_holder1, vds) ; + } + + result_ctxt.temp_vec_node_ = new vector_node <T>(vds,result_ctxt.temp_); + return result_ctxt; + } + template <typename T, typename Operation> - class vec_binop_vecvec_node : public binary_node <T>, - public vector_interface<T> + class vec_binop_vecvec_node exprtk_final + : public binary_node <T> + , public vector_interface<T> { public: - typedef expression_node<T>* expression_ptr; - typedef vector_node<T>* vector_node_ptr; - typedef vector_holder<T>* vector_holder_ptr; - typedef vec_data_store<T> vds_t; + typedef expression_node<T>* expression_ptr; + typedef vector_node<T>* vector_node_ptr; + typedef vector_holder<T> vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; + typedef vec_data_store<T> vds_t; + typedef memory_context_t<T> memory_context; + + using binary_node<T>::branch; vec_binop_vecvec_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) - : binary_node<T>(opr, branch0, branch1), - vec0_node_ptr_(0), - vec1_node_ptr_(0), - temp_ (0), - temp_vec_node_(0), - initialised_(false) + : binary_node<T>(opr, branch0, branch1) + , vec0_node_ptr_(0) + , vec1_node_ptr_(0) + , initialised_(false) { bool v0_is_ivec = false; bool v1_is_ivec = false; - if (is_vector_node(binary_node<T>::branch_[0].first)) + if (is_vector_node(branch(0))) { - vec0_node_ptr_ = static_cast<vector_node_ptr>(binary_node<T>::branch_[0].first); + vec0_node_ptr_ = static_cast<vector_node_ptr>(branch(0)); } - else if (is_ivector_node(binary_node<T>::branch_[0].first)) + else if (is_ivector_node(branch(0))) { vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0); - if (0 != (vi = dynamic_cast<vector_interface<T>*>(binary_node<T>::branch_[0].first))) + if (0 != (vi = dynamic_cast<vector_interface<T>*>(branch(0)))) { vec0_node_ptr_ = vi->vec(); v0_is_ivec = true; } } - if (is_vector_node(binary_node<T>::branch_[1].first)) + if (is_vector_node(branch(1))) { - vec1_node_ptr_ = static_cast<vector_node_ptr>(binary_node<T>::branch_[1].first); + vec1_node_ptr_ = static_cast<vector_node_ptr>(branch(1)); } - else if (is_ivector_node(binary_node<T>::branch_[1].first)) + else if (is_ivector_node(branch(1))) { vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0); - if (0 != (vi = dynamic_cast<vector_interface<T>*>(binary_node<T>::branch_[1].first))) + if (0 != (vi = dynamic_cast<vector_interface<T>*>(branch(1)))) { vec1_node_ptr_ = vi->vec(); v1_is_ivec = true; @@ -11072,164 +13590,180 @@ namespace exprtk vector_holder<T>& vec0 = vec0_node_ptr_->vec_holder(); vector_holder<T>& vec1 = vec1_node_ptr_->vec_holder(); - if (v0_is_ivec && (vec0.size() <= vec1.size())) + if (v0_is_ivec && (vec0.base_size() <= vec1.base_size())) + { vds_ = vds_t(vec0_node_ptr_->vds()); - else if (v1_is_ivec && (vec1.size() <= vec0.size())) + } + else if (v1_is_ivec && (vec1.base_size() <= vec0.base_size())) + { vds_ = vds_t(vec1_node_ptr_->vds()); + } else - vds_ = vds_t(std::min(vec0.size(),vec1.size())); + { + vds_ = vds_t(std::min(vec0.base_size(),vec1.base_size())); + } - temp_ = new vector_holder<T>(vds().data(),vds().size()); - temp_vec_node_ = new vector_node<T> (vds(),temp_); + memory_context_ = make_memory_context(vec0, vec1, vds()); - initialised_ = true; + initialised_ = + (size() <= base_size()) && + binary_node<T>::valid(); } + + assert(valid()); } - ~vec_binop_vecvec_node() override + ~vec_binop_vecvec_node() exprtk_override { - delete temp_; - delete temp_vec_node_; + memory_context_.clear(); } - inline T value() const override + inline T value() const exprtk_override { - if (initialised_) - { - assert(binary_node<T>::branch_[0].first); - assert(binary_node<T>::branch_[1].first); - - binary_node<T>::branch_[0].first->value(); - binary_node<T>::branch_[1].first->value(); + branch(0)->value(); + branch(1)->value(); - const T* vec0 = vec0_node_ptr_->vds().data(); - const T* vec1 = vec1_node_ptr_->vds().data(); - T* vec2 = vds().data(); + const T* vec0 = vec0_node_ptr_->vds().data(); + const T* vec1 = vec1_node_ptr_->vds().data(); + T* vec2 = vds().data(); - loop_unroll::details lud(size()); - const T* upper_bound = vec2 + lud.upper_bound; + loop_unroll::details lud(size()); + const T* upper_bound = vec2 + lud.upper_bound; - while (vec2 < upper_bound) - { - #define exprtk_loop(N) \ - vec2[N] = Operation::process(vec0[N], vec1[N]); \ + while (vec2 < upper_bound) + { + #define exprtk_loop(N) \ + vec2[N] = Operation::process(vec0[N], vec1[N]); \ - exprtk_loop( 0) exprtk_loop( 1) - exprtk_loop( 2) exprtk_loop( 3) - #ifndef exprtk_disable_superscalar_unroll - exprtk_loop( 4) exprtk_loop( 5) - exprtk_loop( 6) exprtk_loop( 7) - exprtk_loop( 8) exprtk_loop( 9) - exprtk_loop(10) exprtk_loop(11) - exprtk_loop(12) exprtk_loop(13) - exprtk_loop(14) exprtk_loop(15) - #endif + exprtk_loop( 0) exprtk_loop( 1) + exprtk_loop( 2) exprtk_loop( 3) + #ifndef exprtk_disable_superscalar_unroll + exprtk_loop( 4) exprtk_loop( 5) + exprtk_loop( 6) exprtk_loop( 7) + exprtk_loop( 8) exprtk_loop( 9) + exprtk_loop(10) exprtk_loop(11) + exprtk_loop(12) exprtk_loop(13) + exprtk_loop(14) exprtk_loop(15) + #endif - vec0 += lud.batch_size; - vec1 += lud.batch_size; - vec2 += lud.batch_size; - } + vec0 += lud.batch_size; + vec1 += lud.batch_size; + vec2 += lud.batch_size; + } - int i = 0; + int i = 0; - exprtk_disable_fallthrough_begin - switch (lud.remainder) - { - #define case_stmt(N) \ - case N : { vec2[i] = Operation::process(vec0[i], vec1[i]); ++i; } \ + switch (lud.remainder) + { + #define case_stmt(N) \ + case N : { vec2[i] = Operation::process(vec0[i], vec1[i]); ++i; } \ + exprtk_fallthrough \ - #ifndef exprtk_disable_superscalar_unroll - case_stmt(15) case_stmt(14) - case_stmt(13) case_stmt(12) - case_stmt(11) case_stmt(10) - case_stmt( 9) case_stmt( 8) - case_stmt( 7) case_stmt( 6) - case_stmt( 5) case_stmt( 4) - #endif - case_stmt( 3) case_stmt( 2) - case_stmt( 1) - } - exprtk_disable_fallthrough_end + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15) case_stmt(14) + case_stmt(13) case_stmt(12) + case_stmt(11) case_stmt(10) + case_stmt( 9) case_stmt( 8) + case_stmt( 7) case_stmt( 6) + case_stmt( 5) case_stmt( 4) + #endif + case_stmt( 3) case_stmt( 2) + case_stmt( 1) + default: break; + } - #undef exprtk_loop - #undef case_stmt + #undef exprtk_loop + #undef case_stmt - return (vds().data())[0]; - } - else - return std::numeric_limits<T>::quiet_NaN(); + return (vds().data())[0]; } - vector_node_ptr vec() const override + vector_node_ptr vec() const exprtk_override { - return temp_vec_node_; + return memory_context_.temp_vec_node_; } - vector_node_ptr vec() override + vector_node_ptr vec() exprtk_override { - return temp_vec_node_; + return memory_context_.temp_vec_node_; } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_vecvecarith; } - std::size_t size() const override + inline bool valid() const exprtk_override + { + return initialised_; + } + + std::size_t size() const exprtk_override { - return vds_.size(); + return std::min( + vec0_node_ptr_->vec_holder().size(), + vec1_node_ptr_->vec_holder().size()); } - vds_t& vds() override + std::size_t base_size() const exprtk_override + { + return std::min( + vec0_node_ptr_->vec_holder().base_size(), + vec1_node_ptr_->vec_holder().base_size()); + } + + vds_t& vds() exprtk_override { return vds_; } - const vds_t& vds() const override + const vds_t& vds() const exprtk_override { return vds_; } private: - vector_node_ptr vec0_node_ptr_; - vector_node_ptr vec1_node_ptr_; - vector_holder_ptr temp_; - vector_node_ptr temp_vec_node_; - bool initialised_; - vds_t vds_; + vector_node_ptr vec0_node_ptr_; + vector_node_ptr vec1_node_ptr_; + bool initialised_; + vds_t vds_; + memory_context memory_context_; }; template <typename T, typename Operation> - class vec_binop_vecval_node : public binary_node <T>, - public vector_interface<T> + class vec_binop_vecval_node exprtk_final + : public binary_node <T> + , public vector_interface<T> { public: - typedef expression_node<T>* expression_ptr; - typedef vector_node<T>* vector_node_ptr; - typedef vector_holder<T>* vector_holder_ptr; - typedef vec_data_store<T> vds_t; + typedef expression_node<T>* expression_ptr; + typedef vector_node<T>* vector_node_ptr; + typedef vector_holder<T> vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; + typedef vec_data_store<T> vds_t; + typedef memory_context_t<T> memory_context; + + using binary_node<T>::branch; vec_binop_vecval_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) - : binary_node<T>(opr, branch0, branch1), - vec0_node_ptr_(0), - temp_ (0), - temp_vec_node_(0) + : binary_node<T>(opr, branch0, branch1) + , vec0_node_ptr_(0) { bool v0_is_ivec = false; - if (is_vector_node(binary_node<T>::branch_[0].first)) + if (is_vector_node(branch(0))) { - vec0_node_ptr_ = static_cast<vector_node_ptr>(binary_node<T>::branch_[0].first); + vec0_node_ptr_ = static_cast<vector_node_ptr>(branch(0)); } - else if (is_ivector_node(binary_node<T>::branch_[0].first)) + else if (is_ivector_node(branch(0))) { vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0); - if (0 != (vi = dynamic_cast<vector_interface<T>*>(binary_node<T>::branch_[0].first))) + if (0 != (vi = dynamic_cast<vector_interface<T>*>(branch(0)))) { vec0_node_ptr_ = vi->vec(); v0_is_ivec = true; @@ -11241,111 +13775,115 @@ namespace exprtk if (v0_is_ivec) vds() = vec0_node_ptr_->vds(); else - vds() = vds_t(vec0_node_ptr_->size()); + vds() = vds_t(vec0_node_ptr_->base_size()); - temp_ = new vector_holder<T>(vds()); - temp_vec_node_ = new vector_node<T> (vds(),temp_); + memory_context_ = make_memory_context(vec0_node_ptr_->vec_holder(), vds()); } + + assert(valid()); } - ~vec_binop_vecval_node() override + ~vec_binop_vecval_node() exprtk_override { - delete temp_; - delete temp_vec_node_; + memory_context_.clear(); } - inline T value() const override + inline T value() const exprtk_override { - if (vec0_node_ptr_) - { - assert(binary_node<T>::branch_[0].first); - assert(binary_node<T>::branch_[1].first); + branch(0)->value(); + const T v = branch(1)->value(); - binary_node<T>::branch_[0].first->value(); - const T v = binary_node<T>::branch_[1].first->value(); + const T* vec0 = vec0_node_ptr_->vds().data(); + T* vec1 = vds().data(); - const T* vec0 = vec0_node_ptr_->vds().data(); - T* vec1 = vds().data(); + loop_unroll::details lud(size()); + const T* upper_bound = vec0 + lud.upper_bound; - loop_unroll::details lud(size()); - const T* upper_bound = vec0 + lud.upper_bound; - - while (vec0 < upper_bound) - { - #define exprtk_loop(N) \ - vec1[N] = Operation::process(vec0[N], v); \ + while (vec0 < upper_bound) + { + #define exprtk_loop(N) \ + vec1[N] = Operation::process(vec0[N], v); \ - exprtk_loop( 0) exprtk_loop( 1) - exprtk_loop( 2) exprtk_loop( 3) - #ifndef exprtk_disable_superscalar_unroll - exprtk_loop( 4) exprtk_loop( 5) - exprtk_loop( 6) exprtk_loop( 7) - exprtk_loop( 8) exprtk_loop( 9) - exprtk_loop(10) exprtk_loop(11) - exprtk_loop(12) exprtk_loop(13) - exprtk_loop(14) exprtk_loop(15) - #endif + exprtk_loop( 0) exprtk_loop( 1) + exprtk_loop( 2) exprtk_loop( 3) + #ifndef exprtk_disable_superscalar_unroll + exprtk_loop( 4) exprtk_loop( 5) + exprtk_loop( 6) exprtk_loop( 7) + exprtk_loop( 8) exprtk_loop( 9) + exprtk_loop(10) exprtk_loop(11) + exprtk_loop(12) exprtk_loop(13) + exprtk_loop(14) exprtk_loop(15) + #endif - vec0 += lud.batch_size; - vec1 += lud.batch_size; - } + vec0 += lud.batch_size; + vec1 += lud.batch_size; + } - int i = 0; + int i = 0; - exprtk_disable_fallthrough_begin - switch (lud.remainder) - { - #define case_stmt(N) \ - case N : { vec1[i] = Operation::process(vec0[i], v); ++i; } \ + switch (lud.remainder) + { + #define case_stmt(N,fall_through) \ + case N : { vec1[i] = Operation::process(vec0[i], v); ++i; } \ + fall_through \ - #ifndef exprtk_disable_superscalar_unroll - case_stmt(15) case_stmt(14) - case_stmt(13) case_stmt(12) - case_stmt(11) case_stmt(10) - case_stmt( 9) case_stmt( 8) - case_stmt( 7) case_stmt( 6) - case_stmt( 5) case_stmt( 4) - #endif - case_stmt( 3) case_stmt( 2) - case_stmt( 1) - } - exprtk_disable_fallthrough_end + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15, exprtk_fallthrough) case_stmt(14, exprtk_fallthrough) + case_stmt(13, exprtk_fallthrough) case_stmt(12, exprtk_fallthrough) + case_stmt(11, exprtk_fallthrough) case_stmt(10, exprtk_fallthrough) + case_stmt( 9, exprtk_fallthrough) case_stmt( 8, exprtk_fallthrough) + case_stmt( 7, exprtk_fallthrough) case_stmt( 6, exprtk_fallthrough) + case_stmt( 5, exprtk_fallthrough) case_stmt( 4, exprtk_fallthrough) + #endif + case_stmt( 3, exprtk_fallthrough) case_stmt( 2, exprtk_fallthrough) + case_stmt( 1, (void)0;) + } - #undef exprtk_loop - #undef case_stmt + #undef exprtk_loop + #undef case_stmt - return (vds().data())[0]; - } - else - return std::numeric_limits<T>::quiet_NaN(); + return (vds().data())[0]; } - vector_node_ptr vec() const override + vector_node_ptr vec() const exprtk_override { - return temp_vec_node_; + return memory_context_.temp_vec_node_; } - vector_node_ptr vec() override + vector_node_ptr vec() exprtk_override { - return temp_vec_node_; + return memory_context_.temp_vec_node_; } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_vecvalarith; } - std::size_t size() const override + inline bool valid() const exprtk_override + { + return + vec0_node_ptr_ && + (size() <= base_size()) && + binary_node<T>::valid(); + } + + std::size_t size() const exprtk_override + { + return vec0_node_ptr_->size(); + } + + std::size_t base_size() const exprtk_override { - return vds().size(); + return vec0_node_ptr_->vec_holder().base_size(); } - vds_t& vds() override + vds_t& vds() exprtk_override { return vds_; } - const vds_t& vds() const override + const vds_t& vds() const exprtk_override { return vds_; } @@ -11353,41 +13891,43 @@ namespace exprtk private: vector_node_ptr vec0_node_ptr_; - vector_holder_ptr temp_; - vector_node_ptr temp_vec_node_; vds_t vds_; + memory_context memory_context_; }; template <typename T, typename Operation> - class vec_binop_valvec_node : public binary_node <T>, - public vector_interface<T> + class vec_binop_valvec_node exprtk_final + : public binary_node <T> + , public vector_interface<T> { public: - typedef expression_node<T>* expression_ptr; - typedef vector_node<T>* vector_node_ptr; - typedef vector_holder<T>* vector_holder_ptr; - typedef vec_data_store<T> vds_t; + typedef expression_node<T>* expression_ptr; + typedef vector_node<T>* vector_node_ptr; + typedef vector_holder<T> vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; + typedef vec_data_store<T> vds_t; + typedef memory_context_t<T> memory_context; + + using binary_node<T>::branch; vec_binop_valvec_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) - : binary_node<T>(opr, branch0, branch1), - vec1_node_ptr_(0), - temp_ (0), - temp_vec_node_(0) + : binary_node<T>(opr, branch0, branch1) + , vec1_node_ptr_(0) { bool v1_is_ivec = false; - if (is_vector_node(binary_node<T>::branch_[1].first)) + if (is_vector_node(branch(1))) { - vec1_node_ptr_ = static_cast<vector_node_ptr>(binary_node<T>::branch_[1].first); + vec1_node_ptr_ = static_cast<vector_node_ptr>(branch(1)); } - else if (is_ivector_node(binary_node<T>::branch_[1].first)) + else if (is_ivector_node(branch(1))) { vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0); - if (0 != (vi = dynamic_cast<vector_interface<T>*>(binary_node<T>::branch_[1].first))) + if (0 != (vi = dynamic_cast<vector_interface<T>*>(branch(1)))) { vec1_node_ptr_ = vi->vec(); v1_is_ivec = true; @@ -11399,111 +13939,116 @@ namespace exprtk if (v1_is_ivec) vds() = vec1_node_ptr_->vds(); else - vds() = vds_t(vec1_node_ptr_->size()); + vds() = vds_t(vec1_node_ptr_->base_size()); - temp_ = new vector_holder<T>(vds()); - temp_vec_node_ = new vector_node<T> (vds(),temp_); + memory_context_ = make_memory_context(vec1_node_ptr_->vec_holder(), vds()); } + + assert(valid()); } - ~vec_binop_valvec_node() override + ~vec_binop_valvec_node() exprtk_override { - delete temp_; - delete temp_vec_node_; + memory_context_.clear(); } - inline T value() const override + inline T value() const exprtk_override { - if (vec1_node_ptr_) - { - assert(binary_node<T>::branch_[0].first); - assert(binary_node<T>::branch_[1].first); + const T v = branch(0)->value(); + branch(1)->value(); - const T v = binary_node<T>::branch_[0].first->value(); - binary_node<T>::branch_[1].first->value(); + T* vec0 = vds().data(); + const T* vec1 = vec1_node_ptr_->vds().data(); - T* vec0 = vds().data(); - const T* vec1 = vec1_node_ptr_->vds().data(); + loop_unroll::details lud(size()); + const T* upper_bound = vec0 + lud.upper_bound; - loop_unroll::details lud(size()); - const T* upper_bound = vec0 + lud.upper_bound; - - while (vec0 < upper_bound) - { - #define exprtk_loop(N) \ - vec0[N] = Operation::process(v, vec1[N]); \ + while (vec0 < upper_bound) + { + #define exprtk_loop(N) \ + vec0[N] = Operation::process(v, vec1[N]); \ - exprtk_loop( 0) exprtk_loop( 1) - exprtk_loop( 2) exprtk_loop( 3) - #ifndef exprtk_disable_superscalar_unroll - exprtk_loop( 4) exprtk_loop( 5) - exprtk_loop( 6) exprtk_loop( 7) - exprtk_loop( 8) exprtk_loop( 9) - exprtk_loop(10) exprtk_loop(11) - exprtk_loop(12) exprtk_loop(13) - exprtk_loop(14) exprtk_loop(15) - #endif + exprtk_loop( 0) exprtk_loop( 1) + exprtk_loop( 2) exprtk_loop( 3) + #ifndef exprtk_disable_superscalar_unroll + exprtk_loop( 4) exprtk_loop( 5) + exprtk_loop( 6) exprtk_loop( 7) + exprtk_loop( 8) exprtk_loop( 9) + exprtk_loop(10) exprtk_loop(11) + exprtk_loop(12) exprtk_loop(13) + exprtk_loop(14) exprtk_loop(15) + #endif - vec0 += lud.batch_size; - vec1 += lud.batch_size; - } + vec0 += lud.batch_size; + vec1 += lud.batch_size; + } - int i = 0; + int i = 0; - exprtk_disable_fallthrough_begin - switch (lud.remainder) - { - #define case_stmt(N) \ - case N : { vec0[i] = Operation::process(v, vec1[i]); ++i; } \ + switch (lud.remainder) + { + #define case_stmt(N,fall_through) \ + case N : { vec0[i] = Operation::process(v, vec1[i]); ++i; } \ + fall_through \ - #ifndef exprtk_disable_superscalar_unroll - case_stmt(15) case_stmt(14) - case_stmt(13) case_stmt(12) - case_stmt(11) case_stmt(10) - case_stmt( 9) case_stmt( 8) - case_stmt( 7) case_stmt( 6) - case_stmt( 5) case_stmt( 4) - #endif - case_stmt( 3) case_stmt( 2) - case_stmt( 1) - } - exprtk_disable_fallthrough_end + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15, exprtk_fallthrough) case_stmt(14, exprtk_fallthrough) + case_stmt(13, exprtk_fallthrough) case_stmt(12, exprtk_fallthrough) + case_stmt(11, exprtk_fallthrough) case_stmt(10, exprtk_fallthrough) + case_stmt( 9, exprtk_fallthrough) case_stmt( 8, exprtk_fallthrough) + case_stmt( 7, exprtk_fallthrough) case_stmt( 6, exprtk_fallthrough) + case_stmt( 5, exprtk_fallthrough) case_stmt( 4, exprtk_fallthrough) + #endif + case_stmt( 3, exprtk_fallthrough) case_stmt( 2, exprtk_fallthrough) + case_stmt( 1, (void)0;) + } - #undef exprtk_loop - #undef case_stmt + #undef exprtk_loop + #undef case_stmt - return (vds().data())[0]; - } - else - return std::numeric_limits<T>::quiet_NaN(); + return (vds().data())[0]; } - vector_node_ptr vec() const override + vector_node_ptr vec() const exprtk_override { - return temp_vec_node_; + return memory_context_.temp_vec_node_; } - vector_node_ptr vec() override + vector_node_ptr vec() exprtk_override { - return temp_vec_node_; + return memory_context_.temp_vec_node_; } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_vecvalarith; } - std::size_t size() const override + inline bool valid() const exprtk_override + { + return + vec1_node_ptr_ && + (size() <= base_size()) && + (vds_.size() <= base_size()) && + binary_node<T>::valid(); + } + + std::size_t size() const exprtk_override + { + return vec1_node_ptr_->vec_holder().size(); + } + + std::size_t base_size() const exprtk_override { - return vds().size(); + return vec1_node_ptr_->vec_holder().base_size(); } - vds_t& vds() override + vds_t& vds() exprtk_override { return vds_; } - const vds_t& vds() const override + const vds_t& vds() const exprtk_override { return vds_; } @@ -11511,39 +14056,41 @@ namespace exprtk private: vector_node_ptr vec1_node_ptr_; - vector_holder_ptr temp_; - vector_node_ptr temp_vec_node_; vds_t vds_; + memory_context memory_context_; }; template <typename T, typename Operation> - class unary_vector_node : public unary_node <T>, - public vector_interface<T> + class unary_vector_node exprtk_final + : public unary_node <T> + , public vector_interface<T> { public: - typedef expression_node<T>* expression_ptr; - typedef vector_node<T>* vector_node_ptr; - typedef vector_holder<T>* vector_holder_ptr; - typedef vec_data_store<T> vds_t; + typedef expression_node<T>* expression_ptr; + typedef vector_node<T>* vector_node_ptr; + typedef vector_holder<T> vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; + typedef vec_data_store<T> vds_t; + typedef memory_context_t<T> memory_context; + + using expression_node<T>::branch; unary_vector_node(const operator_type& opr, expression_ptr branch0) - : unary_node<T>(opr, branch0), - vec0_node_ptr_(0), - temp_ (0), - temp_vec_node_(0) + : unary_node<T>(opr, branch0) + , vec0_node_ptr_(0) { bool vec0_is_ivec = false; - if (is_vector_node(unary_node<T>::branch_.first)) + if (is_vector_node(branch(0))) { - vec0_node_ptr_ = static_cast<vector_node_ptr>(unary_node<T>::branch_.first); + vec0_node_ptr_ = static_cast<vector_node_ptr>(branch(0)); } - else if (is_ivector_node(unary_node<T>::branch_.first)) + else if (is_ivector_node(branch(0))) { vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0); - if (0 != (vi = dynamic_cast<vector_interface<T>*>(unary_node<T>::branch_.first))) + if (0 != (vi = dynamic_cast<vector_interface<T>*>(branch(0)))) { vec0_node_ptr_ = vi->vec(); vec0_is_ivec = true; @@ -11555,188 +14102,366 @@ namespace exprtk if (vec0_is_ivec) vds_ = vec0_node_ptr_->vds(); else - vds_ = vds_t(vec0_node_ptr_->size()); + vds_ = vds_t(vec0_node_ptr_->base_size()); - temp_ = new vector_holder<T>(vds()); - temp_vec_node_ = new vector_node<T> (vds(),temp_); + memory_context_ = make_memory_context(vec0_node_ptr_->vec_holder(), vds()); } + + assert(valid()); } - ~unary_vector_node() override + ~unary_vector_node() exprtk_override { - delete temp_; - delete temp_vec_node_; + memory_context_.clear(); } - inline T value() const override + inline T value() const exprtk_override { - assert(unary_node<T>::branch_.first); + branch()->value(); - unary_node<T>::branch_.first->value(); + const T* vec0 = vec0_node_ptr_->vds().data(); + T* vec1 = vds().data(); - if (vec0_node_ptr_) + loop_unroll::details lud(size()); + const T* upper_bound = vec0 + lud.upper_bound; + + while (vec0 < upper_bound) { - const T* vec0 = vec0_node_ptr_->vds().data(); - T* vec1 = vds().data(); + #define exprtk_loop(N) \ + vec1[N] = Operation::process(vec0[N]); \ - loop_unroll::details lud(size()); - const T* upper_bound = vec0 + lud.upper_bound; + exprtk_loop( 0) exprtk_loop( 1) + exprtk_loop( 2) exprtk_loop( 3) + #ifndef exprtk_disable_superscalar_unroll + exprtk_loop( 4) exprtk_loop( 5) + exprtk_loop( 6) exprtk_loop( 7) + exprtk_loop( 8) exprtk_loop( 9) + exprtk_loop(10) exprtk_loop(11) + exprtk_loop(12) exprtk_loop(13) + exprtk_loop(14) exprtk_loop(15) + #endif - while (vec0 < upper_bound) - { - #define exprtk_loop(N) \ - vec1[N] = Operation::process(vec0[N]); \ + vec0 += lud.batch_size; + vec1 += lud.batch_size; + } - exprtk_loop( 0) exprtk_loop( 1) - exprtk_loop( 2) exprtk_loop( 3) - #ifndef exprtk_disable_superscalar_unroll - exprtk_loop( 4) exprtk_loop( 5) - exprtk_loop( 6) exprtk_loop( 7) - exprtk_loop( 8) exprtk_loop( 9) - exprtk_loop(10) exprtk_loop(11) - exprtk_loop(12) exprtk_loop(13) - exprtk_loop(14) exprtk_loop(15) - #endif + int i = 0; - vec0 += lud.batch_size; - vec1 += lud.batch_size; - } + switch (lud.remainder) + { + #define case_stmt(N) \ + case N : { vec1[i] = Operation::process(vec0[i]); ++i; } \ + exprtk_fallthrough \ - int i = 0; + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15) case_stmt(14) + case_stmt(13) case_stmt(12) + case_stmt(11) case_stmt(10) + case_stmt( 9) case_stmt( 8) + case_stmt( 7) case_stmt( 6) + case_stmt( 5) case_stmt( 4) + #endif + case_stmt( 3) case_stmt( 2) + case_stmt( 1) + default: break; + } - exprtk_disable_fallthrough_begin - switch (lud.remainder) + #undef exprtk_loop + #undef case_stmt + + return (vds().data())[0]; + } + + vector_node_ptr vec() const exprtk_override + { + return memory_context_.temp_vec_node_; + } + + vector_node_ptr vec() exprtk_override + { + return memory_context_.temp_vec_node_; + } + + inline typename expression_node<T>::node_type type() const exprtk_override + { + return expression_node<T>::e_vecunaryop; + } + + inline bool valid() const exprtk_override + { + return vec0_node_ptr_ && unary_node<T>::valid(); + } + + std::size_t size() const exprtk_override + { + return vec0_node_ptr_->vec_holder().size(); + } + + std::size_t base_size() const exprtk_override + { + return vec0_node_ptr_->vec_holder().base_size(); + } + + vds_t& vds() exprtk_override + { + return vds_; + } + + const vds_t& vds() const exprtk_override + { + return vds_; + } + + private: + + vector_node_ptr vec0_node_ptr_; + vds_t vds_; + memory_context memory_context_; + }; + + template <typename T> + class conditional_vector_node exprtk_final + : public expression_node <T> + , public vector_interface<T> + { + public: + + typedef expression_node <T>* expression_ptr; + typedef vector_interface<T>* vec_interface_ptr; + typedef vector_node <T>* vector_node_ptr; + typedef vector_holder <T> vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; + typedef vec_data_store <T> vds_t; + typedef memory_context_t<T> memory_context; + typedef std::pair<expression_ptr,bool> branch_t; + + conditional_vector_node(expression_ptr condition, + expression_ptr consequent, + expression_ptr alternative) + : consequent_node_ptr_ (0) + , alternative_node_ptr_(0) + , temp_vec_node_ (0) + , temp_ (0) + , result_vec_size_ (0) + , initialised_ (false) + { + construct_branch_pair(condition_ , condition ); + construct_branch_pair(consequent_ , consequent ); + construct_branch_pair(alternative_, alternative); + + if (details::is_ivector_node(consequent_.first)) + { + vec_interface_ptr ivec_ptr = dynamic_cast<vec_interface_ptr>(consequent_.first); + + if (0 != ivec_ptr) { - #define case_stmt(N) \ - case N : { vec1[i] = Operation::process(vec0[i]); ++i; } \ + consequent_node_ptr_ = ivec_ptr->vec(); + } + } - #ifndef exprtk_disable_superscalar_unroll - case_stmt(15) case_stmt(14) - case_stmt(13) case_stmt(12) - case_stmt(11) case_stmt(10) - case_stmt( 9) case_stmt( 8) - case_stmt( 7) case_stmt( 6) - case_stmt( 5) case_stmt( 4) - #endif - case_stmt( 3) case_stmt( 2) - case_stmt( 1) + if (details::is_ivector_node(alternative_.first)) + { + vec_interface_ptr ivec_ptr = dynamic_cast<vec_interface_ptr>(alternative_.first); + + if (0 != ivec_ptr) + { + alternative_node_ptr_ = ivec_ptr->vec(); } - exprtk_disable_fallthrough_end + } - #undef exprtk_loop - #undef case_stmt + if (consequent_node_ptr_ && alternative_node_ptr_) + { + const std::size_t vec_size = + std::max(consequent_node_ptr_ ->vec_holder().base_size(), + alternative_node_ptr_->vec_holder().base_size()); + + vds_ = vds_t(vec_size); + memory_context_ = make_memory_context( + consequent_node_ptr_ ->vec_holder(), + alternative_node_ptr_->vec_holder(), + vds()); + + initialised_ = (vec_size > 0); + } + + assert(initialised_); + } + + ~conditional_vector_node() exprtk_override + { + memory_context_.clear(); + } + + inline T value() const exprtk_override + { + T result = T(0); + T* source_vector = 0; + T* result_vector = vds().data(); - return (vds().data())[0]; + if (is_true(condition_)) + { + result = consequent_.first->value(); + source_vector = consequent_node_ptr_->vds().data(); + result_vec_size_ = consequent_node_ptr_->size(); } else - return std::numeric_limits<T>::quiet_NaN(); + { + result = alternative_.first->value(); + source_vector = alternative_node_ptr_->vds().data(); + result_vec_size_ = alternative_node_ptr_->size(); + } + + for (std::size_t i = 0; i < result_vec_size_; ++i) + { + result_vector[i] = source_vector[i]; + } + + return result; } - vector_node_ptr vec() const override + vector_node_ptr vec() const exprtk_override { - return temp_vec_node_; + return memory_context_.temp_vec_node_; } - vector_node_ptr vec() override + vector_node_ptr vec() exprtk_override { - return temp_vec_node_; + return memory_context_.temp_vec_node_; } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { - return expression_node<T>::e_vecunaryop; + return expression_node<T>::e_vecondition; + } + + inline bool valid() const exprtk_override + { + return + initialised_ && + condition_ .first && condition_ .first->valid() && + consequent_ .first && consequent_ .first->valid() && + alternative_.first && alternative_.first->valid() && + size() <= base_size(); + } + + std::size_t size() const exprtk_override + { + return result_vec_size_; } - std::size_t size() const override + std::size_t base_size() const exprtk_override { - return vds().size(); + return std::min( + consequent_node_ptr_ ->vec_holder().base_size(), + alternative_node_ptr_->vec_holder().base_size()); } - vds_t& vds() override + vds_t& vds() exprtk_override { return vds_; } - const vds_t& vds() const override + const vds_t& vds() const exprtk_override { return vds_; } + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override + { + expression_node<T>::ndb_t::collect(condition_ , node_delete_list); + expression_node<T>::ndb_t::collect(consequent_ , node_delete_list); + expression_node<T>::ndb_t::collect(alternative_ , node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node<T>::ndb_t::compute_node_depth + (condition_, consequent_, alternative_); + } + private: - vector_node_ptr vec0_node_ptr_; - vector_holder_ptr temp_; - vector_node_ptr temp_vec_node_; - vds_t vds_; + branch_t condition_; + branch_t consequent_; + branch_t alternative_; + vector_node_ptr consequent_node_ptr_; + vector_node_ptr alternative_node_ptr_; + vector_node_ptr temp_vec_node_; + vector_holder_ptr temp_; + vds_t vds_; + mutable std::size_t result_vec_size_; + bool initialised_; + memory_context memory_context_; }; template <typename T> - class scand_node : public binary_node<T> + class scand_node exprtk_final : public binary_node<T> { public: typedef expression_node<T>* expression_ptr; + using binary_node<T>::branch; scand_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) : binary_node<T>(opr, branch0, branch1) - {} - - inline T value() const override { - assert(binary_node<T>::branch_[0].first); - assert(binary_node<T>::branch_[1].first); + assert(binary_node<T>::valid()); + } + inline T value() const exprtk_override + { return ( std::not_equal_to<T>() - (T(0),binary_node<T>::branch_[0].first->value()) && + (T(0),branch(0)->value()) && std::not_equal_to<T>() - (T(0),binary_node<T>::branch_[1].first->value()) + (T(0),branch(1)->value()) ) ? T(1) : T(0); } }; template <typename T> - class scor_node : public binary_node<T> + class scor_node exprtk_final : public binary_node<T> { public: typedef expression_node<T>* expression_ptr; + using binary_node<T>::branch; scor_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) : binary_node<T>(opr, branch0, branch1) - {} - - inline T value() const override { - assert(binary_node<T>::branch_[0].first); - assert(binary_node<T>::branch_[1].first); + assert(binary_node<T>::valid()); + } + inline T value() const exprtk_override + { return ( std::not_equal_to<T>() - (T(0),binary_node<T>::branch_[0].first->value()) || + (T(0),branch(0)->value()) || std::not_equal_to<T>() - (T(0),binary_node<T>::branch_[1].first->value()) + (T(0),branch(1)->value()) ) ? T(1) : T(0); } }; template <typename T, typename IFunction, std::size_t N> - class function_N_node : public expression_node<T> + class function_N_node exprtk_final : public expression_node<T> { public: - // Function of N paramters. + // Function of N parameters. typedef expression_node<T>* expression_ptr; typedef std::pair<expression_ptr,bool> branch_t; typedef IFunction ifunction; explicit function_N_node(ifunction* func) - : function_((N == func->param_count) ? func : reinterpret_cast<ifunction*>(0)), - parameter_count_(func->param_count) + : function_((N == func->param_count) ? func : reinterpret_cast<ifunction*>(0)) + , parameter_count_(func->param_count) + , initialised_(false) {} template <std::size_t NumBranches> @@ -11747,19 +14472,24 @@ namespace exprtk #pragma warning(push) #pragma warning(disable: 4127) #endif + if (N != NumBranches) + { return false; - else + } + + for (std::size_t i = 0; i < NumBranches; ++i) { - for (std::size_t i = 0; i < NumBranches; ++i) - { - if (b[i]) - branch_[i] = std::make_pair(b[i],branch_deletable(b[i])); - else - return false; - } - return true; + if (b[i] && b[i]->valid()) + branch_[i] = std::make_pair(b[i],branch_deletable(b[i])); + else + return false; } + + initialised_ = function_; + assert(valid()); + return initialised_; + #ifdef _MSC_VER #pragma warning(pop) #endif @@ -11770,26 +14500,43 @@ namespace exprtk return this < (&fn); } - inline T value() const override + inline T value() const exprtk_override { // Needed for incompetent and broken msvc compiler versions #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4127) #endif - if ((0 == function_) || (0 == N)) - return std::numeric_limits<T>::quiet_NaN(); - else - { - T v[N]; - evaluate_branches<T,N>::execute(v,branch_); - return invoke<T,N>::execute(*function_,v); - } + + T v[N]; + evaluate_branches<T,N>::execute(v,branch_); + return invoke<T,N>::execute(*function_,v); + #ifdef _MSC_VER #pragma warning(pop) #endif } + inline typename expression_node<T>::node_type type() const exprtk_override + { + return expression_node<T>::e_function; + } + + inline bool valid() const exprtk_override + { + return initialised_; + } + + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override + { + expression_node<T>::ndb_t::collect(branch_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node<T>::ndb_t::template compute_node_depth<N>(branch_); + } + template <typename T_, std::size_t BranchCount> struct evaluate_branches { @@ -11802,6 +14549,20 @@ namespace exprtk } }; + template <typename T_> + struct evaluate_branches <T_,6> + { + static inline void execute(T_ (&v)[6], const branch_t (&b)[6]) + { + v[0] = b[0].first->value(); + v[1] = b[1].first->value(); + v[2] = b[2].first->value(); + v[3] = b[3].first->value(); + v[4] = b[4].first->value(); + v[5] = b[5].first->value(); + } + }; + template <typename T_> struct evaluate_branches <T_,5> { @@ -11878,119 +14639,119 @@ namespace exprtk struct invoke<T_,18> { static inline T_ execute(ifunction& f, T_ (&v)[18]) - { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],v[10],v[11],v[12],v[13],v[14],v[15],v[16],v[17]); } + { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11], v[12], v[13], v[14], v[15], v[16], v[17]); } }; template <typename T_> struct invoke<T_,17> { static inline T_ execute(ifunction& f, T_ (&v)[17]) - { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],v[10],v[11],v[12],v[13],v[14],v[15],v[16]); } + { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11], v[12], v[13], v[14], v[15], v[16]); } }; template <typename T_> struct invoke<T_,16> { static inline T_ execute(ifunction& f, T_ (&v)[16]) - { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],v[10],v[11],v[12],v[13],v[14],v[15]); } + { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11], v[12], v[13], v[14], v[15]); } }; template <typename T_> struct invoke<T_,15> { static inline T_ execute(ifunction& f, T_ (&v)[15]) - { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],v[10],v[11],v[12],v[13],v[14]); } + { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11], v[12], v[13], v[14]); } }; template <typename T_> struct invoke<T_,14> { static inline T_ execute(ifunction& f, T_ (&v)[14]) - { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],v[10],v[11],v[12],v[13]); } + { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11], v[12], v[13]); } }; template <typename T_> struct invoke<T_,13> { static inline T_ execute(ifunction& f, T_ (&v)[13]) - { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],v[10],v[11],v[12]); } + { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11], v[12]); } }; template <typename T_> struct invoke<T_,12> { static inline T_ execute(ifunction& f, T_ (&v)[12]) - { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],v[10],v[11]); } + { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11]); } }; template <typename T_> struct invoke<T_,11> { static inline T_ execute(ifunction& f, T_ (&v)[11]) - { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],v[10]); } + { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10]); } }; template <typename T_> struct invoke<T_,10> { static inline T_ execute(ifunction& f, T_ (&v)[10]) - { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9]); } + { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9]); } }; template <typename T_> struct invoke<T_,9> { static inline T_ execute(ifunction& f, T_ (&v)[9]) - { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8]); } + { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8]); } }; template <typename T_> struct invoke<T_,8> { static inline T_ execute(ifunction& f, T_ (&v)[8]) - { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]); } + { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]); } }; template <typename T_> struct invoke<T_,7> { static inline T_ execute(ifunction& f, T_ (&v)[7]) - { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6]); } + { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6]); } }; template <typename T_> struct invoke<T_,6> { static inline T_ execute(ifunction& f, T_ (&v)[6]) - { return f(v[0],v[1],v[2],v[3],v[4],v[5]); } + { return f(v[0], v[1], v[2], v[3], v[4], v[5]); } }; template <typename T_> struct invoke<T_,5> { static inline T_ execute(ifunction& f, T_ (&v)[5]) - { return f(v[0],v[1],v[2],v[3],v[4]); } + { return f(v[0], v[1], v[2], v[3], v[4]); } }; template <typename T_> struct invoke<T_,4> { static inline T_ execute(ifunction& f, T_ (&v)[4]) - { return f(v[0],v[1],v[2],v[3]); } + { return f(v[0], v[1], v[2], v[3]); } }; template <typename T_> struct invoke<T_,3> { static inline T_ execute(ifunction& f, T_ (&v)[3]) - { return f(v[0],v[1],v[2]); } + { return f(v[0], v[1], v[2]); } }; template <typename T_> struct invoke<T_,2> { static inline T_ execute(ifunction& f, T_ (&v)[2]) - { return f(v[0],v[1]); } + { return f(v[0], v[1]); } }; template <typename T_> @@ -12000,30 +14761,16 @@ namespace exprtk { return f(v[0]); } }; - inline typename expression_node<T>::node_type type() const override - { - return expression_node<T>::e_function; - } - - void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) override - { - expression_node<T>::ndb_t::template collect<>(branch_, node_delete_list); - } - - std::size_t node_depth() const override - { - return expression_node<T>::ndb_t::template compute_node_depth<N>(branch_); - } - private: ifunction* function_; std::size_t parameter_count_; branch_t branch_[N]; + bool initialised_; }; template <typename T, typename IFunction> - class function_N_node<T,IFunction,0> : public expression_node<T> + class function_N_node<T,IFunction,0> exprtk_final : public expression_node<T> { public: @@ -12032,33 +14779,37 @@ namespace exprtk explicit function_N_node(ifunction* func) : function_((0 == func->param_count) ? func : reinterpret_cast<ifunction*>(0)) - {} + { + assert(valid()); + } inline bool operator <(const function_N_node<T,IFunction,0>& fn) const { return this < (&fn); } - inline T value() const override + inline T value() const exprtk_override { - if (function_) - return (*function_)(); - else - return std::numeric_limits<T>::quiet_NaN(); + return (*function_)(); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_function; } + inline bool valid() const exprtk_override + { + return function_; + } + private: ifunction* function_; }; template <typename T, typename VarArgFunction> - class vararg_function_node : public expression_node<T> + class vararg_function_node exprtk_final : public expression_node<T> { public: @@ -12066,10 +14817,11 @@ namespace exprtk vararg_function_node(VarArgFunction* func, const std::vector<expression_ptr>& arg_list) - : function_(func), - arg_list_(arg_list) + : function_(func) + , arg_list_(arg_list) { value_list_.resize(arg_list.size(),std::numeric_limits<T>::quiet_NaN()); + assert(valid()); } inline bool operator <(const vararg_function_node<T,VarArgFunction>& fn) const @@ -12077,23 +14829,23 @@ namespace exprtk return this < (&fn); } - inline T value() const override + inline T value() const exprtk_override { - if (function_) - { - populate_value_list(); - return (*function_)(value_list_); - } - else - return std::numeric_limits<T>::quiet_NaN(); + populate_value_list(); + return (*function_)(value_list_); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_vafunction; } - void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) override + inline bool valid() const exprtk_override + { + return function_; + } + + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override { for (std::size_t i = 0; i < arg_list_.size(); ++i) { @@ -12104,7 +14856,7 @@ namespace exprtk } } - std::size_t node_depth() const override + std::size_t node_depth() const exprtk_override { return expression_node<T>::ndb_t::compute_node_depth(arg_list_); } @@ -12129,45 +14881,60 @@ namespace exprtk { public: - typedef type_store<T> type_store_t; - typedef expression_node<T>* expression_ptr; - typedef variable_node<T> variable_node_t; - typedef vector_node<T> vector_node_t; - typedef variable_node_t* variable_node_ptr_t; - typedef vector_node_t* vector_node_ptr_t; - typedef range_interface<T> range_interface_t; - typedef range_data_type<T> range_data_type_t; - typedef range_pack<T> range_t; - typedef std::pair<expression_ptr,bool> branch_t; - typedef std::pair<void*,std::size_t> void_t; - typedef std::vector<T> tmp_vs_t; - typedef std::vector<type_store_t> typestore_list_t; - typedef std::vector<range_data_type_t> range_list_t; + typedef type_store<T> type_store_t; + typedef expression_node<T>* expression_ptr; + typedef variable_node<T> variable_node_t; + typedef vector_node<T> vector_node_t; + typedef variable_node_t* variable_node_ptr_t; + typedef vector_node_t* vector_node_ptr_t; + typedef range_interface<T> range_interface_t; + typedef range_data_type<T> range_data_type_t; + typedef typename range_interface<T>::range_t range_t; + + typedef std::pair<expression_ptr,bool> branch_t; + typedef vector_holder<T>* vh_t; + typedef vector_view<T>* vecview_t; + + typedef std::vector<T> tmp_vs_t; + typedef std::vector<type_store_t> typestore_list_t; + typedef std::vector<range_data_type_t> range_list_t; explicit generic_function_node(const std::vector<expression_ptr>& arg_list, GenericFunction* func = reinterpret_cast<GenericFunction*>(0)) - : function_(func), - arg_list_(arg_list) + : function_(func) + , arg_list_(arg_list) {} - ~generic_function_node() override = default; + ~generic_function_node() exprtk_override + { + for (std::size_t i = 0; i < vv_list_.size(); ++i) + { + vecview_t& vv = vv_list_[i]; + if (vv && typestore_list_[i].vec_data) + { + vv->remove_ref(&typestore_list_[i].vec_data); + typestore_list_[i].vec_data = 0; + } + } + } - void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) override + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override { expression_node<T>::ndb_t::collect(branch_, node_delete_list); } - std::size_t node_depth() const override + std::size_t node_depth() const exprtk_final { return expression_node<T>::ndb_t::compute_node_depth(branch_); } virtual bool init_branches() { - expr_as_vec1_store_.resize(arg_list_.size(),T(0) ); - typestore_list_ .resize(arg_list_.size(),type_store_t() ); - range_list_ .resize(arg_list_.size(),range_data_type_t()); - branch_ .resize(arg_list_.size(),branch_t(reinterpret_cast<expression_ptr>(0),false)); + expr_as_vec1_store_.resize(arg_list_.size(), T(0) ); + typestore_list_ .resize(arg_list_.size(), type_store_t() ); + range_list_ .resize(arg_list_.size(), range_data_type_t()); + branch_ .resize(arg_list_.size(), branch_t(reinterpret_cast<expression_ptr>(0),false)); + vv_list_ .resize(arg_list_.size(), vecview_t(0)); for (std::size_t i = 0; i < arg_list_.size(); ++i) { @@ -12185,7 +14952,15 @@ namespace exprtk ts.size = vi->size(); ts.data = vi->vds().data(); ts.type = type_store_t::e_vector; - vi->vec()->vec_holder().set_ref(&ts.vec_data); + + if ( + vi->vec()->vec_holder().rebaseable() && + vi->vec()->vec_holder().rebaseable_instance() + ) + { + vv_list_[i] = vi->vec()->vec_holder().rebaseable_instance(); + vv_list_[i]->set_ref(&ts.vec_data); + } } #ifndef exprtk_disable_string_capabilities else if (is_generally_string_node(arg_list_[i])) @@ -12221,7 +14996,10 @@ namespace exprtk range_list_[i].range = reinterpret_cast<range_t*>(0); } else + { range_list_[i].range = &(ri->range_ref()); + range_param_list_.push_back(i); + } } #endif else if (is_variable_node(arg_list_[i])) @@ -12253,26 +15031,28 @@ namespace exprtk return this < (&fn); } - inline T value() const override + inline T value() const exprtk_override { - if (function_) + if (populate_value_list()) { - if (populate_value_list()) - { - typedef typename GenericFunction::parameter_list_t parameter_list_t; + typedef typename GenericFunction::parameter_list_t parameter_list_t; - return (*function_)(parameter_list_t(typestore_list_)); - } + return (*function_)(parameter_list_t(typestore_list_)); } return std::numeric_limits<T>::quiet_NaN(); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_genfunction; } + inline bool valid() const exprtk_override + { + return function_; + } + protected: inline virtual bool populate_value_list() const @@ -12282,30 +15062,40 @@ namespace exprtk expr_as_vec1_store_[i] = branch_[i].first->value(); } - for (std::size_t i = 0; i < branch_.size(); ++i) + if (!range_param_list_.empty()) { - range_data_type_t& rdt = range_list_[i]; + assert(range_param_list_.size() <= branch_.size()); - if (rdt.range) + for (std::size_t i = 0; i < range_param_list_.size(); ++i) { + const std::size_t index = range_param_list_[i]; + range_data_type_t& rdt = range_list_[index]; + const range_t& rp = (*rdt.range); std::size_t r0 = 0; std::size_t r1 = 0; - if (rp(r0, r1, rdt.size)) - { - type_store_t& ts = typestore_list_[i]; + const std::size_t data_size = + #ifndef exprtk_disable_string_capabilities + rdt.str_node ? rdt.str_node->size() : rdt.size; + #else + rdt.size; + #endif - ts.size = rp.cache_size(); - #ifndef exprtk_disable_string_capabilities - if (ts.type == type_store_t::e_string) - ts.data = const_cast<char_ptr>(rdt.str_node->base()) + rp.cache.first; - else - #endif - ts.data = static_cast<char_ptr>(rdt.data) + (rp.cache.first * rdt.type_size); + if (!rp(r0, r1, data_size)) + { + return false; } + + type_store_t& ts = typestore_list_[index]; + + ts.size = rp.cache_size(); + #ifndef exprtk_disable_string_capabilities + if (ts.type == type_store_t::e_string) + ts.data = const_cast<char_ptr>(rdt.str_node->base()) + rp.cache.first; else - return false; + #endif + ts.data = static_cast<char_ptr>(rdt.data) + (rp.cache.first * rdt.type_size); } } @@ -12318,21 +15108,23 @@ namespace exprtk private: std::vector<expression_ptr> arg_list_; - std::vector<branch_t> branch_; - mutable tmp_vs_t expr_as_vec1_store_; - mutable range_list_t range_list_; + std::vector<branch_t> branch_; + std::vector<vecview_t> vv_list_; + mutable tmp_vs_t expr_as_vec1_store_; + mutable range_list_t range_list_; + std::vector<std::size_t> range_param_list_; }; #ifndef exprtk_disable_string_capabilities template <typename T, typename StringFunction> - class string_function_node : public generic_function_node<T,StringFunction>, - public string_base_node<T>, - public range_interface <T> + class string_function_node : public generic_function_node<T,StringFunction> + , public string_base_node<T> + , public range_interface <T> { public: typedef generic_function_node<T,StringFunction> gen_function_t; - typedef range_pack<T> range_t; + typedef typename range_interface<T>::range_t range_t; string_function_node(StringFunction* func, const std::vector<typename gen_function_t::expression_ptr>& arg_list) @@ -12342,6 +15134,7 @@ namespace exprtk range_.n1_c = std::make_pair<bool,std::size_t>(true,0); range_.cache.first = range_.n0_c.second; range_.cache.second = range_.n1_c.second; + assert(valid()); } inline bool operator <(const string_function_node<T,StringFunction>& fn) const @@ -12349,56 +15142,59 @@ namespace exprtk return this < (&fn); } - inline T value() const override + inline T value() const exprtk_override { - if (gen_function_t::function_) + if (gen_function_t::populate_value_list()) { - if (gen_function_t::populate_value_list()) - { - typedef typename StringFunction::parameter_list_t parameter_list_t; + typedef typename StringFunction::parameter_list_t parameter_list_t; - const T result = (*gen_function_t::function_) - ( - ret_string_, - parameter_list_t(gen_function_t::typestore_list_) - ); + const T result = + (*gen_function_t::function_) + ( + ret_string_, + parameter_list_t(gen_function_t::typestore_list_) + ); - range_.n1_c.second = ret_string_.size() - 1; - range_.cache.second = range_.n1_c.second; + range_.n1_c.second = ret_string_.size(); + range_.cache.second = range_.n1_c.second; - return result; - } + return result; } return std::numeric_limits<T>::quiet_NaN(); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_strfunction; } - std::string str() const override + inline bool valid() const exprtk_override + { + return gen_function_t::function_; + } + + std::string str() const exprtk_override { return ret_string_; } - char_cptr base() const override + char_cptr base() const exprtk_override { return &ret_string_[0]; } - std::size_t size() const override + std::size_t size() const exprtk_override { return ret_string_.size(); } - range_t& range_ref() override + range_t& range_ref() exprtk_override { return range_; } - const range_t& range_ref() const override + const range_t& range_ref() const exprtk_override { return range_; } @@ -12416,35 +15212,35 @@ namespace exprtk public: typedef generic_function_node<T,GenericFunction> gen_function_t; - typedef range_pack<T> range_t; + typedef typename gen_function_t::range_t range_t; multimode_genfunction_node(GenericFunction* func, const std::size_t& param_seq_index, const std::vector<typename gen_function_t::expression_ptr>& arg_list) - : gen_function_t(arg_list,func), - param_seq_index_(param_seq_index) + : gen_function_t(arg_list,func) + , param_seq_index_(param_seq_index) {} - inline T value() const override + inline T value() const exprtk_override { - if (gen_function_t::function_) + assert(gen_function_t::valid()); + + if (gen_function_t::populate_value_list()) { - if (gen_function_t::populate_value_list()) - { - typedef typename GenericFunction::parameter_list_t parameter_list_t; + typedef typename GenericFunction::parameter_list_t parameter_list_t; - return (*gen_function_t::function_) - ( - param_seq_index_, - parameter_list_t(gen_function_t::typestore_list_) - ); - } + return + (*gen_function_t::function_) + ( + param_seq_index_, + parameter_list_t(gen_function_t::typestore_list_) + ); } return std::numeric_limits<T>::quiet_NaN(); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_final { return expression_node<T>::e_genfunction; } @@ -12456,46 +15252,44 @@ namespace exprtk #ifndef exprtk_disable_string_capabilities template <typename T, typename StringFunction> - class multimode_strfunction_node : public string_function_node<T,StringFunction> + class multimode_strfunction_node exprtk_final : public string_function_node<T,StringFunction> { public: typedef string_function_node<T,StringFunction> str_function_t; - typedef range_pack<T> range_t; + typedef typename str_function_t::range_t range_t; multimode_strfunction_node(StringFunction* func, const std::size_t& param_seq_index, const std::vector<typename str_function_t::expression_ptr>& arg_list) - : str_function_t(func,arg_list), - param_seq_index_(param_seq_index) + : str_function_t(func,arg_list) + , param_seq_index_(param_seq_index) {} - inline T value() const override + inline T value() const exprtk_override { - if (str_function_t::function_) + if (str_function_t::populate_value_list()) { - if (str_function_t::populate_value_list()) - { - typedef typename StringFunction::parameter_list_t parameter_list_t; + typedef typename StringFunction::parameter_list_t parameter_list_t; - const T result = (*str_function_t::function_) - ( - param_seq_index_, - str_function_t::ret_string_, - parameter_list_t(str_function_t::typestore_list_) - ); + const T result = + (*str_function_t::function_) + ( + param_seq_index_, + str_function_t::ret_string_, + parameter_list_t(str_function_t::typestore_list_) + ); - str_function_t::range_.n1_c.second = str_function_t::ret_string_.size() - 1; - str_function_t::range_.cache.second = str_function_t::range_.n1_c.second; + str_function_t::range_.n1_c.second = str_function_t::ret_string_.size(); + str_function_t::range_.cache.second = str_function_t::range_.n1_c.second; - return result; - } + return result; } return std::numeric_limits<T>::quiet_NaN(); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_strfunction; } @@ -12506,15 +15300,14 @@ namespace exprtk }; #endif - class return_exception - {}; + class return_exception {}; template <typename T> class null_igenfunc { public: - virtual ~null_igenfunc() = default; + virtual ~null_igenfunc() exprtk_default; typedef type_store<T> generic_type; typedef typename generic_type::parameter_list parameter_list_t; @@ -12527,27 +15320,26 @@ namespace exprtk #ifndef exprtk_disable_return_statement template <typename T> - class return_node : public generic_function_node<T,null_igenfunc<T> > + class return_node exprtk_final : public generic_function_node<T,null_igenfunc<T> > { public: - typedef null_igenfunc<T> igeneric_function_t; + typedef results_context<T> results_context_t; + typedef null_igenfunc<T> igeneric_function_t; typedef igeneric_function_t* igeneric_function_ptr; typedef generic_function_node<T,igeneric_function_t> gen_function_t; - typedef results_context<T> results_context_t; return_node(const std::vector<typename gen_function_t::expression_ptr>& arg_list, results_context_t& rc) - : gen_function_t (arg_list), - results_context_(&rc) - {} + : gen_function_t (arg_list) + , results_context_(&rc) + { + assert(valid()); + } - inline T value() const override + inline T value() const exprtk_override { - if ( - (0 != results_context_) && - gen_function_t::populate_value_list() - ) + if (gen_function_t::populate_value_list()) { typedef typename type_store<T>::parameter_list parameter_list_t; @@ -12560,18 +15352,23 @@ namespace exprtk return std::numeric_limits<T>::quiet_NaN(); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_return; } + inline bool valid() const exprtk_override + { + return results_context_; + } + private: results_context_t* results_context_; }; template <typename T> - class return_envelope_node : public expression_node<T> + class return_envelope_node exprtk_final : public expression_node<T> { public: @@ -12580,16 +15377,15 @@ namespace exprtk typedef std::pair<expression_ptr,bool> branch_t; return_envelope_node(expression_ptr body, results_context_t& rc) - : results_context_(&rc ), - return_invoked_ (false) + : results_context_(&rc ) + , return_invoked_ (false) { construct_branch_pair(body_, body); + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { - assert(body_.first); - try { return_invoked_ = false; @@ -12600,26 +15396,32 @@ namespace exprtk catch(const return_exception&) { return_invoked_ = true; + return std::numeric_limits<T>::quiet_NaN(); } } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_retenv; } + inline bool valid() const exprtk_override + { + return results_context_ && body_.first; + } + inline bool* retinvk_ptr() { return &return_invoked_; } - void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) override + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override { expression_node<T>::ndb_t::collect(body_, node_delete_list); } - std::size_t node_depth() const override + std::size_t node_depth() const exprtk_override { return expression_node<T>::ndb_t::compute_node_depth(body_); } @@ -12702,11 +15504,11 @@ namespace exprtk { typedef typename details::functor_t<T>::Type Type; typedef typename details::functor_t<T>::RefType RefType; - typedef typename details::functor_t<T> functor_t; - typedef typename functor_t::qfunc_t quaternary_functor_t; - typedef typename functor_t::tfunc_t trinary_functor_t; - typedef typename functor_t::bfunc_t binary_functor_t; - typedef typename functor_t::ufunc_t unary_functor_t; + typedef typename details::functor_t<T> functor_t; + typedef typename functor_t::qfunc_t quaternary_functor_t; + typedef typename functor_t::tfunc_t trinary_functor_t; + typedef typename functor_t::bfunc_t binary_functor_t; + typedef typename functor_t::ufunc_t unary_functor_t; }; template <typename T> @@ -12993,7 +15795,7 @@ namespace exprtk } template <typename T> - struct vararg_add_op : public opr_base<T> + struct vararg_add_op exprtk_final : public opr_base<T> { typedef typename opr_base<T>::Type Type; @@ -13016,7 +15818,7 @@ namespace exprtk for (std::size_t i = 0; i < arg_list.size(); ++i) { - result += value(arg_list[i]); + result += value(arg_list[i]); } return result; @@ -13060,7 +15862,7 @@ namespace exprtk }; template <typename T> - struct vararg_mul_op : public opr_base<T> + struct vararg_mul_op exprtk_final : public opr_base<T> { typedef typename opr_base<T>::Type Type; @@ -13127,7 +15929,7 @@ namespace exprtk }; template <typename T> - struct vararg_avg_op : public opr_base<T> + struct vararg_avg_op exprtk_final : public opr_base<T> { typedef typename opr_base<T>::Type Type; @@ -13144,7 +15946,7 @@ namespace exprtk case 3 : return process_3(arg_list); case 4 : return process_4(arg_list); case 5 : return process_5(arg_list); - default : return vararg_add_op<T>::process(arg_list) / arg_list.size(); + default : return vararg_add_op<T>::process(arg_list) / T(arg_list.size()); } } @@ -13183,7 +15985,7 @@ namespace exprtk }; template <typename T> - struct vararg_min_op : public opr_base<T> + struct vararg_min_op exprtk_final : public opr_base<T> { typedef typename opr_base<T>::Type Type; @@ -13254,7 +16056,7 @@ namespace exprtk }; template <typename T> - struct vararg_max_op : public opr_base<T> + struct vararg_max_op exprtk_final : public opr_base<T> { typedef typename opr_base<T>::Type Type; @@ -13325,7 +16127,7 @@ namespace exprtk }; template <typename T> - struct vararg_mand_op : public opr_base<T> + struct vararg_mand_op exprtk_final : public opr_base<T> { typedef typename opr_base<T>::Type Type; @@ -13405,7 +16207,7 @@ namespace exprtk }; template <typename T> - struct vararg_mor_op : public opr_base<T> + struct vararg_mor_op exprtk_final : public opr_base<T> { typedef typename opr_base<T>::Type Type; @@ -13485,7 +16287,7 @@ namespace exprtk }; template <typename T> - struct vararg_multi_op : public opr_base<T> + struct vararg_multi_op exprtk_final : public opr_base<T> { typedef typename opr_base<T>::Type Type; @@ -13506,14 +16308,13 @@ namespace exprtk case 7 : return process_7(arg_list); case 8 : return process_8(arg_list); default : - { - for (std::size_t i = 0; i < (arg_list.size() - 1); ++i) - { - value(arg_list[i]); - } - - return value(arg_list.back()); - } + { + for (std::size_t i = 0; i < (arg_list.size() - 1); ++i) + { + value(arg_list[i]); + } + return value(arg_list.back()); + } } } @@ -13602,7 +16403,7 @@ namespace exprtk static inline T process(const ivector_ptr v) { const T* vec = v->vec()->vds().data(); - const std::size_t vec_size = v->vec()->vds().size(); + const std::size_t vec_size = v->size(); loop_unroll::details lud(vec_size); @@ -13611,24 +16412,24 @@ namespace exprtk T result = T(0); int i = 0; - exprtk_disable_fallthrough_begin switch (vec_size) { - #define case_stmt(N) \ - case N : result += vec[i++]; \ + #define case_stmt(N,fall_through) \ + case N : result += vec[i++]; \ + fall_through \ #ifndef exprtk_disable_superscalar_unroll - case_stmt(16) case_stmt(15) - case_stmt(14) case_stmt(13) - case_stmt(12) case_stmt(11) - case_stmt(10) case_stmt( 9) - case_stmt( 8) case_stmt( 7) - case_stmt( 6) case_stmt( 5) + case_stmt(16, exprtk_fallthrough) case_stmt(15, exprtk_fallthrough) + case_stmt(14, exprtk_fallthrough) case_stmt(13, exprtk_fallthrough) + case_stmt(12, exprtk_fallthrough) case_stmt(11, exprtk_fallthrough) + case_stmt(10, exprtk_fallthrough) case_stmt( 9, exprtk_fallthrough) + case_stmt( 8, exprtk_fallthrough) case_stmt( 7, exprtk_fallthrough) + case_stmt( 6, exprtk_fallthrough) case_stmt( 5, exprtk_fallthrough) + #endif - case_stmt( 4) case_stmt( 3) - case_stmt( 2) case_stmt( 1) + case_stmt( 4, exprtk_fallthrough) case_stmt( 3, exprtk_fallthrough) + case_stmt( 2, exprtk_fallthrough) case_stmt( 1, (void)0;) } - exprtk_disable_fallthrough_end #undef case_stmt @@ -13663,24 +16464,23 @@ namespace exprtk int i = 0; - exprtk_disable_fallthrough_begin switch (lud.remainder) { - #define case_stmt(N) \ - case N : r[0] += vec[i++]; \ + #define case_stmt(N,fall_through) \ + case N : r[0] += vec[i++]; \ + fall_through \ #ifndef exprtk_disable_superscalar_unroll - case_stmt(15) case_stmt(14) - case_stmt(13) case_stmt(12) - case_stmt(11) case_stmt(10) - case_stmt( 9) case_stmt( 8) - case_stmt( 7) case_stmt( 6) - case_stmt( 5) case_stmt( 4) + case_stmt(15, exprtk_fallthrough) case_stmt(14, exprtk_fallthrough) + case_stmt(13, exprtk_fallthrough) case_stmt(12, exprtk_fallthrough) + case_stmt(11, exprtk_fallthrough) case_stmt(10, exprtk_fallthrough) + case_stmt( 9, exprtk_fallthrough) case_stmt( 8, exprtk_fallthrough) + case_stmt( 7, exprtk_fallthrough) case_stmt( 6, exprtk_fallthrough) + case_stmt( 5, exprtk_fallthrough) case_stmt( 4, exprtk_fallthrough) #endif - case_stmt( 3) case_stmt( 2) - case_stmt( 1) + case_stmt( 3, exprtk_fallthrough) case_stmt( 2, exprtk_fallthrough) + case_stmt( 1, (void)0;) } - exprtk_disable_fallthrough_end #undef exprtk_loop #undef case_stmt @@ -13703,7 +16503,7 @@ namespace exprtk static inline T process(const ivector_ptr v) { const T* vec = v->vec()->vds().data(); - const std::size_t vec_size = v->vec()->vds().size(); + const std::size_t vec_size = v->vec()->size(); loop_unroll::details lud(vec_size); @@ -13712,24 +16512,23 @@ namespace exprtk T result = T(1); int i = 0; - exprtk_disable_fallthrough_begin switch (vec_size) { - #define case_stmt(N) \ - case N : result *= vec[i++]; \ + #define case_stmt(N,fall_through) \ + case N : result *= vec[i++]; \ + fall_through \ #ifndef exprtk_disable_superscalar_unroll - case_stmt(16) case_stmt(15) - case_stmt(14) case_stmt(13) - case_stmt(12) case_stmt(11) - case_stmt(10) case_stmt( 9) - case_stmt( 8) case_stmt( 7) - case_stmt( 6) case_stmt( 5) + case_stmt(16, exprtk_fallthrough) case_stmt(15, exprtk_fallthrough) + case_stmt(14, exprtk_fallthrough) case_stmt(13, exprtk_fallthrough) + case_stmt(12, exprtk_fallthrough) case_stmt(11, exprtk_fallthrough) + case_stmt(10, exprtk_fallthrough) case_stmt( 9, exprtk_fallthrough) + case_stmt( 8, exprtk_fallthrough) case_stmt( 7, exprtk_fallthrough) + case_stmt( 6, exprtk_fallthrough) case_stmt( 5, exprtk_fallthrough) #endif - case_stmt( 4) case_stmt( 3) - case_stmt( 2) case_stmt( 1) + case_stmt( 4, exprtk_fallthrough) case_stmt( 3, exprtk_fallthrough) + case_stmt( 2, exprtk_fallthrough) case_stmt( 1, (void)0;) } - exprtk_disable_fallthrough_end #undef case_stmt @@ -13764,33 +16563,32 @@ namespace exprtk int i = 0; - exprtk_disable_fallthrough_begin switch (lud.remainder) { - #define case_stmt(N) \ - case N : r[0] *= vec[i++]; \ + #define case_stmt(N,fall_through) \ + case N : r[0] *= vec[i++]; \ + fall_through \ #ifndef exprtk_disable_superscalar_unroll - case_stmt(15) case_stmt(14) - case_stmt(13) case_stmt(12) - case_stmt(11) case_stmt(10) - case_stmt( 9) case_stmt( 8) - case_stmt( 7) case_stmt( 6) - case_stmt( 5) case_stmt( 4) + case_stmt(15, exprtk_fallthrough) case_stmt(14, exprtk_fallthrough) + case_stmt(13, exprtk_fallthrough) case_stmt(12, exprtk_fallthrough) + case_stmt(11, exprtk_fallthrough) case_stmt(10, exprtk_fallthrough) + case_stmt( 9, exprtk_fallthrough) case_stmt( 8, exprtk_fallthrough) + case_stmt( 7, exprtk_fallthrough) case_stmt( 6, exprtk_fallthrough) + case_stmt( 5, exprtk_fallthrough) case_stmt( 4, exprtk_fallthrough) #endif - case_stmt( 3) case_stmt( 2) - case_stmt( 1) + case_stmt( 3, exprtk_fallthrough) case_stmt( 2, exprtk_fallthrough) + case_stmt( 1, (void)0;) } - exprtk_disable_fallthrough_end #undef exprtk_loop #undef case_stmt return (r[ 0] * r[ 1] * r[ 2] * r[ 3]) #ifndef exprtk_disable_superscalar_unroll - + (r[ 4] * r[ 5] * r[ 6] * r[ 7]) - + (r[ 8] * r[ 9] * r[10] * r[11]) - + (r[12] * r[13] * r[14] * r[15]) + * (r[ 4] * r[ 5] * r[ 6] * r[ 7]) + * (r[ 8] * r[ 9] * r[10] * r[11]) + * (r[12] * r[13] * r[14] * r[15]) #endif ; } @@ -13803,8 +16601,7 @@ namespace exprtk static inline T process(const ivector_ptr v) { - const std::size_t vec_size = v->vec()->vds().size(); - + const T vec_size = T(v->vec()->size()); return vec_add_op<T>::process(v) / vec_size; } }; @@ -13817,7 +16614,7 @@ namespace exprtk static inline T process(const ivector_ptr v) { const T* vec = v->vec()->vds().data(); - const std::size_t vec_size = v->vec()->vds().size(); + const std::size_t vec_size = v->vec()->size(); T result = vec[0]; @@ -13841,7 +16638,7 @@ namespace exprtk static inline T process(const ivector_ptr v) { const T* vec = v->vec()->vds().data(); - const std::size_t vec_size = v->vec()->vds().size(); + const std::size_t vec_size = v->vec()->size(); T result = vec[0]; @@ -13862,7 +16659,7 @@ namespace exprtk { public: - ~vov_base_node() override = default; + ~vov_base_node() exprtk_override exprtk_default; inline virtual operator_type operation() const { @@ -13879,7 +16676,7 @@ namespace exprtk { public: - ~cov_base_node() override = default; + ~cov_base_node() exprtk_override exprtk_default; inline virtual operator_type operation() const { @@ -13896,7 +16693,7 @@ namespace exprtk { public: - ~voc_base_node() override = default; + ~voc_base_node() exprtk_override exprtk_default; inline virtual operator_type operation() const { @@ -13913,7 +16710,7 @@ namespace exprtk { public: - ~vob_base_node() override = default; + ~vob_base_node() exprtk_override exprtk_default; virtual const T& v() const = 0; }; @@ -13923,7 +16720,7 @@ namespace exprtk { public: - ~bov_base_node() override = default; + ~bov_base_node() exprtk_override exprtk_default; virtual const T& v() const = 0; }; @@ -13933,7 +16730,7 @@ namespace exprtk { public: - ~cob_base_node() override = default; + ~cob_base_node() exprtk_override exprtk_default; inline virtual operator_type operation() const { @@ -13952,7 +16749,7 @@ namespace exprtk { public: - ~boc_base_node() override = default; + ~boc_base_node() exprtk_override exprtk_default; inline virtual operator_type operation() const { @@ -13971,7 +16768,7 @@ namespace exprtk { public: - ~uv_base_node() override = default; + ~uv_base_node() exprtk_override exprtk_default; inline virtual operator_type operation() const { @@ -13986,7 +16783,7 @@ namespace exprtk { public: - ~sos_base_node() override = default; + ~sos_base_node() exprtk_override exprtk_default; inline virtual operator_type operation() const { @@ -13999,7 +16796,7 @@ namespace exprtk { public: - ~sosos_base_node() override = default; + ~sosos_base_node() exprtk_override exprtk_default; inline virtual operator_type operation() const { @@ -14012,7 +16809,7 @@ namespace exprtk { public: - ~T0oT1oT2_base_node() override = default; + ~T0oT1oT2_base_node() exprtk_override exprtk_default; virtual std::string type_id() const = 0; }; @@ -14022,13 +16819,13 @@ namespace exprtk { public: - ~T0oT1oT2oT3_base_node() override = default; + ~T0oT1oT2oT3_base_node() exprtk_override exprtk_default; virtual std::string type_id() const = 0; }; template <typename T, typename Operation> - class unary_variable_node : public uv_base_node<T> + class unary_variable_node exprtk_final : public uv_base_node<T> { public: @@ -14039,70 +16836,64 @@ namespace exprtk : v_(var) {} - inline T value() const override + inline T value() const exprtk_override { return Operation::process(v_); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return Operation::type(); } - inline operator_type operation() const override + inline operator_type operation() const exprtk_override { return Operation::operation(); } - inline const T& v() const override + inline const T& v() const exprtk_override { return v_; } private: - unary_variable_node(unary_variable_node<T,Operation>&); - unary_variable_node<T,Operation>& operator=(unary_variable_node<T,Operation>&); + unary_variable_node(const unary_variable_node<T,Operation>&) exprtk_delete; + unary_variable_node<T,Operation>& operator=(const unary_variable_node<T,Operation>&) exprtk_delete; const T& v_; }; template <typename T> - class uvouv_node : public expression_node<T> + class uvouv_node exprtk_final : public expression_node<T> { public: // UOpr1(v0) Op UOpr2(v1) - - typedef expression_node<T>* expression_ptr; typedef typename details::functor_t<T> functor_t; - typedef typename functor_t::bfunc_t bfunc_t; - typedef typename functor_t::ufunc_t ufunc_t; + typedef typename functor_t::bfunc_t bfunc_t; + typedef typename functor_t::ufunc_t ufunc_t; + typedef expression_node<T>* expression_ptr; explicit uvouv_node(const T& var0,const T& var1, ufunc_t uf0, ufunc_t uf1, bfunc_t bf) - : v0_(var0), - v1_(var1), - u0_(uf0 ), - u1_(uf1 ), - f_ (bf ) + : v0_(var0) + , v1_(var1) + , u0_(uf0 ) + , u1_(uf1 ) + , f_ (bf ) {} - inline T value() const override + inline T value() const exprtk_override { return f_(u0_(v0_),u1_(v1_)); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_uvouv; } - inline operator_type operation() const - { - return details::e_default; - } - inline const T& v0() { return v0_; @@ -14130,8 +16921,8 @@ namespace exprtk private: - uvouv_node(uvouv_node<T>&); - uvouv_node<T>& operator=(uvouv_node<T>&); + uvouv_node(const uvouv_node<T>&) exprtk_delete; + uvouv_node<T>& operator=(const uvouv_node<T>&) exprtk_delete; const T& v0_; const T& v1_; @@ -14141,35 +16932,40 @@ namespace exprtk }; template <typename T, typename Operation> - class unary_branch_node : public expression_node<T> + class unary_branch_node exprtk_final : public expression_node<T> { public: - typedef expression_node<T>* expression_ptr; + typedef Operation operation_t; + typedef expression_node<T>* expression_ptr; typedef std::pair<expression_ptr,bool> branch_t; - typedef Operation operation_t; explicit unary_branch_node(expression_ptr branch) { construct_branch_pair(branch_, branch); } - inline T value() const override + inline T value() const exprtk_override { return Operation::process(branch_.first->value()); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return Operation::type(); } - inline operator_type operation() const + inline bool valid() const exprtk_override + { + return branch_.first && branch_.first->valid(); + } + + inline operator_type operation() { return Operation::operation(); } - inline expression_node<T>* branch(const std::size_t&) const override + inline expression_node<T>* branch(const std::size_t&) const exprtk_override { return branch_.first; } @@ -14179,20 +16975,20 @@ namespace exprtk branch_.second = false; } - void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) override + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override { expression_node<T>::ndb_t::collect(branch_, node_delete_list); } - std::size_t node_depth() const override + std::size_t node_depth() const exprtk_override { return expression_node<T>::ndb_t::compute_node_depth(branch_); } private: - unary_branch_node(unary_branch_node<T,Operation>&); - unary_branch_node<T,Operation>& operator=(unary_branch_node<T,Operation>&); + unary_branch_node(const unary_branch_node<T,Operation>&) exprtk_delete; + unary_branch_node<T,Operation>& operator=(const unary_branch_node<T,Operation>&) exprtk_delete; branch_t branch_; }; @@ -14218,7 +17014,7 @@ namespace exprtk struct T0oT1oT2process { typedef typename details::functor_t<T> functor_t; - typedef typename functor_t::bfunc_t bfunc_t; + typedef typename functor_t::bfunc_t bfunc_t; struct mode0 { @@ -14261,7 +17057,7 @@ namespace exprtk struct T0oT1oT20T3process { typedef typename details::functor_t<T> functor_t; - typedef typename functor_t::bfunc_t bfunc_t; + typedef typename functor_t::bfunc_t bfunc_t; struct mode0 { @@ -14375,7 +17171,7 @@ namespace exprtk template <typename T, typename T0, typename T1> const typename expression_node<T>::node_type nodetype_T0oT1<T,T0,T1>::result = expression_node<T>::e_none; - #define synthesis_node_type_define(T0_,T1_,v_) \ + #define synthesis_node_type_define(T0_, T1_, v_) \ template <typename T, typename T0, typename T1> \ struct nodetype_T0oT1<T,T0_,T1_> { static const typename expression_node<T>::node_type result; }; \ template <typename T, typename T0, typename T1> \ @@ -14397,7 +17193,7 @@ namespace exprtk template <typename T, typename T0, typename T1, typename T2> const typename expression_node<T>::node_type nodetype_T0oT1oT2<T,T0,T1,T2>::result = expression_node<T>::e_none; - #define synthesis_node_type_define(T0_,T1_,T2_,v_) \ + #define synthesis_node_type_define(T0_, T1_, T2_, v_) \ template <typename T, typename T0, typename T1, typename T2> \ struct nodetype_T0oT1oT2<T,T0_,T1_,T2_> { static const typename expression_node<T>::node_type result; }; \ template <typename T, typename T0, typename T1, typename T2> \ @@ -14419,7 +17215,7 @@ namespace exprtk template <typename T, typename T0, typename T1, typename T2, typename T3> const typename expression_node<T>::node_type nodetype_T0oT1oT2oT3<T,T0,T1,T2,T3>::result = expression_node<T>::e_none; - #define synthesis_node_type_define(T0_,T1_,T2_,T3_,v_) \ + #define synthesis_node_type_define(T0_, T1_, T2_, T3_, v_) \ template <typename T, typename T0, typename T1, typename T2, typename T3> \ struct nodetype_T0oT1oT2oT3<T,T0_,T1_,T2_,T3_> { static const typename expression_node<T>::node_type result; }; \ template <typename T, typename T0, typename T1, typename T2, typename T3> \ @@ -14444,33 +17240,33 @@ namespace exprtk #undef synthesis_node_type_define template <typename T, typename T0, typename T1> - class T0oT1 : public expression_node<T> + class T0oT1 exprtk_final : public expression_node<T> { public: typedef typename details::functor_t<T> functor_t; - typedef typename functor_t::bfunc_t bfunc_t; + typedef typename functor_t::bfunc_t bfunc_t; typedef T value_type; typedef T0oT1<T,T0,T1> node_type; T0oT1(T0 p0, T1 p1, const bfunc_t p2) - : t0_(p0), - t1_(p1), - f_ (p2) + : t0_(p0) + , t1_(p1) + , f_ (p2) {} - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { static const typename expression_node<T>::node_type result = nodetype_T0oT1<T,T0,T1>::result; return result; } - inline operator_type operation() const + inline operator_type operation() const exprtk_override { return e_default; } - inline T value() const override + inline T value() const exprtk_override { return f_(t0_,t1_); } @@ -14502,8 +17298,8 @@ namespace exprtk private: - T0oT1(T0oT1<T,T0,T1>&) {} - T0oT1<T,T0,T1>& operator=(T0oT1<T,T0,T1>&) { return (*this); } + T0oT1(const T0oT1<T,T0,T1>&) exprtk_delete; + T0oT1<T,T0,T1>& operator=(const T0oT1<T,T0,T1>&) { return (*this); } T0 t0_; T1 t1_; @@ -14511,36 +17307,36 @@ namespace exprtk }; template <typename T, typename T0, typename T1, typename T2, typename ProcessMode> - class T0oT1oT2 : public T0oT1oT2_base_node<T> + class T0oT1oT2 exprtk_final : public T0oT1oT2_base_node<T> { public: typedef typename details::functor_t<T> functor_t; - typedef typename functor_t::bfunc_t bfunc_t; + typedef typename functor_t::bfunc_t bfunc_t; typedef T value_type; typedef T0oT1oT2<T,T0,T1,T2,ProcessMode> node_type; typedef ProcessMode process_mode_t; T0oT1oT2(T0 p0, T1 p1, T2 p2, const bfunc_t p3, const bfunc_t p4) - : t0_(p0), - t1_(p1), - t2_(p2), - f0_(p3), - f1_(p4) + : t0_(p0) + , t1_(p1) + , t2_(p2) + , f0_(p3) + , f1_(p4) {} - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { static const typename expression_node<T>::node_type result = nodetype_T0oT1oT2<T,T0,T1,T2>::result; return result; } - inline operator_type operation() const + inline operator_type operation() { return e_default; } - inline T value() const override + inline T value() const exprtk_override { return ProcessMode::process(t0_, t1_, t2_, f0_, f1_); } @@ -14570,7 +17366,7 @@ namespace exprtk return f1_; } - std::string type_id() const override + std::string type_id() const exprtk_override { return id(); } @@ -14590,8 +17386,8 @@ namespace exprtk private: - T0oT1oT2(node_type&) {} - node_type& operator=(node_type&) { return (*this); } + T0oT1oT2(const node_type&) exprtk_delete; + node_type& operator=(const node_type&) exprtk_delete; T0 t0_; T1 t1_; @@ -14601,12 +17397,12 @@ namespace exprtk }; template <typename T, typename T0_, typename T1_, typename T2_, typename T3_, typename ProcessMode> - class T0oT1oT2oT3 : public T0oT1oT2oT3_base_node<T> + class T0oT1oT2oT3 exprtk_final : public T0oT1oT2oT3_base_node<T> { public: typedef typename details::functor_t<T> functor_t; - typedef typename functor_t::bfunc_t bfunc_t; + typedef typename functor_t::bfunc_t bfunc_t; typedef T value_type; typedef T0_ T0; typedef T1_ T1; @@ -14616,16 +17412,16 @@ namespace exprtk typedef ProcessMode process_mode_t; T0oT1oT2oT3(T0 p0, T1 p1, T2 p2, T3 p3, bfunc_t p4, bfunc_t p5, bfunc_t p6) - : t0_(p0), - t1_(p1), - t2_(p2), - t3_(p3), - f0_(p4), - f1_(p5), - f2_(p6) + : t0_(p0) + , t1_(p1) + , t2_(p2) + , t3_(p3) + , f0_(p4) + , f1_(p5) + , f2_(p6) {} - inline T value() const override + inline T value() const exprtk_override { return ProcessMode::process(t0_, t1_, t2_, t3_, f0_, f1_, f2_); } @@ -14665,7 +17461,7 @@ namespace exprtk return f2_; } - inline std::string type_id() const override + inline std::string type_id() const exprtk_override { return id(); } @@ -14687,8 +17483,8 @@ namespace exprtk private: - T0oT1oT2oT3(node_type&) {} - node_type& operator=(node_type&) { return (*this); } + T0oT1oT2oT3(const node_type&) exprtk_delete; + node_type& operator=(const node_type&) exprtk_delete; T0 t0_; T1 t1_; @@ -14700,34 +17496,34 @@ namespace exprtk }; template <typename T, typename T0, typename T1, typename T2> - class T0oT1oT2_sf3 : public T0oT1oT2_base_node<T> + class T0oT1oT2_sf3 exprtk_final : public T0oT1oT2_base_node<T> { public: typedef typename details::functor_t<T> functor_t; - typedef typename functor_t::tfunc_t tfunc_t; + typedef typename functor_t::tfunc_t tfunc_t; typedef T value_type; typedef T0oT1oT2_sf3<T,T0,T1,T2> node_type; T0oT1oT2_sf3(T0 p0, T1 p1, T2 p2, const tfunc_t p3) - : t0_(p0), - t1_(p1), - t2_(p2), - f_ (p3) + : t0_(p0) + , t1_(p1) + , t2_(p2) + , f_ (p3) {} - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { static const typename expression_node<T>::node_type result = nodetype_T0oT1oT2<T,T0,T1,T2>::result; return result; } - inline operator_type operation() const + inline operator_type operation() const exprtk_override { return e_default; } - inline T value() const override + inline T value() const exprtk_override { return f_(t0_, t1_, t2_); } @@ -14752,7 +17548,7 @@ namespace exprtk return f_; } - std::string type_id() const override + std::string type_id() const exprtk_override { return id(); } @@ -14772,8 +17568,8 @@ namespace exprtk private: - T0oT1oT2_sf3(node_type&) {} - node_type& operator=(node_type&) { return (*this); } + T0oT1oT2_sf3(const node_type&) exprtk_delete; + node_type& operator=(const node_type&) exprtk_delete; T0 t0_; T1 t1_; @@ -14786,7 +17582,7 @@ namespace exprtk { public: - ~sf3ext_type_node() override = default; + ~sf3ext_type_node() exprtk_override exprtk_default; virtual T0 t0() const = 0; @@ -14796,53 +17592,51 @@ namespace exprtk }; template <typename T, typename T0, typename T1, typename T2, typename SF3Operation> - class T0oT1oT2_sf3ext : public sf3ext_type_node<T,T0,T1,T2> + class T0oT1oT2_sf3ext exprtk_final : public sf3ext_type_node<T,T0,T1,T2> { public: - typedef typename details::functor_t<T> functor_t; - typedef typename functor_t::tfunc_t tfunc_t; typedef T value_type; - typedef T0oT1oT2_sf3ext<T,T0,T1,T2,SF3Operation> node_type; + typedef T0oT1oT2_sf3ext<T, T0, T1, T2, SF3Operation> node_type; T0oT1oT2_sf3ext(T0 p0, T1 p1, T2 p2) - : t0_(p0), - t1_(p1), - t2_(p2) + : t0_(p0) + , t1_(p1) + , t2_(p2) {} - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { static const typename expression_node<T>::node_type result = nodetype_T0oT1oT2<T,T0,T1,T2>::result; return result; } - inline operator_type operation() const + inline operator_type operation() { return e_default; } - inline T value() const override + inline T value() const exprtk_override { return SF3Operation::process(t0_, t1_, t2_); } - T0 t0() const override + T0 t0() const exprtk_override { return t0_; } - T1 t1() const override + T1 t1() const exprtk_override { return t1_; } - T2 t2() const override + T2 t2() const exprtk_override { return t2_; } - std::string type_id() const override + std::string type_id() const exprtk_override { return id(); } @@ -14862,8 +17656,8 @@ namespace exprtk private: - T0oT1oT2_sf3ext(node_type&) {} - node_type& operator=(node_type&) { return (*this); } + T0oT1oT2_sf3ext(const node_type&) exprtk_delete; + node_type& operator=(const node_type&) exprtk_delete; T0 t0_; T1 t1_; @@ -14885,37 +17679,37 @@ namespace exprtk } template <typename T, typename T0, typename T1, typename T2, typename T3> - class T0oT1oT2oT3_sf4 : public T0oT1oT2_base_node<T> + class T0oT1oT2oT3_sf4 exprtk_final : public T0oT1oT2_base_node<T> { public: - ~T0oT1oT2oT3_sf4() override = default; + ~T0oT1oT2oT3_sf4() exprtk_override exprtk_default; typedef typename details::functor_t<T> functor_t; - typedef typename functor_t::qfunc_t qfunc_t; + typedef typename functor_t::qfunc_t qfunc_t; typedef T value_type; - typedef T0oT1oT2oT3_sf4<T,T0,T1,T2,T3> node_type; + typedef T0oT1oT2oT3_sf4<T, T0, T1, T2, T3> node_type; T0oT1oT2oT3_sf4(T0 p0, T1 p1, T2 p2, T3 p3, const qfunc_t p4) - : t0_(p0), - t1_(p1), - t2_(p2), - t3_(p3), - f_ (p4) + : t0_(p0) + , t1_(p1) + , t2_(p2) + , t3_(p3) + , f_ (p4) {} - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { static const typename expression_node<T>::node_type result = nodetype_T0oT1oT2oT3<T,T0,T1,T2,T3>::result; return result; } - inline operator_type operation() const + inline operator_type operation() const exprtk_override { return e_default; } - inline T value() const override + inline T value() const exprtk_override { return f_(t0_, t1_, t2_, t3_); } @@ -14945,7 +17739,7 @@ namespace exprtk return f_; } - std::string type_id() const override + std::string type_id() const exprtk_override { return id(); } @@ -14965,8 +17759,8 @@ namespace exprtk private: - T0oT1oT2oT3_sf4(node_type&) {} - node_type& operator=(node_type&) { return (*this); } + T0oT1oT2oT3_sf4(const node_type&) exprtk_delete; + node_type& operator=(const node_type&) exprtk_delete; T0 t0_; T1 t1_; @@ -14976,34 +17770,27 @@ namespace exprtk }; template <typename T, typename T0, typename T1, typename T2, typename T3, typename SF4Operation> - class T0oT1oT2oT3_sf4ext : public T0oT1oT2oT3_base_node<T> + class T0oT1oT2oT3_sf4ext exprtk_final : public T0oT1oT2oT3_base_node<T> { public: - typedef typename details::functor_t<T> functor_t; - typedef typename functor_t::tfunc_t tfunc_t; typedef T value_type; - typedef T0oT1oT2oT3_sf4ext<T,T0,T1,T2,T3,SF4Operation> node_type; + typedef T0oT1oT2oT3_sf4ext<T, T0, T1, T2, T3, SF4Operation> node_type; T0oT1oT2oT3_sf4ext(T0 p0, T1 p1, T2 p2, T3 p3) - : t0_(p0), - t1_(p1), - t2_(p2), - t3_(p3) + : t0_(p0) + , t1_(p1) + , t2_(p2) + , t3_(p3) {} - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { static const typename expression_node<T>::node_type result = nodetype_T0oT1oT2oT3<T,T0,T1,T2,T3>::result; return result; } - inline operator_type operation() const - { - return e_default; - } - - inline T value() const override + inline T value() const exprtk_override { return SF4Operation::process(t0_, t1_, t2_, t3_); } @@ -15028,7 +17815,7 @@ namespace exprtk return t3_; } - std::string type_id() const override + std::string type_id() const exprtk_override { return id(); } @@ -15048,8 +17835,8 @@ namespace exprtk private: - T0oT1oT2oT3_sf4ext(node_type&) {} - node_type& operator=(node_type&) { return (*this); } + T0oT1oT2oT3_sf4ext(const node_type&) exprtk_delete; + node_type& operator=(const node_type&) exprtk_delete; T0 t0_; T1 t1_; @@ -15102,7 +17889,7 @@ namespace exprtk }; template <typename T, typename Operation> - class vov_node : public vov_base_node<T> + class vov_node exprtk_final : public vov_base_node<T> { public: @@ -15111,31 +17898,31 @@ namespace exprtk // variable op variable node explicit vov_node(const T& var0, const T& var1) - : v0_(var0), - v1_(var1) + : v0_(var0) + , v1_(var1) {} - inline T value() const override + inline T value() const exprtk_override { return Operation::process(v0_,v1_); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return Operation::type(); } - inline operator_type operation() const override + inline operator_type operation() const exprtk_override { return Operation::operation(); } - inline const T& v0() const override + inline const T& v0() const exprtk_override { return v0_; } - inline const T& v1() const override + inline const T& v1() const exprtk_override { return v1_; } @@ -15147,12 +17934,12 @@ namespace exprtk private: - vov_node(vov_node<T,Operation>&); - vov_node<T,Operation>& operator=(vov_node<T,Operation>&); + vov_node(const vov_node<T,Operation>&) exprtk_delete; + vov_node<T,Operation>& operator=(const vov_node<T,Operation>&) exprtk_delete; }; template <typename T, typename Operation> - class cov_node : public cov_base_node<T> + class cov_node exprtk_final : public cov_base_node<T> { public: @@ -15161,31 +17948,31 @@ namespace exprtk // constant op variable node explicit cov_node(const T& const_var, const T& var) - : c_(const_var), - v_(var) + : c_(const_var) + , v_(var) {} - inline T value() const override + inline T value() const exprtk_override { return Operation::process(c_,v_); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return Operation::type(); } - inline operator_type operation() const override + inline operator_type operation() const exprtk_override { return Operation::operation(); } - inline const T c() const override + inline const T c() const exprtk_override { return c_; } - inline const T& v() const override + inline const T& v() const exprtk_override { return v_; } @@ -15197,12 +17984,12 @@ namespace exprtk private: - cov_node(const cov_node<T,Operation>&); - cov_node<T,Operation>& operator=(const cov_node<T,Operation>&); + cov_node(const cov_node<T,Operation>&) exprtk_delete; + cov_node<T,Operation>& operator=(const cov_node<T,Operation>&) exprtk_delete; }; template <typename T, typename Operation> - class voc_node : public voc_base_node<T> + class voc_node exprtk_final : public voc_base_node<T> { public: @@ -15211,26 +17998,26 @@ namespace exprtk // variable op constant node explicit voc_node(const T& var, const T& const_var) - : v_(var), - c_(const_var) + : v_(var) + , c_(const_var) {} - inline T value() const override + inline T value() const exprtk_override { return Operation::process(v_,c_); } - inline operator_type operation() const override + inline operator_type operation() const exprtk_override { return Operation::operation(); } - inline const T c() const override + inline const T c() const exprtk_override { return c_; } - inline const T& v() const override + inline const T& v() const exprtk_override { return v_; } @@ -15242,12 +18029,12 @@ namespace exprtk private: - voc_node(const voc_node<T,Operation>&); - voc_node<T,Operation>& operator=(const voc_node<T,Operation>&); + voc_node(const voc_node<T,Operation>&) exprtk_delete; + voc_node<T,Operation>& operator=(const voc_node<T,Operation>&) exprtk_delete; }; template <typename T, typename Operation> - class vob_node : public vob_base_node<T> + class vob_node exprtk_final : public vob_base_node<T> { public: @@ -15255,55 +18042,55 @@ namespace exprtk typedef std::pair<expression_ptr,bool> branch_t; typedef Operation operation_t; - // variable op constant node + // variable op binary node explicit vob_node(const T& var, const expression_ptr branch) : v_(var) { construct_branch_pair(branch_, branch); + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { - assert(branch_.first); return Operation::process(v_,branch_.first->value()); } - inline operator_type operation() const + inline const T& v() const exprtk_override { - return Operation::operation(); + return v_; } - inline const T& v() const override + inline bool valid() const exprtk_override { - return v_; + return branch_.first && branch_.first->valid(); } - inline expression_node<T>* branch(const std::size_t&) const override + inline expression_node<T>* branch(const std::size_t&) const exprtk_override { return branch_.first; } - void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) override + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override { - expression_node<T>::ndb_t::template collect<>(branch_, node_delete_list); + expression_node<T>::ndb_t::collect(branch_, node_delete_list); } - std::size_t node_depth() const override + std::size_t node_depth() const exprtk_override { return expression_node<T>::ndb_t::compute_node_depth(branch_); } private: - vob_node(const vob_node<T,Operation>&); - vob_node<T,Operation>& operator=(const vob_node<T,Operation>&); + vob_node(const vob_node<T,Operation>&) exprtk_delete; + vob_node<T,Operation>& operator=(const vob_node<T,Operation>&) exprtk_delete; const T& v_; branch_t branch_; }; template <typename T, typename Operation> - class bov_node : public bov_base_node<T> + class bov_node exprtk_final : public bov_base_node<T> { public: @@ -15311,55 +18098,55 @@ namespace exprtk typedef std::pair<expression_ptr,bool> branch_t; typedef Operation operation_t; - // variable op constant node + // binary node op variable node explicit bov_node(const expression_ptr branch, const T& var) : v_(var) { construct_branch_pair(branch_, branch); + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { - assert(branch_.first); return Operation::process(branch_.first->value(),v_); } - inline operator_type operation() const + inline const T& v() const exprtk_override { - return Operation::operation(); + return v_; } - inline const T& v() const override + inline bool valid() const exprtk_override { - return v_; + return branch_.first && branch_.first->valid(); } - inline expression_node<T>* branch(const std::size_t&) const override + inline expression_node<T>* branch(const std::size_t&) const exprtk_override { return branch_.first; } - void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) override + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override { - expression_node<T>::ndb_t::template collect<>(branch_, node_delete_list); + expression_node<T>::ndb_t::collect(branch_, node_delete_list); } - std::size_t node_depth() const override + std::size_t node_depth() const exprtk_override { return expression_node<T>::ndb_t::compute_node_depth(branch_); } private: - bov_node(const bov_node<T,Operation>&); - bov_node<T,Operation>& operator=(const bov_node<T,Operation>&); + bov_node(const bov_node<T,Operation>&) exprtk_delete; + bov_node<T,Operation>& operator=(const bov_node<T,Operation>&) exprtk_delete; const T& v_; branch_t branch_; }; template <typename T, typename Operation> - class cob_node : public cob_base_node<T> + class cob_node exprtk_final : public cob_base_node<T> { public: @@ -15367,66 +18154,71 @@ namespace exprtk typedef std::pair<expression_ptr,bool> branch_t; typedef Operation operation_t; - // variable op constant node + // constant op variable node explicit cob_node(const T const_var, const expression_ptr branch) : c_(const_var) { construct_branch_pair(branch_, branch); + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { - assert(branch_.first); return Operation::process(c_,branch_.first->value()); } - inline operator_type operation() const override + inline operator_type operation() const exprtk_override { return Operation::operation(); } - inline const T c() const override + inline const T c() const exprtk_override { return c_; } - inline void set_c(const T new_c) override + inline void set_c(const T new_c) exprtk_override { (*const_cast<T*>(&c_)) = new_c; } - inline expression_node<T>* branch(const std::size_t&) const override + inline bool valid() const exprtk_override + { + return branch_.first && branch_.first->valid(); + } + + inline expression_node<T>* branch(const std::size_t&) const exprtk_override { return branch_.first; } - inline expression_node<T>* move_branch(const std::size_t&) override + inline expression_node<T>* move_branch(const std::size_t&) exprtk_override { branch_.second = false; return branch_.first; } - void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) override + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override { - expression_node<T>::ndb_t::template collect<>(branch_, node_delete_list); + expression_node<T>::ndb_t::collect(branch_, node_delete_list); } - std::size_t node_depth() const override + std::size_t node_depth() const exprtk_override { return expression_node<T>::ndb_t::compute_node_depth(branch_); } private: - cob_node(const cob_node<T,Operation>&); - cob_node<T,Operation>& operator=(const cob_node<T,Operation>&); + cob_node(const cob_node<T,Operation>&) exprtk_delete; + cob_node<T,Operation>& operator=(const cob_node<T,Operation>&) exprtk_delete; const T c_; branch_t branch_; }; template <typename T, typename Operation> - class boc_node : public boc_base_node<T> + class boc_node exprtk_final : public boc_base_node<T> { public: @@ -15434,59 +18226,64 @@ namespace exprtk typedef std::pair<expression_ptr,bool> branch_t; typedef Operation operation_t; - // variable op constant node + // binary node op constant node explicit boc_node(const expression_ptr branch, const T const_var) : c_(const_var) { construct_branch_pair(branch_, branch); + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { - assert(branch_.first); return Operation::process(branch_.first->value(),c_); } - inline operator_type operation() const override + inline operator_type operation() const exprtk_override { return Operation::operation(); } - inline const T c() const override + inline const T c() const exprtk_override { return c_; } - inline void set_c(const T new_c) override + inline void set_c(const T new_c) exprtk_override { (*const_cast<T*>(&c_)) = new_c; } - inline expression_node<T>* branch(const std::size_t&) const override + inline bool valid() const exprtk_override + { + return branch_.first && branch_.first->valid(); + } + + inline expression_node<T>* branch(const std::size_t&) const exprtk_override { return branch_.first; } - inline expression_node<T>* move_branch(const std::size_t&) override + inline expression_node<T>* move_branch(const std::size_t&) exprtk_override { branch_.second = false; return branch_.first; } - void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) override + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override { - expression_node<T>::ndb_t::template collect<>(branch_, node_delete_list); + expression_node<T>::ndb_t::collect(branch_, node_delete_list); } - std::size_t node_depth() const override + std::size_t node_depth() const exprtk_override { return expression_node<T>::ndb_t::compute_node_depth(branch_); } private: - boc_node(const boc_node<T,Operation>&); - boc_node<T,Operation>& operator=(const boc_node<T,Operation>&); + boc_node(const boc_node<T,Operation>&) exprtk_delete; + boc_node<T,Operation>& operator=(const boc_node<T,Operation>&) exprtk_delete; const T c_; branch_t branch_; @@ -15494,7 +18291,7 @@ namespace exprtk #ifndef exprtk_disable_string_capabilities template <typename T, typename SType0, typename SType1, typename Operation> - class sos_node : public sos_base_node<T> + class sos_node exprtk_final : public sos_base_node<T> { public: @@ -15503,21 +18300,21 @@ namespace exprtk // string op string node explicit sos_node(SType0 p0, SType1 p1) - : s0_(p0), - s1_(p1) + : s0_(p0) + , s1_(p1) {} - inline T value() const override + inline T value() const exprtk_override { return Operation::process(s0_,s1_); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return Operation::type(); } - inline operator_type operation() const override + inline operator_type operation() const exprtk_override { return Operation::operation(); } @@ -15539,31 +18336,32 @@ namespace exprtk private: - sos_node(sos_node<T,SType0,SType1,Operation>&); - sos_node<T,SType0,SType1,Operation>& operator=(sos_node<T,SType0,SType1,Operation>&); + sos_node(const sos_node<T,SType0,SType1,Operation>&) exprtk_delete; + sos_node<T,SType0,SType1,Operation>& operator=(const sos_node<T,SType0,SType1,Operation>&) exprtk_delete; }; template <typename T, typename SType0, typename SType1, typename RangePack, typename Operation> - class str_xrox_node : public sos_base_node<T> + class str_xrox_node exprtk_final : public sos_base_node<T> { public: typedef expression_node<T>* expression_ptr; typedef Operation operation_t; + typedef str_xrox_node<T,SType0,SType1,RangePack,Operation> node_type; // string-range op string node explicit str_xrox_node(SType0 p0, SType1 p1, RangePack rp0) - : s0_ (p0 ), - s1_ (p1 ), - rp0_(rp0) + : s0_ (p0 ) + , s1_ (p1 ) + , rp0_(rp0) {} - ~str_xrox_node() override + ~str_xrox_node() exprtk_override { rp0_.free(); } - inline T value() const override + inline T value() const exprtk_override { std::size_t r0 = 0; std::size_t r1 = 0; @@ -15574,12 +18372,12 @@ namespace exprtk return T(0); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return Operation::type(); } - inline operator_type operation() const override + inline operator_type operation() const exprtk_override { return Operation::operation(); } @@ -15602,47 +18400,54 @@ namespace exprtk private: - str_xrox_node(str_xrox_node<T,SType0,SType1,RangePack,Operation>&); - str_xrox_node<T,SType0,SType1,RangePack,Operation>& operator=(str_xrox_node<T,SType0,SType1,RangePack,Operation>&); + str_xrox_node(const node_type&) exprtk_delete; + node_type& operator=(const node_type&) exprtk_delete; }; template <typename T, typename SType0, typename SType1, typename RangePack, typename Operation> - class str_xoxr_node : public sos_base_node<T> + class str_xoxr_node exprtk_final : public sos_base_node<T> { public: typedef expression_node<T>* expression_ptr; typedef Operation operation_t; + typedef str_xoxr_node<T,SType0,SType1,RangePack,Operation> node_type; // string op string range node explicit str_xoxr_node(SType0 p0, SType1 p1, RangePack rp1) - : s0_ (p0 ), - s1_ (p1 ), - rp1_(rp1) + : s0_ (p0 ) + , s1_ (p1 ) + , rp1_(rp1) {} - ~str_xoxr_node() override + ~str_xoxr_node() exprtk_override { rp1_.free(); } - inline T value() const override + inline T value() const exprtk_override { std::size_t r0 = 0; std::size_t r1 = 0; if (rp1_(r0, r1, s1_.size())) - return Operation::process(s0_, s1_.substr(r0, (r1 - r0) + 1)); + { + return Operation::process + ( + s0_, + s1_.substr(r0, (r1 - r0) + 1) + ); + } else return T(0); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return Operation::type(); } - inline operator_type operation() const override + inline operator_type operation() const exprtk_override { return Operation::operation(); } @@ -15665,33 +18470,34 @@ namespace exprtk private: - str_xoxr_node(str_xoxr_node<T,SType0,SType1,RangePack,Operation>&); - str_xoxr_node<T,SType0,SType1,RangePack,Operation>& operator=(str_xoxr_node<T,SType0,SType1,RangePack,Operation>&); + str_xoxr_node(const node_type&) exprtk_delete; + node_type& operator=(const node_type&) exprtk_delete; }; template <typename T, typename SType0, typename SType1, typename RangePack, typename Operation> - class str_xroxr_node : public sos_base_node<T> + class str_xroxr_node exprtk_final : public sos_base_node<T> { public: typedef expression_node<T>* expression_ptr; typedef Operation operation_t; + typedef str_xroxr_node<T,SType0,SType1,RangePack,Operation> node_type; // string-range op string-range node explicit str_xroxr_node(SType0 p0, SType1 p1, RangePack rp0, RangePack rp1) - : s0_ (p0 ), - s1_ (p1 ), - rp0_(rp0), - rp1_(rp1) + : s0_ (p0 ) + , s1_ (p1 ) + , rp0_(rp0) + , rp1_(rp1) {} - ~str_xroxr_node() override + ~str_xroxr_node() exprtk_override { rp0_.free(); rp1_.free(); } - inline T value() const override + inline T value() const exprtk_override { std::size_t r0_0 = 0; std::size_t r0_1 = 0; @@ -15703,21 +18509,22 @@ namespace exprtk rp1_(r0_1, r1_1, s1_.size()) ) { - return Operation::process( - s0_.substr(r0_0, (r1_0 - r0_0) + 1), - s1_.substr(r0_1, (r1_1 - r0_1) + 1) - ); + return Operation::process + ( + s0_.substr(r0_0, (r1_0 - r0_0) + 1), + s1_.substr(r0_1, (r1_1 - r0_1) + 1) + ); } else return T(0); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return Operation::type(); } - inline operator_type operation() const override + inline operator_type operation() const exprtk_override { return Operation::operation(); } @@ -15741,39 +18548,42 @@ namespace exprtk private: - str_xroxr_node(str_xroxr_node<T,SType0,SType1,RangePack,Operation>&); - str_xroxr_node<T,SType0,SType1,RangePack,Operation>& operator=(str_xroxr_node<T,SType0,SType1,RangePack,Operation>&); + str_xroxr_node(const node_type&) exprtk_delete; + node_type& operator=(const node_type&) exprtk_delete; }; template <typename T, typename Operation> - class str_sogens_node : public binary_node<T> + class str_sogens_node exprtk_final : public binary_node<T> { public: typedef expression_node <T>* expression_ptr; - typedef string_base_node<T>* str_base_ptr; - typedef range_pack <T> range_t; - typedef range_t* range_ptr; - typedef range_interface<T> irange_t; - typedef irange_t* irange_ptr; + typedef string_base_node<T>* str_base_ptr; + typedef range_pack <T> range_t; + typedef range_t* range_ptr; + typedef range_interface <T> irange_t; + typedef irange_t* irange_ptr; + + using binary_node<T>::branch; str_sogens_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) - : binary_node<T>(opr, branch0, branch1), - str0_base_ptr_ (0), - str1_base_ptr_ (0), - str0_range_ptr_(0), - str1_range_ptr_(0) + : binary_node<T>(opr, branch0, branch1) + , str0_base_ptr_ (0) + , str1_base_ptr_ (0) + , str0_range_ptr_(0) + , str1_range_ptr_(0) + , initialised_ (false) { - if (is_generally_string_node(binary_node<T>::branch_[0].first)) + if (is_generally_string_node(branch(0))) { - str0_base_ptr_ = dynamic_cast<str_base_ptr>(binary_node<T>::branch_[0].first); + str0_base_ptr_ = dynamic_cast<str_base_ptr>(branch(0)); if (0 == str0_base_ptr_) return; - irange_ptr range = dynamic_cast<irange_ptr>(binary_node<T>::branch_[0].first); + irange_ptr range = dynamic_cast<irange_ptr>(branch(0)); if (0 == range) return; @@ -15781,105 +18591,108 @@ namespace exprtk str0_range_ptr_ = &(range->range_ref()); } - if (is_generally_string_node(binary_node<T>::branch_[1].first)) + if (is_generally_string_node(branch(1))) { - str1_base_ptr_ = dynamic_cast<str_base_ptr>(binary_node<T>::branch_[1].first); + str1_base_ptr_ = dynamic_cast<str_base_ptr>(branch(1)); if (0 == str1_base_ptr_) return; - irange_ptr range = dynamic_cast<irange_ptr>(binary_node<T>::branch_[1].first); + irange_ptr range = dynamic_cast<irange_ptr>(branch(1)); if (0 == range) return; str1_range_ptr_ = &(range->range_ref()); } + + initialised_ = + str0_base_ptr_ && + str1_base_ptr_ && + str0_range_ptr_ && + str1_range_ptr_; + + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { - if ( - str0_base_ptr_ && - str1_base_ptr_ && - str0_range_ptr_ && - str1_range_ptr_ - ) - { - binary_node<T>::branch_[0].first->value(); - binary_node<T>::branch_[1].first->value(); + branch(0)->value(); + branch(1)->value(); - std::size_t str0_r0 = 0; - std::size_t str0_r1 = 0; + std::size_t str0_r0 = 0; + std::size_t str0_r1 = 0; - std::size_t str1_r0 = 0; - std::size_t str1_r1 = 0; + std::size_t str1_r0 = 0; + std::size_t str1_r1 = 0; - const range_t& range0 = (*str0_range_ptr_); - const range_t& range1 = (*str1_range_ptr_); + const range_t& range0 = (*str0_range_ptr_); + const range_t& range1 = (*str1_range_ptr_); - if ( - range0(str0_r0, str0_r1, str0_base_ptr_->size()) && - range1(str1_r0, str1_r1, str1_base_ptr_->size()) - ) - { - return Operation::process( - str0_base_ptr_->str().substr(str0_r0,(str0_r1 - str0_r0) + 1), - str1_base_ptr_->str().substr(str1_r0,(str1_r1 - str1_r0) + 1) - ); - } + if ( + range0(str0_r0, str0_r1, str0_base_ptr_->size()) && + range1(str1_r0, str1_r1, str1_base_ptr_->size()) + ) + { + return Operation::process + ( + str0_base_ptr_->str().substr(str0_r0,(str0_r1 - str0_r0)), + str1_base_ptr_->str().substr(str1_r0,(str1_r1 - str1_r0)) + ); } return std::numeric_limits<T>::quiet_NaN(); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return Operation::type(); } - inline operator_type operation() const + inline bool valid() const exprtk_override { - return Operation::operation(); + return initialised_; } private: - str_sogens_node(str_sogens_node<T,Operation>&); - str_sogens_node<T,Operation>& operator=(str_sogens_node<T,Operation>&); + str_sogens_node(const str_sogens_node<T,Operation>&) exprtk_delete; + str_sogens_node<T,Operation>& operator=(const str_sogens_node<T,Operation>&) exprtk_delete; str_base_ptr str0_base_ptr_; str_base_ptr str1_base_ptr_; range_ptr str0_range_ptr_; range_ptr str1_range_ptr_; + bool initialised_; }; template <typename T, typename SType0, typename SType1, typename SType2, typename Operation> - class sosos_node : public sosos_base_node<T> + class sosos_node exprtk_final : public sosos_base_node<T> { public: typedef expression_node<T>* expression_ptr; typedef Operation operation_t; + typedef sosos_node<T, SType0, SType1, SType2, Operation> node_type; - // variable op variable node + // string op string op string node explicit sosos_node(SType0 p0, SType1 p1, SType2 p2) - : s0_(p0), - s1_(p1), - s2_(p2) + : s0_(p0) + , s1_(p1) + , s2_(p2) {} - inline T value() const override + inline T value() const exprtk_override { - return Operation::process(s0_,s1_,s2_); + return Operation::process(s0_, s1_, s2_); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return Operation::type(); } - inline operator_type operation() const override + inline operator_type operation() const exprtk_override { return Operation::operation(); } @@ -15907,13 +18720,13 @@ namespace exprtk private: - sosos_node(sosos_node<T,SType0,SType1,SType2,Operation>&); - sosos_node<T,SType0,SType1,SType2,Operation>& operator=(sosos_node<T,SType0,SType1,SType2,Operation>&); + sosos_node(const node_type&) exprtk_delete; + node_type& operator=(const node_type&) exprtk_delete; }; #endif template <typename T, typename PowOp> - class ipow_node : public expression_node<T> + class ipow_node exprtk_final: public expression_node<T> { public: @@ -15924,26 +18737,26 @@ namespace exprtk : v_(v) {} - inline T value() const override + inline T value() const exprtk_override { return PowOp::result(v_); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_ipow; } private: - ipow_node(const ipow_node<T,PowOp>&); - ipow_node<T,PowOp>& operator=(const ipow_node<T,PowOp>&); + ipow_node(const ipow_node<T,PowOp>&) exprtk_delete; + ipow_node<T,PowOp>& operator=(const ipow_node<T,PowOp>&) exprtk_delete; const T& v_; }; template <typename T, typename PowOp> - class bipow_node : public expression_node<T> + class bipow_node exprtk_final : public expression_node<T> { public: @@ -15954,39 +18767,44 @@ namespace exprtk explicit bipow_node(expression_ptr branch) { construct_branch_pair(branch_, branch); + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { - assert(branch_.first); return PowOp::result(branch_.first->value()); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_ipow; } - void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) override + inline bool valid() const exprtk_override + { + return branch_.first && branch_.first->valid(); + } + + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override { expression_node<T>::ndb_t::collect(branch_, node_delete_list); } - std::size_t node_depth() const override + std::size_t node_depth() const exprtk_override { return expression_node<T>::ndb_t::compute_node_depth(branch_); } private: - bipow_node(const bipow_node<T,PowOp>&); - bipow_node<T,PowOp>& operator=(const bipow_node<T,PowOp>&); + bipow_node(const bipow_node<T,PowOp>&) exprtk_delete; + bipow_node<T,PowOp>& operator=(const bipow_node<T,PowOp>&) exprtk_delete; branch_t branch_; }; template <typename T, typename PowOp> - class ipowinv_node : public expression_node<T> + class ipowinv_node exprtk_final : public expression_node<T> { public: @@ -15997,26 +18815,26 @@ namespace exprtk : v_(v) {} - inline T value() const override + inline T value() const exprtk_override { return (T(1) / PowOp::result(v_)); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_ipowinv; } private: - ipowinv_node(const ipowinv_node<T,PowOp>&); - ipowinv_node<T,PowOp>& operator=(const ipowinv_node<T,PowOp>&); + ipowinv_node(const ipowinv_node<T,PowOp>&) exprtk_delete; + ipowinv_node<T,PowOp>& operator=(const ipowinv_node<T,PowOp>&) exprtk_delete; const T& v_; }; template <typename T, typename PowOp> - class bipowninv_node : public expression_node<T> + class bipowinv_node exprtk_final : public expression_node<T> { public: @@ -16024,36 +18842,41 @@ namespace exprtk typedef std::pair<expression_ptr, bool> branch_t; typedef PowOp operation_t; - explicit bipowninv_node(expression_ptr branch) + explicit bipowinv_node(expression_ptr branch) { construct_branch_pair(branch_, branch); + assert(valid()); } - inline T value() const override + inline T value() const exprtk_override { - assert(branch_.first); return (T(1) / PowOp::result(branch_.first->value())); } - inline typename expression_node<T>::node_type type() const override + inline typename expression_node<T>::node_type type() const exprtk_override { return expression_node<T>::e_ipowinv; } - void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) override + inline bool valid() const exprtk_override + { + return branch_.first && branch_.first->valid(); + } + + void collect_nodes(typename expression_node<T>::noderef_list_t& node_delete_list) exprtk_override { - expression_node<T>::ndb_t::template collect<>(branch_, node_delete_list); + expression_node<T>::ndb_t::collect(branch_, node_delete_list); } - std::size_t node_depth() const override + std::size_t node_depth() const exprtk_override { return expression_node<T>::ndb_t::compute_node_depth(branch_); } private: - bipowninv_node(const bipowninv_node<T,PowOp>&); - bipowninv_node<T,PowOp>& operator=(const bipowninv_node<T,PowOp>&); + bipowinv_node(const bipowinv_node<T,PowOp>&) exprtk_delete; + bipowinv_node<T,PowOp>& operator=(const bipowinv_node<T,PowOp>&) exprtk_delete; branch_t branch_; }; @@ -16197,6 +19020,46 @@ namespace exprtk return false; } + template <typename T> + inline bool is_loop_node(const expression_node<T>* node) + { + if (node) + { + switch (node->type()) + { + case expression_node<T>::e_for : + case expression_node<T>::e_repeat : + case expression_node<T>::e_while : return true; + default : return false; + } + } + + return false; + } + + template <typename T> + inline bool is_block_node(const expression_node<T>* node) + { + if (node) + { + if (is_loop_node(node)) + { + return true; + } + + switch (node->type()) + { + case expression_node<T>::e_conditional : + case expression_node<T>::e_mswitch : + case expression_node<T>::e_switch : + case expression_node<T>::e_vararg : return true; + default : return false; + } + } + + return false; + } + class node_allocator { public: @@ -16585,61 +19448,61 @@ namespace exprtk inline void load_operations_map(std::multimap<std::string,details::base_operation_t,details::ilesscompare>& m) { - #define register_op(Symbol,Type,Args) \ + #define register_op(Symbol, Type, Args) \ m.insert(std::make_pair(std::string(Symbol),details::base_operation_t(Type,Args))); \ - register_op( "abs", e_abs , 1) - register_op( "acos", e_acos , 1) - register_op( "acosh", e_acosh , 1) - register_op( "asin", e_asin , 1) - register_op( "asinh", e_asinh , 1) - register_op( "atan", e_atan , 1) - register_op( "atanh", e_atanh , 1) - register_op( "ceil", e_ceil , 1) - register_op( "cos", e_cos , 1) - register_op( "cosh", e_cosh , 1) - register_op( "exp", e_exp , 1) - register_op( "expm1", e_expm1 , 1) - register_op( "floor", e_floor , 1) - register_op( "log", e_log , 1) - register_op( "log10", e_log10 , 1) - register_op( "log2", e_log2 , 1) - register_op( "log1p", e_log1p , 1) - register_op( "round", e_round , 1) - register_op( "sin", e_sin , 1) - register_op( "sinc", e_sinc , 1) - register_op( "sinh", e_sinh , 1) - register_op( "sec", e_sec , 1) - register_op( "csc", e_csc , 1) - register_op( "sqrt", e_sqrt , 1) - register_op( "tan", e_tan , 1) - register_op( "tanh", e_tanh , 1) - register_op( "cot", e_cot , 1) - register_op( "rad2deg", e_r2d , 1) - register_op( "deg2rad", e_d2r , 1) - register_op( "deg2grad", e_d2g , 1) - register_op( "grad2deg", e_g2d , 1) - register_op( "sgn", e_sgn , 1) - register_op( "not", e_notl , 1) - register_op( "erf", e_erf , 1) - register_op( "erfc", e_erfc , 1) - register_op( "ncdf", e_ncdf , 1) - register_op( "frac", e_frac , 1) - register_op( "trunc", e_trunc , 1) - register_op( "atan2", e_atan2 , 2) - register_op( "mod", e_mod , 2) - register_op( "logn", e_logn , 2) - register_op( "pow", e_pow , 2) - register_op( "root", e_root , 2) - register_op( "roundn", e_roundn , 2) - register_op( "equal", e_equal , 2) - register_op("not_equal", e_nequal , 2) - register_op( "hypot", e_hypot , 2) - register_op( "shr", e_shr , 2) - register_op( "shl", e_shl , 2) - register_op( "clamp", e_clamp , 3) - register_op( "iclamp", e_iclamp , 3) - register_op( "inrange", e_inrange , 3) + register_op("abs" , e_abs , 1) + register_op("acos" , e_acos , 1) + register_op("acosh" , e_acosh , 1) + register_op("asin" , e_asin , 1) + register_op("asinh" , e_asinh , 1) + register_op("atan" , e_atan , 1) + register_op("atanh" , e_atanh , 1) + register_op("ceil" , e_ceil , 1) + register_op("cos" , e_cos , 1) + register_op("cosh" , e_cosh , 1) + register_op("exp" , e_exp , 1) + register_op("expm1" , e_expm1 , 1) + register_op("floor" , e_floor , 1) + register_op("log" , e_log , 1) + register_op("log10" , e_log10 , 1) + register_op("log2" , e_log2 , 1) + register_op("log1p" , e_log1p , 1) + register_op("round" , e_round , 1) + register_op("sin" , e_sin , 1) + register_op("sinc" , e_sinc , 1) + register_op("sinh" , e_sinh , 1) + register_op("sec" , e_sec , 1) + register_op("csc" , e_csc , 1) + register_op("sqrt" , e_sqrt , 1) + register_op("tan" , e_tan , 1) + register_op("tanh" , e_tanh , 1) + register_op("cot" , e_cot , 1) + register_op("rad2deg" , e_r2d , 1) + register_op("deg2rad" , e_d2r , 1) + register_op("deg2grad" , e_d2g , 1) + register_op("grad2deg" , e_g2d , 1) + register_op("sgn" , e_sgn , 1) + register_op("not" , e_notl , 1) + register_op("erf" , e_erf , 1) + register_op("erfc" , e_erfc , 1) + register_op("ncdf" , e_ncdf , 1) + register_op("frac" , e_frac , 1) + register_op("trunc" , e_trunc , 1) + register_op("atan2" , e_atan2 , 2) + register_op("mod" , e_mod , 2) + register_op("logn" , e_logn , 2) + register_op("pow" , e_pow , 2) + register_op("root" , e_root , 2) + register_op("roundn" , e_roundn , 2) + register_op("equal" , e_equal , 2) + register_op("not_equal" , e_nequal , 2) + register_op("hypot" , e_hypot , 2) + register_op("shr" , e_shr , 2) + register_op("shl" , e_shl , 2) + register_op("clamp" , e_clamp , 3) + register_op("iclamp" , e_iclamp , 3) + register_op("inrange" , e_inrange , 3) #undef register_op } @@ -16650,10 +19513,10 @@ namespace exprtk public: function_traits() - : allow_zero_parameters_(false), - has_side_effects_(true), - min_num_args_(0), - max_num_args_(std::numeric_limits<std::size_t>::max()) + : allow_zero_parameters_(false) + , has_side_effects_(true) + , min_num_args_(0) + , max_num_args_(std::numeric_limits<std::size_t>::max()) {} inline bool& allow_zero_parameters() @@ -16737,7 +19600,7 @@ namespace exprtk : param_count(pc) {} - virtual ~ifunction() = default; + virtual ~ifunction() exprtk_default; #define empty_method_body(N) \ { \ @@ -16828,7 +19691,7 @@ namespace exprtk { public: - virtual ~ivararg_function() = default; + virtual ~ivararg_function() exprtk_default; inline virtual T operator() (const std::vector<T>&) { @@ -16853,12 +19716,12 @@ namespace exprtk typedef type_store<T> generic_type; typedef typename generic_type::parameter_list parameter_list_t; - igeneric_function(const std::string& param_seq = "", const return_type rtr_type = e_rtrn_scalar) - : parameter_sequence(param_seq), - rtrn_type(rtr_type) + explicit igeneric_function(const std::string& param_seq = "", const return_type rtr_type = e_rtrn_scalar) + : parameter_sequence(param_seq) + , rtrn_type(rtr_type) {} - virtual ~igeneric_function() = default; + virtual ~igeneric_function() exprtk_default; #define igeneric_function_empty_body(N) \ { \ @@ -16882,10 +19745,49 @@ namespace exprtk inline virtual T operator() (const std::size_t&, std::string&, parameter_list_t) igeneric_function_empty_body(4) + #undef igeneric_function_empty_body + std::string parameter_sequence; return_type rtrn_type; }; + #ifndef exprtk_disable_string_capabilities + template <typename T> + class stringvar_base + { + public: + + typedef typename details::stringvar_node<T> stringvar_node_t; + + stringvar_base(const std::string& name, stringvar_node_t* svn) + : name_(name) + , string_varnode_(svn) + {} + + bool valid() const + { + return !name_.empty() && (0 != string_varnode_); + } + + std::string name() const + { + assert(string_varnode_); + return name_; + } + + void rebase(std::string& s) + { + assert(string_varnode_); + string_varnode_->rebase(s); + } + + private: + + std::string name_; + stringvar_node_t* string_varnode_; + }; + #endif + template <typename T> class parser; template <typename T> class expression_helper; @@ -16894,71 +19796,78 @@ namespace exprtk { public: - typedef T (*ff00_functor)(); - typedef T (*ff01_functor)(T); - typedef T (*ff02_functor)(T, T); - typedef T (*ff03_functor)(T, T, T); - typedef T (*ff04_functor)(T, T, T, T); - typedef T (*ff05_functor)(T, T, T, T, T); - typedef T (*ff06_functor)(T, T, T, T, T, T); - typedef T (*ff07_functor)(T, T, T, T, T, T, T); - typedef T (*ff08_functor)(T, T, T, T, T, T, T, T); - typedef T (*ff09_functor)(T, T, T, T, T, T, T, T, T); - typedef T (*ff10_functor)(T, T, T, T, T, T, T, T, T, T); - typedef T (*ff11_functor)(T, T, T, T, T, T, T, T, T, T, T); - typedef T (*ff12_functor)(T, T, T, T, T, T, T, T, T, T, T, T); - typedef T (*ff13_functor)(T, T, T, T, T, T, T, T, T, T, T, T, T); - typedef T (*ff14_functor)(T, T, T, T, T, T, T, T, T, T, T, T, T, T); - typedef T (*ff15_functor)(T, T, T, T, T, T, T, T, T, T, T, T, T, T, T); + enum symtab_mutability_type + { + e_unknown = 0, + e_mutable = 1, + e_immutable = 2 + }; + + typedef T (*ff00_functor)(); + typedef T (*ff01_functor)(T); + typedef T (*ff02_functor)(T, T); + typedef T (*ff03_functor)(T, T, T); + typedef T (*ff04_functor)(T, T, T, T); + typedef T (*ff05_functor)(T, T, T, T, T); + typedef T (*ff06_functor)(T, T, T, T, T, T); + typedef T (*ff07_functor)(T, T, T, T, T, T, T); + typedef T (*ff08_functor)(T, T, T, T, T, T, T, T); + typedef T (*ff09_functor)(T, T, T, T, T, T, T, T, T); + typedef T (*ff10_functor)(T, T, T, T, T, T, T, T, T, T); + typedef T (*ff11_functor)(T, T, T, T, T, T, T, T, T, T, T); + typedef T (*ff12_functor)(T, T, T, T, T, T, T, T, T, T, T, T); + typedef T (*ff13_functor)(T, T, T, T, T, T, T, T, T, T, T, T, T); + typedef T (*ff14_functor)(T, T, T, T, T, T, T, T, T, T, T, T, T, T); + typedef T (*ff15_functor)(T, T, T, T, T, T, T, T, T, T, T, T, T, T, T); protected: - struct freefunc00 : public exprtk::ifunction<T> + struct freefunc00 exprtk_final : public exprtk::ifunction<T> { using exprtk::ifunction<T>::operator(); explicit freefunc00(ff00_functor ff) : exprtk::ifunction<T>(0), f(ff) {} - inline T operator() () + inline T operator() () exprtk_override { return f(); } ff00_functor f; }; - struct freefunc01 : public exprtk::ifunction<T> + struct freefunc01 exprtk_final : public exprtk::ifunction<T> { using exprtk::ifunction<T>::operator(); explicit freefunc01(ff01_functor ff) : exprtk::ifunction<T>(1), f(ff) {} - inline T operator() (const T& v0) + inline T operator() (const T& v0) exprtk_override { return f(v0); } ff01_functor f; }; - struct freefunc02 : public exprtk::ifunction<T> + struct freefunc02 exprtk_final : public exprtk::ifunction<T> { using exprtk::ifunction<T>::operator(); explicit freefunc02(ff02_functor ff) : exprtk::ifunction<T>(2), f(ff) {} - inline T operator() (const T& v0, const T& v1) + inline T operator() (const T& v0, const T& v1) exprtk_override { return f(v0, v1); } ff02_functor f; }; - struct freefunc03 : public exprtk::ifunction<T> + struct freefunc03 exprtk_final : public exprtk::ifunction<T> { using exprtk::ifunction<T>::operator(); explicit freefunc03(ff03_functor ff) : exprtk::ifunction<T>(3), f(ff) {} - inline T operator() (const T& v0, const T& v1, const T& v2) + inline T operator() (const T& v0, const T& v1, const T& v2) exprtk_override { return f(v0, v1, v2); } ff03_functor f; }; - struct freefunc04 : public exprtk::ifunction<T> + struct freefunc04 exprtk_final : public exprtk::ifunction<T> { using exprtk::ifunction<T>::operator(); explicit freefunc04(ff04_functor ff) : exprtk::ifunction<T>(4), f(ff) {} - inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3) + inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3) exprtk_override { return f(v0, v1, v2, v3); } ff04_functor f; }; @@ -16968,120 +19877,120 @@ namespace exprtk using exprtk::ifunction<T>::operator(); explicit freefunc05(ff05_functor ff) : exprtk::ifunction<T>(5), f(ff) {} - inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4) + inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4) exprtk_override { return f(v0, v1, v2, v3, v4); } ff05_functor f; }; - struct freefunc06 : public exprtk::ifunction<T> + struct freefunc06 exprtk_final : public exprtk::ifunction<T> { using exprtk::ifunction<T>::operator(); explicit freefunc06(ff06_functor ff) : exprtk::ifunction<T>(6), f(ff) {} - inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, const T& v5) + inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, const T& v5) exprtk_override { return f(v0, v1, v2, v3, v4, v5); } ff06_functor f; }; - struct freefunc07 : public exprtk::ifunction<T> + struct freefunc07 exprtk_final : public exprtk::ifunction<T> { using exprtk::ifunction<T>::operator(); explicit freefunc07(ff07_functor ff) : exprtk::ifunction<T>(7), f(ff) {} inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, - const T& v5, const T& v6) + const T& v5, const T& v6) exprtk_override { return f(v0, v1, v2, v3, v4, v5, v6); } ff07_functor f; }; - struct freefunc08 : public exprtk::ifunction<T> + struct freefunc08 exprtk_final : public exprtk::ifunction<T> { using exprtk::ifunction<T>::operator(); explicit freefunc08(ff08_functor ff) : exprtk::ifunction<T>(8), f(ff) {} inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, - const T& v5, const T& v6, const T& v7) + const T& v5, const T& v6, const T& v7) exprtk_override { return f(v0, v1, v2, v3, v4, v5, v6, v7); } ff08_functor f; }; - struct freefunc09 : public exprtk::ifunction<T> + struct freefunc09 exprtk_final : public exprtk::ifunction<T> { using exprtk::ifunction<T>::operator(); explicit freefunc09(ff09_functor ff) : exprtk::ifunction<T>(9), f(ff) {} inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, - const T& v5, const T& v6, const T& v7, const T& v8) + const T& v5, const T& v6, const T& v7, const T& v8) exprtk_override { return f(v0, v1, v2, v3, v4, v5, v6, v7, v8); } ff09_functor f; }; - struct freefunc10 : public exprtk::ifunction<T> + struct freefunc10 exprtk_final : public exprtk::ifunction<T> { using exprtk::ifunction<T>::operator(); explicit freefunc10(ff10_functor ff) : exprtk::ifunction<T>(10), f(ff) {} inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, - const T& v5, const T& v6, const T& v7, const T& v8, const T& v9) + const T& v5, const T& v6, const T& v7, const T& v8, const T& v9) exprtk_override { return f(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9); } ff10_functor f; }; - struct freefunc11 : public exprtk::ifunction<T> + struct freefunc11 exprtk_final : public exprtk::ifunction<T> { using exprtk::ifunction<T>::operator(); explicit freefunc11(ff11_functor ff) : exprtk::ifunction<T>(11), f(ff) {} inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, - const T& v5, const T& v6, const T& v7, const T& v8, const T& v9, const T& v10) + const T& v5, const T& v6, const T& v7, const T& v8, const T& v9, const T& v10) exprtk_override { return f(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10); } ff11_functor f; }; - struct freefunc12 : public exprtk::ifunction<T> + struct freefunc12 exprtk_final : public exprtk::ifunction<T> { using exprtk::ifunction<T>::operator(); explicit freefunc12(ff12_functor ff) : exprtk::ifunction<T>(12), f(ff) {} inline T operator() (const T& v00, const T& v01, const T& v02, const T& v03, const T& v04, const T& v05, const T& v06, const T& v07, const T& v08, const T& v09, - const T& v10, const T& v11) + const T& v10, const T& v11) exprtk_override { return f(v00, v01, v02, v03, v04, v05, v06, v07, v08, v09, v10, v11); } ff12_functor f; }; - struct freefunc13 : public exprtk::ifunction<T> + struct freefunc13 exprtk_final : public exprtk::ifunction<T> { using exprtk::ifunction<T>::operator(); explicit freefunc13(ff13_functor ff) : exprtk::ifunction<T>(13), f(ff) {} inline T operator() (const T& v00, const T& v01, const T& v02, const T& v03, const T& v04, const T& v05, const T& v06, const T& v07, const T& v08, const T& v09, - const T& v10, const T& v11, const T& v12) + const T& v10, const T& v11, const T& v12) exprtk_override { return f(v00, v01, v02, v03, v04, v05, v06, v07, v08, v09, v10, v11, v12); } ff13_functor f; }; - struct freefunc14 : public exprtk::ifunction<T> + struct freefunc14 exprtk_final : public exprtk::ifunction<T> { using exprtk::ifunction<T>::operator(); explicit freefunc14(ff14_functor ff) : exprtk::ifunction<T>(14), f(ff) {} inline T operator() (const T& v00, const T& v01, const T& v02, const T& v03, const T& v04, const T& v05, const T& v06, const T& v07, const T& v08, const T& v09, - const T& v10, const T& v11, const T& v12, const T& v13) + const T& v10, const T& v11, const T& v12, const T& v13) exprtk_override { return f(v00, v01, v02, v03, v04, v05, v06, v07, v08, v09, v10, v11, v12, v13); } ff14_functor f; }; - struct freefunc15 : public exprtk::ifunction<T> + struct freefunc15 exprtk_final : public exprtk::ifunction<T> { using exprtk::ifunction<T>::operator(); explicit freefunc15(ff15_functor ff) : exprtk::ifunction<T>(15), f(ff) {} inline T operator() (const T& v00, const T& v01, const T& v02, const T& v03, const T& v04, const T& v05, const T& v06, const T& v07, const T& v08, const T& v09, - const T& v10, const T& v11, const T& v12, const T& v13, const T& v14) + const T& v10, const T& v11, const T& v12, const T& v13, const T& v14) exprtk_override { return f(v00, v01, v02, v03, v04, v05, v06, v07, v08, v09, v10, v11, v12, v13, v14); } ff15_functor f; }; @@ -17274,19 +20183,19 @@ namespace exprtk (symbol_name, v, is_const); } - inline bool add(const std::string& symbol_name, RawType& t, const bool is_const = false) + inline bool add(const std::string& symbol_name, RawType& t_, const bool is_const = false) { struct tie { - static inline std::pair<bool,variable_node_t*> make(T& t,const bool is_const = false) + static inline std::pair<bool,variable_node_t*> make(T& t, const bool is_constant = false) { - return std::make_pair(is_const, new variable_node_t(t)); + return std::make_pair(is_constant, new variable_node_t(t)); } #ifndef exprtk_disable_string_capabilities - static inline std::pair<bool,stringvar_node_t*> make(std::string& t,const bool is_const = false) + static inline std::pair<bool,stringvar_node_t*> make(std::string& t, const bool is_constant = false) { - return std::make_pair(is_const, new stringvar_node_t(t)); + return std::make_pair(is_constant, new stringvar_node_t(t)); } #endif @@ -17295,9 +20204,9 @@ namespace exprtk return std::make_pair(is_constant,&t); } - static inline std::pair<bool,vararg_function_t*> make(vararg_function_t& t, const bool is_const = false) + static inline std::pair<bool,vararg_function_t*> make(vararg_function_t& t, const bool is_constant = false) { - return std::make_pair(is_const,&t); + return std::make_pair(is_constant,&t); } static inline std::pair<bool,generic_function_t*> make(generic_function_t& t, const bool is_constant = false) @@ -17310,7 +20219,7 @@ namespace exprtk if (map.end() == itr) { - map[symbol_name] = tie::make(t,is_const); + map[symbol_name] = tie::make(t_,is_const); ++size; } @@ -17341,7 +20250,7 @@ namespace exprtk { static inline bool test(const variable_node_t* p, const void* ptr) { - exprtk_debug(("ptr_match::test() - %p <--> %p\n",(void*)(&(p->ref())),ptr)); + exprtk_debug(("ptr_match::test() - %p <--> %p\n", reinterpret_cast<const void*>(&(p->ref())), ptr)); return (&(p->ref()) == ptr); } }; @@ -17549,13 +20458,15 @@ namespace exprtk }; control_block() - : ref_count(1), - data_(st_data::create()) + : ref_count(1) + , data_(st_data::create()) + , mutability_(e_mutable) {} explicit control_block(st_data* data) - : ref_count(1), - data_(data) + : ref_count(1) + , data_(data) + , mutability_(e_mutable) {} ~control_block() @@ -17591,21 +20502,29 @@ namespace exprtk } } + void set_mutability(const symtab_mutability_type mutability) + { + mutability_ = mutability; + } + std::size_t ref_count; st_data* data_; + symtab_mutability_type mutability_; }; public: - symbol_table() + explicit symbol_table(const symtab_mutability_type mutability = e_mutable) : control_block_(control_block::create()) { + control_block_->set_mutability(mutability); clear(); } ~symbol_table() { - control_block::destroy(control_block_,this); + exprtk::details::dump_ptr("~symbol_table", this); + control_block::destroy(control_block_, this); } symbol_table(const symbol_table<T>& st) @@ -17632,6 +20551,11 @@ namespace exprtk return (this == &st) || (control_block_ == st.control_block_); } + inline symtab_mutability_type mutability() const + { + return valid() ? control_block_->mutability_ : e_unknown; + } + inline void clear_variables(const bool delete_node = true) { local_data().variable_store.clear(delete_node); @@ -17732,6 +20656,24 @@ namespace exprtk else return local_data().stringvar_store.get(string_name); } + + inline stringvar_base<T> get_stringvar_base(const std::string& string_name) const + { + static stringvar_base<T> null_stringvar_base("",reinterpret_cast<stringvar_ptr>(0)); + if (!valid()) + return null_stringvar_base; + else if (!valid_symbol(string_name)) + return null_stringvar_base; + + stringvar_ptr stringvar = local_data().stringvar_store.get(string_name); + + if (0 == stringvar) + { + return null_stringvar_base; + } + + return stringvar_base<T>(string_name,stringvar); + } #endif inline function_ptr get_function(const std::string& function_name) const @@ -18051,6 +20993,34 @@ namespace exprtk return false; } + #define exprtk_define_reserved_function(NN) \ + inline bool add_reserved_function(const std::string& function_name, ff##NN##_functor function) \ + { \ + if (!valid()) \ + { return false; } \ + if (!valid_symbol(function_name,false)) \ + { return false; } \ + if (symbol_exists(function_name,false)) \ + { return false; } \ + \ + exprtk::ifunction<T>* ifunc = new freefunc##NN(function); \ + \ + local_data().free_function_list_.push_back(ifunc); \ + \ + return add_reserved_function(function_name,(*local_data().free_function_list_.back())); \ + } \ + + exprtk_define_reserved_function(00) exprtk_define_reserved_function(01) + exprtk_define_reserved_function(02) exprtk_define_reserved_function(03) + exprtk_define_reserved_function(04) exprtk_define_reserved_function(05) + exprtk_define_reserved_function(06) exprtk_define_reserved_function(07) + exprtk_define_reserved_function(08) exprtk_define_reserved_function(09) + exprtk_define_reserved_function(10) exprtk_define_reserved_function(11) + exprtk_define_reserved_function(12) exprtk_define_reserved_function(13) + exprtk_define_reserved_function(14) exprtk_define_reserved_function(15) + + #undef exprtk_define_reserved_function + template <std::size_t N> inline bool add_vector(const std::string& vector_name, T (&v)[N]) { @@ -18087,7 +21057,7 @@ namespace exprtk return false; else if (symbol_exists(vector_name)) return false; - else if (v.empty()) + else if (0 == v.size()) return false; else return local_data().vector_store.add(vector_name,v); @@ -18101,7 +21071,7 @@ namespace exprtk return false; else if (symbol_exists(vector_name)) return false; - else if (v.empty()) + else if (0 == v.size()) return false; else return local_data().vector_store.add(vector_name,v); @@ -18225,12 +21195,48 @@ namespace exprtk template <typename Allocator, template <typename, typename> class Sequence> - inline std::size_t get_vector_list(Sequence<std::string,Allocator>& vlist) const + inline std::size_t get_vector_list(Sequence<std::string,Allocator>& vec_list) const { if (!valid()) return 0; else - return local_data().vector_store.get_list(vlist); + return local_data().vector_store.get_list(vec_list); + } + + template <typename Allocator, + template <typename, typename> class Sequence> + inline std::size_t get_function_list(Sequence<std::string,Allocator>& function_list) const + { + if (!valid()) + return 0; + + std::vector<std::string> function_names; + std::size_t count = 0; + + count += local_data().function_store .get_list(function_names); + count += local_data().vararg_function_store .get_list(function_names); + count += local_data().generic_function_store .get_list(function_names); + count += local_data().string_function_store .get_list(function_names); + count += local_data().overload_function_store.get_list(function_names); + + std::set<std::string> function_set; + + for (std::size_t i = 0; i < function_names.size(); ++i) + { + function_set.insert(function_names[i]); + } + + std::copy(function_set.begin(), function_set.end(), + std::back_inserter(function_list)); + + return count; + } + + inline std::vector<std::string> get_function_list() const + { + std::vector<std::string> result; + get_function_list(result); + return result; } inline bool symbol_exists(const std::string& symbol_name, const bool check_reserved_symb = true) const @@ -18421,6 +21427,38 @@ namespace exprtk } } + inline void load_variables_from(const symbol_table<T>& st) + { + std::vector<std::string> name_list; + + st.local_data().variable_store.get_list(name_list); + + if (!name_list.empty()) + { + for (std::size_t i = 0; i < name_list.size(); ++i) + { + T& variable = st.get_variable(name_list[i])->ref(); + add_variable(name_list[i], variable); + } + } + } + + inline void load_vectors_from(const symbol_table<T>& st) + { + std::vector<std::string> name_list; + + st.local_data().vector_store.get_list(name_list); + + if (!name_list.empty()) + { + for (std::size_t i = 0; i < name_list.size(); ++i) + { + vector_holder_t& vecholder = *st.get_vector(name_list[i]); + add_vector(name_list[i], vecholder.data(), vecholder.size()); + } + } + } + private: inline bool valid_symbol(const std::string& symbol, const bool check_reserved_symb = true) const @@ -18490,7 +21528,7 @@ namespace exprtk control_block* control_block_; friend class parser<T>; - }; + }; // class symbol_table template <typename T> class function_compositor; @@ -18501,8 +21539,8 @@ namespace exprtk private: typedef details::expression_node<T>* expression_ptr; - typedef details::vector_holder<T>* vector_holder_ptr; - typedef std::vector<symbol_table<T> > symtab_list_t; + typedef details::vector_holder<T>* vector_holder_ptr; + typedef std::vector<symbol_table<T> > symtab_list_t; struct control_block { @@ -18516,18 +21554,33 @@ namespace exprtk e_string }; + static std::string to_str(data_type dt) + { + switch(dt) + { + case e_unknown : return "e_unknown "; + case e_expr : return "e_expr" ; + case e_vecholder : return "e_vecholder"; + case e_data : return "e_data" ; + case e_vecdata : return "e_vecdata" ; + case e_string : return "e_string" ; + } + + return ""; + } + struct data_pack { data_pack() - : pointer(0), - type(e_unknown), - size(0) + : pointer(0) + , type(e_unknown) + , size(0) {} data_pack(void* ptr, const data_type dt, const std::size_t sz = 0) - : pointer(ptr), - type(dt), - size(sz) + : pointer(ptr) + , type(dt) + , size(sz) {} void* pointer; @@ -18537,21 +21590,22 @@ namespace exprtk typedef std::vector<data_pack> local_data_list_t; typedef results_context<T> results_context_t; + typedef control_block* cntrl_blck_ptr_t; control_block() - : ref_count(0), - expr (0), - results (0), - retinv_null(false), - return_invoked(&retinv_null) + : ref_count(0) + , expr (0) + , results (0) + , retinv_null(false) + , return_invoked(&retinv_null) {} explicit control_block(expression_ptr e) - : ref_count(1), - expr (e), - results (0), - retinv_null(false), - return_invoked(&retinv_null) + : ref_count(1) + , expr (e) + , results (0) + , retinv_null(false) + , return_invoked(&retinv_null) {} ~control_block() @@ -18590,12 +21644,12 @@ namespace exprtk delete results; } - static inline control_block* create(expression_ptr e) + static inline cntrl_blck_ptr_t create(expression_ptr e) { return new control_block(e); } - static inline void destroy(control_block*& cntrl_blck) + static inline void destroy(cntrl_blck_ptr_t& cntrl_blck) { if (cntrl_blck) { @@ -18630,8 +21684,8 @@ namespace exprtk } expression(const expression<T>& e) - : control_block_ (e.control_block_ ), - symbol_table_list_(e.symbol_table_list_) + : control_block_ (e.control_block_ ) + , symbol_table_list_(e.symbol_table_list_) { control_block_->ref_count++; } @@ -18683,6 +21737,7 @@ namespace exprtk inline expression<T>& release() { + exprtk::details::dump_ptr("expression::release", this); control_block::destroy(control_block_); return (*this); @@ -18716,9 +21771,18 @@ namespace exprtk return details::is_true(value()); } - inline void register_symbol_table(symbol_table<T>& st) + inline bool register_symbol_table(symbol_table<T>& st) { + for (std::size_t i = 0; i < symbol_table_list_.size(); ++i) + { + if (st == symbol_table_list_[i]) + { + return false; + } + } + symbol_table_list_.push_back(st); + return true; } inline const symbol_table<T>& get_symbol_table(const std::size_t& index = 0) const @@ -18731,6 +21795,11 @@ namespace exprtk return symbol_table_list_[index]; } + std::size_t num_symbol_tables() const + { + return symbol_table_list_.size(); + } + typedef results_context<T> results_context_t; inline const results_context_t& results() const @@ -18846,7 +21915,7 @@ namespace exprtk } } - inline void set_retinvk(bool* retinvk_ptr) + inline void set_retinvk(bool* const retinvk_ptr) { if (control_block_) { @@ -18860,70 +21929,182 @@ namespace exprtk friend class parser<T>; friend class expression_helper<T>; friend class function_compositor<T>; - }; + template <typename TT> + friend bool is_valid(const expression<TT>& expr); + }; // class expression template <typename T> class expression_helper { public: - static inline bool is_constant(const expression<T>& expr) + enum node_types + { + e_literal, + e_variable, + e_string, + e_unary, + e_binary, + e_function, + e_vararg, + e_null, + e_assert, + e_sf3ext, + e_sf4ext + }; + + static inline bool is_literal(const expression<T>& expr) { - return details::is_constant_node(expr.control_block_->expr); + return expr.control_block_ && details::is_literal_node(expr.control_block_->expr); } static inline bool is_variable(const expression<T>& expr) { - return details::is_variable_node(expr.control_block_->expr); + return expr.control_block_ && details::is_variable_node(expr.control_block_->expr); + } + + static inline bool is_string(const expression<T>& expr) + { + return expr.control_block_ && details::is_generally_string_node(expr.control_block_->expr); } static inline bool is_unary(const expression<T>& expr) { - return details::is_unary_node(expr.control_block_->expr); + return expr.control_block_ && details::is_unary_node(expr.control_block_->expr); } static inline bool is_binary(const expression<T>& expr) { - return details::is_binary_node(expr.control_block_->expr); + return expr.control_block_ && details::is_binary_node(expr.control_block_->expr); } static inline bool is_function(const expression<T>& expr) { - return details::is_function(expr.control_block_->expr); + return expr.control_block_ && details::is_function(expr.control_block_->expr); + } + + static inline bool is_vararg(const expression<T>& expr) + { + return expr.control_block_ && details::is_vararg_node(expr.control_block_->expr); } static inline bool is_null(const expression<T>& expr) { - return details::is_null_node(expr.control_block_->expr); + return expr.control_block_ && details::is_null_node(expr.control_block_->expr); + } + + static inline bool is_assert(const expression<T>& expr) + { + return expr.control_block_ && details::is_assert_node(expr.control_block_->expr); + } + + static inline bool is_sf3ext(const expression<T>& expr) + { + return expr.control_block_ && details::is_sf3ext_node(expr.control_block_->expr); + } + + static inline bool is_sf4ext(const expression<T>& expr) + { + return expr.control_block_ && details::is_sf4ext_node(expr.control_block_->expr); + } + + static inline bool is_type(const expression<T>& expr, const node_types node_type) + { + if (0 == expr.control_block_) + { + return false; + } + + switch (node_type) + { + case e_literal : return is_literal_node(expr); + case e_variable : return is_variable (expr); + case e_string : return is_string (expr); + case e_unary : return is_unary (expr); + case e_binary : return is_binary (expr); + case e_function : return is_function (expr); + case e_null : return is_null (expr); + case e_assert : return is_assert (expr); + case e_sf3ext : return is_sf3ext (expr); + case e_sf4ext : return is_sf4ext (expr); + }; + + return false; + } + + static inline bool match_type_sequence(const expression<T>& expr, const std::vector<node_types>& type_seq) + { + if ((0 == expr.control_block_) || !is_vararg(expr)) + { + return false; + } + + typedef details::vararg_node<T, exprtk::details::vararg_multi_op<T> > mo_vararg_t; + + mo_vararg_t* vnode = dynamic_cast<mo_vararg_t*>(expr.control_block_->expr); + + if ( + (0 == vnode) || + type_seq.empty() || + (vnode->size() < type_seq.size()) + ) + { + return false; + } + + for (std::size_t i = 0; i < type_seq.size(); ++i) + { + assert((*vnode)[i]); + + switch(type_seq[i]) + { + case e_literal : { if (details::is_literal_node ((*vnode)[i])) continue; } break; + case e_variable : { if (details::is_variable_node ((*vnode)[i])) continue; } break; + case e_string : { if (details::is_generally_string_node((*vnode)[i])) continue; } break; + case e_unary : { if (details::is_unary_node ((*vnode)[i])) continue; } break; + case e_binary : { if (details::is_binary_node ((*vnode)[i])) continue; } break; + case e_function : { if (details::is_function ((*vnode)[i])) continue; } break; + case e_null : { if (details::is_null_node ((*vnode)[i])) continue; } break; + case e_assert : { if (details::is_assert_node ((*vnode)[i])) continue; } break; + case e_sf3ext : { if (details::is_sf3ext_node ((*vnode)[i])) continue; } break; + case e_sf4ext : { if (details::is_sf4ext_node ((*vnode)[i])) continue; } break; + case e_vararg : break; + } + + return false; + } + + return true; } }; template <typename T> inline bool is_valid(const expression<T>& expr) { - return !expression_helper<T>::is_null(expr); + return expr.control_block_ && !expression_helper<T>::is_null(expr); } namespace parser_error { enum error_mode { - e_unknown = 0, - e_syntax = 1, - e_token = 2, - e_numeric = 4, - e_symtab = 5, - e_lexer = 6, - e_helper = 7, - e_parser = 8 + e_unknown = 0, + e_syntax = 1, + e_token = 2, + e_numeric = 4, + e_symtab = 5, + e_lexer = 6, + e_synthesis = 7, + e_helper = 8, + e_parser = 9 }; struct type { type() - : mode(parser_error::e_unknown), - line_no (0), - column_no(0) + : mode(parser_error::e_unknown) + , line_no (0) + , column_no(0) {} lexer::token token; @@ -18944,7 +22125,7 @@ namespace exprtk t.token.type = lexer::token::e_error; t.diagnostic = diagnostic; t.src_location = src_location; - exprtk_debug(("%s\n",diagnostic .c_str())); + exprtk_debug(("%s\n", diagnostic .c_str())); return t; } @@ -18954,11 +22135,11 @@ namespace exprtk const std::string& src_location = "") { type t; - t.mode = mode; - t.token = tk; - t.diagnostic = diagnostic; + t.mode = mode; + t.token = tk; + t.diagnostic = diagnostic; t.src_location = src_location; - exprtk_debug(("%s\n",diagnostic .c_str())); + exprtk_debug(("%s\n", diagnostic .c_str())); return t; } @@ -19045,92 +22226,96 @@ namespace exprtk enum precedence_level { - e_level00, - e_level01, - e_level02, - e_level03, - e_level04, - e_level05, - e_level06, - e_level07, - e_level08, - e_level09, - e_level10, - e_level11, - e_level12, - e_level13, - e_level14 - }; - - typedef const T& cref_t; - typedef const T const_t; - typedef ifunction <T> F; - typedef ivararg_function <T> VAF; - typedef igeneric_function <T> GF; - typedef ifunction <T> ifunction_t; - typedef ivararg_function <T> ivararg_function_t; - typedef igeneric_function <T> igeneric_function_t; - typedef details::expression_node <T> expression_node_t; - typedef details::literal_node <T> literal_node_t; - typedef details::unary_node <T> unary_node_t; - typedef details::binary_node <T> binary_node_t; - typedef details::trinary_node <T> trinary_node_t; - typedef details::quaternary_node <T> quaternary_node_t; - typedef details::conditional_node<T> conditional_node_t; - typedef details::cons_conditional_node<T> cons_conditional_node_t; - typedef details::while_loop_node <T> while_loop_node_t; - typedef details::repeat_until_loop_node<T> repeat_until_loop_node_t; - typedef details::for_loop_node <T> for_loop_node_t; + e_level00, e_level01, e_level02, e_level03, e_level04, + e_level05, e_level06, e_level07, e_level08, e_level09, + e_level10, e_level11, e_level12, e_level13, e_level14 + }; + + typedef const T& cref_t; + typedef const T const_t; + typedef ifunction<T> F; + typedef ivararg_function<T> VAF; + typedef igeneric_function<T> GF; + typedef ifunction<T> ifunction_t; + typedef ivararg_function<T> ivararg_function_t; + typedef igeneric_function<T> igeneric_function_t; + typedef details::expression_node<T> expression_node_t; + typedef details::literal_node<T> literal_node_t; + typedef details::unary_node<T> unary_node_t; + typedef details::binary_node<T> binary_node_t; + typedef details::trinary_node<T> trinary_node_t; + typedef details::quaternary_node<T> quaternary_node_t; + typedef details::conditional_node<T> conditional_node_t; + typedef details::cons_conditional_node<T> cons_conditional_node_t; + typedef details::while_loop_node<T> while_loop_node_t; + typedef details::repeat_until_loop_node<T> repeat_until_loop_node_t; + typedef details::for_loop_node<T> for_loop_node_t; + typedef details::while_loop_rtc_node<T> while_loop_rtc_node_t; + typedef details::repeat_until_loop_rtc_node<T> repeat_until_loop_rtc_node_t; + typedef details::for_loop_rtc_node<T> for_loop_rtc_node_t; #ifndef exprtk_disable_break_continue - typedef details::while_loop_bc_node <T> while_loop_bc_node_t; - typedef details::repeat_until_loop_bc_node<T> repeat_until_loop_bc_node_t; - typedef details::for_loop_bc_node<T> for_loop_bc_node_t; + typedef details::while_loop_bc_node<T> while_loop_bc_node_t; + typedef details::repeat_until_loop_bc_node<T> repeat_until_loop_bc_node_t; + typedef details::for_loop_bc_node<T> for_loop_bc_node_t; + typedef details::while_loop_bc_rtc_node<T> while_loop_bc_rtc_node_t; + typedef details::repeat_until_loop_bc_rtc_node<T> repeat_until_loop_bc_rtc_node_t; + typedef details::for_loop_bc_rtc_node<T> for_loop_bc_rtc_node_t; #endif - typedef details::switch_node <T> switch_node_t; - typedef details::variable_node <T> variable_node_t; - typedef details::vector_elem_node<T> vector_elem_node_t; - typedef details::rebasevector_elem_node<T> rebasevector_elem_node_t; - typedef details::rebasevector_celem_node<T> rebasevector_celem_node_t; - typedef details::vector_node <T> vector_node_t; - typedef details::range_pack <T> range_t; + typedef details::switch_node<T> switch_node_t; + typedef details::variable_node<T> variable_node_t; + typedef details::vector_elem_node<T> vector_elem_node_t; + typedef details::vector_celem_node<T> vector_celem_node_t; + typedef details::vector_elem_rtc_node<T> vector_elem_rtc_node_t; + typedef details::vector_celem_rtc_node<T> vector_celem_rtc_node_t; + typedef details::rebasevector_elem_node<T> rebasevector_elem_node_t; + typedef details::rebasevector_celem_node<T> rebasevector_celem_node_t; + typedef details::rebasevector_elem_rtc_node<T> rebasevector_elem_rtc_node_t; + typedef details::rebasevector_celem_rtc_node<T> rebasevector_celem_rtc_node_t; + typedef details::vector_node<T> vector_node_t; + typedef details::vector_size_node<T> vector_size_node_t; + typedef details::range_pack<T> range_t; #ifndef exprtk_disable_string_capabilities - typedef details::stringvar_node <T> stringvar_node_t; - typedef details::string_literal_node<T> string_literal_node_t; - typedef details::string_range_node <T> string_range_node_t; - typedef details::const_string_range_node<T> const_string_range_node_t; - typedef details::generic_string_range_node<T> generic_string_range_node_t; - typedef details::string_concat_node <T> string_concat_node_t; - typedef details::assignment_string_node<T> assignment_string_node_t; - typedef details::assignment_string_range_node<T> assignment_string_range_node_t; - typedef details::conditional_string_node<T> conditional_string_node_t; - typedef details::cons_conditional_str_node<T> cons_conditional_str_node_t; + typedef details::stringvar_node<T> stringvar_node_t; + typedef details::string_literal_node<T> string_literal_node_t; + typedef details::string_range_node<T> string_range_node_t; + typedef details::const_string_range_node<T> const_string_range_node_t; + typedef details::generic_string_range_node<T> generic_string_range_node_t; + typedef details::string_concat_node<T> string_concat_node_t; + typedef details::assignment_string_node<T> assignment_string_node_t; + typedef details::assignment_string_range_node<T> assignment_string_range_node_t; + typedef details::conditional_string_node<T> conditional_string_node_t; + typedef details::cons_conditional_str_node<T> cons_conditional_str_node_t; #endif - typedef details::assignment_node<T> assignment_node_t; - typedef details::assignment_vec_elem_node <T> assignment_vec_elem_node_t; - typedef details::assignment_rebasevec_elem_node <T> assignment_rebasevec_elem_node_t; - typedef details::assignment_rebasevec_celem_node<T> assignment_rebasevec_celem_node_t; - typedef details::assignment_vec_node <T> assignment_vec_node_t; - typedef details::assignment_vecvec_node <T> assignment_vecvec_node_t; - typedef details::scand_node<T> scand_node_t; - typedef details::scor_node<T> scor_node_t; - typedef lexer::token token_t; - typedef expression_node_t* expression_node_ptr; - typedef expression<T> expression_t; + typedef details::assignment_node<T> assignment_node_t; + typedef details::assignment_vec_elem_node<T> assignment_vec_elem_node_t; + typedef details::assignment_vec_elem_rtc_node<T> assignment_vec_elem_rtc_node_t; + typedef details::assignment_rebasevec_elem_node<T> assignment_rebasevec_elem_node_t; + typedef details::assignment_rebasevec_elem_rtc_node<T> assignment_rebasevec_elem_rtc_node_t; + typedef details::assignment_rebasevec_celem_node<T> assignment_rebasevec_celem_node_t; + typedef details::assignment_vec_node<T> assignment_vec_node_t; + typedef details::assignment_vecvec_node<T> assignment_vecvec_node_t; + typedef details::conditional_vector_node<T> conditional_vector_node_t; + typedef details::scand_node<T> scand_node_t; + typedef details::scor_node<T> scor_node_t; + typedef lexer::token token_t; + typedef expression_node_t* expression_node_ptr; + typedef expression<T> expression_t; typedef symbol_table<T> symbol_table_t; - typedef typename expression<T>::symtab_list_t symbol_table_list_t; - typedef details::vector_holder<T>* vector_holder_ptr; + typedef typename expression<T>::symtab_list_t symbol_table_list_t; + typedef details::vector_holder<T> vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; - typedef typename details::functor_t<T> functor_t; + typedef typename details::functor_t<T> functor_t; typedef typename functor_t::qfunc_t quaternary_functor_t; - typedef typename functor_t::tfunc_t trinary_functor_t; - typedef typename functor_t::bfunc_t binary_functor_t; - typedef typename functor_t::ufunc_t unary_functor_t; + typedef typename functor_t::tfunc_t trinary_functor_t; + typedef typename functor_t::bfunc_t binary_functor_t; + typedef typename functor_t::ufunc_t unary_functor_t; typedef details::operator_type operator_t; - typedef std::map<operator_t, unary_functor_t> unary_op_map_t; - typedef std::map<operator_t, binary_functor_t> binary_op_map_t; - typedef std::map<operator_t,trinary_functor_t> trinary_op_map_t; + typedef std::map<operator_t, unary_functor_t > unary_op_map_t; + typedef std::map<operator_t, binary_functor_t > binary_op_map_t; + typedef std::map<operator_t, trinary_functor_t> trinary_op_map_t; typedef std::map<std::string,std::pair<trinary_functor_t ,operator_t> > sf3_map_t; typedef std::map<std::string,std::pair<quaternary_functor_t,operator_t> > sf4_map_t; @@ -19139,28 +22324,28 @@ namespace exprtk typedef std::multimap<std::string,details::base_operation_t,details::ilesscompare> base_ops_map_t; typedef std::set<std::string,details::ilesscompare> disabled_func_set_t; - typedef details::T0oT1_define<T, cref_t, cref_t> vov_t; - typedef details::T0oT1_define<T, const_t, cref_t> cov_t; - typedef details::T0oT1_define<T, cref_t, const_t> voc_t; - - typedef details::T0oT1oT2_define<T, cref_t, cref_t, cref_t> vovov_t; - typedef details::T0oT1oT2_define<T, cref_t, cref_t, const_t> vovoc_t; - typedef details::T0oT1oT2_define<T, cref_t, const_t, cref_t> vocov_t; - typedef details::T0oT1oT2_define<T, const_t, cref_t, cref_t> covov_t; - typedef details::T0oT1oT2_define<T, const_t, cref_t, const_t> covoc_t; - typedef details::T0oT1oT2_define<T, const_t, const_t, cref_t> cocov_t; - typedef details::T0oT1oT2_define<T, cref_t, const_t, const_t> vococ_t; - - typedef details::T0oT1oT2oT3_define<T, cref_t, cref_t, cref_t, cref_t> vovovov_t; - typedef details::T0oT1oT2oT3_define<T, cref_t, cref_t, cref_t, const_t> vovovoc_t; - typedef details::T0oT1oT2oT3_define<T, cref_t, cref_t, const_t, cref_t> vovocov_t; - typedef details::T0oT1oT2oT3_define<T, cref_t, const_t, cref_t, cref_t> vocovov_t; - typedef details::T0oT1oT2oT3_define<T, const_t, cref_t, cref_t, cref_t> covovov_t; - - typedef details::T0oT1oT2oT3_define<T, const_t, cref_t, const_t, cref_t> covocov_t; - typedef details::T0oT1oT2oT3_define<T, cref_t, const_t, cref_t, const_t> vocovoc_t; - typedef details::T0oT1oT2oT3_define<T, const_t, cref_t, cref_t, const_t> covovoc_t; - typedef details::T0oT1oT2oT3_define<T, cref_t, const_t, const_t, cref_t> vococov_t; + typedef details::T0oT1_define<T, cref_t , cref_t > vov_t; + typedef details::T0oT1_define<T, const_t, cref_t > cov_t; + typedef details::T0oT1_define<T, cref_t , const_t> voc_t; + + typedef details::T0oT1oT2_define<T, cref_t , cref_t , cref_t > vovov_t; + typedef details::T0oT1oT2_define<T, cref_t , cref_t , const_t> vovoc_t; + typedef details::T0oT1oT2_define<T, cref_t , const_t, cref_t > vocov_t; + typedef details::T0oT1oT2_define<T, const_t, cref_t , cref_t > covov_t; + typedef details::T0oT1oT2_define<T, const_t, cref_t , const_t> covoc_t; + typedef details::T0oT1oT2_define<T, const_t, const_t, cref_t > cocov_t; + typedef details::T0oT1oT2_define<T, cref_t , const_t, const_t> vococ_t; + + typedef details::T0oT1oT2oT3_define<T, cref_t , cref_t , cref_t , cref_t > vovovov_t; + typedef details::T0oT1oT2oT3_define<T, cref_t , cref_t , cref_t , const_t> vovovoc_t; + typedef details::T0oT1oT2oT3_define<T, cref_t , cref_t , const_t, cref_t > vovocov_t; + typedef details::T0oT1oT2oT3_define<T, cref_t , const_t, cref_t , cref_t > vocovov_t; + typedef details::T0oT1oT2oT3_define<T, const_t, cref_t , cref_t , cref_t > covovov_t; + + typedef details::T0oT1oT2oT3_define<T, const_t, cref_t , const_t, cref_t > covocov_t; + typedef details::T0oT1oT2oT3_define<T, cref_t , const_t, cref_t , const_t> vocovoc_t; + typedef details::T0oT1oT2oT3_define<T, const_t, cref_t , cref_t , const_t> covovoc_t; + typedef details::T0oT1oT2oT3_define<T, cref_t , const_t, const_t, cref_t > vococov_t; typedef results_context<T> results_context_t; @@ -19171,6 +22356,7 @@ namespace exprtk enum element_type { e_none , + e_literal , e_variable, e_vector , e_vecelem , @@ -19178,28 +22364,29 @@ namespace exprtk }; typedef details::vector_holder<T> vector_holder_t; - typedef variable_node_t* variable_node_ptr; - typedef vector_holder_t* vector_holder_ptr; - typedef expression_node_t* expression_node_ptr; + typedef literal_node_t* literal_node_ptr; + typedef variable_node_t* variable_node_ptr; + typedef vector_holder_t* vector_holder_ptr; + typedef expression_node_t* expression_node_ptr; #ifndef exprtk_disable_string_capabilities - typedef stringvar_node_t* stringvar_node_ptr; + typedef stringvar_node_t* stringvar_node_ptr; #endif scope_element() - : name("???"), - size (std::numeric_limits<std::size_t>::max()), - index(std::numeric_limits<std::size_t>::max()), - depth(std::numeric_limits<std::size_t>::max()), - ref_count(0), - ip_index (0), - type (e_none), - active(false), - data (0), - var_node(0), - vec_node(0) - #ifndef exprtk_disable_string_capabilities - ,str_node(0) - #endif + : name("???") + , size (std::numeric_limits<std::size_t>::max()) + , index(std::numeric_limits<std::size_t>::max()) + , depth(std::numeric_limits<std::size_t>::max()) + , ref_count(0) + , ip_index (0) + , type (e_none) + , active (false) + , data (0) + , var_node (0) + , vec_node (0) + #ifndef exprtk_disable_string_capabilities + , str_node(0) + #endif {} bool operator < (const scope_element& se) const @@ -19259,12 +22446,12 @@ namespace exprtk public: typedef expression_node_t* expression_node_ptr; - typedef variable_node_t* variable_node_ptr; - typedef parser<T> parser_t; + typedef variable_node_t* variable_node_ptr; + typedef parser<T> parser_t; explicit scope_element_manager(parser<T>& p) - : parser_(p), - input_param_cnt_(0) + : parser_(p) + , input_param_cnt_(0) {} inline std::size_t size() const @@ -19377,6 +22564,10 @@ namespace exprtk switch (se.type) { + case scope_element::e_literal : delete reinterpret_cast<T*>(se.data); + delete se.var_node; + break; + case scope_element::e_variable : delete reinterpret_cast<T*>(se.data); delete se.var_node; break; @@ -19441,9 +22632,29 @@ namespace exprtk return expression_node_ptr(0); } + inline std::string get_vector_name(const T* data) + { + for (std::size_t i = 0; i < element_.size(); ++i) + { + scope_element& se = element_[i]; + + if ( + se.active && + se.vec_node && + (se.vec_node->data() == data) + ) + { + return se.name; + } + } + + return "neo-vector"; + } + private: - scope_element_manager& operator=(const scope_element_manager&); + scope_element_manager(const scope_element_manager&) exprtk_delete; + scope_element_manager& operator=(const scope_element_manager&) exprtk_delete; parser_t& parser_; std::vector<scope_element> element_; @@ -19483,11 +22694,136 @@ namespace exprtk private: - scope_handler& operator=(const scope_handler&); + scope_handler(const scope_handler&) exprtk_delete; + scope_handler& operator=(const scope_handler&) exprtk_delete; parser_t& parser_; }; + template <typename T_> + struct halfopen_range_policy + { + static inline bool is_within(const T_& v, const T_& begin, const T_& end) + { + assert(begin <= end); + return (begin <= v) && (v < end); + } + + static inline bool is_less(const T_& v, const T_& begin) + { + return (v < begin); + } + + static inline bool is_greater(const T_& v, const T_& end) + { + return (end <= v); + } + + static inline bool end_inclusive() + { + return false; + } + }; + + template <typename T_> + struct closed_range_policy + { + static inline bool is_within(const T_& v, const T_& begin, const T_& end) + { + assert(begin <= end); + return (begin <= v) && (v <= end); + } + + static inline bool is_less(const T_& v, const T_& begin) + { + return (v < begin); + } + + static inline bool is_greater(const T_& v, const T_& end) + { + return (end < v); + } + + static inline bool end_inclusive() + { + return true; + } + }; + + template <typename IntervalPointType, + typename RangePolicy = halfopen_range_policy<IntervalPointType> > + class interval_container_t + { + public: + + typedef IntervalPointType interval_point_t; + typedef std::pair<interval_point_t, interval_point_t> interval_t; + typedef std::map<interval_point_t, interval_t> interval_map_t; + typedef typename interval_map_t::const_iterator interval_map_citr_t; + + std::size_t size() const + { + return interval_map_.size(); + } + + void reset() + { + interval_map_.clear(); + } + + bool in_interval(const interval_point_t point, interval_t& interval) const + { + interval_map_citr_t itr = RangePolicy::end_inclusive() ? + interval_map_.lower_bound(point): + interval_map_.upper_bound(point); + + for (; itr != interval_map_.end(); ++itr) + { + const interval_point_t& begin = itr->second.first; + const interval_point_t& end = itr->second.second; + + if (RangePolicy::is_within(point, begin, end)) + { + interval = interval_t(begin,end); + return true; + } + else if (RangePolicy::is_greater(point, end)) + { + break; + } + } + + return false; + } + + bool in_interval(const interval_point_t point) const + { + interval_t interval; + return in_interval(point,interval); + } + + bool add_interval(const interval_point_t begin, const interval_point_t end) + { + if ((end <= begin) || in_interval(begin) || in_interval(end)) + { + return false; + } + + interval_map_[end] = std::make_pair(begin, end); + + return true; + } + + bool add_interval(const interval_t interval) + { + return add_interval(interval.first, interval.second); + } + + private: + + interval_map_t interval_map_; + }; + class stack_limit_handler { public: @@ -19495,22 +22831,23 @@ namespace exprtk typedef parser<T> parser_t; explicit stack_limit_handler(parser<T>& p) - : parser_(p), - limit_exceeded_(false) + : parser_(p) + , limit_exceeded_(false) { if (++parser_.state_.stack_depth > parser_.settings_.max_stack_depth_) { limit_exceeded_ = true; - parser_.set_error( - make_error(parser_error::e_parser, - "ERR000 - Current stack depth " + details::to_str(parser_.state_.stack_depth) + - " exceeds maximum allowed stack depth of " + details::to_str(parser_.settings_.max_stack_depth_), - exprtk_error_location)); + parser_.set_error(make_error( + parser_error::e_parser, + "ERR000 - Current stack depth " + details::to_str(parser_.state_.stack_depth) + + " exceeds maximum allowed stack depth of " + details::to_str(parser_.settings_.max_stack_depth_), + exprtk_error_location)); } } ~stack_limit_handler() { + assert(parser_.state_.stack_depth > 0); parser_.state_.stack_depth--; } @@ -19521,7 +22858,8 @@ namespace exprtk private: - stack_limit_handler& operator=(const stack_limit_handler&); + stack_limit_handler(const stack_limit_handler&) exprtk_delete; + stack_limit_handler& operator=(const stack_limit_handler&) exprtk_delete; parser_t& parser_; bool limit_exceeded_; @@ -19531,16 +22869,51 @@ namespace exprtk { symbol_table_list_t symtab_list_; - typedef typename symbol_table_t::local_data_t local_data_t; - typedef typename symbol_table_t::variable_ptr variable_ptr; - typedef typename symbol_table_t::function_ptr function_ptr; + typedef typename symbol_table_t::local_data_t local_data_t; + typedef typename symbol_table_t::variable_ptr variable_ptr; + typedef typename symbol_table_t::function_ptr function_ptr; #ifndef exprtk_disable_string_capabilities typedef typename symbol_table_t::stringvar_ptr stringvar_ptr; #endif - typedef typename symbol_table_t::vector_holder_ptr vector_holder_ptr; - typedef typename symbol_table_t::vararg_function_ptr vararg_function_ptr; + typedef typename symbol_table_t::vector_holder_ptr vector_holder_ptr; + typedef typename symbol_table_t::vararg_function_ptr vararg_function_ptr; typedef typename symbol_table_t::generic_function_ptr generic_function_ptr; + struct variable_context + { + variable_context() + : symbol_table(0) + , variable(0) + {} + + const symbol_table_t* symbol_table; + variable_ptr variable; + }; + + struct vector_context + { + vector_context() + : symbol_table(0) + , vector_holder(0) + {} + + const symbol_table_t* symbol_table; + vector_holder_ptr vector_holder; + }; + + #ifndef exprtk_disable_string_capabilities + struct string_context + { + string_context() + : symbol_table(0) + , str_var(0) + {} + + const symbol_table_t* symbol_table; + stringvar_ptr str_var; + }; + #endif + inline bool empty() const { return symtab_list_.empty(); @@ -19581,6 +22954,32 @@ namespace exprtk return false; } + inline variable_context get_variable_context(const std::string& variable_name) const + { + variable_context result; + + if (valid_symbol(variable_name)) + { + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + { + continue; + } + + result.variable = local_data(i) + .variable_store.get(variable_name); + if (result.variable) + { + result.symbol_table = &symtab_list_[i]; + break; + } + } + } + + return result; + } + inline variable_ptr get_variable(const std::string& variable_name) const { if (!valid_symbol(variable_name)) @@ -19621,6 +23020,32 @@ namespace exprtk } #ifndef exprtk_disable_string_capabilities + inline string_context get_string_context(const std::string& string_name) const + { + string_context result; + + if (!valid_symbol(string_name)) + return result; + + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + { + continue; + } + + result.str_var = local_data(i).stringvar_store.get(string_name); + + if (result.str_var) + { + result.symbol_table = &symtab_list_[i]; + break; + } + } + + return result; + } + inline stringvar_ptr get_stringvar(const std::string& string_name) const { if (!valid_symbol(string_name)) @@ -19748,6 +23173,31 @@ namespace exprtk return result; } + inline vector_context get_vector_context(const std::string& vector_name) const + { + vector_context result; + if (!valid_symbol(vector_name)) + return result; + + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + { + continue; + } + + result.vector_holder = local_data(i).vector_store.get(vector_name); + + if (result.vector_holder) + { + result.symbol_table = &symtab_list_[i]; + break; + } + } + + return result; + } + inline vector_holder_ptr get_vector(const std::string& vector_name) const { if (!valid_symbol(vector_name)) @@ -19758,12 +23208,16 @@ namespace exprtk for (std::size_t i = 0; i < symtab_list_.size(); ++i) { if (!symtab_list_[i].valid()) + { continue; - else - result = - local_data(i).vector_store.get(vector_name); + } - if (result) break; + result = local_data(i).vector_store.get(vector_name); + + if (result) + { + break; + } } return result; @@ -19777,9 +23231,14 @@ namespace exprtk for (std::size_t i = 0; i < symtab_list_.size(); ++i) { if (!symtab_list_[i].valid()) + { continue; - else if (local_data(i).variable_store.is_constant(symbol_name)) + } + + if (local_data(i).variable_store.is_constant(symbol_name)) + { return true; + } } return false; @@ -19797,7 +23256,7 @@ namespace exprtk continue; else if (!local_data(i).stringvar_store.symbol_exists(symbol_name)) continue; - else if ( local_data(i).stringvar_store.is_constant(symbol_name)) + else if (local_data(i).stringvar_store.is_constant(symbol_name)) return true; } @@ -19810,9 +23269,14 @@ namespace exprtk for (std::size_t i = 0; i < symtab_list_.size(); ++i) { if (!symtab_list_[i].valid()) + { continue; - else if (symtab_list_[i].symbol_exists(symbol)) + } + + if (symtab_list_[i].symbol_exists(symbol)) + { return true; + } } return false; @@ -19972,6 +23436,7 @@ namespace exprtk { parsing_return_stmt = false; parsing_break_stmt = false; + parsing_assert_stmt = false; return_stmt_present = false; side_effect_present = false; scope_depth = 0; @@ -19989,12 +23454,13 @@ namespace exprtk { side_effect_present = true; - exprtk_debug(("activate_side_effect() - caller: %s\n",source.c_str())); + exprtk_debug(("activate_side_effect() - caller: %s\n", source.c_str())); } } bool parsing_return_stmt; bool parsing_break_stmt; + bool parsing_assert_stmt; bool return_stmt_present; bool side_effect_present; bool type_check_enabled; @@ -20027,7 +23493,7 @@ namespace exprtk : mode(m) {} - virtual ~unknown_symbol_resolver() = default; + virtual ~unknown_symbol_resolver() exprtk_default; virtual bool process(const std::string& /*unknown_symbol*/, usr_symbol_type& st, @@ -20081,12 +23547,12 @@ namespace exprtk typedef std::vector<symbol_t> symbol_list_t; dependent_entity_collector(const std::size_t options = e_ct_none) - : options_(options), - collect_variables_ ((options_ & e_ct_variables ) == e_ct_variables ), - collect_functions_ ((options_ & e_ct_functions ) == e_ct_functions ), - collect_assignments_((options_ & e_ct_assignments) == e_ct_assignments), - return_present_ (false), - final_stmt_return_(false) + : options_(options) + , collect_variables_ ((options_ & e_ct_variables ) == e_ct_variables ) + , collect_functions_ ((options_ & e_ct_functions ) == e_ct_functions ) + , collect_assignments_((options_ & e_ct_assignments) == e_ct_assignments) + , return_present_ (false) + , final_stmt_return_(false) {} template <typename Allocator, @@ -20103,11 +23569,14 @@ namespace exprtk details::case_normalise(symbol_name_list_[i].first); } - std::sort(symbol_name_list_.begin(),symbol_name_list_.end()); + std::sort(symbol_name_list_.begin(), symbol_name_list_.end()); - std::unique_copy(symbol_name_list_.begin(), - symbol_name_list_.end (), - std::back_inserter(symbols_list)); + std::unique_copy + ( + symbol_name_list_.begin(), + symbol_name_list_.end (), + std::back_inserter(symbols_list) + ); return symbols_list.size(); } @@ -20128,9 +23597,12 @@ namespace exprtk std::sort(assignment_name_list_.begin(),assignment_name_list_.end()); - std::unique_copy(assignment_name_list_.begin(), - assignment_name_list_.end (), - std::back_inserter(assignment_list)); + std::unique_copy + ( + assignment_name_list_.begin(), + assignment_name_list_.end (), + std::back_inserter(assignment_list) + ); return assignment_list.size(); } @@ -20259,20 +23731,20 @@ namespace exprtk enum settings_base_funcs { e_bf_unknown = 0, - e_bf_abs , e_bf_acos , e_bf_acosh , e_bf_asin , - e_bf_asinh , e_bf_atan , e_bf_atan2 , e_bf_atanh , - e_bf_avg , e_bf_ceil , e_bf_clamp , e_bf_cos , - e_bf_cosh , e_bf_cot , e_bf_csc , e_bf_equal , - e_bf_erf , e_bf_erfc , e_bf_exp , e_bf_expm1 , - e_bf_floor , e_bf_frac , e_bf_hypot , e_bf_iclamp , - e_bf_like , e_bf_log , e_bf_log10 , e_bf_log1p , - e_bf_log2 , e_bf_logn , e_bf_mand , e_bf_max , - e_bf_min , e_bf_mod , e_bf_mor , e_bf_mul , - e_bf_ncdf , e_bf_pow , e_bf_root , e_bf_round , - e_bf_roundn , e_bf_sec , e_bf_sgn , e_bf_sin , - e_bf_sinc , e_bf_sinh , e_bf_sqrt , e_bf_sum , - e_bf_swap , e_bf_tan , e_bf_tanh , e_bf_trunc , - e_bf_not_equal , e_bf_inrange , e_bf_deg2grad , e_bf_deg2rad, + e_bf_abs , e_bf_acos , e_bf_acosh , e_bf_asin , + e_bf_asinh , e_bf_atan , e_bf_atan2 , e_bf_atanh , + e_bf_avg , e_bf_ceil , e_bf_clamp , e_bf_cos , + e_bf_cosh , e_bf_cot , e_bf_csc , e_bf_equal , + e_bf_erf , e_bf_erfc , e_bf_exp , e_bf_expm1 , + e_bf_floor , e_bf_frac , e_bf_hypot , e_bf_iclamp , + e_bf_like , e_bf_log , e_bf_log10 , e_bf_log1p , + e_bf_log2 , e_bf_logn , e_bf_mand , e_bf_max , + e_bf_min , e_bf_mod , e_bf_mor , e_bf_mul , + e_bf_ncdf , e_bf_pow , e_bf_root , e_bf_round , + e_bf_roundn , e_bf_sec , e_bf_sgn , e_bf_sin , + e_bf_sinc , e_bf_sinh , e_bf_sqrt , e_bf_sum , + e_bf_swap , e_bf_tan , e_bf_tanh , e_bf_trunc , + e_bf_not_equal , e_bf_inrange , e_bf_deg2grad , e_bf_deg2rad , e_bf_rad2deg , e_bf_grad2deg }; @@ -20290,8 +23762,8 @@ namespace exprtk enum settings_logic_opr { e_logic_unknown = 0, - e_logic_and, e_logic_nand, e_logic_nor, - e_logic_not, e_logic_or, e_logic_xnor, + e_logic_and, e_logic_nand , e_logic_nor , + e_logic_not, e_logic_or , e_logic_xnor, e_logic_xor, e_logic_scand, e_logic_scor }; @@ -20312,22 +23784,24 @@ namespace exprtk enum settings_inequality_opr { e_ineq_unknown = 0, - e_ineq_lt, e_ineq_lte, e_ineq_eq, - e_ineq_equal, e_ineq_ne, e_ineq_nequal, - e_ineq_gte, e_ineq_gt + e_ineq_lt , e_ineq_lte, e_ineq_eq , + e_ineq_equal, e_ineq_ne , e_ineq_nequal, + e_ineq_gte , e_ineq_gt }; - static const std::size_t compile_all_opts = e_replacer + - e_joiner + - e_numeric_check + - e_bracket_check + - e_sequence_check + - e_commutative_check + - e_strength_reduction; + static const std::size_t default_compile_all_opts = + e_replacer + + e_joiner + + e_numeric_check + + e_bracket_check + + e_sequence_check + + e_commutative_check + + e_strength_reduction; - settings_store(const std::size_t compile_options = compile_all_opts) - : max_stack_depth_(400), - max_node_depth_(10000) + settings_store(const std::size_t compile_options = default_compile_all_opts) + : max_stack_depth_(400) + , max_node_depth_(10000) + , max_local_vector_size_(2000000000) { load_compile_options(compile_options); } @@ -20374,12 +23848,24 @@ namespace exprtk return (*this); } + settings_store& enable_commutative_check() + { + enable_commutative_check_ = true; + return (*this); + } + + settings_store& enable_strength_reduction() + { + enable_strength_reduction_ = true; + return (*this); + } + settings_store& disable_all_base_functions() { std::copy(details::base_function_list, details::base_function_list + details::base_function_list_size, std::insert_iterator<disabled_entity_set_t> - (disabled_func_set_, disabled_func_set_.begin())); + (disabled_func_set_, disabled_func_set_.begin())); return (*this); } @@ -20388,7 +23874,7 @@ namespace exprtk std::copy(details::cntrl_struct_list, details::cntrl_struct_list + details::cntrl_struct_list_size, std::insert_iterator<disabled_entity_set_t> - (disabled_ctrl_set_, disabled_ctrl_set_.begin())); + (disabled_ctrl_set_, disabled_ctrl_set_.begin())); return (*this); } @@ -20406,7 +23892,7 @@ namespace exprtk std::copy(details::arithmetic_ops_list, details::arithmetic_ops_list + details::arithmetic_ops_list_size, std::insert_iterator<disabled_entity_set_t> - (disabled_arithmetic_set_, disabled_arithmetic_set_.begin())); + (disabled_arithmetic_set_, disabled_arithmetic_set_.begin())); return (*this); } @@ -20415,7 +23901,7 @@ namespace exprtk std::copy(details::assignment_ops_list, details::assignment_ops_list + details::assignment_ops_list_size, std::insert_iterator<disabled_entity_set_t> - (disabled_assignment_set_, disabled_assignment_set_.begin())); + (disabled_assignment_set_, disabled_assignment_set_.begin())); return (*this); } @@ -20424,7 +23910,7 @@ namespace exprtk std::copy(details::inequality_ops_list, details::inequality_ops_list + details::inequality_ops_list_size, std::insert_iterator<disabled_entity_set_t> - (disabled_inequality_set_, disabled_inequality_set_.begin())); + (disabled_inequality_set_, disabled_inequality_set_.begin())); return (*this); } @@ -20434,6 +23920,18 @@ namespace exprtk return (*this); } + settings_store& disable_commutative_check() + { + enable_commutative_check_ = false; + return (*this); + } + + settings_store& disable_strength_reduction() + { + enable_strength_reduction_ = false; + return (*this); + } + bool replacer_enabled () const { return enable_replacer_; } bool commutative_check_enabled () const { return enable_commutative_check_; } bool joiner_enabled () const { return enable_joiner_; } @@ -20559,7 +24057,7 @@ namespace exprtk .find(inequality_opr_to_string(inequality)); } - settings_store& disable_base_function(settings_base_funcs bf) + settings_store& disable_base_function(const settings_base_funcs bf) { if ( (e_bf_unknown != bf) && @@ -20572,7 +24070,7 @@ namespace exprtk return (*this); } - settings_store& disable_control_structure(settings_control_structs ctrl_struct) + settings_store& disable_control_structure(const settings_control_structs ctrl_struct) { if ( (e_ctrl_unknown != ctrl_struct) && @@ -20585,7 +24083,7 @@ namespace exprtk return (*this); } - settings_store& disable_logic_operation(settings_logic_opr logic) + settings_store& disable_logic_operation(const settings_logic_opr logic) { if ( (e_logic_unknown != logic) && @@ -20598,7 +24096,7 @@ namespace exprtk return (*this); } - settings_store& disable_arithmetic_operation(settings_arithmetic_opr arithmetic) + settings_store& disable_arithmetic_operation(const settings_arithmetic_opr arithmetic) { if ( (e_arith_unknown != arithmetic) && @@ -20611,7 +24109,7 @@ namespace exprtk return (*this); } - settings_store& disable_assignment_operation(settings_assignment_opr assignment) + settings_store& disable_assignment_operation(const settings_assignment_opr assignment) { if ( (e_assign_unknown != assignment) && @@ -20624,7 +24122,7 @@ namespace exprtk return (*this); } - settings_store& disable_inequality_operation(settings_inequality_opr inequality) + settings_store& disable_inequality_operation(const settings_inequality_opr inequality) { if ( (e_ineq_unknown != inequality) && @@ -20637,7 +24135,7 @@ namespace exprtk return (*this); } - settings_store& enable_base_function(settings_base_funcs bf) + settings_store& enable_base_function(const settings_base_funcs bf) { if ( (e_bf_unknown != bf) && @@ -20655,7 +24153,7 @@ namespace exprtk return (*this); } - settings_store& enable_control_structure(settings_control_structs ctrl_struct) + settings_store& enable_control_structure(const settings_control_structs ctrl_struct) { if ( (e_ctrl_unknown != ctrl_struct) && @@ -20673,7 +24171,7 @@ namespace exprtk return (*this); } - settings_store& enable_logic_operation(settings_logic_opr logic) + settings_store& enable_logic_operation(const settings_logic_opr logic) { if ( (e_logic_unknown != logic) && @@ -20691,7 +24189,7 @@ namespace exprtk return (*this); } - settings_store& enable_arithmetic_operation(settings_arithmetic_opr arithmetic) + settings_store& enable_arithmetic_operation(const settings_arithmetic_opr arithmetic) { if ( (e_arith_unknown != arithmetic) && @@ -20709,7 +24207,7 @@ namespace exprtk return (*this); } - settings_store& enable_assignment_operation(settings_assignment_opr assignment) + settings_store& enable_assignment_operation(const settings_assignment_opr assignment) { if ( (e_assign_unknown != assignment) && @@ -20727,7 +24225,7 @@ namespace exprtk return (*this); } - settings_store& enable_inequality_operation(settings_inequality_opr inequality) + settings_store& enable_inequality_operation(const settings_inequality_opr inequality) { if ( (e_ineq_unknown != inequality) && @@ -20745,9 +24243,9 @@ namespace exprtk return (*this); } - void set_max_stack_depth(const std::size_t mx_stack_depth) + void set_max_stack_depth(const std::size_t max_stack_depth) { - max_stack_depth_ = mx_stack_depth; + max_stack_depth_ = max_stack_depth; } void set_max_node_depth(const std::size_t max_node_depth) @@ -20755,6 +24253,26 @@ namespace exprtk max_node_depth_ = max_node_depth; } + void set_max_local_vector_size(const std::size_t max_local_vector_size) + { + max_local_vector_size_ = max_local_vector_size; + } + + std::size_t max_stack_depth() const + { + return max_stack_depth_; + } + + std::size_t max_node_depth() const + { + return max_node_depth_; + } + + std::size_t max_local_vector_size() const + { + return max_local_vector_size_; + } + private: void load_compile_options(const std::size_t compile_options) @@ -20784,7 +24302,7 @@ namespace exprtk case details::e_mulass : return "*="; case details::e_divass : return "/="; case details::e_modass : return "%="; - default : return ""; + default : return "" ; } } @@ -20797,7 +24315,8 @@ namespace exprtk case details::e_mul : return "*"; case details::e_div : return "/"; case details::e_mod : return "%"; - default : return ""; + case details::e_pow : return "^"; + default : return "" ; } } @@ -20805,15 +24324,15 @@ namespace exprtk { switch (opr) { - case details::e_lt : return "<"; + case details::e_lt : return "<" ; case details::e_lte : return "<="; case details::e_eq : return "=="; - case details::e_equal : return "="; + case details::e_equal : return "=" ; case details::e_ne : return "!="; case details::e_nequal: return "<>"; case details::e_gte : return ">="; - case details::e_gt : return ">"; - default : return ""; + case details::e_gt : return ">" ; + default : return "" ; } } @@ -20855,28 +24374,32 @@ namespace exprtk std::size_t max_stack_depth_; std::size_t max_node_depth_; + std::size_t max_local_vector_size_; friend class parser<T>; }; typedef settings_store settings_t; - parser(const settings_t& settings = settings_t()) - : settings_(settings), - resolve_unknown_symbol_(false), - results_context_(0), - unknown_symbol_resolver_(reinterpret_cast<unknown_symbol_resolver*>(0)), + explicit parser(const settings_t& settings = settings_t()) + : settings_(settings) + , resolve_unknown_symbol_(false) + , results_context_(0) + , unknown_symbol_resolver_(reinterpret_cast<unknown_symbol_resolver*>(0)) #ifdef _MSC_VER #pragma warning(push) #pragma warning (disable:4355) #endif - sem_(*this), + , sem_(*this) #ifdef _MSC_VER #pragma warning(pop) #endif - operator_joiner_2_(2), - operator_joiner_3_(3), - loop_runtime_check_(0) + , operator_joiner_2_(2) + , operator_joiner_3_(3) + , loop_runtime_check_(0) + , vector_access_runtime_check_(0) + , compilation_check_ptr_(0) + , assert_check_(0) { init_precompilation(); @@ -20889,26 +24412,26 @@ namespace exprtk expression_generator_.init_synthesize_map(); expression_generator_.set_parser(*this); - expression_generator_.set_uom(unary_op_map_); - expression_generator_.set_bom(binary_op_map_); + expression_generator_.set_uom (unary_op_map_ ); + expression_generator_.set_bom (binary_op_map_ ); expression_generator_.set_ibom(inv_binary_op_map_); - expression_generator_.set_sf3m(sf3_map_); - expression_generator_.set_sf4m(sf4_map_); + expression_generator_.set_sf3m(sf3_map_ ); + expression_generator_.set_sf4m(sf4_map_ ); expression_generator_.set_strength_reduction_state(settings_.strength_reduction_enabled()); } - ~parser() = default; + ~parser() exprtk_default; inline void init_precompilation() { - if (settings_.collect_variables_enabled()) - dec_.collect_variables() = true; + dec_.collect_variables() = + settings_.collect_variables_enabled(); - if (settings_.collect_functions_enabled()) - dec_.collect_functions() = true; + dec_.collect_functions() = + settings_.collect_functions_enabled(); - if (settings_.collect_assignments_enabled()) - dec_.collect_assignments() = true; + dec_.collect_assignments() = + settings_.collect_assignments_enabled(); if (settings_.replacer_enabled()) { @@ -20965,11 +24488,15 @@ namespace exprtk inline bool compile(const std::string& expression_string, expression<T>& expr) { - state_ .reset(); - error_list_ .clear(); - brkcnt_list_ .clear(); - synthesis_error_.clear(); - sem_ .cleanup(); + state_ .reset(); + error_list_ .clear(); + brkcnt_list_ .clear(); + synthesis_error_ .clear(); + immutable_memory_map_.reset(); + immutable_symtok_map_.clear(); + current_state_stack_ .clear(); + assert_ids_ .clear(); + sem_ .cleanup(); return_cleanup(); @@ -20977,10 +24504,10 @@ namespace exprtk if (expression_string.empty()) { - set_error( - make_error(parser_error::e_syntax, - "ERR001 - Empty expression!", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + "ERR001 - Empty expression!", + exprtk_error_location)); return false; } @@ -20993,11 +24520,17 @@ namespace exprtk if (lexer().empty()) { - set_error( - make_error(parser_error::e_syntax, - "ERR002 - Empty expression!", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + "ERR002 - Empty expression!", + exprtk_error_location)); + + return false; + } + if (halt_compilation_check()) + { + exprtk_debug(("halt_compilation_check() - compile checkpoint 0\n")); return false; } @@ -21006,6 +24539,12 @@ namespace exprtk return false; } + if (halt_compilation_check()) + { + exprtk_debug(("halt_compilation_check() - compile checkpoint 1\n")); + return false; + } + symtab_store_.symtab_list_ = expr.get_symbol_table_list(); dec_.clear(); @@ -21039,11 +24578,11 @@ namespace exprtk { if (error_list_.empty()) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR003 - Invalid expression encountered", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR003 - Invalid expression encountered", + exprtk_error_location)); } if ((0 != e) && branch_deletable(e)) @@ -21062,11 +24601,8 @@ namespace exprtk inline expression_t compile(const std::string& expression_string, symbol_table_t& symtab) { expression_t expression; - expression.register_symbol_table(symtab); - compile(expression_string,expression); - return expression; } @@ -21098,11 +24634,11 @@ namespace exprtk default : diagnostic += "Unknown compiler error"; } - set_error( - make_error(parser_error::e_lexer, - lexer()[i], - diagnostic + ": " + lexer()[i].value, - exprtk_error_location)); + set_error(make_error( + parser_error::e_lexer, + lexer()[i], + diagnostic + ": " + lexer()[i].value, + exprtk_error_location)); } } } @@ -21135,29 +24671,29 @@ namespace exprtk if (helper_assembly_.error_token_scanner) { lexer::helper::bracket_checker* bracket_checker_ptr = 0; - lexer::helper::numeric_checker* numeric_checker_ptr = 0; + lexer::helper::numeric_checker<T>* numeric_checker_ptr = 0; lexer::helper::sequence_validator* sequence_validator_ptr = 0; lexer::helper::sequence_validator_3tokens* sequence_validator3_ptr = 0; if (0 != (bracket_checker_ptr = dynamic_cast<lexer::helper::bracket_checker*>(helper_assembly_.error_token_scanner))) { - set_error( - make_error(parser_error::e_token, - bracket_checker_ptr->error_token(), - "ERR005 - Mismatched brackets: '" + bracket_checker_ptr->error_token().value + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_token, + bracket_checker_ptr->error_token(), + "ERR005 - Mismatched brackets: '" + bracket_checker_ptr->error_token().value + "'", + exprtk_error_location)); } - else if (0 != (numeric_checker_ptr = dynamic_cast<lexer::helper::numeric_checker*>(helper_assembly_.error_token_scanner))) + else if (0 != (numeric_checker_ptr = dynamic_cast<lexer::helper::numeric_checker<T>*>(helper_assembly_.error_token_scanner))) { for (std::size_t i = 0; i < numeric_checker_ptr->error_count(); ++i) { lexer::token error_token = lexer()[numeric_checker_ptr->error_index(i)]; - set_error( - make_error(parser_error::e_token, - error_token, - "ERR006 - Invalid numeric token: '" + error_token.value + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_token, + error_token, + "ERR006 - Invalid numeric token: '" + error_token.value + "'", + exprtk_error_location)); } if (numeric_checker_ptr->error_count()) @@ -21171,13 +24707,13 @@ namespace exprtk { std::pair<lexer::token,lexer::token> error_token = sequence_validator_ptr->error(i); - set_error( - make_error(parser_error::e_token, - error_token.first, - "ERR007 - Invalid token sequence: '" + - error_token.first.value + "' and '" + - error_token.second.value + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_token, + error_token.first, + "ERR007 - Invalid token sequence: '" + + error_token.first.value + "' and '" + + error_token.second.value + "'", + exprtk_error_location)); } if (sequence_validator_ptr->error_count()) @@ -21191,13 +24727,13 @@ namespace exprtk { std::pair<lexer::token,lexer::token> error_token = sequence_validator3_ptr->error(i); - set_error( - make_error(parser_error::e_token, - error_token.first, - "ERR008 - Invalid token sequence: '" + - error_token.first.value + "' and '" + - error_token.second.value + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_token, + error_token.first, + "ERR008 - Invalid token sequence: '" + + error_token.first.value + "' and '" + + error_token.second.value + "'", + exprtk_error_location)); } if (sequence_validator3_ptr->error_count()) @@ -21222,9 +24758,11 @@ namespace exprtk inline parser_error::type get_error(const std::size_t& index) const { if (index < error_list_.size()) + { return error_list_[index]; - else - throw std::invalid_argument("parser::get_error() - Invalid error index specificed"); + } + + throw std::invalid_argument("parser::get_error() - Invalid error index specified"); } inline std::string error() const @@ -21293,11 +24831,41 @@ namespace exprtk loop_runtime_check_ = &lrtchk; } + inline void register_vector_access_runtime_check(vector_access_runtime_check& vartchk) + { + vector_access_runtime_check_ = &vartchk; + } + + inline void register_compilation_timeout_check(compilation_check& compchk) + { + compilation_check_ptr_ = &compchk; + } + + inline void register_assert_check(assert_check& assrt_chck) + { + assert_check_ = &assrt_chck; + } + inline void clear_loop_runtime_check() { loop_runtime_check_ = loop_runtime_check_ptr(0); } + inline void clear_vector_access_runtime_check() + { + vector_access_runtime_check_ = vector_access_runtime_check_ptr(0); + } + + inline void clear_compilation_timeout_check() + { + compilation_check_ptr_ = compilation_check_ptr(0); + } + + inline void clear_assert_check() + { + assert_check_ = assert_check_ptr(0); + } + private: inline bool valid_base_operation(const std::string& symbol) const @@ -21387,7 +24955,7 @@ namespace exprtk scoped_vec_delete<expression_node_t> sdd((*this),arg_list); lexer::token begin_token; - lexer::token end_token; + lexer::token end_token; for ( ; ; ) { @@ -21401,11 +24969,11 @@ namespace exprtk { if (error_list_.empty()) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR009 - Invalid expression encountered", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR009 - Invalid expression encountered", + exprtk_error_location)); } return error_node(); @@ -21433,15 +25001,31 @@ namespace exprtk exprtk_debug(("-------------------------------------------------\n")); } - if (lexer().finished()) - break; - else if (token_is(token_t::e_eof,prsrhlpr_t::e_hold)) + if (token_is(token_t::e_eof,prsrhlpr_t::e_hold)) { if (lexer().finished()) break; else next_token(); } + else if ( + !settings_.commutative_check_enabled() && + ( + current_token().type == token_t::e_symbol || + current_token().type == token_t::e_number || + current_token().type == token_t::e_string || + token_is_bracket(prsrhlpr_t::e_hold) + ) + ) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR010 - Invalid syntax '" + current_token().value + "' possible missing operator or context", + exprtk_error_location)); + + return error_node(); + } } if ( @@ -21459,13 +25043,17 @@ namespace exprtk return result; } - std::string construct_subexpr(lexer::token& begin_token, lexer::token& end_token) + std::string construct_subexpr(lexer::token& begin_token, + lexer::token& end_token, + const bool cleanup_whitespace = true) { std::string result = lexer().substr(begin_token.position,end_token.position); - - for (std::size_t i = 0; i < result.size(); ++i) + if (cleanup_whitespace) { - if (details::is_whitespace(result[i])) result[i] = ' '; + for (std::size_t i = 0; i < result.size(); ++i) + { + if (details::is_whitespace(result[i])) result[i] = ' '; + } } return result; @@ -21477,11 +25065,13 @@ namespace exprtk { inline void set(const precedence_level& l, const precedence_level& r, - const details::operator_type& o) + const details::operator_type& o, + const token_t tkn = token_t()) { - left = l; - right = r; + left = l; + right = r; operation = o; + token = tkn; } inline void reset() @@ -21494,10 +25084,58 @@ namespace exprtk precedence_level left; precedence_level right; details::operator_type operation; + token_t token; }; + inline void push_current_state(const state_t current_state) + { + current_state_stack_.push_back(current_state); + } + + inline void pop_current_state() + { + if (!current_state_stack_.empty()) + { + current_state_stack_.pop_back(); + } + } + + inline state_t current_state() const + { + return (!current_state_stack_.empty()) ? + current_state_stack_.back() : + state_t(); + } + + inline bool halt_compilation_check() + { + compilation_check::compilation_context context; + + if (compilation_check_ptr_ && !compilation_check_ptr_->continue_compilation(context)) + { + const std::string error_message = + !context.error_message.empty() ? " Details: " + context.error_message : ""; + + set_error(make_error( + parser_error::e_parser, + token_t(), + "ERR011 - Internal compilation check failed." + error_message, + exprtk_error_location)); + + return true; + } + + return false; + } + inline expression_node_ptr parse_expression(precedence_level precedence = e_level00) { + if (halt_compilation_check()) + { + exprtk_debug(("halt_compilation_check() - parse_expression checkpoint 2\n")); + return error_node(); + } + stack_limit_handler slh(*this); if (!slh) @@ -21512,6 +25150,11 @@ namespace exprtk return error_node(); } + if (token_is(token_t::e_eof,prsrhlpr_t::e_hold)) + { + return expression; + } + bool break_loop = false; state_t current_state; @@ -21522,110 +25165,111 @@ namespace exprtk switch (current_token().type) { - case token_t::e_assign : current_state.set(e_level00,e_level00, details::e_assign); break; - case token_t::e_addass : current_state.set(e_level00,e_level00, details::e_addass); break; - case token_t::e_subass : current_state.set(e_level00,e_level00, details::e_subass); break; - case token_t::e_mulass : current_state.set(e_level00,e_level00, details::e_mulass); break; - case token_t::e_divass : current_state.set(e_level00,e_level00, details::e_divass); break; - case token_t::e_modass : current_state.set(e_level00,e_level00, details::e_modass); break; - case token_t::e_swap : current_state.set(e_level00,e_level00, details::e_swap ); break; - case token_t::e_lt : current_state.set(e_level05,e_level06, details:: e_lt); break; - case token_t::e_lte : current_state.set(e_level05,e_level06, details:: e_lte); break; - case token_t::e_eq : current_state.set(e_level05,e_level06, details:: e_eq); break; - case token_t::e_ne : current_state.set(e_level05,e_level06, details:: e_ne); break; - case token_t::e_gte : current_state.set(e_level05,e_level06, details:: e_gte); break; - case token_t::e_gt : current_state.set(e_level05,e_level06, details:: e_gt); break; - case token_t::e_add : current_state.set(e_level07,e_level08, details:: e_add); break; - case token_t::e_sub : current_state.set(e_level07,e_level08, details:: e_sub); break; - case token_t::e_div : current_state.set(e_level10,e_level11, details:: e_div); break; - case token_t::e_mul : current_state.set(e_level10,e_level11, details:: e_mul); break; - case token_t::e_mod : current_state.set(e_level10,e_level11, details:: e_mod); break; - case token_t::e_pow : current_state.set(e_level12,e_level12, details:: e_pow); break; - default : if (token_t::e_symbol == current_token().type) - { - static const std::string s_and = "and"; - static const std::string s_nand = "nand"; - static const std::string s_or = "or"; - static const std::string s_nor = "nor"; - static const std::string s_xor = "xor"; - static const std::string s_xnor = "xnor"; - static const std::string s_in = "in"; - static const std::string s_like = "like"; - static const std::string s_ilike = "ilike"; - static const std::string s_and1 = "&"; - static const std::string s_or1 = "|"; - static const std::string s_not = "not"; - - if (details::imatch(current_token().value,s_and)) - { - current_state.set(e_level03, e_level04, details::e_and); - break; - } - else if (details::imatch(current_token().value,s_and1)) - { - #ifndef exprtk_disable_sc_andor - current_state.set(e_level03, e_level04, details::e_scand); - #else - current_state.set(e_level03, e_level04, details::e_and); - #endif - break; - } - else if (details::imatch(current_token().value,s_nand)) - { - current_state.set(e_level03, e_level04, details::e_nand); - break; - } - else if (details::imatch(current_token().value,s_or)) - { - current_state.set(e_level01, e_level02, details::e_or); - break; - } - else if (details::imatch(current_token().value,s_or1)) - { - #ifndef exprtk_disable_sc_andor - current_state.set(e_level01, e_level02, details::e_scor); - #else - current_state.set(e_level01, e_level02, details::e_or); - #endif - break; - } - else if (details::imatch(current_token().value,s_nor)) - { - current_state.set(e_level01, e_level02, details::e_nor); - break; - } - else if (details::imatch(current_token().value,s_xor)) - { - current_state.set(e_level01, e_level02, details::e_xor); - break; - } - else if (details::imatch(current_token().value,s_xnor)) - { - current_state.set(e_level01, e_level02, details::e_xnor); - break; - } - else if (details::imatch(current_token().value,s_in)) - { - current_state.set(e_level04, e_level04, details::e_in); - break; - } - else if (details::imatch(current_token().value,s_like)) - { - current_state.set(e_level04, e_level04, details::e_like); - break; - } - else if (details::imatch(current_token().value,s_ilike)) - { - current_state.set(e_level04, e_level04, details::e_ilike); - break; - } - else if (details::imatch(current_token().value,s_not)) - { - break; - } - } - - break_loop = true; + case token_t::e_assign : current_state.set(e_level00, e_level00, details::e_assign, current_token()); break; + case token_t::e_addass : current_state.set(e_level00, e_level00, details::e_addass, current_token()); break; + case token_t::e_subass : current_state.set(e_level00, e_level00, details::e_subass, current_token()); break; + case token_t::e_mulass : current_state.set(e_level00, e_level00, details::e_mulass, current_token()); break; + case token_t::e_divass : current_state.set(e_level00, e_level00, details::e_divass, current_token()); break; + case token_t::e_modass : current_state.set(e_level00, e_level00, details::e_modass, current_token()); break; + case token_t::e_swap : current_state.set(e_level00, e_level00, details::e_swap , current_token()); break; + case token_t::e_lt : current_state.set(e_level05, e_level06, details::e_lt , current_token()); break; + case token_t::e_lte : current_state.set(e_level05, e_level06, details::e_lte , current_token()); break; + case token_t::e_eq : current_state.set(e_level05, e_level06, details::e_eq , current_token()); break; + case token_t::e_ne : current_state.set(e_level05, e_level06, details::e_ne , current_token()); break; + case token_t::e_gte : current_state.set(e_level05, e_level06, details::e_gte , current_token()); break; + case token_t::e_gt : current_state.set(e_level05, e_level06, details::e_gt , current_token()); break; + case token_t::e_add : current_state.set(e_level07, e_level08, details::e_add , current_token()); break; + case token_t::e_sub : current_state.set(e_level07, e_level08, details::e_sub , current_token()); break; + case token_t::e_div : current_state.set(e_level10, e_level11, details::e_div , current_token()); break; + case token_t::e_mul : current_state.set(e_level10, e_level11, details::e_mul , current_token()); break; + case token_t::e_mod : current_state.set(e_level10, e_level11, details::e_mod , current_token()); break; + case token_t::e_pow : current_state.set(e_level12, e_level12, details::e_pow , current_token()); break; + default : + if (token_t::e_symbol == current_token().type) + { + static const std::string s_and = "and" ; + static const std::string s_nand = "nand" ; + static const std::string s_or = "or" ; + static const std::string s_nor = "nor" ; + static const std::string s_xor = "xor" ; + static const std::string s_xnor = "xnor" ; + static const std::string s_in = "in" ; + static const std::string s_like = "like" ; + static const std::string s_ilike = "ilike"; + static const std::string s_and1 = "&" ; + static const std::string s_or1 = "|" ; + static const std::string s_not = "not" ; + + if (details::imatch(current_token().value,s_and)) + { + current_state.set(e_level03, e_level04, details::e_and, current_token()); + break; + } + else if (details::imatch(current_token().value,s_and1)) + { + #ifndef exprtk_disable_sc_andor + current_state.set(e_level03, e_level04, details::e_scand, current_token()); + #else + current_state.set(e_level03, e_level04, details::e_and, current_token()); + #endif + break; + } + else if (details::imatch(current_token().value,s_nand)) + { + current_state.set(e_level03, e_level04, details::e_nand, current_token()); + break; + } + else if (details::imatch(current_token().value,s_or)) + { + current_state.set(e_level01, e_level02, details::e_or, current_token()); + break; + } + else if (details::imatch(current_token().value,s_or1)) + { + #ifndef exprtk_disable_sc_andor + current_state.set(e_level01, e_level02, details::e_scor, current_token()); + #else + current_state.set(e_level01, e_level02, details::e_or, current_token()); + #endif + break; + } + else if (details::imatch(current_token().value,s_nor)) + { + current_state.set(e_level01, e_level02, details::e_nor, current_token()); + break; + } + else if (details::imatch(current_token().value,s_xor)) + { + current_state.set(e_level01, e_level02, details::e_xor, current_token()); + break; + } + else if (details::imatch(current_token().value,s_xnor)) + { + current_state.set(e_level01, e_level02, details::e_xnor, current_token()); + break; + } + else if (details::imatch(current_token().value,s_in)) + { + current_state.set(e_level04, e_level04, details::e_in, current_token()); + break; + } + else if (details::imatch(current_token().value,s_like)) + { + current_state.set(e_level04, e_level04, details::e_like, current_token()); + break; + } + else if (details::imatch(current_token().value,s_ilike)) + { + current_state.set(e_level04, e_level04, details::e_ilike, current_token()); + break; + } + else if (details::imatch(current_token().value,s_not)) + { + break; + } + } + + break_loop = true; } if (break_loop) @@ -21645,49 +25289,49 @@ namespace exprtk if (is_invalid_logic_operation(current_state.operation)) { - free_node(node_allocator_,expression); + free_node(node_allocator_, expression); - set_error( - make_error(parser_error::e_syntax, - prev_token, - "ERR010 - Invalid or disabled logic operation '" + details::to_str(current_state.operation) + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + prev_token, + "ERR012 - Invalid or disabled logic operation '" + details::to_str(current_state.operation) + "'", + exprtk_error_location)); return error_node(); } else if (is_invalid_arithmetic_operation(current_state.operation)) { - free_node(node_allocator_,expression); + free_node(node_allocator_, expression); - set_error( - make_error(parser_error::e_syntax, - prev_token, - "ERR011 - Invalid or disabled arithmetic operation '" + details::to_str(current_state.operation) + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + prev_token, + "ERR013 - Invalid or disabled arithmetic operation '" + details::to_str(current_state.operation) + "'", + exprtk_error_location)); return error_node(); } else if (is_invalid_inequality_operation(current_state.operation)) { - free_node(node_allocator_,expression); + free_node(node_allocator_, expression); - set_error( - make_error(parser_error::e_syntax, - prev_token, - "ERR012 - Invalid inequality operation '" + details::to_str(current_state.operation) + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + prev_token, + "ERR014 - Invalid inequality operation '" + details::to_str(current_state.operation) + "'", + exprtk_error_location)); return error_node(); } else if (is_invalid_assignment_operation(current_state.operation)) { - free_node(node_allocator_,expression); + free_node(node_allocator_, expression); - set_error( - make_error(parser_error::e_syntax, - prev_token, - "ERR013 - Invalid or disabled assignment operation '" + details::to_str(current_state.operation) + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + prev_token, + "ERR015 - Invalid or disabled assignment operation '" + details::to_str(current_state.operation) + "'", + exprtk_error_location)); return error_node(); } @@ -21695,44 +25339,48 @@ namespace exprtk if (0 != (right_branch = parse_expression(current_state.right))) { if ( - details::is_return_node( expression) || + details::is_return_node(expression ) || details::is_return_node(right_branch) ) { - free_node(node_allocator_, expression); + free_node(node_allocator_, expression ); free_node(node_allocator_, right_branch); - set_error( - make_error(parser_error::e_syntax, - prev_token, - "ERR014 - Return statements cannot be part of sub-expressions", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + prev_token, + "ERR016 - Return statements cannot be part of sub-expressions", + exprtk_error_location)); return error_node(); } + push_current_state(current_state); + new_expression = expression_generator_ ( current_state.operation, expression, right_branch ); + + pop_current_state(); } if (0 == new_expression) { if (error_list_.empty()) { - set_error( - make_error(parser_error::e_syntax, - prev_token, - !synthesis_error_.empty() ? - synthesis_error_ : - "ERR015 - General parsing error at token: '" + prev_token.value + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + prev_token, + !synthesis_error_.empty() ? + synthesis_error_ : + "ERR017 - General parsing error at token: '" + prev_token.value + "'", + exprtk_error_location)); } - free_node(node_allocator_, expression); + free_node(node_allocator_, expression ); free_node(node_allocator_, right_branch); return error_node(); @@ -21741,7 +25389,7 @@ namespace exprtk { if ( token_is(token_t::e_ternary,prsrhlpr_t::e_hold) && - (precedence == e_level00) + (e_level00 == precedence) ) { expression = parse_ternary_conditional_statement(new_expression); @@ -21755,14 +25403,35 @@ namespace exprtk if ((0 != expression) && (expression->node_depth() > settings_.max_node_depth_)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR016 - Expression depth of " + details::to_str(static_cast<int>(expression->node_depth())) + - " exceeds maximum allowed expression depth of " + details::to_str(static_cast<int>(settings_.max_node_depth_)), - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR018 - Expression depth of " + details::to_str(static_cast<int>(expression->node_depth())) + + " exceeds maximum allowed expression depth of " + details::to_str(static_cast<int>(settings_.max_node_depth_)), + exprtk_error_location)); - free_node(node_allocator_,expression); + free_node(node_allocator_, expression); + + return error_node(); + } + else if ( + !settings_.commutative_check_enabled() && + !details::is_logic_opr(current_token().value) && + (current_state.operation == details::e_default) && + ( + current_token().type == token_t::e_symbol || + current_token().type == token_t::e_number || + current_token().type == token_t::e_string + ) + ) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR019 - Invalid syntax '" + current_token().value + "' possible missing operator or context", + exprtk_error_location)); + + free_node(node_allocator_, expression); return error_node(); } @@ -21780,7 +25449,7 @@ namespace exprtk { expression_node_ptr un_r = n->branch(0); n->release(); - free_node(node_allocator_,node); + free_node(node_allocator_, node); node = un_r; return true; @@ -21802,20 +25471,20 @@ namespace exprtk (0 != (return_node = sem_ .get_variable(v))) ) { - free_node(node_allocator_,node); + free_node(node_allocator_, node); node = return_node; return true; } else { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR017 - Failed to find variable node in symbol table", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR020 - Failed to find variable node in symbol table", + exprtk_error_location)); - free_node(node_allocator_,node); + free_node(node_allocator_, node); return false; } @@ -21833,9 +25502,9 @@ namespace exprtk struct scoped_expression_delete { scoped_expression_delete(parser<T>& pr, expression_node_ptr& expression) - : delete_ptr(true), - parser_(pr), - expression_(expression) + : delete_ptr(true) + , parser_(pr) + , expression_(expression) {} ~scoped_expression_delete() @@ -21852,7 +25521,8 @@ namespace exprtk private: - scoped_expression_delete& operator=(const scoped_expression_delete&); + scoped_expression_delete(const scoped_expression_delete&) exprtk_delete; + scoped_expression_delete& operator=(const scoped_expression_delete&) exprtk_delete; }; template <typename Type, std::size_t N> @@ -21861,15 +25531,15 @@ namespace exprtk typedef Type* ptr_t; scoped_delete(parser<T>& pr, ptr_t& p) - : delete_ptr(true), - parser_(pr), - p_(&p) + : delete_ptr(true) + , parser_(pr) + , p_(&p) {} scoped_delete(parser<T>& pr, ptr_t (&p)[N]) - : delete_ptr(true), - parser_(pr), - p_(&p[0]) + : delete_ptr(true) + , parser_(pr) + , p_(&p[0]) {} ~scoped_delete() @@ -21889,7 +25559,8 @@ namespace exprtk private: - scoped_delete<Type,N>& operator=(const scoped_delete<Type,N>&); + scoped_delete(const scoped_delete<Type,N>&) exprtk_delete; + scoped_delete<Type,N>& operator=(const scoped_delete<Type,N>&) exprtk_delete; }; template <typename Type> @@ -21898,9 +25569,9 @@ namespace exprtk typedef Type* ptr_t; scoped_deq_delete(parser<T>& pr, std::deque<ptr_t>& deq) - : delete_ptr(true), - parser_(pr), - deq_(deq) + : delete_ptr(true) + , parser_(pr) + , deq_(deq) {} ~scoped_deq_delete() @@ -21909,6 +25580,7 @@ namespace exprtk { for (std::size_t i = 0; i < deq_.size(); ++i) { + exprtk_debug(("~scoped_deq_delete() - deleting node: %p\n", reinterpret_cast<void*>(deq_[i]))); free_node(parser_.node_allocator_,deq_[i]); } @@ -21922,7 +25594,8 @@ namespace exprtk private: - scoped_deq_delete<Type>& operator=(const scoped_deq_delete<Type>&); + scoped_deq_delete(const scoped_deq_delete<Type>&) exprtk_delete; + scoped_deq_delete<Type>& operator=(const scoped_deq_delete<Type>&) exprtk_delete; }; template <typename Type> @@ -21931,9 +25604,9 @@ namespace exprtk typedef Type* ptr_t; scoped_vec_delete(parser<T>& pr, std::vector<ptr_t>& vec) - : delete_ptr(true), - parser_(pr), - vec_(vec) + : delete_ptr(true) + , parser_(pr) + , vec_(vec) {} ~scoped_vec_delete() @@ -21942,6 +25615,7 @@ namespace exprtk { for (std::size_t i = 0; i < vec_.size(); ++i) { + exprtk_debug(("~scoped_vec_delete() - deleting node: %p\n", reinterpret_cast<void*>(vec_[i]))); free_node(parser_.node_allocator_,vec_[i]); } @@ -21949,13 +25623,19 @@ namespace exprtk } } + ptr_t operator[](const std::size_t index) + { + return vec_[index]; + } + bool delete_ptr; parser<T>& parser_; std::vector<ptr_t>& vec_; private: - scoped_vec_delete<Type>& operator=(const scoped_vec_delete<Type>&); + scoped_vec_delete(const scoped_vec_delete<Type>&) exprtk_delete; + scoped_vec_delete<Type>& operator=(const scoped_vec_delete<Type>&) exprtk_delete; }; struct scoped_bool_negator @@ -21973,8 +25653,8 @@ namespace exprtk struct scoped_bool_or_restorer { explicit scoped_bool_or_restorer(bool& bb) - : b(bb), - original_value_(bb) + : b(bb) + , original_value_(bb) {} ~scoped_bool_or_restorer() @@ -22029,11 +25709,11 @@ namespace exprtk case 19 : func_node = parse_function_call<19>(function,function_name); break; case 20 : func_node = parse_function_call<20>(function,function_name); break; default : { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR018 - Invalid number of parameters for function: '" + function_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR021 - Invalid number of parameters for function: '" + function_name + "'", + exprtk_error_location)); return error_node(); } @@ -22043,11 +25723,11 @@ namespace exprtk return func_node; else { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR019 - Failed to generate call to function: '" + function_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR022 - Failed to generate call to function: '" + function_name + "'", + exprtk_error_location)); return error_node(); } @@ -22062,11 +25742,11 @@ namespace exprtk #endif if (0 == NumberofParameters) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR020 - Expecting ifunction '" + function_name + "' to have non-zero parameter count", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR023 - Expecting ifunction '" + function_name + "' to have non-zero parameter count", + exprtk_error_location)); return error_node(); } @@ -22085,11 +25765,11 @@ namespace exprtk if (!token_is(token_t::e_lbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR021 - Expecting argument list for function: '" + function_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR024 - Expecting argument list for function: '" + function_name + "'", + exprtk_error_location)); return error_node(); } @@ -22100,11 +25780,11 @@ namespace exprtk if (0 == branch[i]) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR022 - Failed to parse argument " + details::to_str(i) + " for function: '" + function_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR025 - Failed to parse argument " + details::to_str(i) + " for function: '" + function_name + "'", + exprtk_error_location)); return error_node(); } @@ -22112,11 +25792,11 @@ namespace exprtk { if (!token_is(token_t::e_comma)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR023 - Invalid number of arguments for function: '" + function_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR026 - Invalid number of arguments for function: '" + function_name + "'", + exprtk_error_location)); return error_node(); } @@ -22125,11 +25805,11 @@ namespace exprtk if (!token_is(token_t::e_rbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR024 - Invalid number of arguments for function: '" + function_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR027 - Invalid number of arguments for function: '" + function_name + "'", + exprtk_error_location)); return error_node(); } @@ -22154,13 +25834,13 @@ namespace exprtk !token_is(token_t::e_rbracket) ) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR025 - Expecting '()' to proceed call to function: '" + function_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR028 - Expecting '()' to proceed call to function: '" + function_name + "'", + exprtk_error_location)); - free_node(node_allocator_,result); + free_node(node_allocator_, result); return error_node(); } @@ -22179,23 +25859,23 @@ namespace exprtk if (!token_is(token_t::e_lbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR026 - Expected a '(' at start of function call to '" + function_name + - "', instead got: '" + current_token().value + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR029 - Expected a '(' at start of function call to '" + function_name + + "', instead got: '" + current_token().value + "'", + exprtk_error_location)); return 0; } if (token_is(token_t::e_rbracket, e_hold)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR027 - Expected at least one input parameter for function call '" + function_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR030 - Expected at least one input parameter for function call '" + function_name + "'", + exprtk_error_location)); return 0; } @@ -22217,11 +25897,11 @@ namespace exprtk continue; else { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR028 - Expected a ',' between function input parameters, instead got: '" + current_token().value + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR031 - Expected a ',' between function input parameters, instead got: '" + current_token().value + "'", + exprtk_error_location)); return 0; } @@ -22229,11 +25909,11 @@ namespace exprtk if (sd.delete_ptr) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR029 - Invalid number of input parameters passed to function '" + function_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR032 - Invalid number of input parameters passed to function '" + function_name + "'", + exprtk_error_location)); return 0; } @@ -22252,11 +25932,11 @@ namespace exprtk if (0 == std::distance(itr_range.first,itr_range.second)) { - set_error( - make_error(parser_error::e_syntax, - diagnostic_token, - "ERR030 - No entry found for base operation: " + operation_name, - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + diagnostic_token, + "ERR033 - No entry found for base operation: " + operation_name, + exprtk_error_location)); return error_node(); } @@ -22299,11 +25979,11 @@ namespace exprtk free_node(node_allocator_, param_list[i]); } - set_error( - make_error(parser_error::e_syntax, - diagnostic_token, - "ERR031 - Invalid number of input parameters for call to function: '" + operation_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + diagnostic_token, + "ERR034 - Invalid number of input parameters for call to function: '" + operation_name + "'", + exprtk_error_location)); return error_node(); } @@ -22319,75 +25999,118 @@ namespace exprtk if (!token_is(token_t::e_comma)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR032 - Expected ',' between if-statement condition and consequent", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR035 - Expected ',' between if-statement condition and consequent", + exprtk_error_location)); + result = false; } else if (0 == (consequent = parse_expression())) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR033 - Failed to parse consequent for if-statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR036 - Failed to parse consequent for if-statement", + exprtk_error_location)); + result = false; } else if (!token_is(token_t::e_comma)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR034 - Expected ',' between if-statement consequent and alternative", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR037 - Expected ',' between if-statement consequent and alternative", + exprtk_error_location)); + result = false; } else if (0 == (alternative = parse_expression())) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR035 - Failed to parse alternative for if-statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR038 - Failed to parse alternative for if-statement", + exprtk_error_location)); + result = false; } else if (!token_is(token_t::e_rbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR036 - Expected ')' at the end of if-statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR039 - Expected ')' at the end of if-statement", + exprtk_error_location)); + result = false; } #ifndef exprtk_disable_string_capabilities if (result) { - const bool consq_is_str = is_generally_string_node( consequent); + const bool consq_is_str = is_generally_string_node(consequent ); const bool alter_is_str = is_generally_string_node(alternative); if (consq_is_str || alter_is_str) { if (consq_is_str && alter_is_str) { - return expression_generator_ - .conditional_string(condition, consequent, alternative); + expression_node_ptr result_node = + expression_generator_ + .conditional_string(condition, consequent, alternative); + + if (result_node && result_node->valid()) + { + return result_node; + } + + set_error(make_error( + parser_error::e_synthesis, + current_token(), + "ERR040 - Failed to synthesize node: conditional_string", + exprtk_error_location)); + + free_node(node_allocator_, result_node); + return error_node(); } - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR037 - Return types of ternary if-statement differ", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR041 - Return types of if-statement differ: string/non-string", + exprtk_error_location)); result = false; } } #endif + if (result) + { + const bool consq_is_vec = is_ivector_node(consequent ); + const bool alter_is_vec = is_ivector_node(alternative); + + if (consq_is_vec || alter_is_vec) + { + if (consq_is_vec && alter_is_vec) + { + return expression_generator_ + .conditional_vector(condition, consequent, alternative); + } + + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR042 - Return types of if-statement differ: vector/non-vector", + exprtk_error_location)); + + result = false; + } + } + if (!result) { free_node(node_allocator_, condition ); @@ -22412,11 +26135,31 @@ namespace exprtk { if (0 == (consequent = parse_multi_sequence("if-statement-01"))) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR038 - Failed to parse body of consequent for if-statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR043 - Failed to parse body of consequent for if-statement", + exprtk_error_location)); + + result = false; + } + else if + ( + !settings_.commutative_check_enabled() && + !token_is("else",prsrhlpr_t::e_hold) && + !token_is_loop(prsrhlpr_t::e_hold) && + !token_is_arithmetic_opr(prsrhlpr_t::e_hold) && + !token_is_right_bracket (prsrhlpr_t::e_hold) && + !token_is_ineq_opr (prsrhlpr_t::e_hold) && + !token_is(token_t::e_ternary,prsrhlpr_t::e_hold) && + !token_is(token_t::e_eof ,prsrhlpr_t::e_hold) + ) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR044 - Expected ';' at the end of the consequent for if-statement (1)", + exprtk_error_location)); result = false; } @@ -22433,24 +26176,24 @@ namespace exprtk if (0 != (consequent = parse_expression())) { - if (!token_is(token_t::e_eof)) + if (!token_is(token_t::e_eof, prsrhlpr_t::e_hold)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR039 - Expected ';' at the end of the consequent for if-statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR045 - Expected ';' at the end of the consequent for if-statement (2)", + exprtk_error_location)); result = false; } } else { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR040 - Failed to parse body of consequent for if-statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR046 - Failed to parse body of consequent for if-statement", + exprtk_error_location)); result = false; } @@ -22458,19 +26201,27 @@ namespace exprtk if (result) { - if (details::imatch(current_token().value,"else")) + if ( + details::imatch(current_token().value,"else") || + (token_is(token_t::e_eof, prsrhlpr_t::e_hold) && peek_token_is("else")) + ) { next_token(); + if (details::imatch(current_token().value,"else")) + { + next_token(); + } + if (token_is(token_t::e_lcrlbracket,prsrhlpr_t::e_hold)) { if (0 == (alternative = parse_multi_sequence("else-statement-01"))) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR041 - Failed to parse body of the 'else' for if-statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR047 - Failed to parse body of the 'else' for if-statement", + exprtk_error_location)); result = false; } @@ -22479,35 +26230,39 @@ namespace exprtk { if (0 == (alternative = parse_conditional_statement())) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR042 - Failed to parse body of if-else statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR048 - Failed to parse body of if-else statement", + exprtk_error_location)); result = false; } } else if (0 != (alternative = parse_expression())) { - if (!token_is(token_t::e_eof)) + if ( + !token_is(token_t::e_ternary , prsrhlpr_t::e_hold) && + !token_is(token_t::e_rcrlbracket, prsrhlpr_t::e_hold) && + !token_is(token_t::e_eof) + ) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR043 - Expected ';' at the end of the 'else-if' for the if-statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR049 - Expected ';' at the end of the 'else-if' for the if-statement", + exprtk_error_location)); result = false; } } else { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR044 - Failed to parse body of the 'else' for if-statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR050 - Failed to parse body of the 'else' for if-statement", + exprtk_error_location)); result = false; } @@ -22517,7 +26272,7 @@ namespace exprtk #ifndef exprtk_disable_string_capabilities if (result) { - const bool consq_is_str = is_generally_string_node( consequent); + const bool consq_is_str = is_generally_string_node(consequent ); const bool alter_is_str = is_generally_string_node(alternative); if (consq_is_str || alter_is_str) @@ -22528,21 +26283,44 @@ namespace exprtk .conditional_string(condition, consequent, alternative); } - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR045 - Return types of ternary if-statement differ", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR051 - Return types of if-statement differ: string/non-string", + exprtk_error_location)); result = false; } } #endif + if (result) + { + const bool consq_is_vec = is_ivector_node(consequent ); + const bool alter_is_vec = is_ivector_node(alternative); + + if (consq_is_vec || alter_is_vec) + { + if (consq_is_vec && alter_is_vec) + { + return expression_generator_ + .conditional_vector(condition, consequent, alternative); + } + + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR052 - Return types of if-statement differ: vector/non-vector", + exprtk_error_location)); + + result = false; + } + } + if (!result) { - free_node(node_allocator_, condition); - free_node(node_allocator_, consequent); + free_node(node_allocator_, condition ); + free_node(node_allocator_, consequent ); free_node(node_allocator_, alternative); return error_node(); @@ -22560,21 +26338,21 @@ namespace exprtk if (!token_is(token_t::e_lbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR046 - Expected '(' at start of if-statement, instead got: '" + current_token().value + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR053 - Expected '(' at start of if-statement, instead got: '" + current_token().value + "'", + exprtk_error_location)); return error_node(); } else if (0 == (condition = parse_expression())) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR047 - Failed to parse condition for if-statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR054 - Failed to parse condition for if-statement", + exprtk_error_location)); return error_node(); } @@ -22585,30 +26363,32 @@ namespace exprtk } else if (token_is(token_t::e_rbracket)) { - // 00. if (x) y; - // 01. if (x) y; else z; - // 02. if (x) y; else {z0; ... zn;} - // 03. if (x) y; else if (z) w; - // 04. if (x) y; else if (z) w; else u; - // 05. if (x) y; else if (z) w; else {u0; ... un;} - // 06. if (x) y; else if (z) {w0; ... wn;} - // 07. if (x) {y0; ... yn;} - // 08. if (x) {y0; ... yn;} else z; - // 09. if (x) {y0; ... yn;} else {z0; ... zn;}; - // 10. if (x) {y0; ... yn;} else if (z) w; - // 11. if (x) {y0; ... yn;} else if (z) w; else u; - // 12. if (x) {y0; ... nex;} else if (z) w; else {u0 ... un;} - // 13. if (x) {y0; ... yn;} else if (z) {w0; ... wn;} + /* + 00. if (x) y; + 01. if (x) y; else z; + 02. if (x) y; else {z0; ... zn;} + 03. if (x) y; else if (z) w; + 04. if (x) y; else if (z) w; else u; + 05. if (x) y; else if (z) w; else {u0; ... un;} + 06. if (x) y; else if (z) {w0; ... wn;} + 07. if (x) {y0; ... yn;} + 08. if (x) {y0; ... yn;} else z; + 09. if (x) {y0; ... yn;} else {z0; ... zn;}; + 10. if (x) {y0; ... yn;} else if (z) w; + 11. if (x) {y0; ... yn;} else if (z) w; else u; + 12. if (x) {y0; ... nex;} else if (z) w; else {u0 ... un;} + 13. if (x) {y0; ... yn;} else if (z) {w0; ... wn;} + */ return parse_conditional_statement_02(condition); } - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR048 - Invalid if-statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR055 - Invalid if-statement", + exprtk_error_location)); - free_node(node_allocator_,condition); + free_node(node_allocator_, condition); return error_node(); } @@ -22623,51 +26403,51 @@ namespace exprtk if (0 == condition) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR049 - Encountered invalid condition branch for ternary if-statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR056 - Encountered invalid condition branch for ternary if-statement", + exprtk_error_location)); return error_node(); } else if (!token_is(token_t::e_ternary)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR050 - Expected '?' after condition of ternary if-statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR057 - Expected '?' after condition of ternary if-statement", + exprtk_error_location)); result = false; } else if (0 == (consequent = parse_expression())) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR051 - Failed to parse consequent for ternary if-statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR058 - Failed to parse consequent for ternary if-statement", + exprtk_error_location)); result = false; } else if (!token_is(token_t::e_colon)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR052 - Expected ':' between ternary if-statement consequent and alternative", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR059 - Expected ':' between ternary if-statement consequent and alternative", + exprtk_error_location)); result = false; } else if (0 == (alternative = parse_expression())) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR053 - Failed to parse alternative for ternary if-statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR060 - Failed to parse alternative for ternary if-statement", + exprtk_error_location)); result = false; } @@ -22675,7 +26455,7 @@ namespace exprtk #ifndef exprtk_disable_string_capabilities if (result) { - const bool consq_is_str = is_generally_string_node( consequent); + const bool consq_is_str = is_generally_string_node(consequent ); const bool alter_is_str = is_generally_string_node(alternative); if (consq_is_str || alter_is_str) @@ -22686,21 +26466,44 @@ namespace exprtk .conditional_string(condition, consequent, alternative); } - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR054 - Return types of ternary if-statement differ", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR061 - Return types of ternary differ: string/non-string", + exprtk_error_location)); result = false; } } #endif + if (result) + { + const bool consq_is_vec = is_ivector_node(consequent ); + const bool alter_is_vec = is_ivector_node(alternative); + + if (consq_is_vec || alter_is_vec) + { + if (consq_is_vec && alter_is_vec) + { + return expression_generator_ + .conditional_vector(condition, consequent, alternative); + } + + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR062 - Return types of ternary differ: vector/non-vector", + exprtk_error_location)); + + result = false; + } + } + if (!result) { - free_node(node_allocator_, condition); - free_node(node_allocator_, consequent); + free_node(node_allocator_, condition ); + free_node(node_allocator_, consequent ); free_node(node_allocator_, alternative); return error_node(); @@ -22714,11 +26517,11 @@ namespace exprtk { if (settings_.logic_disabled("not")) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR055 - Invalid or disabled logic operation 'not'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR063 - Invalid or disabled logic operation 'not'", + exprtk_error_location)); return error_node(); } @@ -22726,6 +26529,12 @@ namespace exprtk return parse_base_operation(); } + void handle_brkcnt_scope_exit() + { + assert(!brkcnt_list_.empty()); + brkcnt_list_.pop_front(); + } + inline expression_node_ptr parse_while_loop() { // Parse: [while][(][test expr][)][{][expression][}] @@ -22739,31 +26548,31 @@ namespace exprtk if (!token_is(token_t::e_lbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR056 - Expected '(' at start of while-loop condition statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR064 - Expected '(' at start of while-loop condition statement", + exprtk_error_location)); return error_node(); } else if (0 == (condition = parse_expression())) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR057 - Failed to parse condition for while-loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR065 - Failed to parse condition for while-loop", + exprtk_error_location)); return error_node(); } else if (!token_is(token_t::e_rbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR058 - Expected ')' at end of while-loop condition statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR066 - Expected ')' at end of while-loop condition statement", + exprtk_error_location)); result = false; } @@ -22774,40 +26583,53 @@ namespace exprtk { scoped_inc_dec sid(state_.parsing_loop_stmt_count); - if (0 == (branch = parse_multi_sequence("while-loop"))) + if (0 == (branch = parse_multi_sequence("while-loop", true))) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR059 - Failed to parse body of while-loop")); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR067 - Failed to parse body of while-loop")); result = false; } else if (0 == (result_node = expression_generator_.while_loop(condition, branch, brkcnt_list_.front()))) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR060 - Failed to synthesize while-loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR068 - Failed to synthesize while-loop", + exprtk_error_location)); result = false; } } + handle_brkcnt_scope_exit(); + if (!result) { - free_node(node_allocator_, branch); - free_node(node_allocator_, condition); + free_node(node_allocator_, branch ); + free_node(node_allocator_, condition ); free_node(node_allocator_, result_node); - brkcnt_list_.pop_front(); - return error_node(); } - else + + if (result_node && result_node->valid()) + { return result_node; + } + + set_error(make_error( + parser_error::e_synthesis, + current_token(), + "ERR069 - Failed to synthesize 'valid' while-loop", + exprtk_error_location)); + + free_node(node_allocator_, result_node); + + return error_node(); } inline expression_node_ptr parse_repeat_until_loop() @@ -22831,7 +26653,7 @@ namespace exprtk } else { - const token_t::token_type seperator = token_t::e_eof; + const token_t::token_type separator = token_t::e_eof; scope_handler sh(*this); @@ -22862,13 +26684,13 @@ namespace exprtk const bool is_next_until = peek_token_is(token_t::e_symbol) && peek_token_is("until"); - if (!token_is(seperator) && is_next_until) + if (!token_is(separator) && is_next_until) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR061 - Expected '" + token_t::to_str(seperator) + "' in body of repeat until loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR070 - Expected '" + token_t::to_str(separator) + "' in body of repeat until loop", + exprtk_error_location)); return error_node(); } @@ -22886,13 +26708,11 @@ namespace exprtk if (sdd.delete_ptr) { - brkcnt_list_.pop_front(); - - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR062 - Failed to parse body of repeat until loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR071 - Failed to parse body of repeat until loop", + exprtk_error_location)); return error_node(); } @@ -22900,72 +26720,76 @@ namespace exprtk if (!token_is(token_t::e_lbracket)) { - brkcnt_list_.pop_front(); - - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR063 - Expected '(' before condition statement of repeat until loop", - exprtk_error_location)); - - free_node(node_allocator_,branch); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR072 - Expected '(' before condition statement of repeat until loop", + exprtk_error_location)); + free_node(node_allocator_, branch); return error_node(); } else if (0 == (condition = parse_expression())) { - brkcnt_list_.pop_front(); - - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR064 - Failed to parse condition for repeat until loop", - exprtk_error_location)); - - free_node(node_allocator_,branch); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR073 - Failed to parse condition for repeat until loop", + exprtk_error_location)); + free_node(node_allocator_, branch); return error_node(); } else if (!token_is(token_t::e_rbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR065 - Expected ')' after condition of repeat until loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR074 - Expected ')' after condition of repeat until loop", + exprtk_error_location)); - free_node(node_allocator_, branch); + free_node(node_allocator_, branch ); free_node(node_allocator_, condition); - brkcnt_list_.pop_front(); - return error_node(); } - expression_node_ptr result; - - result = expression_generator_ - .repeat_until_loop(condition, branch, brkcnt_list_.front()); + expression_node_ptr result_node = + expression_generator_ + .repeat_until_loop( + condition, + branch, + brkcnt_list_.front()); - if (0 == result) + if (0 == result_node) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR066 - Failed to synthesize repeat until loop", - exprtk_error_location)); - - free_node(node_allocator_,condition); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR075 - Failed to synthesize repeat until loop", + exprtk_error_location)); - brkcnt_list_.pop_front(); + free_node(node_allocator_, condition); return error_node(); } - else + + handle_brkcnt_scope_exit(); + + if (result_node && result_node->valid()) { - brkcnt_list_.pop_front(); - return result; + return result_node; } + + set_error(make_error( + parser_error::e_synthesis, + current_token(), + "ERR076 - Failed to synthesize 'valid' repeat until loop", + exprtk_error_location)); + + free_node(node_allocator_, result_node); + + return error_node(); } inline expression_node_ptr parse_for_loop() @@ -22984,11 +26808,11 @@ namespace exprtk if (!token_is(token_t::e_lbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR067 - Expected '(' at start of for-loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR077 - Expected '(' at start of for-loop", + exprtk_error_location)); return error_node(); } @@ -23004,21 +26828,21 @@ namespace exprtk if (!token_is(token_t::e_symbol,prsrhlpr_t::e_hold)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR068 - Expected a variable at the start of initialiser section of for-loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR078 - Expected a variable at the start of initialiser section of for-loop", + exprtk_error_location)); return error_node(); } else if (!peek_token_is(token_t::e_assign)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR069 - Expected variable assignment of initialiser section of for-loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR079 - Expected variable assignment of initialiser section of for-loop", + exprtk_error_location)); return error_node(); } @@ -23029,11 +26853,11 @@ namespace exprtk if ((se->name == loop_counter_symbol) && se->active) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR070 - For-loop variable '" + loop_counter_symbol+ "' is being shadowed by a previous declaration", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR080 - For-loop variable '" + loop_counter_symbol+ "' is being shadowed by a previous declaration", + exprtk_error_location)); return error_node(); } @@ -23042,7 +26866,7 @@ namespace exprtk if ( !se->active && (se->name == loop_counter_symbol) && - (se->type == scope_element::e_variable) + (se->type == scope_element::e_variable) ) { se->active = true; @@ -23061,11 +26885,11 @@ namespace exprtk if (!sem_.add_element(nse)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR071 - Failed to add new local variable '" + loop_counter_symbol + "' to SEM", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR081 - Failed to add new local variable '" + loop_counter_symbol + "' to SEM", + exprtk_error_location)); sem_.free_element(nse); @@ -23073,7 +26897,7 @@ namespace exprtk } else { - exprtk_debug(("parse_for_loop() - INFO - Added new local variable: %s\n",nse.name.c_str())); + exprtk_debug(("parse_for_loop() - INFO - Added new local variable: %s\n", nse.name.c_str())); state_.activate_side_effect("parse_for_loop()"); } @@ -23083,21 +26907,21 @@ namespace exprtk if (0 == (initialiser = parse_expression())) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR072 - Failed to parse initialiser of for-loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR082 - Failed to parse initialiser of for-loop", + exprtk_error_location)); result = false; } else if (!token_is(token_t::e_eof)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR073 - Expected ';' after initialiser of for-loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR083 - Expected ';' after initialiser of for-loop", + exprtk_error_location)); result = false; } @@ -23107,21 +26931,21 @@ namespace exprtk { if (0 == (condition = parse_expression())) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR074 - Failed to parse condition of for-loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR084 - Failed to parse condition of for-loop", + exprtk_error_location)); result = false; } else if (!token_is(token_t::e_eof)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR075 - Expected ';' after condition section of for-loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR085 - Expected ';' after condition section of for-loop", + exprtk_error_location)); result = false; } @@ -23131,21 +26955,21 @@ namespace exprtk { if (0 == (incrementor = parse_expression())) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR076 - Failed to parse incrementor of for-loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR086 - Failed to parse incrementor of for-loop", + exprtk_error_location)); result = false; } else if (!token_is(token_t::e_rbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR077 - Expected ')' after incrementor section of for-loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR087 - Expected ')' after incrementor section of for-loop", + exprtk_error_location)); result = false; } @@ -23157,13 +26981,13 @@ namespace exprtk scoped_inc_dec sid(state_.parsing_loop_stmt_count); - if (0 == (loop_body = parse_multi_sequence("for-loop"))) + if (0 == (loop_body = parse_multi_sequence("for-loop", true))) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR078 - Failed to parse body of for-loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR088 - Failed to parse body of for-loop", + exprtk_error_location)); result = false; } @@ -23177,29 +27001,34 @@ namespace exprtk } free_node(node_allocator_, initialiser); - free_node(node_allocator_, condition); + free_node(node_allocator_, condition ); free_node(node_allocator_, incrementor); - free_node(node_allocator_, loop_body); - - if (!brkcnt_list_.empty()) - { - brkcnt_list_.pop_front(); - } - + free_node(node_allocator_, loop_body ); return error_node(); } - else - { - expression_node_ptr result_node = - expression_generator_.for_loop(initialiser, - condition, - incrementor, - loop_body, - brkcnt_list_.front()); - brkcnt_list_.pop_front(); + expression_node_ptr result_node = + expression_generator_.for_loop(initialiser, + condition, + incrementor, + loop_body, + brkcnt_list_.front()); + handle_brkcnt_scope_exit(); + + if (result_node && result_node->valid()) + { return result_node; } + + set_error(make_error( + parser_error::e_synthesis, + current_token(), + "ERR089 - Failed to synthesize 'valid' for-loop", + exprtk_error_location)); + + free_node(node_allocator_, result_node); + + return error_node(); } inline expression_node_ptr parse_switch_statement() @@ -23209,11 +27038,11 @@ namespace exprtk if (!details::imatch(current_token().value,"switch")) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR079 - Expected keyword 'switch'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR090 - Expected keyword 'switch'", + exprtk_error_location)); return error_node(); } @@ -23224,11 +27053,11 @@ namespace exprtk if (!token_is(token_t::e_lcrlbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR080 - Expected '{' for call to switch statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR091 - Expected '{' for call to switch statement", + exprtk_error_location)); return error_node(); } @@ -23249,18 +27078,21 @@ namespace exprtk return error_node(); else if (!token_is(token_t::e_colon)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR081 - Expected ':' for case of switch statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR092 - Expected ':' for case of switch statement", + exprtk_error_location)); free_node(node_allocator_, condition); return error_node(); } - expression_node_ptr consequent = parse_expression(); + expression_node_ptr consequent = + (token_is(token_t::e_lcrlbracket,prsrhlpr_t::e_hold)) ? + parse_multi_sequence("switch-consequent") : + parse_expression(); if (0 == consequent) { @@ -23270,13 +27102,13 @@ namespace exprtk } else if (!token_is(token_t::e_eof)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR082 - Expected ';' at end of case for switch statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR093 - Expected ';' at end of case for switch statement", + exprtk_error_location)); - free_node(node_allocator_, condition); + free_node(node_allocator_, condition ); free_node(node_allocator_, consequent); return error_node(); @@ -23285,12 +27117,12 @@ namespace exprtk // Can we optimise away the case statement? if (is_constant_node(condition) && is_false(condition)) { - free_node(node_allocator_, condition); + free_node(node_allocator_, condition ); free_node(node_allocator_, consequent); } else { - arg_list.push_back( condition); + arg_list.push_back(condition ); arg_list.push_back(consequent); } @@ -23299,11 +27131,11 @@ namespace exprtk { if (0 != default_statement) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR083 - Multiple default cases for switch statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR094 - Multiple default cases for switch statement", + exprtk_error_location)); return error_node(); } @@ -23312,29 +27144,29 @@ namespace exprtk if (!token_is(token_t::e_colon)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR084 - Expected ':' for default of switch statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR095 - Expected ':' for default of switch statement", + exprtk_error_location)); return error_node(); } - if (token_is(token_t::e_lcrlbracket,prsrhlpr_t::e_hold)) - default_statement = parse_multi_sequence("switch-default"); - else - default_statement = parse_expression(); + default_statement = + (token_is(token_t::e_lcrlbracket,prsrhlpr_t::e_hold)) ? + parse_multi_sequence("switch-default"): + parse_expression(); if (0 == default_statement) return error_node(); else if (!token_is(token_t::e_eof)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR085 - Expected ';' at end of default for switch statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR096 - Expected ';' at end of default for switch statement", + exprtk_error_location)); return error_node(); } @@ -23343,11 +27175,11 @@ namespace exprtk break; else { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR086 - Expected '}' at end of switch statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR097 - Expected '}' at end of switch statement", + exprtk_error_location)); return error_node(); } @@ -23359,6 +27191,10 @@ namespace exprtk { arg_list.push_back(default_statement); } + else + { + arg_list.push_back(node_allocator_.allocate_c<literal_node_t>(std::numeric_limits<T>::quiet_NaN())); + } result = expression_generator_.switch_statement(arg_list, (0 != default_statement)); @@ -23374,11 +27210,11 @@ namespace exprtk if (!details::imatch(current_token().value,"[*]")) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR087 - Expected token '[*]'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR098 - Expected token '[*]'", + exprtk_error_location)); return error_node(); } @@ -23389,11 +27225,11 @@ namespace exprtk if (!token_is(token_t::e_lcrlbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR088 - Expected '{' for call to [*] statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR099 - Expected '{' for call to [*] statement", + exprtk_error_location)); return error_node(); } @@ -23402,11 +27238,11 @@ namespace exprtk { if (!details::imatch("case",current_token().value)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR089 - Expected a 'case' statement for multi-switch", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR100 - Expected a 'case' statement for multi-switch", + exprtk_error_location)); return error_node(); } @@ -23420,27 +27256,30 @@ namespace exprtk if (!token_is(token_t::e_colon)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR090 - Expected ':' for case of [*] statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR101 - Expected ':' for case of [*] statement", + exprtk_error_location)); return error_node(); } - expression_node_ptr consequent = parse_expression(); + expression_node_ptr consequent = + (token_is(token_t::e_lcrlbracket,prsrhlpr_t::e_hold)) ? + parse_multi_sequence("multi-switch-consequent") : + parse_expression(); if (0 == consequent) return error_node(); if (!token_is(token_t::e_eof)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR091 - Expected ';' at end of case for [*] statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR102 - Expected ';' at end of case for [*] statement", + exprtk_error_location)); return error_node(); } @@ -23448,12 +27287,12 @@ namespace exprtk // Can we optimise away the case statement? if (is_constant_node(condition) && is_false(condition)) { - free_node(node_allocator_, condition); + free_node(node_allocator_, condition ); free_node(node_allocator_, consequent); } else { - arg_list.push_back( condition); + arg_list.push_back(condition ); arg_list.push_back(consequent); } @@ -23465,11 +27304,11 @@ namespace exprtk if (!token_is(token_t::e_rcrlbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR092 - Expected '}' at end of [*] statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR103 - Expected '}' at end of [*] statement", + exprtk_error_location)); return error_node(); } @@ -23491,11 +27330,11 @@ namespace exprtk if (details::imatch(symbol,"~")) { next_token(); - return parse_multi_sequence(); + return check_block_statement_closure(parse_multi_sequence()); } else if (details::imatch(symbol,"[*]")) { - return parse_multi_switch_statement(); + return check_block_statement_closure(parse_multi_switch_statement()); } else if (details::imatch(symbol, "avg" )) opt_type = details::e_avg ; else if (details::imatch(symbol, "mand")) opt_type = details::e_mand; @@ -23506,11 +27345,11 @@ namespace exprtk else if (details::imatch(symbol, "sum" )) opt_type = details::e_sum ; else { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR093 - Unsupported vararg function: " + symbol, - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR104 - Unsupported built-in vararg function: " + symbol, + exprtk_error_location)); return error_node(); } @@ -23523,11 +27362,23 @@ namespace exprtk if (!token_is(token_t::e_lbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR094 - Expected '(' for call to vararg function: " + symbol, - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR105 - Expected '(' for call to vararg function: " + symbol, + exprtk_error_location)); + + return error_node(); + } + + if (token_is(token_t::e_rbracket)) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR106 - vararg function: " + symbol + + " requires at least one input parameter", + exprtk_error_location)); return error_node(); } @@ -23545,11 +27396,11 @@ namespace exprtk break; else if (!token_is(token_t::e_comma)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR095 - Expected ',' for call to vararg function: " + symbol, - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR107 - Expected ',' for call to vararg function: " + symbol, + exprtk_error_location)); return error_node(); } @@ -23566,13 +27417,13 @@ namespace exprtk { if (!token_is(token_t::e_lsqrbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR096 - Expected '[' as start of string range definition", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR108 - Expected '[' as start of string range definition", + exprtk_error_location)); - free_node(node_allocator_,expression); + free_node(node_allocator_, expression); return error_node(); } @@ -23585,7 +27436,7 @@ namespace exprtk if (!parse_range(rp,true)) { - free_node(node_allocator_,expression); + free_node(node_allocator_, expression); return error_node(); } @@ -23594,19 +27445,32 @@ namespace exprtk if (0 == result) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR097 - Failed to generate string range node", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR109 - Failed to generate string range node", + exprtk_error_location)); - free_node(node_allocator_,expression); + free_node(node_allocator_, expression); rp.free(); } rp.clear(); - return result; + if (result && result->valid()) + { + return result; + } + + set_error(make_error( + parser_error::e_synthesis, + current_token(), + "ERR110 - Failed to synthesize node: string_range_node", + exprtk_error_location)); + + free_node(node_allocator_, result); + rp.free(); + return error_node(); } #else inline expression_node_ptr parse_string_range_statement(expression_node_ptr&) @@ -23615,7 +27479,7 @@ namespace exprtk } #endif - inline void parse_pending_string_rangesize(expression_node_ptr& expression) + inline bool parse_pending_string_rangesize(expression_node_ptr& expression) { // Allow no more than 100 range calls, eg: s[][][]...[][] const std::size_t max_rangesize_parses = 100; @@ -23633,6 +27497,61 @@ namespace exprtk { expression = parse_string_range_statement(expression); } + + return (i > 1); + } + + inline void parse_pending_vector_index_operator(expression_node_ptr& expression) + { + if + ( + (0 != expression) && + error_list_.empty() && + is_ivector_node(expression) + ) + { + if ( + settings_.commutative_check_enabled() && + token_is(token_t::e_mul,prsrhlpr_t::e_hold) && + peek_token_is(token_t::e_lsqrbracket) + ) + { + token_is(token_t::e_mul); + token_is(token_t::e_lsqrbracket); + } + else if (token_is(token_t::e_lsqrbracket,prsrhlpr_t::e_hold)) + { + token_is(token_t::e_lsqrbracket); + } + else if ( + token_is(token_t::e_rbracket,prsrhlpr_t::e_hold) && + peek_token_is(token_t::e_lsqrbracket) + ) + { + token_is(token_t::e_rbracket ); + token_is(token_t::e_lsqrbracket); + } + else + return; + + details::vector_interface<T>* vi = dynamic_cast<details::vector_interface<T>*>(expression); + + if (vi) + { + details::vector_holder<T>& vec = vi->vec()->vec_holder(); + const std::string vector_name = sem_.get_vector_name(vec.data()); + expression_node_ptr index = parse_vector_index(vector_name); + + if (index) + { + expression = synthesize_vector_element(vector_name, &vec, expression, index); + return; + } + } + + free_node(node_allocator_, expression); + expression = error_node(); + } } template <typename Allocator1, @@ -23649,6 +27568,10 @@ namespace exprtk Sequence<expression_node_ptr,Allocator1> tmp_expression_list; + exprtk_debug(("simplify() - expression_list.size: %d side_effect_list.size(): %d\n", + static_cast<int>(expression_list .size()), + static_cast<int>(side_effect_list.size()))); + bool return_node_present = false; for (std::size_t i = 0; i < (expression_list.size() - 1); ++i) @@ -23668,7 +27591,7 @@ namespace exprtk for (std::size_t j = i + 1; j < expression_list.size(); ++j) { - free_node(node_allocator_,expression_list[j]); + free_node(node_allocator_, expression_list[j]); } return_node_present = true; @@ -23681,7 +27604,7 @@ namespace exprtk !side_effect_list[i] ) { - free_node(node_allocator_,expression_list[i]); + free_node(node_allocator_, expression_list[i]); continue; } else @@ -23703,8 +27626,8 @@ namespace exprtk } if ( - return_node_present || - side_effect_list.back() || + return_node_present || + side_effect_list.back() || (expression_list.size() > 1) ) state_.activate_side_effect("simplify()"); @@ -23717,31 +27640,34 @@ namespace exprtk return expression_generator_.vararg_function(details::e_multi,expression_list); } - inline expression_node_ptr parse_multi_sequence(const std::string& source = "") + inline expression_node_ptr parse_multi_sequence(const std::string& source = "", + const bool enforce_crlbrackets = false) { + token_t::token_type open_bracket = token_t::e_lcrlbracket; token_t::token_type close_bracket = token_t::e_rcrlbracket; - token_t::token_type seperator = token_t::e_eof; + token_t::token_type separator = token_t::e_eof; - if (!token_is(token_t::e_lcrlbracket)) + if (!token_is(open_bracket)) { - if (token_is(token_t::e_lbracket)) + if (!enforce_crlbrackets && token_is(token_t::e_lbracket)) { + open_bracket = token_t::e_lbracket; close_bracket = token_t::e_rbracket; - seperator = token_t::e_comma; + separator = token_t::e_comma; } else { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR098 - Expected '" + token_t::to_str(close_bracket) + "' for call to multi-sequence" + - ((!source.empty()) ? std::string(" section of " + source): ""), - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR111 - Expected '" + token_t::to_str(open_bracket) + "' for call to multi-sequence" + + ((!source.empty()) ? std::string(" section of " + source): ""), + exprtk_error_location)); return error_node(); } } - else if (token_is(token_t::e_rcrlbracket)) + else if (token_is(close_bracket)) { return node_allocator_.allocate<details::null_node<T> >(); } @@ -23776,13 +27702,13 @@ namespace exprtk const bool is_next_close = peek_token_is(close_bracket); - if (!token_is(seperator) && is_next_close) + if (!token_is(separator) && is_next_close) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR099 - Expected '" + details::to_str(seperator) + "' for call to multi-sequence section of " + source, - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR112 - Expected '" + lexer::token::seperator_to_str(separator) + "' for call to multi-sequence section of " + source, + exprtk_error_location)); return error_node(); } @@ -23791,7 +27717,7 @@ namespace exprtk break; } - result = simplify(arg_list,side_effect_list,source.empty()); + result = simplify(arg_list, side_effect_list, source.empty()); sdd.delete_ptr = (0 == result); return result; @@ -23800,23 +27726,23 @@ namespace exprtk inline bool parse_range(range_t& rp, const bool skip_lsqr = false) { // Examples of valid ranges: - // 1. [1:5] -> 1..5 - // 2. [ :5] -> 0..5 - // 3. [1: ] -> 1..end - // 4. [x:y] -> x..y where x <= y - // 5. [x+1:y/2] -> x+1..y/2 where x+1 <= y/2 - // 6. [ :y] -> 0..y where 0 <= y - // 7. [x: ] -> x..end where x <= end + // 1. [1:5] -> [1,5) + // 2. [ :5] -> [0,5) + // 3. [1: ] -> [1,end) + // 4. [x:y] -> [x,y) where x <= y + // 5. [x+1:y/2] -> [x+1,y/2) where x+1 <= y/2 + // 6. [ :y] -> [0,y) where 0 <= y + // 7. [x: ] -> [x,end) where x <= end rp.clear(); if (!skip_lsqr && !token_is(token_t::e_lsqrbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR100 - Expected '[' for start of range", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR113 - Expected '[' for start of range", + exprtk_error_location)); return false; } @@ -23833,11 +27759,11 @@ namespace exprtk if (0 == r0) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR101 - Failed parse begin section of range", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR114 - Failed parse begin section of range", + exprtk_error_location)); return false; } @@ -23852,15 +27778,15 @@ namespace exprtk rp.cache.first = rp.n0_c.second; } - free_node(node_allocator_,r0); + free_node(node_allocator_, r0); if (r0_value < T(0)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR102 - Range lower bound less than zero! Constraint: r0 >= 0", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR115 - Range lower bound less than zero! Constraint: r0 >= 0", + exprtk_error_location)); return false; } @@ -23873,11 +27799,11 @@ namespace exprtk if (!token_is(token_t::e_colon)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR103 - Expected ':' for break in range", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR116 - Expected ':' for break in range", + exprtk_error_location)); rp.free(); @@ -23896,11 +27822,11 @@ namespace exprtk if (0 == r1) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR104 - Failed parse end section of range", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR117 - Failed parse end section of range", + exprtk_error_location)); rp.free(); @@ -23917,15 +27843,15 @@ namespace exprtk rp.cache.second = rp.n1_c.second; } - free_node(node_allocator_,r1); + free_node(node_allocator_, r1); if (r1_value < T(0)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR105 - Range upper bound less than zero! Constraint: r1 >= 0", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR118 - Range upper bound less than zero! Constraint: r1 >= 0", + exprtk_error_location)); rp.free(); @@ -23940,11 +27866,11 @@ namespace exprtk if (!token_is(token_t::e_rsqrbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR106 - Expected ']' for start of range", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR119 - Expected ']' for start of range", + exprtk_error_location)); rp.free(); @@ -23968,11 +27894,11 @@ namespace exprtk if (!rp_result || (r0 > r1)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR107 - Invalid range, Constraint: r0 <= r1", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR120 - Invalid range, Constraint: r0 <= r1", + exprtk_error_location)); return false; } @@ -24007,24 +27933,36 @@ namespace exprtk } else { - if (!symtab_store_.is_conststr_stringvar(symbol)) + typedef typename symtab_store::string_context str_ctxt_t; + str_ctxt_t str_ctx = symtab_store_.get_string_context(symbol); + + if ((0 == str_ctx.str_var) || !symtab_store_.is_conststr_stringvar(symbol)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR108 - Unknown string symbol", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR121 - Unknown string symbol", + exprtk_error_location)); return error_node(); } - result = symtab_store_.get_stringvar(symbol); + assert(str_ctx.str_var != 0); + assert(str_ctx.symbol_table != 0); + + result = str_ctx.str_var; if (symtab_store_.is_constant_string(symbol)) { const_str_node = static_cast<strvar_node_t>(result); result = expression_generator_(const_str_node->str()); } + else if (symbol_table_t::e_immutable == str_ctx.symbol_table->mutability()) + { + lodge_immutable_symbol( + current_token(), + make_memory_range(str_ctx.str_var->base(), str_ctx.str_var->size())); + } lodge_symbol(symbol, e_st_string); } @@ -24040,7 +27978,7 @@ namespace exprtk if (const_str_node) { - free_node(node_allocator_,result); + free_node(node_allocator_, result); return expression_generator_(T(const_str_node->size())); } @@ -24053,13 +27991,13 @@ namespace exprtk if (!parse_range(rp)) { - free_node(node_allocator_,result); + free_node(node_allocator_, result); return error_node(); } else if (const_str_node) { - free_node(node_allocator_,result); + free_node(node_allocator_, result); result = expression_generator_(const_str_node->ref(),rp); } else @@ -24096,7 +28034,7 @@ namespace exprtk next_token(); next_token(); - free_node(node_allocator_,result); + free_node(node_allocator_, result); return expression_generator_(T(const_str.size())); } @@ -24105,13 +28043,13 @@ namespace exprtk if (!parse_range(rp)) { - free_node(node_allocator_,result); + free_node(node_allocator_, result); rp.free(); return error_node(); } - free_node(node_allocator_,result); + free_node(node_allocator_, result); if (rp.n1_c.first && (rp.n1_c.second == std::numeric_limits<std::size_t>::max())) { @@ -24124,13 +28062,13 @@ namespace exprtk (rp.n1_c.first && (rp.n1_c.second >= const_str.size())) ) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR109 - Overflow in range for string: '" + const_str + "'[" + - (rp.n0_c.first ? details::to_str(static_cast<int>(rp.n0_c.second)) : "?") + ":" + - (rp.n1_c.first ? details::to_str(static_cast<int>(rp.n1_c.second)) : "?") + "]", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR122 - Overflow in range for string: '" + const_str + "'[" + + (rp.n0_c.first ? details::to_str(static_cast<int>(rp.n0_c.second)) : "?") + ":" + + (rp.n1_c.first ? details::to_str(static_cast<int>(rp.n1_c.second)) : "?") + "]", + exprtk_error_location)); rp.free(); @@ -24154,35 +28092,82 @@ namespace exprtk } #endif + inline expression_node_ptr parse_vector_index(const std::string& vector_name = "") + { + expression_node_ptr index_expr = error_node(); + + if (0 == (index_expr = parse_expression())) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR123 - Failed to parse index for vector: '" + vector_name + "'", + exprtk_error_location)); + + return error_node(); + } + else if (!token_is(token_t::e_rsqrbracket)) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR124 - Expected ']' for index of vector: '" + vector_name + "'", + exprtk_error_location)); + + free_node(node_allocator_, index_expr); + + return error_node(); + } + + return index_expr; + } + inline expression_node_ptr parse_vector() { - const std::string symbol = current_token().value; + const std::string vector_name = current_token().value; vector_holder_ptr vec = vector_holder_ptr(0); - const scope_element& se = sem_.get_active_element(symbol); + const scope_element& se = sem_.get_active_element(vector_name); if ( - !details::imatch(se.name, symbol) || + !details::imatch(se.name, vector_name) || (se.depth > state_.scope_depth) || (scope_element::e_vector != se.type) ) { - if (0 == (vec = symtab_store_.get_vector(symbol))) + typedef typename symtab_store::vector_context vec_ctxt_t; + vec_ctxt_t vec_ctx = symtab_store_.get_vector_context(vector_name); + + if (0 == vec_ctx.vector_holder) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR110 - Symbol '" + symbol+ " not a vector", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR125 - Symbol '" + vector_name + " not a vector", + exprtk_error_location)); return error_node(); } + + assert(0 != vec_ctx.vector_holder); + assert(0 != vec_ctx.symbol_table ); + + vec = vec_ctx.vector_holder; + + if (symbol_table_t::e_immutable == vec_ctx.symbol_table->mutability()) + { + lodge_immutable_symbol( + current_token(), + make_memory_range(vec->data(), vec->size())); + } } else + { vec = se.vec_node; + } - expression_node_ptr index_expr = error_node(); + assert(0 != vec); next_token(); @@ -24192,31 +28177,28 @@ namespace exprtk } else if (token_is(token_t::e_rsqrbracket)) { - return expression_generator_(T(vec->size())); + return (vec->rebaseable()) ? + node_allocator_.allocate<vector_size_node_t>(vec) : + expression_generator_(T(vec->size())); } - else if (0 == (index_expr = parse_expression())) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR111 - Failed to parse index for vector: '" + symbol + "'", - exprtk_error_location)); - return error_node(); - } - else if (!token_is(token_t::e_rsqrbracket)) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR112 - Expected ']' for index of vector: '" + symbol + "'", - exprtk_error_location)); + expression_node_ptr index_expr = parse_vector_index(vector_name); - free_node(node_allocator_,index_expr); + if (index_expr) + { + expression_node_ptr vec_node = node_allocator_.allocate<vector_node_t>(vec); - return error_node(); + return synthesize_vector_element(vector_name, vec, vec_node, index_expr); } + return error_node(); + } + + inline expression_node_ptr synthesize_vector_element(const std::string& vector_name, + vector_holder_ptr vec, + expression_node_ptr vec_node, + expression_node_ptr index_expr) + { // Perform compile-time range check if (details::is_constant_node(index_expr)) { @@ -24225,20 +28207,21 @@ namespace exprtk if (index >= vec_size) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR113 - Index of " + details::to_str(index) + " out of range for " - "vector '" + symbol + "' of size " + details::to_str(vec_size), - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR126 - Index of " + details::to_str(index) + " out of range for " + "vector '" + vector_name + "' of size " + details::to_str(vec_size), + exprtk_error_location)); - free_node(node_allocator_,index_expr); + free_node(node_allocator_, vec_node ); + free_node(node_allocator_, index_expr); return error_node(); } } - return expression_generator_.vector_element(symbol, vec, index_expr); + return expression_generator_.vector_element(vector_name, vec, vec_node, index_expr); } inline expression_node_ptr parse_vararg_function_call(ivararg_function<T>* vararg_function, const std::string& vararg_function_name) @@ -24257,12 +28240,12 @@ namespace exprtk { if (!vararg_function->allow_zero_parameters()) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR114 - Zero parameter call to vararg function: " - + vararg_function_name + " not allowed", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR127 - Zero parameter call to vararg function: " + + vararg_function_name + " not allowed", + exprtk_error_location)); return error_node(); } @@ -24282,12 +28265,12 @@ namespace exprtk break; else if (!token_is(token_t::e_comma)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR115 - Expected ',' for call to vararg function: " - + vararg_function_name, - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR128 - Expected ',' for call to vararg function: " + + vararg_function_name, + exprtk_error_location)); return error_node(); } @@ -24296,37 +28279,37 @@ namespace exprtk } else if (!vararg_function->allow_zero_parameters()) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR116 - Zero parameter call to vararg function: " - + vararg_function_name + " not allowed", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR129 - Zero parameter call to vararg function: " + + vararg_function_name + " not allowed", + exprtk_error_location)); return error_node(); } if (arg_list.size() < vararg_function->min_num_args()) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR117 - Invalid number of parameters to call to vararg function: " - + vararg_function_name + ", require at least " - + details::to_str(static_cast<int>(vararg_function->min_num_args())) + " parameters", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR130 - Invalid number of parameters to call to vararg function: " + + vararg_function_name + ", require at least " + + details::to_str(static_cast<int>(vararg_function->min_num_args())) + " parameters", + exprtk_error_location)); return error_node(); } else if (arg_list.size() > vararg_function->max_num_args()) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR118 - Invalid number of parameters to call to vararg function: " - + vararg_function_name + ", require no more than " - + details::to_str(static_cast<int>(vararg_function->max_num_args())) + " parameters", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR131 - Invalid number of parameters to call to vararg function: " + + vararg_function_name + ", require no more than " + + details::to_str(static_cast<int>(vararg_function->max_num_args())) + " parameters", + exprtk_error_location)); return error_node(); } @@ -24362,10 +28345,10 @@ namespace exprtk const std::string& func_name, const std::string& func_prototypes, const return_type_t default_return_type) - : invalid_state_(true), - parser_(p), - function_name_(func_name), - default_return_type_(default_return_type) + : invalid_state_(true) + , parser_(p) + , function_name_(func_name) + , default_return_type_(default_return_type) { parse_function_prototypes(func_prototypes); } @@ -24397,14 +28380,13 @@ namespace exprtk if (1 == error_list.size()) { - parser_. - set_error( - make_error(parser_error::e_syntax, - parser_.current_token(), - "ERR119 - Failed parameter type check for function '" + function_name_ + "', " - "Expected '" + function_definition_list_[0].param_seq + - "' call set: '" + param_seq + "'", - exprtk_error_location)); + parser_.set_error(make_error( + parser_error::e_syntax, + parser_.current_token(), + "ERR132 - Failed parameter type check for function '" + function_name_ + "', " + "Expected '" + function_definition_list_[0].param_seq + + "' call set: '" + param_seq + "'", + exprtk_error_location)); } else { @@ -24419,14 +28401,13 @@ namespace exprtk } } - parser_. - set_error( - make_error(parser_error::e_syntax, - parser_.current_token(), - "ERR120 - Failed parameter type check for function '" + function_name_ + "', " - "Best match: '" + function_definition_list_[max_diff_index].param_seq + - "' call set: '" + param_seq + "'", - exprtk_error_location)); + parser_.set_error(make_error( + parser_error::e_syntax, + parser_.current_token(), + "ERR133 - Failed parameter type check for function '" + function_name_ + "', " + "Best match: '" + function_definition_list_[max_diff_index].param_seq + + "' call set: '" + param_seq + "'", + exprtk_error_location)); } return false; @@ -24561,13 +28542,12 @@ namespace exprtk { invalid_state_ = false; - parser_. - set_error( - make_error(parser_error::e_syntax, - parser_.current_token(), - "ERR121 - Invalid parameter sequence of '" + param_seq_list[i] + - "' for function: " + function_name_, - exprtk_error_location)); + parser_.set_error(make_error( + parser_error::e_syntax, + parser_.current_token(), + "ERR134 - Invalid parameter sequence of '" + param_seq_list[i] + + "' for function: " + function_name_, + exprtk_error_location)); return; } @@ -24577,15 +28557,14 @@ namespace exprtk { invalid_state_ = false; - parser_. - set_error( - make_error(parser_error::e_syntax, - parser_.current_token(), - "ERR122 - Function '" + function_name_ + "' has a parameter sequence conflict between " + - "pseq_idx[" + details::to_str(seq_itr->second) + "] and" + - "pseq_idx[" + details::to_str(i) + "] " + - "param seq: " + param_seq_list[i], - exprtk_error_location)); + parser_.set_error(make_error( + parser_error::e_syntax, + parser_.current_token(), + "ERR135 - Function '" + function_name_ + "' has a parameter sequence conflict between " + + "pseq_idx[" + details::to_str(seq_itr->second) + "] and" + + "pseq_idx[" + details::to_str(i) + "] " + + "param seq: " + param_seq_list[i], + exprtk_error_location)); return; } @@ -24593,8 +28572,8 @@ namespace exprtk } } - type_checker(const type_checker&); - type_checker& operator=(const type_checker&); + type_checker(const type_checker&) exprtk_delete; + type_checker& operator=(const type_checker&) exprtk_delete; bool invalid_state_; parser_t& parser_; @@ -24613,15 +28592,19 @@ namespace exprtk std::string param_type_list; - type_checker tc((*this), function_name, function->parameter_sequence, type_checker::e_string); + type_checker tc( + (*this), + function_name, + function->parameter_sequence, + type_checker::e_string); if (tc.invalid()) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR123 - Type checker instantiation failure for generic function: " + function_name, - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR136 - Type checker instantiation failure for generic function: " + function_name, + exprtk_error_location)); return error_node(); } @@ -24635,12 +28618,12 @@ namespace exprtk !tc .allow_zero_parameters() ) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR124 - Zero parameter call to generic function: " - + function_name + " not allowed", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR137 - Zero parameter call to generic function: " + + function_name + " not allowed", + exprtk_error_location)); return error_node(); } @@ -24667,11 +28650,11 @@ namespace exprtk break; else if (!token_is(token_t::e_comma)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR125 - Expected ',' for call to generic function: " + function_name, - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR138 - Expected ',' for call to generic function: " + function_name, + exprtk_error_location)); return error_node(); } @@ -24684,12 +28667,12 @@ namespace exprtk !tc .allow_zero_parameters () ) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR126 - Zero parameter call to generic function: " - + function_name + " not allowed", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR139 - Zero parameter call to generic function: " + + function_name + " not allowed", + exprtk_error_location)); return error_node(); } @@ -24701,22 +28684,21 @@ namespace exprtk !tc.verify(param_type_list, param_seq_index) ) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR127 - Invalid input parameter sequence for call to generic function: " + function_name, - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR140 - Invalid input parameter sequence for call to generic function: " + function_name, + exprtk_error_location)); return error_node(); } expression_node_ptr result = error_node(); - if (tc.paramseq_count() <= 1) - result = expression_generator_ - .generic_function_call(function, arg_list); - else - result = expression_generator_ + result = (tc.paramseq_count() <= 1) ? + expression_generator_ + .generic_function_call(function, arg_list) : + expression_generator_ .generic_function_call(function, arg_list, param_seq_index); sdd.delete_ptr = (0 == result); @@ -24739,12 +28721,12 @@ namespace exprtk !tc .allow_zero_parameters() ) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR128 - Zero parameter call to generic function: " - + function_name + " not allowed", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR141 - Zero parameter call to generic function: " + + function_name + " not allowed", + exprtk_error_location)); return false; } @@ -24771,11 +28753,11 @@ namespace exprtk break; else if (!token_is(token_t::e_comma)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR129 - Expected ',' for call to string function: " + function_name, - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR142 - Expected ',' for call to string function: " + function_name, + exprtk_error_location)); return false; } @@ -24818,22 +28800,21 @@ namespace exprtk if (!tc.verify(param_type_list, param_seq_index)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR130 - Invalid input parameter sequence for call to string function: " + function_name, - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR143 - Invalid input parameter sequence for call to string function: " + function_name, + exprtk_error_location)); return error_node(); } expression_node_ptr result = error_node(); - if (tc.paramseq_count() <= 1) - result = expression_generator_ - .string_function_call(function, arg_list); - else - result = expression_generator_ + result = (tc.paramseq_count() <= 1) ? + expression_generator_ + .string_function_call(function, arg_list) : + expression_generator_ .string_function_call(function, arg_list, param_seq_index); sdd.delete_ptr = (0 == result); @@ -24870,11 +28851,11 @@ namespace exprtk if (!tc.verify(param_type_list, param_seq_index)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR131 - Invalid input parameter sequence for call to overloaded function: " + function_name, - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR144 - Invalid input parameter sequence for call to overloaded function: " + function_name, + exprtk_error_location)); return error_node(); } @@ -24901,11 +28882,11 @@ namespace exprtk } else { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR132 - Invalid return type for call to overloaded function: " + function_name, - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR145 - Invalid return type for call to overloaded function: " + function_name, + exprtk_error_location)); } sdd.delete_ptr = (0 == result); @@ -24929,11 +28910,11 @@ namespace exprtk if (!p.token_is(token_t::e_lbracket)) { - p.set_error( - make_error(parser_error::e_syntax, - p.current_token(), - "ERR133 - Expected '(' for special function '" + sf_name + "'", - exprtk_error_location)); + p.set_error(make_error( + parser_error::e_syntax, + p.current_token(), + "ERR146 - Expected '(' for special function '" + sf_name + "'", + exprtk_error_location)); return error_node(); } @@ -24950,11 +28931,11 @@ namespace exprtk { if (!p.token_is(token_t::e_comma)) { - p.set_error( - make_error(parser_error::e_syntax, - p.current_token(), - "ERR134 - Expected ',' before next parameter of special function '" + sf_name + "'", - exprtk_error_location)); + p.set_error(make_error( + parser_error::e_syntax, + p.current_token(), + "ERR147 - Expected ',' before next parameter of special function '" + sf_name + "'", + exprtk_error_location)); return p.error_node(); } @@ -24963,11 +28944,11 @@ namespace exprtk if (!p.token_is(token_t::e_rbracket)) { - p.set_error( - make_error(parser_error::e_syntax, - p.current_token(), - "ERR135 - Invalid number of parameters for special function '" + sf_name + "'", - exprtk_error_location)); + p.set_error(make_error( + parser_error::e_syntax, + p.current_token(), + "ERR148 - Invalid number of parameters for special function '" + sf_name + "'", + exprtk_error_location)); return p.error_node(); } @@ -24990,11 +28971,11 @@ namespace exprtk !details::is_digit(sf_name[3]) ) { - set_error( - make_error(parser_error::e_token, - current_token(), - "ERR136 - Invalid special function[1]: " + sf_name, - exprtk_error_location)); + set_error(make_error( + parser_error::e_token, + current_token(), + "ERR149 - Invalid special function[1]: " + sf_name, + exprtk_error_location)); return error_node(); } @@ -25004,11 +28985,11 @@ namespace exprtk if (id >= details::e_sffinal) { - set_error( - make_error(parser_error::e_token, - current_token(), - "ERR137 - Invalid special function[2]: " + sf_name, - exprtk_error_location)); + set_error(make_error( + parser_error::e_token, + current_token(), + "ERR150 - Invalid special function[2]: " + sf_name, + exprtk_error_location)); return error_node(); } @@ -25036,21 +29017,21 @@ namespace exprtk { if (state_.parsing_break_stmt) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR138 - Invoking 'break' within a break call is not allowed", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR151 - Invoking 'break' within a break call is not allowed", + exprtk_error_location)); return error_node(); } else if (0 == state_.parsing_loop_stmt_count) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR139 - Invalid use of 'break', allowed only in the scope of a loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR152 - Invalid use of 'break', allowed only in the scope of a loop", + exprtk_error_location)); return error_node(); } @@ -25069,23 +29050,23 @@ namespace exprtk { if (0 == (return_expr = parse_expression())) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR140 - Failed to parse return expression for 'break' statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR153 - Failed to parse return expression for 'break' statement", + exprtk_error_location)); return error_node(); } else if (!token_is(token_t::e_rsqrbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR141 - Expected ']' at the completion of break's return expression", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR154 - Expected ']' at the completion of break's return expression", + exprtk_error_location)); - free_node(node_allocator_,return_expr); + free_node(node_allocator_, return_expr); return error_node(); } @@ -25097,11 +29078,11 @@ namespace exprtk } else { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR142 - Invalid use of 'break', allowed only in the scope of a loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR155 - Invalid use of 'break', allowed only in the scope of a loop", + exprtk_error_location)); } return error_node(); @@ -25111,11 +29092,11 @@ namespace exprtk { if (0 == state_.parsing_loop_stmt_count) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR143 - Invalid use of 'continue', allowed only in the scope of a loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR156 - Invalid use of 'continue', allowed only in the scope of a loop", + exprtk_error_location)); return error_node(); } @@ -25133,123 +29114,222 @@ namespace exprtk inline expression_node_ptr parse_define_vector_statement(const std::string& vec_name) { - expression_node_ptr size_expr = error_node(); + expression_node_ptr size_expression_node = error_node(); if (!token_is(token_t::e_lsqrbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR144 - Expected '[' as part of vector size definition", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR157 - Expected '[' as part of vector size definition", + exprtk_error_location)); return error_node(); } - else if (0 == (size_expr = parse_expression())) + else if (0 == (size_expression_node = parse_expression())) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR145 - Failed to determine size of vector '" + vec_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR158 - Failed to determine size of vector '" + vec_name + "'", + exprtk_error_location)); return error_node(); } - else if (!is_constant_node(size_expr)) + else if (!is_constant_node(size_expression_node)) { - free_node(node_allocator_,size_expr); + const bool is_rebaseble_vector = + (size_expression_node->type() == details::expression_node<T>::e_vecsize) && + static_cast<details::vector_size_node<T>*>(size_expression_node)->vec_holder()->rebaseable(); - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR146 - Expected a literal number as size of vector '" + vec_name + "'", - exprtk_error_location)); + free_node(node_allocator_, size_expression_node); + + const std::string error_msg = (is_rebaseble_vector) ? + std::string("Rebasable/Resizable vector cannot be used to define the size of vector") : + std::string("Expected a constant literal number as size of vector"); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR159 - " + error_msg + " '" + vec_name + "'", + exprtk_error_location)); return error_node(); } - const T vector_size = size_expr->value(); + const T vector_size = size_expression_node->value(); - free_node(node_allocator_,size_expr); + free_node(node_allocator_, size_expression_node); - const T max_vector_size = T(2000000000.0); + const std::size_t max_vector_size = settings_.max_local_vector_size(); if ( (vector_size <= T(0)) || std::not_equal_to<T>() (T(0),vector_size - details::numeric::trunc(vector_size)) || - (vector_size > max_vector_size) + (static_cast<std::size_t>(vector_size) > max_vector_size) ) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR147 - Invalid vector size. Must be an integer in the range [0,2e9], size: " + - details::to_str(details::numeric::to_int32(vector_size)), - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR160 - Invalid vector size. Must be an integer in the " + "range [0," + details::to_str(static_cast<std::size_t>(max_vector_size)) + "], size: " + + details::to_str(details::numeric::to_int32(vector_size)), + exprtk_error_location)); return error_node(); } + typename symbol_table_t::vector_holder_ptr vec_holder = typename symbol_table_t::vector_holder_ptr(0); + + const std::size_t vec_size = static_cast<std::size_t>(details::numeric::to_int32(vector_size)); + + scope_element& se = sem_.get_element(vec_name); + + if (se.name == vec_name) + { + if (se.active) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR161 - Illegal redefinition of local vector: '" + vec_name + "'", + exprtk_error_location)); + + return error_node(); + } + else if ( + (se.size == vec_size) && + (scope_element::e_vector == se.type) + ) + { + vec_holder = se.vec_node; + se.active = true; + se.depth = state_.scope_depth; + se.ref_count++; + } + } + + if (0 == vec_holder) + { + scope_element nse; + nse.name = vec_name; + nse.active = true; + nse.ref_count = 1; + nse.type = scope_element::e_vector; + nse.depth = state_.scope_depth; + nse.size = vec_size; + nse.data = new T[vec_size]; + nse.vec_node = new typename scope_element::vector_holder_t(reinterpret_cast<T*>(nse.data),nse.size); + + details::set_zero_value(reinterpret_cast<T*>(nse.data),vec_size); + + if (!sem_.add_element(nse)) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR162 - Failed to add new local vector '" + vec_name + "' to SEM", + exprtk_error_location)); + + sem_.free_element(nse); + + return error_node(); + } + + vec_holder = nse.vec_node; + + exprtk_debug(("parse_define_vector_statement() - INFO - Added new local vector: %s[%d]\n", + nse.name.c_str(), + static_cast<int>(nse.size))); + } + + state_.activate_side_effect("parse_define_vector_statement()"); + + lodge_symbol(vec_name, e_st_local_vector); + std::vector<expression_node_ptr> vec_initilizer_list; scoped_vec_delete<expression_node_t> svd((*this),vec_initilizer_list); bool single_value_initialiser = false; + bool range_value_initialiser = false; bool vec_to_vec_initialiser = false; bool null_initialisation = false; if (!token_is(token_t::e_rsqrbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR148 - Expected ']' as part of vector size definition", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR163 - Expected ']' as part of vector size definition", + exprtk_error_location)); return error_node(); } - else if (!token_is(token_t::e_eof)) + else if (!token_is(token_t::e_eof, prsrhlpr_t::e_hold)) { if (!token_is(token_t::e_assign)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR149 - Expected ':=' as part of vector definition", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR164 - Expected ':=' as part of vector definition", + exprtk_error_location)); return error_node(); } else if (token_is(token_t::e_lsqrbracket)) { - expression_node_ptr initialiser = parse_expression(); + expression_node_ptr initialiser_component = parse_expression(); - if (0 == initialiser) + if (0 == initialiser_component) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR150 - Failed to parse single vector initialiser", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR165 - Failed to parse first component of vector initialiser for vector: " + vec_name, + exprtk_error_location)); return error_node(); } - vec_initilizer_list.push_back(initialiser); + vec_initilizer_list.push_back(initialiser_component); + + if (token_is(token_t::e_colon)) + { + initialiser_component = parse_expression(); + + if (0 == initialiser_component) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR166 - Failed to parse second component of vector initialiser for vector: " + vec_name, + exprtk_error_location)); + + return error_node(); + } + + vec_initilizer_list.push_back(initialiser_component); + } if (!token_is(token_t::e_rsqrbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR151 - Expected ']' to close single value vector initialiser", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR167 - Expected ']' to close single value vector initialiser", + exprtk_error_location)); return error_node(); } - single_value_initialiser = true; + switch (vec_initilizer_list.size()) + { + case 1 : single_value_initialiser = true; break; + case 2 : range_value_initialiser = true; break; + } } else if (!token_is(token_t::e_lcrlbracket)) { @@ -25259,9 +29339,9 @@ namespace exprtk if (token_t::e_symbol == current_token().type) { // Is it a locally defined vector? - const scope_element& se = sem_.get_active_element(current_token().value); + const scope_element& lcl_se = sem_.get_active_element(current_token().value); - if (scope_element::e_vector == se.type) + if (scope_element::e_vector == lcl_se.type) { if (0 != (initialiser = parse_expression())) vec_initilizer_list.push_back(initialiser); @@ -25287,11 +29367,11 @@ namespace exprtk { if (0 == initialiser) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR152 - Expected '{' as part of vector initialiser list", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR168 - Expected '{' as part of vector initialiser list", + exprtk_error_location)); return error_node(); } @@ -25307,11 +29387,11 @@ namespace exprtk if (0 == initialiser) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR153 - Expected '{' as part of vector initialiser list", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR169 - Expected '{' as part of vector initialiser list", + exprtk_error_location)); return error_node(); } @@ -25325,11 +29405,11 @@ namespace exprtk if (!token_is(token_t::e_comma) && is_next_close) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR154 - Expected ',' between vector initialisers", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR170 - Expected ',' between vector initialisers", + exprtk_error_location)); return error_node(); } @@ -25345,99 +29425,118 @@ namespace exprtk !token_is(token_t::e_rsqrbracket, prsrhlpr_t::e_hold) ) { - if (!token_is(token_t::e_eof)) + if (!token_is(token_t::e_eof,prsrhlpr_t::e_hold)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR155 - Expected ';' at end of vector definition", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR171 - Expected ';' at end of vector definition", + exprtk_error_location)); return error_node(); } } - if (vec_initilizer_list.size() > vector_size) + if ( + !single_value_initialiser && + !range_value_initialiser && + (T(vec_initilizer_list.size()) > vector_size) + ) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR156 - Initialiser list larger than the number of elements in the vector: '" + vec_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR172 - Initialiser list larger than the number of elements in the vector: '" + vec_name + "'", + exprtk_error_location)); return error_node(); } } - typename symbol_table_t::vector_holder_ptr vec_holder = typename symbol_table_t::vector_holder_ptr(0); - - const std::size_t vec_size = static_cast<std::size_t>(details::numeric::to_int32(vector_size)); - - scope_element& se = sem_.get_element(vec_name); + expression_node_ptr result = error_node(); - if (se.name == vec_name) + if ( + (vec_initilizer_list.size() == 1) && + single_value_initialiser + ) { - if (se.active) + if (details::is_constant_node(vec_initilizer_list[0])) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR157 - Illegal redefinition of local vector: '" + vec_name + "'", - exprtk_error_location)); - - return error_node(); + // vector_init_zero_value_node var v[10] := [0] + if (T(0) == vec_initilizer_list[0]->value()) + { + result = node_allocator_ + .allocate<details::vector_init_zero_value_node<T> >( + (*vec_holder)[0], + vec_size, + vec_initilizer_list); + } + else + { + // vector_init_single_constvalue_node var v[10] := [123] + result = node_allocator_ + .allocate<details::vector_init_single_constvalue_node<T> >( + (*vec_holder)[0], + vec_size, + vec_initilizer_list); + } } - else if ( - (se.size == vec_size) && - (scope_element::e_vector == se.type) - ) + else { - vec_holder = se.vec_node; - se.active = true; - se.depth = state_.scope_depth; - se.ref_count++; + // vector_init_single_value_node var v[10] := [123 + (x / y)] + result = node_allocator_ + .allocate<details::vector_init_single_value_node<T> >( + (*vec_holder)[0], + vec_size, + vec_initilizer_list); } } - - if (0 == vec_holder) + else if ( + (vec_initilizer_list.size() == 2) && + range_value_initialiser + ) { - scope_element nse; - nse.name = vec_name; - nse.active = true; - nse.ref_count = 1; - nse.type = scope_element::e_vector; - nse.depth = state_.scope_depth; - nse.size = vec_size; - nse.data = new T[vec_size]; - nse.vec_node = new typename scope_element::vector_holder_t(reinterpret_cast<T*>(nse.data),nse.size); + bool base_const = details::is_constant_node(vec_initilizer_list[0]); + bool inc_const = details::is_constant_node(vec_initilizer_list[1]); - if (!sem_.add_element(nse)) + if (base_const && inc_const) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR158 - Failed to add new local vector '" + vec_name + "' to SEM", - exprtk_error_location)); - - sem_.free_element(nse); - - return error_node(); + // vector_init_single_value_node var v[10] := [1 : 3.5] + result = node_allocator_ + .allocate<details::vector_init_iota_constconst_node<T> >( + (*vec_holder)[0], + vec_size, + vec_initilizer_list); + } + else if (base_const && !inc_const) + { + // vector_init_single_value_node var v[10] := [1 : x + y] + result = node_allocator_ + .allocate<details::vector_init_iota_constnconst_node<T> >( + (*vec_holder)[0], + vec_size, + vec_initilizer_list); + } + else if (!base_const && inc_const) + { + // vector_init_single_value_node var v[10] := [x + y : 3] + result = node_allocator_ + .allocate<details::vector_init_iota_nconstconst_node<T> >( + (*vec_holder)[0], + vec_size, + vec_initilizer_list); + } + else if (!base_const && !inc_const) + { + // vector_init_single_value_node var v[10] := [x + y : z / w] + result = node_allocator_ + .allocate<details::vector_init_iota_nconstnconst_node<T> >( + (*vec_holder)[0], + vec_size, + vec_initilizer_list); } - - vec_holder = nse.vec_node; - - exprtk_debug(("parse_define_vector_statement() - INFO - Added new local vector: %s[%d]\n", - nse.name.c_str(), - static_cast<int>(nse.size))); } - - state_.activate_side_effect("parse_define_vector_statement()"); - - lodge_symbol(vec_name, e_st_local_vector); - - expression_node_ptr result = error_node(); - - if (null_initialisation) + else if (null_initialisation) result = expression_generator_(T(0.0)); else if (vec_to_vec_initialiser) { @@ -25449,16 +29548,31 @@ namespace exprtk vec_initilizer_list[0]); } else + { result = node_allocator_ - .allocate<details::vector_assignment_node<T> >( + .allocate<details::vector_initialisation_node<T> >( (*vec_holder)[0], vec_size, vec_initilizer_list, single_value_initialiser); + } - svd.delete_ptr = (0 == result); + svd.delete_ptr = false; - return result; + if (result && result->valid()) + { + return result; + } + + details::free_node(node_allocator_, result); + + set_error(make_error( + parser_error::e_synthesis, + current_token(), + "ERR173 - Failed to generate initialisation node for vector: " + vec_name, + exprtk_error_location)); + + return error_node(); } #ifndef exprtk_disable_string_capabilities @@ -25472,13 +29586,13 @@ namespace exprtk { if (se.active) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR159 - Illegal redefinition of local variable: '" + str_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR174 - Illegal redefinition of local variable: '" + str_name + "'", + exprtk_error_location)); - free_node(node_allocator_,initialisation_expression); + free_node(node_allocator_, initialisation_expression); return error_node(); } @@ -25504,13 +29618,13 @@ namespace exprtk if (!sem_.add_element(nse)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR160 - Failed to add new local string variable '" + str_name + "' to SEM", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR175 - Failed to add new local string variable '" + str_name + "' to SEM", + exprtk_error_location)); - free_node(node_allocator_,initialisation_expression); + free_node(node_allocator_, initialisation_expression); sem_.free_element(nse); @@ -25519,7 +29633,7 @@ namespace exprtk str_node = nse.str_node; - exprtk_debug(("parse_define_string_statement() - INFO - Added new local string variable: %s\n",nse.name.c_str())); + exprtk_debug(("parse_define_string_statement() - INFO - Added new local string variable: %s\n", nse.name.c_str())); } lodge_symbol(str_name, e_st_local_string); @@ -25550,11 +29664,11 @@ namespace exprtk { if (settings_.vardef_disabled()) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR161 - Illegal variable definition", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR176 - Illegal variable definition", + exprtk_error_location)); return error_node(); } @@ -25571,41 +29685,41 @@ namespace exprtk if (!token_is(token_t::e_symbol)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR162 - Expected a symbol for variable definition", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR177 - Expected a symbol for variable definition", + exprtk_error_location)); return error_node(); } else if (details::is_reserved_symbol(var_name)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR163 - Illegal redefinition of reserved keyword: '" + var_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR178 - Illegal redefinition of reserved keyword: '" + var_name + "'", + exprtk_error_location)); return error_node(); } else if (symtab_store_.symbol_exists(var_name)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR164 - Illegal redefinition of variable '" + var_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR179 - Illegal redefinition of variable '" + var_name + "'", + exprtk_error_location)); return error_node(); } else if (local_variable_is_shadowed(var_name)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR165 - Illegal redefinition of local variable: '" + var_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR180 - Illegal redefinition of local variable: '" + var_name + "'", + exprtk_error_location)); return error_node(); } @@ -25621,11 +29735,11 @@ namespace exprtk { if (0 == (initialisation_expression = parse_expression())) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR166 - Failed to parse initialisation expression", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR181 - Failed to parse initialisation expression for variable '" + var_name + "'", + exprtk_error_location)); return error_node(); } @@ -25639,13 +29753,13 @@ namespace exprtk { if (!token_is(token_t::e_eof,prsrhlpr_t::e_hold)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR167 - Expected ';' after variable definition", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR182 - Expected ';' after variable '" + var_name + "' definition", + exprtk_error_location)); - free_node(node_allocator_,initialisation_expression); + free_node(node_allocator_, initialisation_expression); return error_node(); } @@ -25667,11 +29781,11 @@ namespace exprtk { if (se.active) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR168 - Illegal redefinition of local variable: '" + var_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR183 - Illegal redefinition of local variable: '" + var_name + "'", + exprtk_error_location)); free_node(node_allocator_, initialisation_expression); @@ -25699,11 +29813,11 @@ namespace exprtk if (!sem_.add_element(nse)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR169 - Failed to add new local variable '" + var_name + "' to SEM", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR184 - Failed to add new local variable '" + var_name + "' to SEM", + exprtk_error_location)); free_node(node_allocator_, initialisation_expression); @@ -25714,7 +29828,7 @@ namespace exprtk var_node = nse.var_node; - exprtk_debug(("parse_define_var_statement() - INFO - Added new local variable: %s\n",nse.name.c_str())); + exprtk_debug(("parse_define_var_statement() - INFO - Added new local variable: %s\n", nse.name.c_str())); } state_.activate_side_effect("parse_define_var_statement()"); @@ -25729,6 +29843,174 @@ namespace exprtk return expression_generator_(details::e_assign,branch); } + inline expression_node_ptr parse_define_constvar_statement() + { + if (settings_.vardef_disabled()) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR185 - Illegal const variable definition", + exprtk_error_location)); + + return error_node(); + } + else if (!token_is("const")) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR186 - Expected 'const' keyword for const-variable definition", + exprtk_error_location)); + + return error_node(); + } + else if (!token_is("var")) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR187 - Expected 'var' keyword for const-variable definition", + exprtk_error_location)); + + return error_node(); + } + + const std::string var_name = current_token().value; + + expression_node_ptr initialisation_expression = error_node(); + + if (!token_is(token_t::e_symbol)) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR188 - Expected a symbol for const-variable definition", + exprtk_error_location)); + + return error_node(); + } + else if (details::is_reserved_symbol(var_name)) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR189 - Illegal redefinition of reserved keyword: '" + var_name + "'", + exprtk_error_location)); + + return error_node(); + } + else if (symtab_store_.symbol_exists(var_name)) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR190 - Illegal redefinition of variable '" + var_name + "'", + exprtk_error_location)); + + return error_node(); + } + else if (local_variable_is_shadowed(var_name)) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR191 - Illegal redefinition of local variable: '" + var_name + "'", + exprtk_error_location)); + + return error_node(); + } + else if (token_is(token_t::e_assign)) + { + if (0 == (initialisation_expression = parse_expression())) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR192 - Failed to parse initialisation expression for const-variable: '" + var_name + "'", + exprtk_error_location)); + + return error_node(); + } + else if (!details::is_literal_node(initialisation_expression)) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR193 - initialisation expression for const-variable: '" + var_name + "' must be a constant/literal", + exprtk_error_location)); + + free_node(node_allocator_, initialisation_expression); + + return error_node(); + } + } + + const T init_value = initialisation_expression->value(); + + free_node(node_allocator_, initialisation_expression); + + expression_node_ptr var_node = reinterpret_cast<expression_node_ptr>(0); + + scope_element& se = sem_.get_element(var_name); + + if (se.name == var_name) + { + if (se.active) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR194 - Illegal redefinition of local variable: '" + var_name + "'", + exprtk_error_location)); + + return error_node(); + } + else if (scope_element::e_literal == se.type) + { + var_node = se.var_node; + se.active = true; + se.depth = state_.scope_depth; + se.ref_count++; + } + } + + if (0 == var_node) + { + scope_element nse; + nse.name = var_name; + nse.active = true; + nse.ref_count = 1; + nse.type = scope_element::e_literal; + nse.depth = state_.scope_depth; + nse.data = 0; + nse.var_node = node_allocator_.allocate<literal_node_t>(init_value); + + if (!sem_.add_element(nse)) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR195 - Failed to add new local const-variable '" + var_name + "' to SEM", + exprtk_error_location)); + + sem_.free_element(nse); + + return error_node(); + } + + var_node = nse.var_node; + + exprtk_debug(("parse_define_constvar_statement() - INFO - Added new local const-variable: %s\n", nse.name.c_str())); + } + + state_.activate_side_effect("parse_define_constvar_statement()"); + + lodge_symbol(var_name, e_st_local_variable); + + return expression_generator_(var_node->value()); + } + inline expression_node_ptr parse_uninitialised_var_statement(const std::string& var_name) { if ( @@ -25736,21 +30018,21 @@ namespace exprtk !token_is(token_t::e_rcrlbracket) ) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR170 - Expected a '{}' for uninitialised var definition", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR196 - Expected a '{}' for uninitialised var definition", + exprtk_error_location)); return error_node(); } else if (!token_is(token_t::e_eof,prsrhlpr_t::e_hold)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR171 - Expected ';' after uninitialised variable definition", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR197 - Expected ';' after uninitialised variable definition", + exprtk_error_location)); return error_node(); } @@ -25763,11 +30045,11 @@ namespace exprtk { if (se.active) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR172 - Illegal redefinition of local variable: '" + var_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR198 - Illegal redefinition of local variable: '" + var_name + "'", + exprtk_error_location)); return error_node(); } @@ -25793,11 +30075,11 @@ namespace exprtk if (!sem_.add_element(nse)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR173 - Failed to add new local variable '" + var_name + "' to SEM", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR199 - Failed to add new local variable '" + var_name + "' to SEM", + exprtk_error_location)); sem_.free_element(nse); @@ -25826,11 +30108,11 @@ namespace exprtk if (!token_is(token_t::e_lbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR174 - Expected '(' at start of swap statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR200 - Expected '(' at start of swap statement", + exprtk_error_location)); return error_node(); } @@ -25845,11 +30127,11 @@ namespace exprtk if (!token_is(token_t::e_symbol,prsrhlpr_t::e_hold)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR175 - Expected a symbol for variable or vector element definition", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR201 - Expected a symbol for variable or vector element definition", + exprtk_error_location)); return error_node(); } @@ -25857,11 +30139,11 @@ namespace exprtk { if (0 == (variable0 = parse_vector())) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR176 - First parameter to swap is an invalid vector element: '" + var0_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR202 - First parameter to swap is an invalid vector element: '" + var0_name + "'", + exprtk_error_location)); return error_node(); } @@ -25890,11 +30172,11 @@ namespace exprtk if (0 == variable0) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR177 - First parameter to swap is an invalid variable: '" + var0_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR203 - First parameter to swap is an invalid variable: '" + var0_name + "'", + exprtk_error_location)); return error_node(); } @@ -25904,15 +30186,15 @@ namespace exprtk if (!token_is(token_t::e_comma)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR178 - Expected ',' between parameters to swap", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR204 - Expected ',' between parameters to swap", + exprtk_error_location)); if (variable0_generated) { - free_node(node_allocator_,variable0); + free_node(node_allocator_, variable0); } return error_node(); @@ -25922,15 +30204,15 @@ namespace exprtk if (!token_is(token_t::e_symbol,prsrhlpr_t::e_hold)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR179 - Expected a symbol for variable or vector element definition", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR205 - Expected a symbol for variable or vector element definition", + exprtk_error_location)); if (variable0_generated) { - free_node(node_allocator_,variable0); + free_node(node_allocator_, variable0); } return error_node(); @@ -25939,15 +30221,15 @@ namespace exprtk { if (0 == (variable1 = parse_vector())) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR180 - Second parameter to swap is an invalid vector element: '" + var1_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR206 - Second parameter to swap is an invalid vector element: '" + var1_name + "'", + exprtk_error_location)); if (variable0_generated) { - free_node(node_allocator_,variable0); + free_node(node_allocator_, variable0); } return error_node(); @@ -25977,15 +30259,15 @@ namespace exprtk if (0 == variable1) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR181 - Second parameter to swap is an invalid variable: '" + var1_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR207 - Second parameter to swap is an invalid variable: '" + var1_name + "'", + exprtk_error_location)); if (variable0_generated) { - free_node(node_allocator_,variable0); + free_node(node_allocator_, variable0); } return error_node(); @@ -25996,20 +30278,20 @@ namespace exprtk if (!token_is(token_t::e_rbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR182 - Expected ')' at end of swap statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR208 - Expected ')' at end of swap statement", + exprtk_error_location)); if (variable0_generated) { - free_node(node_allocator_,variable0); + free_node(node_allocator_, variable0); } if (variable1_generated) { - free_node(node_allocator_,variable1); + free_node(node_allocator_, variable1); } return error_node(); @@ -26031,12 +30313,12 @@ namespace exprtk if (variable0_generated) { - free_node(node_allocator_,variable0); + free_node(node_allocator_, variable0); } if (variable1_generated) { - free_node(node_allocator_,variable1); + free_node(node_allocator_, variable1); } } else @@ -26053,11 +30335,11 @@ namespace exprtk { if (state_.parsing_return_stmt) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR183 - Return call within a return call is not allowed", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR209 - Return call within a return call is not allowed", + exprtk_error_location)); return error_node(); } @@ -26077,11 +30359,11 @@ namespace exprtk if (!token_is(token_t::e_lsqrbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR184 - Expected '[' at start of return statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR210 - Expected '[' at start of return statement", + exprtk_error_location)); return error_node(); } @@ -26100,11 +30382,11 @@ namespace exprtk break; else if (!token_is(token_t::e_comma)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR185 - Expected ',' between values during call to return", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR211 - Expected ',' between values during call to return", + exprtk_error_location)); return error_node(); } @@ -26112,11 +30394,11 @@ namespace exprtk } else if (settings_.zero_return_disabled()) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR186 - Zero parameter return statement not allowed", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR212 - Zero parameter return statement not allowed", + exprtk_error_location)); return error_node(); } @@ -26127,11 +30409,11 @@ namespace exprtk { if (!arg_list.empty()) { - set_error( - make_error(parser_error::e_syntax, - prev_token, - "ERR187 - Invalid ']' found during return call", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + prev_token, + "ERR213 - Invalid ']' found during return call", + exprtk_error_location)); return error_node(); } @@ -26170,6 +30452,194 @@ namespace exprtk } #endif + inline expression_node_ptr parse_assert_statement() + { + assert(details::imatch(current_token().value, "assert")); + + if (state_.parsing_assert_stmt) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR214 - Assert statement within an assert statement is not allowed", + exprtk_error_location)); + + return error_node(); + } + + scoped_bool_negator sbn(state_.parsing_assert_stmt); + + next_token(); + + std::vector<expression_node_ptr> assert_arg_list(3, error_node()); + scoped_vec_delete<expression_node_t> sdd((*this), assert_arg_list); + + expression_node_ptr& assert_condition = assert_arg_list[0]; + expression_node_ptr& assert_message = assert_arg_list[1]; + expression_node_ptr& assert_id = assert_arg_list[2]; + + if (!token_is(token_t::e_lbracket)) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR215 - Expected '(' at start of assert statement", + exprtk_error_location)); + + return error_node(); + } + + const token_t start_token = current_token(); + + // Parse the assert condition + if (0 == (assert_condition = parse_expression())) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR216 - Failed to parse condition for assert statement", + exprtk_error_location)); + + return error_node(); + } + + const token_t end_token = current_token(); + + if (!token_is(token_t::e_rbracket)) + { + if (!token_is(token_t::e_comma)) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR217 - Expected ',' between condition and message for assert statement", + exprtk_error_location)); + + return error_node(); + } + // Parse the assert message + else if ( + (0 == (assert_message = parse_expression())) || + !details::is_generally_string_node(assert_message) + ) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR218 - " + + (assert_message ? + std::string("Expected string for assert message") : + std::string("Failed to parse message for assert statement")), + exprtk_error_location)); + + return error_node(); + } + else if (!token_is(token_t::e_rbracket)) + { + if (!token_is(token_t::e_comma)) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR219 - Expected ',' between message and ID for assert statement", + exprtk_error_location)); + + return error_node(); + } + // Parse assert ID + else if ( + (0 == (assert_id = parse_expression())) || + !details::is_const_string_node(assert_id) + ) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR220 - " + + (assert_id ? + std::string("Expected literal string for assert ID") : + std::string("Failed to parse string for assert ID")), + exprtk_error_location)); + + return error_node(); + } + else if (!token_is(token_t::e_rbracket)) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR221 - Expected ')' at start of assert statement", + exprtk_error_location)); + + return error_node(); + } + } + } + + exprtk::assert_check::assert_context context; + context.condition = lexer().substr(start_token.position, end_token.position); + context.offet = start_token.position; + + if (0 == assert_check_) + { + exprtk_debug(("parse_assert_statement() - assert functionality is disabled. assert condition: %s\n", + context.condition.c_str())); + + return new details::null_node<T>(); + } + + #ifndef exprtk_disable_string_capabilities + if (assert_message && details::is_const_string_node(assert_message)) + { + context.message = dynamic_cast<details::string_base_node<T>*>(assert_message)->str(); + } + + if (assert_id && details::is_const_string_node(assert_id)) + { + context.id = dynamic_cast<details::string_base_node<T>*>(assert_id)->str(); + + if (assert_ids_.end() != assert_ids_.find(context.id)) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR222 - Duplicate assert ID: " + context.id, + exprtk_error_location)); + + return error_node(); + } + + assert_ids_.insert(context.id); + free_node(node_allocator_, assert_id); + } + #endif + + expression_node_ptr result_node = + expression_generator_.assert_call( + assert_condition, + assert_message, + context); + + exprtk_debug(("parse_assert_statement() - assert condition: [%s]\n", context.condition.c_str() )); + exprtk_debug(("parse_assert_statement() - assert message: [%s]\n", context.message .c_str() )); + exprtk_debug(("parse_assert_statement() - assert id: [%s]\n", context.id .c_str() )); + exprtk_debug(("parse_assert_statement() - assert offset: [%d]\n", static_cast<int>(context.offet))); + + if (0 == result_node) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR223 - Failed to synthesize assert", + exprtk_error_location)); + + return error_node(); + } + + sdd.delete_ptr = false; + return result_node; + } + inline bool post_variable_process(const std::string& symbol) { if ( @@ -26180,11 +30650,11 @@ namespace exprtk { if (!settings_.commutative_check_enabled()) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR188 - Invalid sequence of variable '"+ symbol + "' and bracket", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR224 - Invalid sequence of variable '" + symbol + "' and bracket", + exprtk_error_location)); return false; } @@ -26199,26 +30669,29 @@ namespace exprtk { bool implied_mul = false; - if (is_generally_string_node(branch)) + if (details::is_generally_string_node(branch)) + return true; + + if (details::is_ivector_node(branch)) return true; const lexer::parser_helper::token_advance_mode hold = prsrhlpr_t::e_hold; switch (token) { - case token_t::e_lcrlbracket : implied_mul = token_is(token_t::e_lbracket ,hold) || - token_is(token_t::e_lcrlbracket,hold) || - token_is(token_t::e_lsqrbracket,hold) ; + case token_t::e_lcrlbracket : implied_mul = token_is(token_t::e_lbracket , hold) || + token_is(token_t::e_lcrlbracket, hold) || + token_is(token_t::e_lsqrbracket, hold) ; break; - case token_t::e_lbracket : implied_mul = token_is(token_t::e_lbracket ,hold) || - token_is(token_t::e_lcrlbracket,hold) || - token_is(token_t::e_lsqrbracket,hold) ; + case token_t::e_lbracket : implied_mul = token_is(token_t::e_lbracket , hold) || + token_is(token_t::e_lcrlbracket, hold) || + token_is(token_t::e_lsqrbracket, hold) ; break; - case token_t::e_lsqrbracket : implied_mul = token_is(token_t::e_lbracket ,hold) || - token_is(token_t::e_lcrlbracket,hold) || - token_is(token_t::e_lsqrbracket,hold) ; + case token_t::e_lsqrbracket : implied_mul = token_is(token_t::e_lbracket , hold) || + token_is(token_t::e_lcrlbracket, hold) || + token_is(token_t::e_lsqrbracket, hold) ; break; default : return true; @@ -26228,11 +30701,11 @@ namespace exprtk { if (!settings_.commutative_check_enabled()) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR189 - Invalid sequence of brackets", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR225 - Invalid sequence of brackets", + exprtk_error_location)); return false; } @@ -26247,27 +30720,65 @@ namespace exprtk return true; } + typedef typename interval_container_t<const void*>::interval_t interval_t; + typedef interval_container_t<const void*> immutable_memory_map_t; + typedef std::map<interval_t,token_t> immutable_symtok_map_t; + + inline interval_t make_memory_range(const T& t) + { + const T* begin = reinterpret_cast<const T*>(&t); + const T* end = begin + 1; + return interval_t(begin, end); + } + + inline interval_t make_memory_range(const T* begin, const std::size_t size) + { + return interval_t(begin, begin + size); + } + + inline interval_t make_memory_range(details::char_cptr begin, const std::size_t size) + { + return interval_t(begin, begin + size); + } + + void lodge_immutable_symbol(const lexer::token& token, const interval_t interval) + { + immutable_memory_map_.add_interval(interval); + immutable_symtok_map_[interval] = token; + } + inline expression_node_ptr parse_symtab_symbol() { const std::string symbol = current_token().value; // Are we dealing with a variable or a special constant? - expression_node_ptr variable = symtab_store_.get_variable(symbol); + typedef typename symtab_store::variable_context var_ctxt_t; + var_ctxt_t var_ctx = symtab_store_.get_variable_context(symbol); - if (variable) + if (var_ctx.variable) { + assert(var_ctx.symbol_table); + + expression_node_ptr result_variable = var_ctx.variable; + if (symtab_store_.is_constant_node(symbol)) { - variable = expression_generator_(variable->value()); + result_variable = expression_generator_(var_ctx.variable->value()); + } + else if (symbol_table_t::e_immutable == var_ctx.symbol_table->mutability()) + { + lodge_immutable_symbol(current_token(), make_memory_range(var_ctx.variable->ref())); + result_variable = var_ctx.variable; } if (!post_variable_process(symbol)) return error_node(); lodge_symbol(symbol, e_st_variable); + next_token(); - return variable; + return result_variable; } // Are we dealing with a locally defined variable, vector or string? @@ -26277,7 +30788,10 @@ namespace exprtk if (se.active && details::imatch(se.name, symbol)) { - if (scope_element::e_variable == se.type) + if ( + (scope_element::e_variable == se.type) || + (scope_element::e_literal == se.type) + ) { se.active = true; lodge_symbol(symbol, e_st_local_variable); @@ -26287,7 +30801,9 @@ namespace exprtk next_token(); - return se.var_node; + return (scope_element::e_variable == se.type) ? + se.var_node : + expression_generator_(se.var_node->value()); } else if (scope_element::e_vector == se.type) { @@ -26325,11 +30841,11 @@ namespace exprtk return func_node; else { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR190 - Failed to generate node for function: '" + symbol + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR226 - Failed to generate node for function: '" + symbol + "'", + exprtk_error_location)); return error_node(); } @@ -26351,11 +30867,11 @@ namespace exprtk return vararg_func_node; else { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR191 - Failed to generate node for vararg function: '" + symbol + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR227 - Failed to generate node for vararg function: '" + symbol + "'", + exprtk_error_location)); return error_node(); } @@ -26377,11 +30893,11 @@ namespace exprtk return genericfunc_node; else { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR192 - Failed to generate node for generic function: '" + symbol + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR228 - Failed to generate node for generic function: '" + symbol + "'", + exprtk_error_location)); return error_node(); } @@ -26404,11 +30920,11 @@ namespace exprtk return stringfunc_node; else { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR193 - Failed to generate node for string function: '" + symbol + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR229 - Failed to generate node for string function: '" + symbol + "'", + exprtk_error_location)); return error_node(); } @@ -26430,11 +30946,11 @@ namespace exprtk return overloadfunc_node; else { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR194 - Failed to generate node for overload function: '" + symbol + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR230 - Failed to generate node for overload function: '" + symbol + "'", + exprtk_error_location)); return error_node(); } @@ -26456,11 +30972,11 @@ namespace exprtk !details::is_base_function(symbol) ) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR195 - Invalid use of reserved symbol '" + symbol + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR231 - Invalid use of reserved symbol '" + symbol + "'", + exprtk_error_location)); return error_node(); } @@ -26487,11 +31003,13 @@ namespace exprtk switch (usr_symbol_type) { - case unknown_symbol_resolver::e_usr_variable_type : create_result = symtab.create_variable(symbol, default_value); - break; + case unknown_symbol_resolver::e_usr_variable_type : + create_result = symtab.create_variable(symbol, default_value); + break; - case unknown_symbol_resolver::e_usr_constant_type : create_result = symtab.add_constant(symbol, default_value); - break; + case unknown_symbol_resolver::e_usr_constant_type : + create_result = symtab.add_constant(symbol, default_value); + break; default : create_result = false; } @@ -26519,12 +31037,12 @@ namespace exprtk } } - set_error( - make_error(parser_error::e_symtab, - current_token(), - "ERR196 - Failed to create variable: '" + symbol + "'" + - (error_message.empty() ? "" : " - " + error_message), - exprtk_error_location)); + set_error(make_error( + parser_error::e_symtab, + current_token(), + "ERR232 - Failed to create variable: '" + symbol + "'" + + (error_message.empty() ? "" : " - " + error_message), + exprtk_error_location)); } else if (unknown_symbol_resolver::e_usrmode_extended == unknown_symbol_resolver_->mode) @@ -26539,27 +31057,51 @@ namespace exprtk } } - set_error( - make_error(parser_error::e_symtab, - current_token(), - "ERR197 - Failed to resolve symbol: '" + symbol + "'" + - (error_message.empty() ? "" : " - " + error_message), - exprtk_error_location)); + set_error(make_error( + parser_error::e_symtab, + current_token(), + "ERR233 - Failed to resolve symbol: '" + symbol + "'" + + (error_message.empty() ? "" : " - " + error_message), + exprtk_error_location)); } return error_node(); } } - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR198 - Undefined symbol: '" + symbol + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR234 - Undefined symbol: '" + symbol + "'", + exprtk_error_location)); return error_node(); } + inline expression_node_ptr check_block_statement_closure(expression_node_ptr expression) + { + if ( + expression && + ( + (current_token().type == token_t::e_symbol) || + (current_token().type == token_t::e_number) + ) + ) + { + free_node(node_allocator_, expression); + + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR235 - Invalid syntax '" + current_token().value + "' possible missing operator or context", + exprtk_error_location)); + + return error_node(); + } + + return expression; + } + inline expression_node_ptr parse_symbol() { static const std::string symbol_if = "if" ; @@ -26571,103 +31113,116 @@ namespace exprtk static const std::string symbol_break = "break" ; static const std::string symbol_continue = "continue"; static const std::string symbol_var = "var" ; + static const std::string symbol_const = "const" ; static const std::string symbol_swap = "swap" ; static const std::string symbol_return = "return" ; static const std::string symbol_not = "not" ; + static const std::string symbol_assert = "assert" ; - if (valid_vararg_operation(current_token().value)) + const std::string symbol = current_token().value; + + if (valid_vararg_operation(symbol)) { return parse_vararg_function(); } - else if (details::imatch(current_token().value, symbol_not)) + else if (details::imatch(symbol, symbol_not)) { return parse_not_statement(); } - else if (valid_base_operation(current_token().value)) + else if (valid_base_operation(symbol)) { return parse_base_operation(); } else if ( - details::imatch(current_token().value, symbol_if) && - settings_.control_struct_enabled(current_token().value) + details::imatch(symbol, symbol_if) && + settings_.control_struct_enabled(symbol) ) { return parse_conditional_statement(); } else if ( - details::imatch(current_token().value, symbol_while) && - settings_.control_struct_enabled(current_token().value) + details::imatch(symbol, symbol_while) && + settings_.control_struct_enabled(symbol) ) { - return parse_while_loop(); + return check_block_statement_closure(parse_while_loop()); } else if ( - details::imatch(current_token().value, symbol_repeat) && - settings_.control_struct_enabled(current_token().value) + details::imatch(symbol, symbol_repeat) && + settings_.control_struct_enabled(symbol) ) { - return parse_repeat_until_loop(); + return check_block_statement_closure(parse_repeat_until_loop()); } else if ( - details::imatch(current_token().value, symbol_for) && - settings_.control_struct_enabled(current_token().value) + details::imatch(symbol, symbol_for) && + settings_.control_struct_enabled(symbol) ) { - return parse_for_loop(); + return check_block_statement_closure(parse_for_loop()); } else if ( - details::imatch(current_token().value, symbol_switch) && - settings_.control_struct_enabled(current_token().value) + details::imatch(symbol, symbol_switch) && + settings_.control_struct_enabled(symbol) ) { - return parse_switch_statement(); + return check_block_statement_closure(parse_switch_statement()); } - else if (details::is_valid_sf_symbol(current_token().value)) + else if (details::is_valid_sf_symbol(symbol)) { return parse_special_function(); } - else if (details::imatch(current_token().value, symbol_null)) + else if (details::imatch(symbol, symbol_null)) { return parse_null_statement(); } #ifndef exprtk_disable_break_continue - else if (details::imatch(current_token().value, symbol_break)) + else if (details::imatch(symbol, symbol_break)) { return parse_break_statement(); } - else if (details::imatch(current_token().value, symbol_continue)) + else if (details::imatch(symbol, symbol_continue)) { return parse_continue_statement(); } #endif - else if (details::imatch(current_token().value, symbol_var)) + else if (details::imatch(symbol, symbol_var)) { return parse_define_var_statement(); } - else if (details::imatch(current_token().value, symbol_swap)) + else if (details::imatch(symbol, symbol_const)) + { + return parse_define_constvar_statement(); + } + else if (details::imatch(symbol, symbol_swap)) { return parse_swap_statement(); } #ifndef exprtk_disable_return_statement else if ( - details::imatch(current_token().value, symbol_return) && - settings_.control_struct_enabled(current_token().value) + details::imatch(symbol, symbol_return) && + settings_.control_struct_enabled(symbol) ) { - return parse_return_statement(); + return check_block_statement_closure(parse_return_statement()); } #endif + else if (details::imatch(symbol, symbol_assert)) + { + return parse_assert_statement(); + } else if (symtab_store_.valid() || !sem_.empty()) { return parse_symtab_symbol(); } else { - set_error( - make_error(parser_error::e_symtab, - current_token(), - "ERR199 - Variable or function detected, yet symbol-table is invalid, Symbol: " + current_token().value, - exprtk_error_location)); + set_error(make_error( + parser_error::e_symtab, + current_token(), + "ERR236 - Unknown variable or function encountered. Symbol table(s) " + "is either invalid or does not contain symbol: '" + symbol + "'", + exprtk_error_location)); return error_node(); } @@ -26694,11 +31249,11 @@ namespace exprtk if (0 == literal_exp) { - set_error( - make_error(parser_error::e_numeric, - current_token(), - "ERR200 - Failed generate node for scalar: '" + current_token().value + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_numeric, + current_token(), + "ERR237 - Failed generate node for scalar: '" + current_token().value + "'", + exprtk_error_location)); return error_node(); } @@ -26708,11 +31263,11 @@ namespace exprtk } else { - set_error( - make_error(parser_error::e_numeric, - current_token(), - "ERR201 - Failed to convert '" + current_token().value + "' to a number", - exprtk_error_location)); + set_error(make_error( + parser_error::e_numeric, + current_token(), + "ERR238 - Failed to convert '" + current_token().value + "' to a number", + exprtk_error_location)); return error_node(); } @@ -26732,25 +31287,32 @@ namespace exprtk next_token(); if (0 == (branch = parse_expression())) + { return error_node(); - else if (!token_is(token_t::e_rbracket)) + } + + token_is(token_t::e_eof); + + if (!token_is(token_t::e_rbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR202 - Expected ')' instead of: '" + current_token().value + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR239 - Expected ')' instead of: '" + current_token().value + "'", + exprtk_error_location)); - free_node(node_allocator_,branch); + details::free_node(node_allocator_, branch); return error_node(); } else if (!post_bracket_process(token_t::e_lbracket,branch)) { - free_node(node_allocator_,branch); + details::free_node(node_allocator_, branch); return error_node(); } + + parse_pending_vector_index_operator(branch); } else if (token_t::e_lsqrbracket == current_token().type) { @@ -26760,19 +31322,19 @@ namespace exprtk return error_node(); else if (!token_is(token_t::e_rsqrbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR203 - Expected ']' instead of: '" + current_token().value + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR240 - Expected ']' instead of: '" + current_token().value + "'", + exprtk_error_location)); - free_node(node_allocator_,branch); + details::free_node(node_allocator_, branch); return error_node(); } else if (!post_bracket_process(token_t::e_lsqrbracket,branch)) { - free_node(node_allocator_,branch); + details::free_node(node_allocator_, branch); return error_node(); } @@ -26785,19 +31347,19 @@ namespace exprtk return error_node(); else if (!token_is(token_t::e_rcrlbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR204 - Expected '}' instead of: '" + current_token().value + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR241 - Expected '}' instead of: '" + current_token().value + "'", + exprtk_error_location)); - free_node(node_allocator_,branch); + details::free_node(node_allocator_, branch); return error_node(); } else if (!post_bracket_process(token_t::e_lcrlbracket,branch)) { - free_node(node_allocator_,branch); + details::free_node(node_allocator_, branch); return error_node(); } @@ -26819,7 +31381,7 @@ namespace exprtk if (0 == result) { - free_node(node_allocator_,branch); + details::free_node(node_allocator_, branch); return error_node(); } @@ -26834,21 +31396,21 @@ namespace exprtk } else if (token_t::e_eof == current_token().type) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR205 - Premature end of expression[1]", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR242 - Premature end of expression[1]", + exprtk_error_location)); return error_node(); } else { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR206 - Premature end of expression[2]", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR243 - Premature end of expression[2]", + exprtk_error_location)); return error_node(); } @@ -26949,6 +31511,8 @@ namespace exprtk register_synthezier(synthesize_covocov_expression4) register_synthezier(synthesize_vocovoc_expression4) register_synthezier(synthesize_covovoc_expression4) + + #undef register_synthezier #endif } @@ -27001,7 +31565,7 @@ namespace exprtk { typename binary_op_map_t::iterator bop_itr = binary_op_map_->find(operation); - if ((*binary_op_map_).end() == bop_itr) + if (binary_op_map_->end() == bop_itr) return false; bop = bop_itr->second; @@ -27413,13 +31977,20 @@ namespace exprtk if (details::is_string_node(branch[0])) return !b1_is_genstring; + else if (details::is_literal_node(branch[0])) + return true; else return ( - !details::is_variable_node (branch[0]) && - !details::is_vector_elem_node (branch[0]) && - !details::is_rebasevector_elem_node (branch[0]) && - !details::is_rebasevector_celem_node(branch[0]) && - !details::is_vector_node (branch[0]) + !details::is_variable_node (branch[0]) && + !details::is_vector_elem_node (branch[0]) && + !details::is_vector_celem_node (branch[0]) && + !details::is_vector_elem_rtc_node (branch[0]) && + !details::is_vector_celem_rtc_node (branch[0]) && + !details::is_rebasevector_elem_node (branch[0]) && + !details::is_rebasevector_celem_node (branch[0]) && + !details::is_rebasevector_elem_rtc_node (branch[0]) && + !details::is_rebasevector_celem_rtc_node(branch[0]) && + !details::is_vector_node (branch[0]) ) || b1_is_genstring; } @@ -27549,9 +32120,9 @@ namespace exprtk (details::e_equal == operation) || (details::e_and == operation) || (details::e_nand == operation) || - (details:: e_or == operation) || - (details:: e_nor == operation) || - (details:: e_xor == operation) || + (details::e_or == operation) || + (details::e_nor == operation) || + (details::e_xor == operation) || (details::e_xnor == operation) ); } @@ -27574,18 +32145,42 @@ namespace exprtk { if ((0 == branch[0]) || (0 == branch[1])) { + parser_->set_error(parser_error::make_error( + parser_error::e_syntax, + parser_->current_state().token, + "ERR244 - Invalid branches received for operator '" + details::to_str(operation) + "'", + exprtk_error_location)); + return error_node(); } else if (is_invalid_string_op(operation,branch)) { + parser_->set_error(parser_error::make_error( + parser_error::e_syntax, + parser_->current_state().token, + "ERR245 - Invalid branch pair for string operator '" + details::to_str(operation) + "'", + exprtk_error_location)); + return error_node(); } else if (is_invalid_assignment_op(operation,branch)) { + parser_->set_error(parser_error::make_error( + parser_error::e_syntax, + parser_->current_state().token, + "ERR246 - Invalid branch pair for assignment operator '" + details::to_str(operation) + "'", + exprtk_error_location)); + return error_node(); } else if (is_invalid_break_continue_op(branch)) { + parser_->set_error(parser_error::make_error( + parser_error::e_syntax, + parser_->current_state().token, + "ERR247 - Invalid branch pair for break/continue operator '" + details::to_str(operation) + "'", + exprtk_error_location)); + return error_node(); } else if (details::e_assign == operation) @@ -27704,10 +32299,22 @@ namespace exprtk { details::free_all_nodes(*node_allocator_,branch); + parser_->set_error(parser_error::make_error( + parser_error::e_syntax, + parser_->current_state().token, + "ERR248 - Invalid branches operator '" + details::to_str(operation) + "'", + exprtk_error_location)); + return error_node(); } else if (is_invalid_string_op(operation, branch)) { + parser_->set_error(parser_error::make_error( + parser_error::e_syntax, + parser_->current_state().token, + "ERR249 - Invalid branches for string operator '" + details::to_str(operation) + "'", + exprtk_error_location)); + return error_node(); } else if (is_string_operation(operation, branch)) @@ -27750,9 +32357,19 @@ namespace exprtk { if ((0 == condition) || (0 == consequent)) { - free_node(*node_allocator_, condition); - free_node(*node_allocator_, consequent); - free_node(*node_allocator_, alternative); + details::free_node(*node_allocator_, condition ); + details::free_node(*node_allocator_, consequent ); + details::free_node(*node_allocator_, alternative); + + const std::string invalid_branches = + ((0 == condition ) ? std::string("condition ") : "") + + ((0 == consequent) ? std::string("consequent") : "") ; + + parser_->set_error(parser_error::make_error( + parser_error::e_parser, + parser_->current_state().token, + "ERR250 - Invalid " + invalid_branches + " for conditional statement", + exprtk_error_location)); return error_node(); } @@ -27762,16 +32379,16 @@ namespace exprtk // True branch if (details::is_true(condition)) { - free_node(*node_allocator_, condition); - free_node(*node_allocator_, alternative); + details::free_node(*node_allocator_, condition ); + details::free_node(*node_allocator_, alternative); return consequent; } // False branch else { - free_node(*node_allocator_, condition); - free_node(*node_allocator_, consequent); + details::free_node(*node_allocator_, condition ); + details::free_node(*node_allocator_, consequent); if (alternative) return alternative; @@ -27779,14 +32396,34 @@ namespace exprtk return node_allocator_->allocate<details::null_node<T> >(); } } - else if ((0 != consequent) && (0 != alternative)) + + expression_node_ptr result = error_node(); + std::string node_name = "Unknown!"; + + if ((0 != consequent) && (0 != alternative)) { - return node_allocator_-> - allocate<conditional_node_t>(condition, consequent, alternative); + result = node_allocator_->allocate<conditional_node_t>(condition, consequent, alternative); + node_name = "conditional_node_t"; } else - return node_allocator_-> - allocate<cons_conditional_node_t>(condition, consequent); + { + result = node_allocator_->allocate<cons_conditional_node_t>(condition, consequent); + node_name = "cons_conditional_node_t"; + } + + if (result && result->valid()) + { + return result; + } + + parser_->set_error(parser_error::make_error( + parser_error::e_parser, + token_t(), + "ERR251 - Failed to synthesize node: " + node_name, + exprtk_error_location)); + + details::free_node(*node_allocator_, result); + return error_node(); } #ifndef exprtk_disable_string_capabilities @@ -27796,9 +32433,19 @@ namespace exprtk { if ((0 == condition) || (0 == consequent)) { - free_node(*node_allocator_, condition); - free_node(*node_allocator_, consequent); - free_node(*node_allocator_, alternative); + details::free_node(*node_allocator_, condition ); + details::free_node(*node_allocator_, consequent ); + details::free_node(*node_allocator_, alternative); + + const std::string invalid_branches = + ((0 == condition ) ? std::string("condition ") : "") + + ((0 == consequent) ? std::string("consequent") : "") ; + + parser_->set_error(parser_error::make_error( + parser_error::e_parser, + parser_->current_state().token, + "ERR252 - Invalid " + invalid_branches + " for string conditional statement", + exprtk_error_location)); return error_node(); } @@ -27808,16 +32455,16 @@ namespace exprtk // True branch if (details::is_true(condition)) { - free_node(*node_allocator_, condition); - free_node(*node_allocator_, alternative); + details::free_node(*node_allocator_, condition ); + details::free_node(*node_allocator_, alternative); return consequent; } // False branch else { - free_node(*node_allocator_, condition); - free_node(*node_allocator_, consequent); + details::free_node(*node_allocator_, condition ); + details::free_node(*node_allocator_, consequent); if (alternative) return alternative; @@ -27827,10 +32474,25 @@ namespace exprtk } } else if ((0 != consequent) && (0 != alternative)) - return node_allocator_-> - allocate<conditional_string_node_t>(condition, consequent, alternative); - else - return error_node(); + { + expression_node_ptr result = + node_allocator_->allocate<conditional_string_node_t>(condition, consequent, alternative); + + if (result && result->valid()) + { + return result; + } + + parser_->set_error(parser_error::make_error( + parser_error::e_parser, + token_t(), + "ERR253 - Failed to synthesize node: conditional_string_node_t", + exprtk_error_location)); + + details::free_node(*node_allocator_, result); + } + + return error_node(); } #else inline expression_node_ptr conditional_string(expression_node_ptr, @@ -27841,6 +32503,61 @@ namespace exprtk } #endif + inline expression_node_ptr conditional_vector(expression_node_ptr condition, + expression_node_ptr consequent, + expression_node_ptr alternative) const + { + if ((0 == condition) || (0 == consequent)) + { + details::free_node(*node_allocator_, condition ); + details::free_node(*node_allocator_, consequent ); + details::free_node(*node_allocator_, alternative); + + const std::string invalid_branches = + ((0 == condition ) ? std::string("condition ") : "") + + ((0 == consequent) ? std::string("consequent") : "") ; + + parser_->set_error(parser_error::make_error( + parser_error::e_parser, + parser_->current_state().token, + "ERR254 - Invalid " + invalid_branches + " for vector conditional statement", + exprtk_error_location)); + + return error_node(); + } + // Can the condition be immediately evaluated? if so optimise. + else if (details::is_constant_node(condition)) + { + // True branch + if (details::is_true(condition)) + { + details::free_node(*node_allocator_, condition ); + details::free_node(*node_allocator_, alternative); + + return consequent; + } + // False branch + else + { + details::free_node(*node_allocator_, condition ); + details::free_node(*node_allocator_, consequent); + + if (alternative) + return alternative; + else + return node_allocator_->allocate<details::null_node<T> >(); + + } + } + else if ((0 != consequent) && (0 != alternative)) + { + return node_allocator_-> + allocate<conditional_vector_node_t>(condition, consequent, alternative); + } + else + return error_node(); + } + inline loop_runtime_check_ptr get_loop_runtime_check(const loop_runtime_check::loop_types loop_type) const { if ( @@ -27854,45 +32571,70 @@ namespace exprtk return loop_runtime_check_ptr(0); } + inline vector_access_runtime_check_ptr get_vector_access_runtime_check() const + { + return parser_->vector_access_runtime_check_; + } + inline expression_node_ptr while_loop(expression_node_ptr& condition, expression_node_ptr& branch, - const bool brkcont = false) const + const bool break_continue_present = false) const { - if (!brkcont && details::is_constant_node(condition)) + if ( + !break_continue_present && + !parser_->state_.return_stmt_present && + details::is_constant_node(condition) + ) { expression_node_ptr result = error_node(); if (details::is_true(condition)) + { // Infinite loops are not allowed. + + parser_->set_error(parser_error::make_error( + parser_error::e_parser, + parser_->current_state().token, + "ERR255 - Infinite loop condition without 'break' or 'return' not allowed in while-loops", + exprtk_error_location)); + result = error_node(); + } else result = node_allocator_->allocate<details::null_node<Type> >(); - free_node(*node_allocator_, condition); - free_node(*node_allocator_, branch); + details::free_node(*node_allocator_, condition); + details::free_node(*node_allocator_, branch ); return result; } else if (details::is_null_node(condition)) { - free_node(*node_allocator_,condition); + details::free_node(*node_allocator_,condition); return branch; } - else if (!brkcont) - return node_allocator_->allocate<while_loop_node_t> - ( - condition, - branch, - get_loop_runtime_check(loop_runtime_check::e_while_loop) - ); + + loop_runtime_check_ptr rtc = get_loop_runtime_check(loop_runtime_check::e_while_loop); + + if (!break_continue_present) + { + if (rtc) + return node_allocator_->allocate<while_loop_rtc_node_t> + (condition, branch, rtc); + else + return node_allocator_->allocate<while_loop_node_t> + (condition, branch); + } #ifndef exprtk_disable_break_continue else - return node_allocator_->allocate<while_loop_bc_node_t> - ( - condition, - branch, - get_loop_runtime_check(loop_runtime_check::e_while_loop) - ); + { + if (rtc) + return node_allocator_->allocate<while_loop_bc_rtc_node_t> + (condition, branch, rtc); + else + return node_allocator_->allocate<while_loop_bc_node_t> + (condition, branch); + } #else return error_node(); #endif @@ -27900,9 +32642,9 @@ namespace exprtk inline expression_node_ptr repeat_until_loop(expression_node_ptr& condition, expression_node_ptr& branch, - const bool brkcont = false) const + const bool break_continue_present = false) const { - if (!brkcont && details::is_constant_node(condition)) + if (!break_continue_present && details::is_constant_node(condition)) { if ( details::is_true(condition) && @@ -27914,32 +32656,39 @@ namespace exprtk return branch; } - free_node(*node_allocator_, condition); - free_node(*node_allocator_, branch); + details::free_node(*node_allocator_, condition); + details::free_node(*node_allocator_, branch ); return error_node(); } else if (details::is_null_node(condition)) { - free_node(*node_allocator_,condition); + details::free_node(*node_allocator_,condition); return branch; } - else if (!brkcont) - return node_allocator_->allocate<repeat_until_loop_node_t> - ( - condition, - branch, - get_loop_runtime_check(loop_runtime_check::e_repeat_until_loop) - ); + + loop_runtime_check_ptr rtc = get_loop_runtime_check(loop_runtime_check::e_repeat_until_loop); + + if (!break_continue_present) + { + if (rtc) + return node_allocator_->allocate<repeat_until_loop_rtc_node_t> + (condition, branch, rtc); + else + return node_allocator_->allocate<repeat_until_loop_node_t> + (condition, branch); + } #ifndef exprtk_disable_break_continue else - return node_allocator_->allocate<repeat_until_loop_bc_node_t> - ( - condition, - branch, - get_loop_runtime_check(loop_runtime_check::e_repeat_until_loop) - ); + { + if (rtc) + return node_allocator_->allocate<repeat_until_loop_bc_rtc_node_t> + (condition, branch, rtc); + else + return node_allocator_->allocate<repeat_until_loop_bc_node_t> + (condition, branch); + } #else return error_node(); #endif @@ -27949,55 +32698,92 @@ namespace exprtk expression_node_ptr& condition, expression_node_ptr& incrementor, expression_node_ptr& loop_body, - bool brkcont = false) const + bool break_continue_present = false) const { - if (!brkcont && details::is_constant_node(condition)) + if ( + !break_continue_present && + !parser_->state_.return_stmt_present && + details::is_constant_node(condition) + ) { expression_node_ptr result = error_node(); if (details::is_true(condition)) + { // Infinite loops are not allowed. + + parser_->set_error(parser_error::make_error( + parser_error::e_parser, + parser_->current_state().token, + "ERR256 - Infinite loop condition without 'break' or 'return' not allowed in for-loop", + exprtk_error_location)); + result = error_node(); + } else result = node_allocator_->allocate<details::null_node<Type> >(); - free_node(*node_allocator_, initialiser); - free_node(*node_allocator_, condition); - free_node(*node_allocator_, incrementor); - free_node(*node_allocator_, loop_body); + details::free_node(*node_allocator_, initialiser); + details::free_node(*node_allocator_, condition ); + details::free_node(*node_allocator_, incrementor); + details::free_node(*node_allocator_, loop_body ); return result; } else if (details::is_null_node(condition) || (0 == condition)) { - free_node(*node_allocator_, initialiser); - free_node(*node_allocator_, condition); - free_node(*node_allocator_, incrementor); + details::free_node(*node_allocator_, initialiser); + details::free_node(*node_allocator_, condition ); + details::free_node(*node_allocator_, incrementor); return loop_body; } - else if (!brkcont) - return node_allocator_->allocate<for_loop_node_t> - ( - initialiser, - condition, - incrementor, - loop_body, - get_loop_runtime_check(loop_runtime_check::e_for_loop) - ); + loop_runtime_check_ptr rtc = get_loop_runtime_check(loop_runtime_check::e_for_loop); + + if (!break_continue_present) + { + if (rtc) + return node_allocator_->allocate<for_loop_rtc_node_t> + ( + initialiser, + condition, + incrementor, + loop_body, + rtc + ); + else + return node_allocator_->allocate<for_loop_node_t> + ( + initialiser, + condition, + incrementor, + loop_body + ); + } #ifndef exprtk_disable_break_continue else - return node_allocator_->allocate<for_loop_bc_node_t> - ( - initialiser, - condition, - incrementor, - loop_body, - get_loop_runtime_check(loop_runtime_check::e_for_loop) - ); + { + if (rtc) + return node_allocator_->allocate<for_loop_bc_rtc_node_t> + ( + initialiser, + condition, + incrementor, + loop_body, + rtc + ); + else + return node_allocator_->allocate<for_loop_bc_node_t> + ( + initialiser, + condition, + incrementor, + loop_body + ); + } #else - return error_node(); + return error_node(); #endif } @@ -28056,8 +32842,8 @@ namespace exprtk if (0 == result) { - T zero = T(0); - result = node_allocator_->allocate<literal_node_t>(zero); + const T zero = T(0); + result = node_allocator_->allocate<literal_node_t>(zero); } for (std::size_t i = 0; i < arg_list.size(); ++i) @@ -28066,7 +32852,7 @@ namespace exprtk if (current_expr && (current_expr != result)) { - free_node(*node_allocator_,current_expr); + details::free_node(*node_allocator_,current_expr); } } @@ -28080,49 +32866,57 @@ namespace exprtk #define case_stmt(N) \ if (is_true(arg[(2 * N)].first)) { return arg[(2 * N) + 1].first->value(); } \ - struct switch_1 + struct switch_impl_1 { static inline T process(const arg_list_t& arg) { case_stmt(0) + assert(arg.size() == ((2 * 1) + 1)); + return arg.back().first->value(); } }; - struct switch_2 + struct switch_impl_2 { static inline T process(const arg_list_t& arg) { case_stmt(0) case_stmt(1) + assert(arg.size() == ((2 * 2) + 1)); + return arg.back().first->value(); } }; - struct switch_3 + struct switch_impl_3 { static inline T process(const arg_list_t& arg) { case_stmt(0) case_stmt(1) case_stmt(2) + assert(arg.size() == ((2 * 3) + 1)); + return arg.back().first->value(); } }; - struct switch_4 + struct switch_impl_4 { static inline T process(const arg_list_t& arg) { case_stmt(0) case_stmt(1) case_stmt(2) case_stmt(3) + assert(arg.size() == ((2 * 4) + 1)); + return arg.back().first->value(); } }; - struct switch_5 + struct switch_impl_5 { static inline T process(const arg_list_t& arg) { @@ -28130,11 +32924,13 @@ namespace exprtk case_stmt(2) case_stmt(3) case_stmt(4) + assert(arg.size() == ((2 * 5) + 1)); + return arg.back().first->value(); } }; - struct switch_6 + struct switch_impl_6 { static inline T process(const arg_list_t& arg) { @@ -28142,11 +32938,13 @@ namespace exprtk case_stmt(2) case_stmt(3) case_stmt(4) case_stmt(5) + assert(arg.size() == ((2 * 6) + 1)); + return arg.back().first->value(); } }; - struct switch_7 + struct switch_impl_7 { static inline T process(const arg_list_t& arg) { @@ -28155,6 +32953,8 @@ namespace exprtk case_stmt(4) case_stmt(5) case_stmt(6) + assert(arg.size() == ((2 * 7) + 1)); + return arg.back().first->value(); } }; @@ -28182,11 +32982,11 @@ namespace exprtk switch ((arg_list.size() - 1) / 2) { - #define case_stmt(N) \ - case N : \ - return node_allocator_-> \ - allocate<details::switch_n_node \ - <Type,typename switch_nodes::switch_##N> >(arg_list); \ + #define case_stmt(N) \ + case N : \ + return node_allocator_-> \ + allocate<details::switch_n_node \ + <Type,typename switch_nodes::switch_impl_##N > >(arg_list); \ case_stmt(1) case_stmt(2) @@ -28217,47 +33017,69 @@ namespace exprtk return node_allocator_->allocate<details::multi_switch_node<Type> >(arg_list); } - #define unary_opr_switch_statements \ - case_stmt(details:: e_abs, details:: abs_op) \ - case_stmt(details:: e_acos, details:: acos_op) \ - case_stmt(details::e_acosh, details::acosh_op) \ - case_stmt(details:: e_asin, details:: asin_op) \ - case_stmt(details::e_asinh, details::asinh_op) \ - case_stmt(details:: e_atan, details:: atan_op) \ - case_stmt(details::e_atanh, details::atanh_op) \ - case_stmt(details:: e_ceil, details:: ceil_op) \ - case_stmt(details:: e_cos, details:: cos_op) \ - case_stmt(details:: e_cosh, details:: cosh_op) \ - case_stmt(details:: e_exp, details:: exp_op) \ - case_stmt(details::e_expm1, details::expm1_op) \ - case_stmt(details::e_floor, details::floor_op) \ - case_stmt(details:: e_log, details:: log_op) \ - case_stmt(details::e_log10, details::log10_op) \ - case_stmt(details:: e_log2, details:: log2_op) \ - case_stmt(details::e_log1p, details::log1p_op) \ - case_stmt(details:: e_neg, details:: neg_op) \ - case_stmt(details:: e_pos, details:: pos_op) \ - case_stmt(details::e_round, details::round_op) \ - case_stmt(details:: e_sin, details:: sin_op) \ - case_stmt(details:: e_sinc, details:: sinc_op) \ - case_stmt(details:: e_sinh, details:: sinh_op) \ - case_stmt(details:: e_sqrt, details:: sqrt_op) \ - case_stmt(details:: e_tan, details:: tan_op) \ - case_stmt(details:: e_tanh, details:: tanh_op) \ - case_stmt(details:: e_cot, details:: cot_op) \ - case_stmt(details:: e_sec, details:: sec_op) \ - case_stmt(details:: e_csc, details:: csc_op) \ - case_stmt(details:: e_r2d, details:: r2d_op) \ - case_stmt(details:: e_d2r, details:: d2r_op) \ - case_stmt(details:: e_d2g, details:: d2g_op) \ - case_stmt(details:: e_g2d, details:: g2d_op) \ - case_stmt(details:: e_notl, details:: notl_op) \ - case_stmt(details:: e_sgn, details:: sgn_op) \ - case_stmt(details:: e_erf, details:: erf_op) \ - case_stmt(details:: e_erfc, details:: erfc_op) \ - case_stmt(details:: e_ncdf, details:: ncdf_op) \ - case_stmt(details:: e_frac, details:: frac_op) \ - case_stmt(details::e_trunc, details::trunc_op) \ + inline expression_node_ptr assert_call(expression_node_ptr& assert_condition, + expression_node_ptr& assert_message, + const assert_check::assert_context& context) + { + typedef details::assert_node<Type> alloc_type; + + expression_node_ptr result = node_allocator_->allocate_rrrr<alloc_type> + (assert_condition, assert_message, parser_->assert_check_, context); + + if (result && result->valid()) + { + parser_->state_.activate_side_effect("assert_call()"); + return result; + } + + details::free_node(*node_allocator_, result ); + details::free_node(*node_allocator_, assert_condition); + details::free_node(*node_allocator_, assert_message ); + + return error_node(); + } + + #define unary_opr_switch_statements \ + case_stmt(details::e_abs , details::abs_op ) \ + case_stmt(details::e_acos , details::acos_op ) \ + case_stmt(details::e_acosh , details::acosh_op) \ + case_stmt(details::e_asin , details::asin_op ) \ + case_stmt(details::e_asinh , details::asinh_op) \ + case_stmt(details::e_atan , details::atan_op ) \ + case_stmt(details::e_atanh , details::atanh_op) \ + case_stmt(details::e_ceil , details::ceil_op ) \ + case_stmt(details::e_cos , details::cos_op ) \ + case_stmt(details::e_cosh , details::cosh_op ) \ + case_stmt(details::e_exp , details::exp_op ) \ + case_stmt(details::e_expm1 , details::expm1_op) \ + case_stmt(details::e_floor , details::floor_op) \ + case_stmt(details::e_log , details::log_op ) \ + case_stmt(details::e_log10 , details::log10_op) \ + case_stmt(details::e_log2 , details::log2_op ) \ + case_stmt(details::e_log1p , details::log1p_op) \ + case_stmt(details::e_neg , details::neg_op ) \ + case_stmt(details::e_pos , details::pos_op ) \ + case_stmt(details::e_round , details::round_op) \ + case_stmt(details::e_sin , details::sin_op ) \ + case_stmt(details::e_sinc , details::sinc_op ) \ + case_stmt(details::e_sinh , details::sinh_op ) \ + case_stmt(details::e_sqrt , details::sqrt_op ) \ + case_stmt(details::e_tan , details::tan_op ) \ + case_stmt(details::e_tanh , details::tanh_op ) \ + case_stmt(details::e_cot , details::cot_op ) \ + case_stmt(details::e_sec , details::sec_op ) \ + case_stmt(details::e_csc , details::csc_op ) \ + case_stmt(details::e_r2d , details::r2d_op ) \ + case_stmt(details::e_d2r , details::d2r_op ) \ + case_stmt(details::e_d2g , details::d2g_op ) \ + case_stmt(details::e_g2d , details::g2d_op ) \ + case_stmt(details::e_notl , details::notl_op ) \ + case_stmt(details::e_sgn , details::sgn_op ) \ + case_stmt(details::e_erf , details::erf_op ) \ + case_stmt(details::e_erfc , details::erfc_op ) \ + case_stmt(details::e_ncdf , details::ncdf_op ) \ + case_stmt(details::e_frac , details::frac_op ) \ + case_stmt(details::e_trunc , details::trunc_op) \ inline expression_node_ptr synthesize_uv_expression(const details::operator_type& operation, expression_node_ptr (&branch)[1]) @@ -28266,7 +33088,7 @@ namespace exprtk switch (operation) { - #define case_stmt(op0,op1) \ + #define case_stmt(op0, op1) \ case op0 : return node_allocator_-> \ allocate<typename details::unary_variable_node<Type,op1<Type> > >(v); \ @@ -28281,7 +33103,7 @@ namespace exprtk { switch (operation) { - #define case_stmt(op0,op1) \ + #define case_stmt(op0, op1) \ case op0 : return node_allocator_-> \ allocate<typename details::unary_vector_node<Type,op1<Type> > > \ (operation, branch[0]); \ @@ -28297,7 +33119,7 @@ namespace exprtk { switch (operation) { - #define case_stmt(op0,op1) \ + #define case_stmt(op0, op1) \ case op0 : return node_allocator_-> \ allocate<typename details::unary_branch_node<Type,op1<Type> > >(branch[0]); \ @@ -28336,6 +33158,8 @@ namespace exprtk default : return error_node(); } + assert(temp_node); + const T v = temp_node->value(); details::free_node(*node_allocator_,temp_node); @@ -28439,6 +33263,8 @@ namespace exprtk default : return error_node(); } + assert(temp_node); + const T v = temp_node->value(); details::free_node(*node_allocator_,temp_node); @@ -28521,7 +33347,7 @@ namespace exprtk switch (operation) { - #define case_stmt(op0,op1) \ + #define case_stmt(op0, op1) \ case op0 : temp_node = node_allocator_-> \ allocate<details::vararg_node<Type,op1<Type> > > \ (arg_list); \ @@ -28559,11 +33385,12 @@ namespace exprtk template <typename Allocator, template <typename, typename> class Sequence> - inline expression_node_ptr varnode_optimise_varargfunc(const details::operator_type& operation, Sequence<expression_node_ptr,Allocator>& arg_list) + inline expression_node_ptr varnode_optimise_varargfunc(const details::operator_type& operation, + Sequence<expression_node_ptr,Allocator>& arg_list) { switch (operation) { - #define case_stmt(op0,op1) \ + #define case_stmt(op0, op1) \ case op0 : return node_allocator_-> \ allocate<details::vararg_varnode<Type,op1<Type> > >(arg_list); \ @@ -28582,13 +33409,14 @@ namespace exprtk template <typename Allocator, template <typename, typename> class Sequence> - inline expression_node_ptr vectorize_func(const details::operator_type& operation, Sequence<expression_node_ptr,Allocator>& arg_list) + inline expression_node_ptr vectorize_func(const details::operator_type& operation, + Sequence<expression_node_ptr,Allocator>& arg_list) { if (1 == arg_list.size()) { switch (operation) { - #define case_stmt(op0,op1) \ + #define case_stmt(op0, op1) \ case op0 : return node_allocator_-> \ allocate<details::vectorize_node<Type,op1<Type> > >(arg_list[0]); \ @@ -28607,7 +33435,8 @@ namespace exprtk template <typename Allocator, template <typename, typename> class Sequence> - inline expression_node_ptr vararg_function(const details::operator_type& operation, Sequence<expression_node_ptr,Allocator>& arg_list) + inline expression_node_ptr vararg_function(const details::operator_type& operation, + Sequence<expression_node_ptr,Allocator>& arg_list) { if (!all_nodes_valid(arg_list)) { @@ -28617,9 +33446,9 @@ namespace exprtk } else if (is_constant_foldable(arg_list)) return const_optimise_varargfunc(operation,arg_list); - else if ((arg_list.size() == 1) && details::is_ivector_node(arg_list[0])) + else if ((1 == arg_list.size()) && details::is_ivector_node(arg_list[0])) return vectorize_func(operation,arg_list); - else if ((arg_list.size() == 1) && special_one_parameter_vararg(operation)) + else if ((1 == arg_list.size()) && special_one_parameter_vararg(operation)) return arg_list[0]; else if (all_nodes_variables(arg_list)) return varnode_optimise_varargfunc(operation,arg_list); @@ -28627,17 +33456,32 @@ namespace exprtk #ifndef exprtk_disable_string_capabilities if (details::e_smulti == operation) { - return node_allocator_-> + expression_node_ptr result = node_allocator_-> allocate<details::str_vararg_node<Type,details::vararg_multi_op<Type> > >(arg_list); + if (result && result->valid()) + { + return result; + } + + parser_->set_error(parser_error::make_error( + parser_error::e_synthesis, + token_t(), + "ERR257 - Failed to synthesize node: str_vararg_node<vararg_multi_op>", + exprtk_error_location)); + + details::free_node(*node_allocator_, result); } else #endif { + expression_node_ptr result = error_node(); + switch (operation) { - #define case_stmt(op0,op1) \ - case op0 : return node_allocator_-> \ + #define case_stmt(op0, op1) \ + case op0 : result = node_allocator_-> \ allocate<details::vararg_node<Type,op1<Type> > >(arg_list); \ + break; \ case_stmt(details::e_sum , details::vararg_add_op ) case_stmt(details::e_prod , details::vararg_mul_op ) @@ -28650,7 +33494,22 @@ namespace exprtk #undef case_stmt default : return error_node(); } + + if (result && result->valid()) + { + return result; + } + + parser_->set_error(parser_error::make_error( + parser_error::e_synthesis, + token_t(), + "ERR258 - Failed to synthesize node: vararg_node", + exprtk_error_location)); + + details::free_node(*node_allocator_, result); } + + return error_node(); } template <std::size_t N> @@ -28691,7 +33550,19 @@ namespace exprtk return error_node(); } - return result; + if (result && result->valid()) + { + return result; + } + + parser_->set_error(parser_error::make_error( + parser_error::e_synthesis, + token_t(), + "ERR259 - Failed to synthesize node: function_N_node_t", + exprtk_error_location)); + + details::free_node(*node_allocator_, result); + return error_node(); } } @@ -28728,7 +33599,19 @@ namespace exprtk parser_->state_.activate_side_effect("vararg_function_call()"); - return result; + if (result && result->valid()) + { + return result; + } + + parser_->set_error(parser_error::make_error( + parser_error::e_synthesis, + token_t(), + "ERR260 - Failed to synthesize node: vararg_function_node<ivararg_function_t>", + exprtk_error_location)); + + details::free_node(*node_allocator_, result); + return error_node(); } inline expression_node_ptr generic_function_call(igeneric_function_t* gf, @@ -28747,14 +33630,23 @@ namespace exprtk const std::size_t no_psi = std::numeric_limits<std::size_t>::max(); expression_node_ptr result = error_node(); + std::string node_name = "Unknown"; if (no_psi == param_seq_index) + { result = node_allocator_->allocate<alloc_type1>(arg_list,gf); + node_name = "generic_function_node<igeneric_function_t>"; + } else + { result = node_allocator_->allocate<alloc_type2>(gf, param_seq_index, arg_list); + node_name = "multimode_genfunction_node<igeneric_function_t>"; + } alloc_type1* genfunc_node_ptr = static_cast<alloc_type1*>(result); + assert(genfunc_node_ptr); + if ( !arg_list.empty() && !gf->has_side_effects() && @@ -28772,9 +33664,20 @@ namespace exprtk } else if (genfunc_node_ptr->init_branches()) { - parser_->state_.activate_side_effect("generic_function_call()"); + if (result && result->valid()) + { + parser_->state_.activate_side_effect("generic_function_call()"); + return result; + } - return result; + parser_->set_error(parser_error::make_error( + parser_error::e_synthesis, + token_t(), + "ERR261 - Failed to synthesize node: " + node_name, + exprtk_error_location)); + + details::free_node(*node_allocator_, result); + return error_node(); } else { @@ -28802,14 +33705,23 @@ namespace exprtk const std::size_t no_psi = std::numeric_limits<std::size_t>::max(); expression_node_ptr result = error_node(); + std::string node_name = "Unknown"; if (no_psi == param_seq_index) + { result = node_allocator_->allocate<alloc_type1>(gf,arg_list); + node_name = "string_function_node<igeneric_function_t>"; + } else + { result = node_allocator_->allocate<alloc_type2>(gf, param_seq_index, arg_list); + node_name = "multimode_strfunction_node<igeneric_function_t>"; + } alloc_type1* strfunc_node_ptr = static_cast<alloc_type1*>(result); + assert(strfunc_node_ptr); + if ( !arg_list.empty() && !gf->has_side_effects() && @@ -28826,9 +33738,20 @@ namespace exprtk } else if (strfunc_node_ptr->init_branches()) { - parser_->state_.activate_side_effect("string_function_call()"); + if (result && result->valid()) + { + parser_->state_.activate_side_effect("string_function_call()"); + return result; + } - return result; + parser_->set_error(parser_error::make_error( + parser_error::e_synthesis, + token_t(), + "ERR262 - Failed to synthesize node: " + node_name, + exprtk_error_location)); + + details::free_node(*node_allocator_, result); + return error_node(); } else { @@ -28856,16 +33779,29 @@ namespace exprtk alloc_type* return_node_ptr = static_cast<alloc_type*>(result); + assert(return_node_ptr); + if (return_node_ptr->init_branches()) { - parser_->state_.activate_side_effect("return_call()"); + if (result && result->valid()) + { + parser_->state_.activate_side_effect("return_call()"); + return result; + } - return result; + parser_->set_error(parser_error::make_error( + parser_error::e_synthesis, + token_t(), + "ERR263 - Failed to synthesize node: return_node", + exprtk_error_location)); + + details::free_node(*node_allocator_, result); + return error_node(); } else { - details::free_node (*node_allocator_,result ); - details::free_all_nodes(*node_allocator_,arg_list); + details::free_node (*node_allocator_, result ); + details::free_all_nodes(*node_allocator_, arg_list); return error_node(); } @@ -28898,28 +33834,93 @@ namespace exprtk } #endif - inline expression_node_ptr vector_element(const std::string& symbol, - vector_holder_ptr vector_base, + inline expression_node_ptr vector_element(const std::string& symbol, + vector_holder_ptr vector_base, + expression_node_ptr vec_node, expression_node_ptr index) { expression_node_ptr result = error_node(); + std::string node_name = "Unknown"; if (details::is_constant_node(index)) { - std::size_t i = static_cast<std::size_t>(details::numeric::to_int64(index->value())); + const std::size_t vec_index = static_cast<std::size_t>(details::numeric::to_int64(index->value())); details::free_node(*node_allocator_,index); + if (vec_index >= vector_base->size()) + { + parser_->set_error(parser_error::make_error( + parser_error::e_parser, + token_t(), + "ERR264 - Index of " + details::to_str(vec_index) + " out of range for " + "vector '" + symbol + "' of size " + details::to_str(vector_base->size()), + exprtk_error_location)); + + details::free_node(*node_allocator_,vec_node); + + return error_node(); + } + if (vector_base->rebaseable()) { - return node_allocator_->allocate<rebasevector_celem_node_t>(i,vector_base); + vector_access_runtime_check_ptr rtc = get_vector_access_runtime_check(); + + result = (rtc) ? + node_allocator_->allocate<rebasevector_celem_rtc_node_t>(vec_node, vec_index, vector_base, rtc) : + node_allocator_->allocate<rebasevector_celem_node_t >(vec_node, vec_index, vector_base ) ; + + node_name = (rtc) ? + "rebasevector_elem_rtc_node_t" : + "rebasevector_elem_node_t" ; + + if (result && result->valid()) + { + return result; + } + + parser_->set_error(parser_error::make_error( + parser_error::e_synthesis, + token_t(), + "ERR265 - Failed to synthesize node: " + node_name + " for vector: " + symbol, + exprtk_error_location)); + + details::free_node(*node_allocator_, result); + return error_node(); + } + else if (details::is_ivector_node(vec_node) && !details::is_vector_node(vec_node)) + { + vector_access_runtime_check_ptr rtc = get_vector_access_runtime_check(); + + result = (rtc) ? + node_allocator_->allocate<vector_celem_rtc_node_t>(vec_node, vec_index, vector_base, rtc) : + node_allocator_->allocate<vector_celem_node_t >(vec_node, vec_index, vector_base ) ; + + node_name = (rtc) ? + "vector_elem_rtc_node_t" : + "vector_elem_node_t" ; + + if (result && result->valid()) + { + return result; + } + + parser_->set_error(parser_error::make_error( + parser_error::e_synthesis, + token_t(), + "ERR266 - Failed to synthesize node: " + node_name + " for vector: " + symbol, + exprtk_error_location)); + + details::free_node(*node_allocator_, result); + return error_node(); } - const scope_element& se = parser_->sem_.get_element(symbol,i); + const scope_element& se = parser_->sem_.get_element(symbol,vec_index); - if (se.index == i) + if (se.index == vec_index) { result = se.var_node; + details::free_node(*node_allocator_,vec_node); } else { @@ -28928,10 +33929,10 @@ namespace exprtk nse.active = true; nse.ref_count = 1; nse.type = scope_element::e_vecelem; - nse.index = i; + nse.index = vec_index; nse.depth = parser_->state_.scope_depth; nse.data = 0; - nse.var_node = node_allocator_->allocate<variable_node_t>((*(*vector_base)[i])); + nse.var_node = node_allocator_->allocate<variable_node_t>((*(*vector_base)[vec_index])); if (!parser_->sem_.add_element(nse)) { @@ -28942,19 +33943,55 @@ namespace exprtk result = error_node(); } - exprtk_debug(("vector_element() - INFO - Added new local vector element: %s\n",nse.name.c_str())); + details::free_node(*node_allocator_,vec_node); + + exprtk_debug(("vector_element() - INFO - Added new local vector element: %s\n", nse.name.c_str())); parser_->state_.activate_side_effect("vector_element()"); result = nse.var_node; + node_name = "variable_node_t"; } } - else if (vector_base->rebaseable()) - result = node_allocator_->allocate<rebasevector_elem_node_t>(index,vector_base); else - result = node_allocator_->allocate<vector_elem_node_t>(index,vector_base); + { + vector_access_runtime_check_ptr rtc = get_vector_access_runtime_check(); - return result; + if (vector_base->rebaseable()) + { + result = (rtc) ? + node_allocator_->allocate<rebasevector_elem_rtc_node_t>(vec_node, index, vector_base, rtc) : + node_allocator_->allocate<rebasevector_elem_node_t >(vec_node, index, vector_base ) ; + + node_name = (rtc) ? + "rebasevector_elem_rtc_node_t" : + "rebasevector_elem_node_t" ; + } + else + { + result = rtc ? + node_allocator_->allocate<vector_elem_rtc_node_t>(vec_node, index, vector_base, rtc) : + node_allocator_->allocate<vector_elem_node_t >(vec_node, index, vector_base ) ; + + node_name = (rtc) ? + "vector_elem_rtc_node_t" : + "vector_elem_node_t" ; + } + } + + if (result && result->valid()) + { + return result; + } + + parser_->set_error(parser_error::make_error( + parser_error::e_synthesis, + token_t(), + "ERR267 - Failed to synthesize node: " + node_name, + exprtk_error_location)); + + details::free_node(*node_allocator_, result); + return error_node(); } private: @@ -29039,43 +34076,130 @@ namespace exprtk } } + const void* base_ptr(expression_node_ptr node) + { + if (node) + { + switch(node->type()) + { + case details::expression_node<T>::e_variable: + return reinterpret_cast<const void*>(&static_cast<variable_node_t*>(node)->ref()); + + case details::expression_node<T>::e_vecelem: + return reinterpret_cast<const void*>(&static_cast<vector_elem_node_t*>(node)->ref()); + + case details::expression_node<T>::e_veccelem: + return reinterpret_cast<const void*>(&static_cast<vector_celem_node_t*>(node)->ref()); + + case details::expression_node<T>::e_vecelemrtc: + return reinterpret_cast<const void*>(&static_cast<vector_elem_rtc_node_t*>(node)->ref()); + + case details::expression_node<T>::e_veccelemrtc: + return reinterpret_cast<const void*>(&static_cast<vector_celem_rtc_node_t*>(node)->ref()); + + case details::expression_node<T>::e_rbvecelem: + return reinterpret_cast<const void*>(&static_cast<rebasevector_elem_node_t*>(node)->ref()); + + case details::expression_node<T>::e_rbvecelemrtc: + return reinterpret_cast<const void*>(&static_cast<rebasevector_elem_rtc_node_t*>(node)->ref()); + + case details::expression_node<T>::e_rbveccelem: + return reinterpret_cast<const void*>(&static_cast<rebasevector_celem_node_t*>(node)->ref()); + + case details::expression_node<T>::e_rbveccelemrtc: + return reinterpret_cast<const void*>(&static_cast<rebasevector_celem_rtc_node_t*>(node)->ref()); + + case details::expression_node<T>::e_vector: + return reinterpret_cast<const void*>(static_cast<vector_node_t*>(node)->vec_holder().data()); + + #ifndef exprtk_disable_string_capabilities + case details::expression_node<T>::e_stringvar: + return reinterpret_cast<const void*>((static_cast<stringvar_node_t*>(node)->base())); + + case details::expression_node<T>::e_stringvarrng: + return reinterpret_cast<const void*>((static_cast<string_range_node_t*>(node)->base())); + #endif + default : return reinterpret_cast<const void*>(0); + } + } + + return reinterpret_cast<const void*>(0); + } + + bool assign_immutable_symbol(expression_node_ptr node) + { + interval_t interval; + const void* baseptr_addr = base_ptr(node); + + exprtk_debug(("assign_immutable_symbol - base ptr addr: %p\n", baseptr_addr)); + + if (parser_->immutable_memory_map_.in_interval(baseptr_addr,interval)) + { + typename immutable_symtok_map_t::iterator itr = parser_->immutable_symtok_map_.find(interval); + + if (parser_->immutable_symtok_map_.end() != itr) + { + token_t& token = itr->second; + parser_->set_error(parser_error::make_error( + parser_error::e_parser, + token, + "ERR268 - Symbol '" + token.value + "' cannot be assigned-to as it is immutable.", + exprtk_error_location)); + } + else + parser_->set_synthesis_error("Unable to assign symbol is immutable."); + + return true; + } + + return false; + } + inline expression_node_ptr synthesize_assignment_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) { - if (details::is_variable_node(branch[0])) + if (assign_immutable_symbol(branch[0])) + { + return error_node(); + } + else if (details::is_variable_node(branch[0])) { lodge_assignment(e_st_variable,branch[0]); - return synthesize_expression<assignment_node_t,2>(operation,branch); } - else if (details::is_vector_elem_node(branch[0])) + else if (details::is_vector_elem_node(branch[0]) || details::is_vector_celem_node(branch[0])) { lodge_assignment(e_st_vecelem,branch[0]); - return synthesize_expression<assignment_vec_elem_node_t, 2>(operation, branch); } + else if (details::is_vector_elem_rtc_node(branch[0]) || details::is_vector_celem_rtc_node(branch[0])) + { + lodge_assignment(e_st_vecelem,branch[0]); + return synthesize_expression<assignment_vec_elem_rtc_node_t, 2>(operation, branch); + } else if (details::is_rebasevector_elem_node(branch[0])) { lodge_assignment(e_st_vecelem,branch[0]); - return synthesize_expression<assignment_rebasevec_elem_node_t, 2>(operation, branch); } + else if (details::is_rebasevector_elem_rtc_node(branch[0])) + { + lodge_assignment(e_st_vecelem,branch[0]); + return synthesize_expression<assignment_rebasevec_elem_rtc_node_t, 2>(operation, branch); + } else if (details::is_rebasevector_celem_node(branch[0])) { lodge_assignment(e_st_vecelem,branch[0]); - return synthesize_expression<assignment_rebasevec_celem_node_t, 2>(operation, branch); } #ifndef exprtk_disable_string_capabilities else if (details::is_string_node(branch[0])) { lodge_assignment(e_st_string,branch[0]); - return synthesize_expression<assignment_string_node_t,2>(operation, branch); } else if (details::is_string_range_node(branch[0])) { lodge_assignment(e_st_string,branch[0]); - return synthesize_expression<assignment_string_range_node_t,2>(operation, branch); } #endif @@ -29085,12 +34209,26 @@ namespace exprtk if (details::is_ivector_node(branch[1])) return synthesize_expression<assignment_vecvec_node_t,2>(operation, branch); - else + else return synthesize_expression<assignment_vec_node_t,2>(operation, branch); } + else if (details::is_literal_node(branch[0])) + { + parser_->set_error(parser_error::make_error( + parser_error::e_syntax, + parser_->current_state().token, + "ERR269 - Cannot assign value to const variable", + exprtk_error_location)); + + return error_node(); + } else { - parser_->set_synthesis_error("Invalid assignment operation.[1]"); + parser_->set_error(parser_error::make_error( + parser_error::e_syntax, + parser_->current_state().token, + "ERR270 - Invalid branches for assignment operator '" + details::to_str(operation) + "'", + exprtk_error_location)); return error_node(); } @@ -29099,22 +34237,32 @@ namespace exprtk inline expression_node_ptr synthesize_assignment_operation_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) { + if (assign_immutable_symbol(branch[0])) + { + return error_node(); + } + + expression_node_ptr result = error_node(); + std::string node_name = "Unknown"; + if (details::is_variable_node(branch[0])) { lodge_assignment(e_st_variable,branch[0]); switch (operation) { - #define case_stmt(op0,op1) \ - case op0 : return node_allocator_-> \ + #define case_stmt(op0, op1) \ + case op0 : result = node_allocator_-> \ template allocate_rrr<typename details::assignment_op_node<Type,op1<Type> > > \ (operation, branch[0], branch[1]); \ - - case_stmt(details::e_addass,details::add_op) - case_stmt(details::e_subass,details::sub_op) - case_stmt(details::e_mulass,details::mul_op) - case_stmt(details::e_divass,details::div_op) - case_stmt(details::e_modass,details::mod_op) + node_name = "assignment_op_node"; \ + break; \ + + case_stmt(details::e_addass , details::add_op) + case_stmt(details::e_subass , details::sub_op) + case_stmt(details::e_mulass , details::mul_op) + case_stmt(details::e_divass , details::div_op) + case_stmt(details::e_modass , details::mod_op) #undef case_stmt default : return error_node(); } @@ -29125,16 +34273,62 @@ namespace exprtk switch (operation) { - #define case_stmt(op0,op1) \ - case op0 : return node_allocator_-> \ + #define case_stmt(op0, op1) \ + case op0 : result = node_allocator_-> \ template allocate_rrr<typename details::assignment_vec_elem_op_node<Type,op1<Type> > > \ (operation, branch[0], branch[1]); \ + node_name = "assignment_vec_elem_op_node"; \ + break; \ + + case_stmt(details::e_addass , details::add_op) + case_stmt(details::e_subass , details::sub_op) + case_stmt(details::e_mulass , details::mul_op) + case_stmt(details::e_divass , details::div_op) + case_stmt(details::e_modass , details::mod_op) + #undef case_stmt + default : return error_node(); + } + } + else if (details::is_vector_elem_rtc_node(branch[0])) + { + lodge_assignment(e_st_vecelem,branch[0]); - case_stmt(details::e_addass,details::add_op) - case_stmt(details::e_subass,details::sub_op) - case_stmt(details::e_mulass,details::mul_op) - case_stmt(details::e_divass,details::div_op) - case_stmt(details::e_modass,details::mod_op) + switch (operation) + { + #define case_stmt(op0, op1) \ + case op0 : result = node_allocator_-> \ + template allocate_rrr<typename details::assignment_vec_elem_op_rtc_node<Type,op1<Type> > > \ + (operation, branch[0], branch[1]); \ + node_name = "assignment_vec_elem_op_rtc_node"; \ + break; \ + + case_stmt(details::e_addass , details::add_op) + case_stmt(details::e_subass , details::sub_op) + case_stmt(details::e_mulass , details::mul_op) + case_stmt(details::e_divass , details::div_op) + case_stmt(details::e_modass , details::mod_op) + #undef case_stmt + default : return error_node(); + } + } + else if (details::is_vector_celem_rtc_node(branch[0])) + { + lodge_assignment(e_st_vecelem,branch[0]); + + switch (operation) + { + #define case_stmt(op0, op1) \ + case op0 : result = node_allocator_-> \ + template allocate_rrr<typename details::assignment_vec_celem_op_rtc_node<Type,op1<Type> > > \ + (operation, branch[0], branch[1]); \ + node_name = "assignment_vec_celem_op_rtc_node"; \ + break; \ + + case_stmt(details::e_addass , details::add_op) + case_stmt(details::e_subass , details::sub_op) + case_stmt(details::e_mulass , details::mul_op) + case_stmt(details::e_divass , details::div_op) + case_stmt(details::e_modass , details::mod_op) #undef case_stmt default : return error_node(); } @@ -29145,16 +34339,18 @@ namespace exprtk switch (operation) { - #define case_stmt(op0,op1) \ - case op0 : return node_allocator_-> \ + #define case_stmt(op0, op1) \ + case op0 : result = node_allocator_-> \ template allocate_rrr<typename details::assignment_rebasevec_elem_op_node<Type,op1<Type> > > \ (operation, branch[0], branch[1]); \ - - case_stmt(details::e_addass,details::add_op) - case_stmt(details::e_subass,details::sub_op) - case_stmt(details::e_mulass,details::mul_op) - case_stmt(details::e_divass,details::div_op) - case_stmt(details::e_modass,details::mod_op) + node_name = "assignment_rebasevec_elem_op_node"; \ + break; \ + + case_stmt(details::e_addass , details::add_op) + case_stmt(details::e_subass , details::sub_op) + case_stmt(details::e_mulass , details::mul_op) + case_stmt(details::e_divass , details::div_op) + case_stmt(details::e_modass , details::mod_op) #undef case_stmt default : return error_node(); } @@ -29165,16 +34361,62 @@ namespace exprtk switch (operation) { - #define case_stmt(op0,op1) \ - case op0 : return node_allocator_-> \ + #define case_stmt(op0, op1) \ + case op0 : result = node_allocator_-> \ template allocate_rrr<typename details::assignment_rebasevec_celem_op_node<Type,op1<Type> > > \ (operation, branch[0], branch[1]); \ + node_name = "assignment_rebasevec_celem_op_node"; \ + break; \ + + case_stmt(details::e_addass , details::add_op) + case_stmt(details::e_subass , details::sub_op) + case_stmt(details::e_mulass , details::mul_op) + case_stmt(details::e_divass , details::div_op) + case_stmt(details::e_modass , details::mod_op) + #undef case_stmt + default : return error_node(); + } + } + else if (details::is_rebasevector_elem_rtc_node(branch[0])) + { + lodge_assignment(e_st_vecelem,branch[0]); - case_stmt(details::e_addass,details::add_op) - case_stmt(details::e_subass,details::sub_op) - case_stmt(details::e_mulass,details::mul_op) - case_stmt(details::e_divass,details::div_op) - case_stmt(details::e_modass,details::mod_op) + switch (operation) + { + #define case_stmt(op0, op1) \ + case op0 : result = node_allocator_-> \ + template allocate_rrr<typename details::assignment_rebasevec_elem_op_rtc_node<Type,op1<Type> > > \ + (operation, branch[0], branch[1]); \ + node_name = "assignment_rebasevec_elem_op_rtc_node"; \ + break; \ + + case_stmt(details::e_addass , details::add_op) + case_stmt(details::e_subass , details::sub_op) + case_stmt(details::e_mulass , details::mul_op) + case_stmt(details::e_divass , details::div_op) + case_stmt(details::e_modass , details::mod_op) + #undef case_stmt + default : return error_node(); + } + } + else if (details::is_rebasevector_celem_rtc_node(branch[0])) + { + lodge_assignment(e_st_vecelem,branch[0]); + + switch (operation) + { + #define case_stmt(op0, op1) \ + case op0 : result = node_allocator_-> \ + template allocate_rrr<typename details::assignment_rebasevec_celem_op_rtc_node<Type,op1<Type> > > \ + (operation, branch[0], branch[1]); \ + node_name = "assignment_rebasevec_celem_op_rtc_node"; \ + break; \ + + case_stmt(details::e_addass , details::add_op) + case_stmt(details::e_subass , details::sub_op) + case_stmt(details::e_mulass , details::mul_op) + case_stmt(details::e_divass , details::div_op) + case_stmt(details::e_modass , details::mod_op) #undef case_stmt default : return error_node(); } @@ -29187,16 +34429,18 @@ namespace exprtk { switch (operation) { - #define case_stmt(op0,op1) \ - case op0 : return node_allocator_-> \ + #define case_stmt(op0, op1) \ + case op0 : result = node_allocator_-> \ template allocate_rrr<typename details::assignment_vecvec_op_node<Type,op1<Type> > > \ (operation, branch[0], branch[1]); \ - - case_stmt(details::e_addass,details::add_op) - case_stmt(details::e_subass,details::sub_op) - case_stmt(details::e_mulass,details::mul_op) - case_stmt(details::e_divass,details::div_op) - case_stmt(details::e_modass,details::mod_op) + node_name = "assignment_rebasevec_celem_op_node"; \ + break; \ + + case_stmt(details::e_addass , details::add_op) + case_stmt(details::e_subass , details::sub_op) + case_stmt(details::e_mulass , details::mul_op) + case_stmt(details::e_divass , details::div_op) + case_stmt(details::e_modass , details::mod_op) #undef case_stmt default : return error_node(); } @@ -29205,16 +34449,18 @@ namespace exprtk { switch (operation) { - #define case_stmt(op0,op1) \ - case op0 : return node_allocator_-> \ + #define case_stmt(op0, op1) \ + case op0 : result = node_allocator_-> \ template allocate_rrr<typename details::assignment_vec_op_node<Type,op1<Type> > > \ (operation, branch[0], branch[1]); \ - - case_stmt(details::e_addass,details::add_op) - case_stmt(details::e_subass,details::sub_op) - case_stmt(details::e_mulass,details::mul_op) - case_stmt(details::e_divass,details::div_op) - case_stmt(details::e_modass,details::mod_op) + node_name = "assignment_vec_op_node"; \ + break; \ + + case_stmt(details::e_addass , details::add_op) + case_stmt(details::e_subass , details::sub_op) + case_stmt(details::e_mulass , details::mul_op) + case_stmt(details::e_divass , details::div_op) + case_stmt(details::e_modass , details::mod_op) #undef case_stmt default : return error_node(); } @@ -29230,15 +34476,34 @@ namespace exprtk lodge_assignment(e_st_string,branch[0]); - return synthesize_expression<addass_t,2>(operation,branch); + result = synthesize_expression<addass_t,2>(operation,branch); + node_name = "assignment_string_node<T,details::asn_addassignment>"; } #endif else { - parser_->set_synthesis_error("Invalid assignment operation[2]"); + parser_->set_error(parser_error::make_error( + parser_error::e_syntax, + parser_->current_state().token, + "ERR271 - Invalid branches for assignment operator '" + details::to_str(operation) + "'", + exprtk_error_location)); return error_node(); } + + if (result && result->valid()) + { + return result; + } + + parser_->set_error(parser_error::make_error( + parser_error::e_synthesis, + token_t(), + "ERR272 - Failed to synthesize node: " + node_name, + exprtk_error_location)); + + details::free_node(*node_allocator_, result); + return error_node(); } inline expression_node_ptr synthesize_veceqineqlogic_operation_expression(const details::operator_type& operation, @@ -29247,29 +34512,34 @@ namespace exprtk const bool is_b0_ivec = details::is_ivector_node(branch[0]); const bool is_b1_ivec = details::is_ivector_node(branch[1]); - #define batch_eqineq_logic_case \ - case_stmt(details:: e_lt, details:: lt_op) \ - case_stmt(details:: e_lte, details:: lte_op) \ - case_stmt(details:: e_gt, details:: gt_op) \ - case_stmt(details:: e_gte, details:: gte_op) \ - case_stmt(details:: e_eq, details:: eq_op) \ - case_stmt(details:: e_ne, details:: ne_op) \ - case_stmt(details::e_equal, details::equal_op) \ - case_stmt(details:: e_and, details:: and_op) \ - case_stmt(details:: e_nand, details:: nand_op) \ - case_stmt(details:: e_or, details:: or_op) \ - case_stmt(details:: e_nor, details:: nor_op) \ - case_stmt(details:: e_xor, details:: xor_op) \ - case_stmt(details:: e_xnor, details:: xnor_op) \ + #define batch_eqineq_logic_case \ + case_stmt(details::e_lt , details::lt_op ) \ + case_stmt(details::e_lte , details::lte_op ) \ + case_stmt(details::e_gt , details::gt_op ) \ + case_stmt(details::e_gte , details::gte_op ) \ + case_stmt(details::e_eq , details::eq_op ) \ + case_stmt(details::e_ne , details::ne_op ) \ + case_stmt(details::e_equal , details::equal_op) \ + case_stmt(details::e_and , details::and_op ) \ + case_stmt(details::e_nand , details::nand_op ) \ + case_stmt(details::e_or , details::or_op ) \ + case_stmt(details::e_nor , details::nor_op ) \ + case_stmt(details::e_xor , details::xor_op ) \ + case_stmt(details::e_xnor , details::xnor_op ) \ + + expression_node_ptr result = error_node(); + std::string node_name = "Unknown"; if (is_b0_ivec && is_b1_ivec) { switch (operation) { - #define case_stmt(op0,op1) \ - case op0 : return node_allocator_-> \ + #define case_stmt(op0, op1) \ + case op0 : result = node_allocator_-> \ template allocate_rrr<typename details::vec_binop_vecvec_node<Type,op1<Type> > > \ (operation, branch[0], branch[1]); \ + node_name = "vec_binop_vecvec_node"; \ + break; \ batch_eqineq_logic_case #undef case_stmt @@ -29280,10 +34550,12 @@ namespace exprtk { switch (operation) { - #define case_stmt(op0,op1) \ - case op0 : return node_allocator_-> \ + #define case_stmt(op0, op1) \ + case op0 : result = node_allocator_-> \ template allocate_rrr<typename details::vec_binop_vecval_node<Type,op1<Type> > > \ (operation, branch[0], branch[1]); \ + node_name = "vec_binop_vecval_node"; \ + break; \ batch_eqineq_logic_case #undef case_stmt @@ -29294,10 +34566,12 @@ namespace exprtk { switch (operation) { - #define case_stmt(op0,op1) \ - case op0 : return node_allocator_-> \ + #define case_stmt(op0, op1) \ + case op0 : result = node_allocator_-> \ template allocate_rrr<typename details::vec_binop_valvec_node<Type,op1<Type> > > \ (operation, branch[0], branch[1]); \ + node_name = "vec_binop_valvec_node"; \ + break; \ batch_eqineq_logic_case #undef case_stmt @@ -29307,6 +34581,20 @@ namespace exprtk else return error_node(); + if (result && result->valid()) + { + return result; + } + + parser_->set_error(parser_error::make_error( + parser_error::e_synthesis, + token_t(), + "ERR273 - Failed to synthesize node: " + node_name, + exprtk_error_location)); + + details::free_node(*node_allocator_, result); + return error_node(); + #undef batch_eqineq_logic_case } @@ -29316,21 +34604,26 @@ namespace exprtk const bool is_b0_ivec = details::is_ivector_node(branch[0]); const bool is_b1_ivec = details::is_ivector_node(branch[1]); - #define vector_ops \ - case_stmt(details::e_add,details::add_op) \ - case_stmt(details::e_sub,details::sub_op) \ - case_stmt(details::e_mul,details::mul_op) \ - case_stmt(details::e_div,details::div_op) \ - case_stmt(details::e_mod,details::mod_op) \ + #define vector_ops \ + case_stmt(details::e_add , details::add_op) \ + case_stmt(details::e_sub , details::sub_op) \ + case_stmt(details::e_mul , details::mul_op) \ + case_stmt(details::e_div , details::div_op) \ + case_stmt(details::e_mod , details::mod_op) \ + + expression_node_ptr result = error_node(); + std::string node_name = "Unknown"; if (is_b0_ivec && is_b1_ivec) { switch (operation) { - #define case_stmt(op0,op1) \ - case op0 : return node_allocator_-> \ + #define case_stmt(op0, op1) \ + case op0 : result = node_allocator_-> \ template allocate_rrr<typename details::vec_binop_vecvec_node<Type,op1<Type> > > \ (operation, branch[0], branch[1]); \ + node_name = "vec_binop_vecvec_node"; \ + break; \ vector_ops case_stmt(details::e_pow,details:: pow_op) @@ -29342,10 +34635,12 @@ namespace exprtk { switch (operation) { - #define case_stmt(op0,op1) \ - case op0 : return node_allocator_-> \ + #define case_stmt(op0, op1) \ + case op0 : result = node_allocator_-> \ template allocate_rrr<typename details::vec_binop_vecval_node<Type,op1<Type> > > \ (operation, branch[0], branch[1]); \ + node_name = "vec_binop_vecval_node(b0ivec,!b1ivec)"; \ + break; \ vector_ops case_stmt(details::e_pow,details:: pow_op) @@ -29357,10 +34652,12 @@ namespace exprtk { switch (operation) { - #define case_stmt(op0,op1) \ - case op0 : return node_allocator_-> \ + #define case_stmt(op0, op1) \ + case op0 : result = node_allocator_-> \ template allocate_rrr<typename details::vec_binop_valvec_node<Type,op1<Type> > > \ (operation, branch[0], branch[1]); \ + node_name = "vec_binop_vecval_node(!b0ivec,b1ivec)"; \ + break; \ vector_ops #undef case_stmt @@ -29370,6 +34667,20 @@ namespace exprtk else return error_node(); + if (result && result->valid()) + { + return result; + } + + parser_->set_error(parser_error::make_error( + parser_error::e_synthesis, + token_t(), + "ERR274 - Failed to synthesize node: " + node_name, + exprtk_error_location)); + + details::free_node(*node_allocator_, result); + return error_node(); + #undef vector_ops } @@ -29387,6 +34698,7 @@ namespace exprtk #endif expression_node_ptr result = error_node(); + std::string node_name = "Unknown"; if (v0_is_ivar && v1_is_ivar) { @@ -29400,36 +34712,57 @@ namespace exprtk (0 != (v1 = dynamic_cast<variable_node_ptr>(branch[1]))) ) { - result = node_allocator_->allocate<details::swap_node<T> >(v0,v1); + result = node_allocator_->allocate<details::swap_node<T> >(v0,v1); + node_name = "swap_node"; } else - result = node_allocator_->allocate<details::swap_generic_node<T> >(branch[0],branch[1]); + { + result = node_allocator_->allocate<details::swap_generic_node<T> >(branch[0],branch[1]); + node_name = "swap_generic_node"; + } } else if (v0_is_ivec && v1_is_ivec) { - result = node_allocator_->allocate<details::swap_vecvec_node<T> >(branch[0],branch[1]); + result = node_allocator_->allocate<details::swap_vecvec_node<T> >(branch[0],branch[1]); + node_name = "swap_vecvec_node"; } #ifndef exprtk_disable_string_capabilities else if (v0_is_str && v1_is_str) { if (is_string_node(branch[0]) && is_string_node(branch[1])) + { result = node_allocator_->allocate<details::swap_string_node<T> > (branch[0], branch[1]); + node_name = "swap_string_node"; + } else + { result = node_allocator_->allocate<details::swap_genstrings_node<T> > (branch[0], branch[1]); + node_name = "swap_genstrings_node"; + } } #endif else { parser_->set_synthesis_error("Only variables, strings, vectors or vector elements can be swapped"); - return error_node(); } - parser_->state_.activate_side_effect("synthesize_swap_expression()"); + if (result && result->valid()) + { + parser_->state_.activate_side_effect("synthesize_swap_expression()"); + return result; + } - return result; + parser_->set_error(parser_error::make_error( + parser_error::e_synthesis, + token_t(), + "ERR275 - Failed to synthesize node: " + node_name, + exprtk_error_location)); + + details::free_node(*node_allocator_, result); + return error_node(); } #ifndef exprtk_disable_sc_andor @@ -29467,8 +34800,8 @@ namespace exprtk if (result) { - free_node(*node_allocator_, branch[0]); - free_node(*node_allocator_, branch[1]); + details::free_node(*node_allocator_, branch[0]); + details::free_node(*node_allocator_, branch[1]); return result; } @@ -29490,27 +34823,27 @@ namespace exprtk } #endif - #define basic_opr_switch_statements \ - case_stmt(details::e_add, details::add_op) \ - case_stmt(details::e_sub, details::sub_op) \ - case_stmt(details::e_mul, details::mul_op) \ - case_stmt(details::e_div, details::div_op) \ - case_stmt(details::e_mod, details::mod_op) \ - case_stmt(details::e_pow, details::pow_op) \ - - #define extended_opr_switch_statements \ - case_stmt(details:: e_lt, details:: lt_op) \ - case_stmt(details:: e_lte, details:: lte_op) \ - case_stmt(details:: e_gt, details:: gt_op) \ - case_stmt(details:: e_gte, details:: gte_op) \ - case_stmt(details:: e_eq, details:: eq_op) \ - case_stmt(details:: e_ne, details:: ne_op) \ - case_stmt(details:: e_and, details:: and_op) \ - case_stmt(details::e_nand, details::nand_op) \ - case_stmt(details:: e_or, details:: or_op) \ - case_stmt(details:: e_nor, details:: nor_op) \ - case_stmt(details:: e_xor, details:: xor_op) \ - case_stmt(details::e_xnor, details::xnor_op) \ + #define basic_opr_switch_statements \ + case_stmt(details::e_add , details::add_op) \ + case_stmt(details::e_sub , details::sub_op) \ + case_stmt(details::e_mul , details::mul_op) \ + case_stmt(details::e_div , details::div_op) \ + case_stmt(details::e_mod , details::mod_op) \ + case_stmt(details::e_pow , details::pow_op) \ + + #define extended_opr_switch_statements \ + case_stmt(details::e_lt , details::lt_op ) \ + case_stmt(details::e_lte , details::lte_op ) \ + case_stmt(details::e_gt , details::gt_op ) \ + case_stmt(details::e_gte , details::gte_op ) \ + case_stmt(details::e_eq , details::eq_op ) \ + case_stmt(details::e_ne , details::ne_op ) \ + case_stmt(details::e_and , details::and_op ) \ + case_stmt(details::e_nand , details::nand_op) \ + case_stmt(details::e_or , details::or_op ) \ + case_stmt(details::e_nor , details::nor_op ) \ + case_stmt(details::e_xor , details::xor_op ) \ + case_stmt(details::e_xnor , details::xnor_op) \ #ifndef exprtk_disable_cardinal_pow_optimisation template <typename TType, template <typename, typename> class IPowNode> @@ -29585,7 +34918,7 @@ namespace exprtk else if (not_recipricol) return cardinal_pow_optimisation_impl<expression_node_ptr,details::bipow_node>(branch[0],p); else - return cardinal_pow_optimisation_impl<expression_node_ptr,details::bipowninv_node>(branch[0],p); + return cardinal_pow_optimisation_impl<expression_node_ptr,details::bipowinv_node>(branch[0],p); } #else inline expression_node_ptr cardinal_pow_optimisation(T&, const T&) @@ -29741,7 +35074,7 @@ namespace exprtk switch (operation) { - #define case_stmt(op0,op1) \ + #define case_stmt(op0, op1) \ case op0 : return expr_gen.node_allocator_-> \ template allocate<typename details::binary_ext_node<Type,op1<Type> > > \ (branch[0], branch[1]); \ @@ -29773,7 +35106,7 @@ namespace exprtk if (synthesis_result) { - free_node(*expr_gen.node_allocator_,branch[1]); + details::free_node(*expr_gen.node_allocator_,branch[1]); return result; } } @@ -29794,7 +35127,7 @@ namespace exprtk { const Type& v1 = static_cast<uvbn_ptr_t>(branch[1])->v(); - free_node(*expr_gen.node_allocator_,branch[1]); + details::free_node(*expr_gen.node_allocator_,branch[1]); switch (operation) { @@ -29816,7 +35149,7 @@ namespace exprtk switch (operation) { - #define case_stmt(op0,op1) \ + #define case_stmt(op0, op1) \ case op0 : return expr_gen.node_allocator_-> \ template allocate_rc<typename details::vob_node<Type,op1<Type> > > \ (v, branch[1]); \ @@ -29848,7 +35181,7 @@ namespace exprtk if (synthesis_result) { - free_node(*expr_gen.node_allocator_, branch[0]); + details::free_node(*expr_gen.node_allocator_, branch[0]); return result; } @@ -29872,7 +35205,7 @@ namespace exprtk { const Type& v0 = static_cast<uvbn_ptr_t>(branch[0])->v(); - free_node(*expr_gen.node_allocator_,branch[0]); + details::free_node(*expr_gen.node_allocator_,branch[0]); switch (operation) { @@ -29902,7 +35235,7 @@ namespace exprtk switch (operation) { - #define case_stmt(op0,op1) \ + #define case_stmt(op0, op1) \ case op0 : return expr_gen.node_allocator_-> \ template allocate_cr<typename details::bov_node<Type,op1<Type> > > \ (branch[0], v); \ @@ -29923,17 +35256,17 @@ namespace exprtk { const Type c = static_cast<details::literal_node<Type>*>(branch[0])->value(); - free_node(*expr_gen.node_allocator_,branch[0]); + details::free_node(*expr_gen.node_allocator_,branch[0]); if (std::equal_to<T>()(T(0),c) && (details::e_mul == operation)) { - free_node(*expr_gen.node_allocator_,branch[1]); + details::free_node(*expr_gen.node_allocator_,branch[1]); return expr_gen(T(0)); } else if (std::equal_to<T>()(T(0),c) && (details::e_div == operation)) { - free_node(*expr_gen.node_allocator_, branch[1]); + details::free_node(*expr_gen.node_allocator_, branch[1]); return expr_gen(T(0)); } @@ -29948,8 +35281,8 @@ namespace exprtk // 1. (1 * (2 * (3 * (4 * (5 * (6 * (7 * (8 * (9 + x))))))))) --> 40320 * (9 + x) // 2. (1 + (2 + (3 + (4 + (5 + (6 + (7 + (8 + (9 + x))))))))) --> 45 + x if ( - (operation == details::e_mul) || - (operation == details::e_add) + (details::e_mul == operation) || + (details::e_add == operation) ) { details::cob_base_node<Type>* cobnode = static_cast<details::cob_base_node<Type>*>(branch[1]); @@ -30014,7 +35347,7 @@ namespace exprtk default : return error_node(); } - free_node(*expr_gen.node_allocator_,branch[1]); + details::free_node(*expr_gen.node_allocator_,branch[1]); return new_cobnode; } @@ -30031,7 +35364,7 @@ namespace exprtk if (synthesis_result) { - free_node(*expr_gen.node_allocator_,branch[1]); + details::free_node(*expr_gen.node_allocator_,branch[1]); return result; } @@ -30040,7 +35373,7 @@ namespace exprtk switch (operation) { - #define case_stmt(op0,op1) \ + #define case_stmt(op0, op1) \ case op0 : return expr_gen.node_allocator_-> \ template allocate_tt<typename details::cob_node<Type,op1<Type> > > \ (c, branch[1]); \ @@ -30065,13 +35398,13 @@ namespace exprtk if (std::equal_to<T>()(T(0),c) && (details::e_mul == operation)) { - free_node(*expr_gen.node_allocator_, branch[0]); + details::free_node(*expr_gen.node_allocator_, branch[0]); return expr_gen(T(0)); } else if (std::equal_to<T>()(T(0),c) && (details::e_div == operation)) { - free_node(*expr_gen.node_allocator_, branch[0]); + details::free_node(*expr_gen.node_allocator_, branch[0]); return expr_gen(std::numeric_limits<T>::quiet_NaN()); } @@ -30086,8 +35419,8 @@ namespace exprtk // 1. (((((((((x + 9) * 8) * 7) * 6) * 5) * 4) * 3) * 2) * 1) --> (x + 9) * 40320 // 2. (((((((((x + 9) + 8) + 7) + 6) + 5) + 4) + 3) + 2) + 1) --> x + 45 if ( - (operation == details::e_mul) || - (operation == details::e_add) + (details::e_mul == operation) || + (details::e_add == operation) ) { details::boc_base_node<Type>* bocnode = static_cast<details::boc_base_node<Type>*>(branch[0]); @@ -30159,7 +35492,7 @@ namespace exprtk switch (operation) { - #define case_stmt(op0,op1) \ + #define case_stmt(op0, op1) \ case op0 : return expr_gen.node_allocator_-> \ template allocate_cr<typename details::boc_node<Type,op1<Type> > > \ (branch[0], c); \ @@ -30189,33 +35522,33 @@ namespace exprtk if (std::equal_to<T>()(T(0),c) && (details::e_mul == operation)) { - free_node(*expr_gen.node_allocator_, branch[0]); - free_node(*expr_gen.node_allocator_, branch[1]); + details::free_node(*expr_gen.node_allocator_, branch[0]); + details::free_node(*expr_gen.node_allocator_, branch[1]); return expr_gen(T(0)); } else if (std::equal_to<T>()(T(0),c) && (details::e_div == operation)) { - free_node(*expr_gen.node_allocator_, branch[0]); - free_node(*expr_gen.node_allocator_, branch[1]); + details::free_node(*expr_gen.node_allocator_, branch[0]); + details::free_node(*expr_gen.node_allocator_, branch[1]); return expr_gen(T(std::numeric_limits<T>::quiet_NaN())); } else if (std::equal_to<T>()(T(0),c) && (details::e_add == operation)) { - free_node(*expr_gen.node_allocator_, branch[1]); + details::free_node(*expr_gen.node_allocator_, branch[1]); return branch[0]; } else if (std::equal_to<T>()(T(1),c) && (details::e_mul == operation)) { - free_node(*expr_gen.node_allocator_, branch[1]); + details::free_node(*expr_gen.node_allocator_, branch[1]); return branch[0]; } else if (std::equal_to<T>()(T(1),c) && (details::e_div == operation)) { - free_node(*expr_gen.node_allocator_, branch[1]); + details::free_node(*expr_gen.node_allocator_, branch[1]); return branch[0]; } @@ -30258,13 +35591,13 @@ namespace exprtk template allocate_tt<typename details::cob_node<Type,details::div_op<Type> > > (cobnode->c() / c, cobnode->move_branch(0)); - free_node(*expr_gen.node_allocator_, branch[0]); + details::free_node(*expr_gen.node_allocator_, branch[0]); } } if (result) { - free_node(*expr_gen.node_allocator_,branch[1]); + details::free_node(*expr_gen.node_allocator_,branch[1]); } } @@ -30277,27 +35610,27 @@ namespace exprtk if (std::equal_to<T>()(T(0),c) && (details::e_mul == operation)) { - free_node(*expr_gen.node_allocator_, branch[0]); - free_node(*expr_gen.node_allocator_, branch[1]); + details::free_node(*expr_gen.node_allocator_, branch[0]); + details::free_node(*expr_gen.node_allocator_, branch[1]); return expr_gen(T(0)); } else if (std::equal_to<T>()(T(0),c) && (details::e_div == operation)) { - free_node(*expr_gen.node_allocator_, branch[0]); - free_node(*expr_gen.node_allocator_, branch[1]); + details::free_node(*expr_gen.node_allocator_, branch[0]); + details::free_node(*expr_gen.node_allocator_, branch[1]); return expr_gen(T(0)); } else if (std::equal_to<T>()(T(0),c) && (details::e_add == operation)) { - free_node(*expr_gen.node_allocator_, branch[0]); + details::free_node(*expr_gen.node_allocator_, branch[0]); return branch[1]; } else if (std::equal_to<T>()(T(1),c) && (details::e_mul == operation)) { - free_node(*expr_gen.node_allocator_, branch[0]); + details::free_node(*expr_gen.node_allocator_, branch[0]); return branch[1]; } @@ -30315,7 +35648,7 @@ namespace exprtk template allocate_tt<typename details::cob_node<Type,details::sub_op<Type> > > (c - cobnode->c(), cobnode->move_branch(0)); - free_node(*expr_gen.node_allocator_,branch[1]); + details::free_node(*expr_gen.node_allocator_,branch[1]); } } else if (details::e_sub == cobnode->operation()) @@ -30331,7 +35664,7 @@ namespace exprtk template allocate_tt<typename details::cob_node<Type,details::add_op<Type> > > (c - cobnode->c(), cobnode->move_branch(0)); - free_node(*expr_gen.node_allocator_,branch[1]); + details::free_node(*expr_gen.node_allocator_,branch[1]); } } else if (details::e_mul == cobnode->operation()) @@ -30347,7 +35680,7 @@ namespace exprtk template allocate_tt<typename details::cob_node<Type,details::div_op<Type> > > (c / cobnode->c(), cobnode->move_branch(0)); - free_node(*expr_gen.node_allocator_,branch[1]); + details::free_node(*expr_gen.node_allocator_,branch[1]); } } else if (details::e_div == cobnode->operation()) @@ -30363,13 +35696,13 @@ namespace exprtk template allocate_tt<typename details::cob_node<Type,details::mul_op<Type> > > (c / cobnode->c(), cobnode->move_branch(0)); - free_node(*expr_gen.node_allocator_,branch[1]); + details::free_node(*expr_gen.node_allocator_,branch[1]); } } if (result) { - free_node(*expr_gen.node_allocator_,branch[0]); + details::free_node(*expr_gen.node_allocator_,branch[0]); } } @@ -30422,7 +35755,7 @@ namespace exprtk template allocate_tt<typename details::boc_node<Type,details::add_op<Type> > > (bocnode->move_branch(0), c - bocnode->c()); - free_node(*expr_gen.node_allocator_,branch[0]); + details::free_node(*expr_gen.node_allocator_,branch[0]); } else if (details::e_sub == operation) { @@ -30444,7 +35777,7 @@ namespace exprtk if (result) { - free_node(*expr_gen.node_allocator_, branch[1]); + details::free_node(*expr_gen.node_allocator_, branch[1]); } } @@ -30468,7 +35801,7 @@ namespace exprtk template allocate_tt<typename details::cob_node<Type,details::sub_op<Type> > > (c - bocnode->c(), bocnode->move_branch(0)); - free_node(*expr_gen.node_allocator_,branch[1]); + details::free_node(*expr_gen.node_allocator_,branch[1]); } } else if (details::e_sub == bocnode->operation()) @@ -30479,7 +35812,7 @@ namespace exprtk template allocate_tt<typename details::boc_node<Type,details::add_op<Type> > > (bocnode->move_branch(0), c - bocnode->c()); - free_node(*expr_gen.node_allocator_,branch[1]); + details::free_node(*expr_gen.node_allocator_,branch[1]); } else if (details::e_sub == operation) { @@ -30487,7 +35820,7 @@ namespace exprtk template allocate_tt<typename details::cob_node<Type,details::sub_op<Type> > > (c + bocnode->c(), bocnode->move_branch(0)); - free_node(*expr_gen.node_allocator_,branch[1]); + details::free_node(*expr_gen.node_allocator_,branch[1]); } } else if (details::e_mul == bocnode->operation()) @@ -30503,7 +35836,7 @@ namespace exprtk template allocate_tt<typename details::cob_node<Type,details::div_op<Type> > > (c / bocnode->c(), bocnode->move_branch(0)); - free_node(*expr_gen.node_allocator_,branch[1]); + details::free_node(*expr_gen.node_allocator_,branch[1]); } } else if (details::e_div == bocnode->operation()) @@ -30519,13 +35852,13 @@ namespace exprtk template allocate_tt<typename details::cob_node<Type,details::div_op<Type> > > (c * bocnode->c(), bocnode->move_branch(0)); - free_node(*expr_gen.node_allocator_,branch[1]); + details::free_node(*expr_gen.node_allocator_,branch[1]); } } if (result) { - free_node(*expr_gen.node_allocator_,branch[0]); + details::free_node(*expr_gen.node_allocator_,branch[0]); } } @@ -30568,7 +35901,7 @@ namespace exprtk switch (operation) { - #define case_stmt(op0,op1) \ + #define case_stmt(op0, op1) \ case op0 : return expr_gen.node_allocator_-> \ template allocate_rr<typename details::vov_node<Type,op1<Type> > > \ (v1, v2); \ @@ -30603,7 +35936,7 @@ namespace exprtk switch (operation) { - #define case_stmt(op0,op1) \ + #define case_stmt(op0, op1) \ case op0 : return expr_gen.node_allocator_-> \ template allocate_cr<typename details::cov_node<Type,op1<Type> > > \ (c, v); \ @@ -30647,7 +35980,7 @@ namespace exprtk switch (operation) { - #define case_stmt(op0,op1) \ + #define case_stmt(op0, op1) \ case op0 : return expr_gen.node_allocator_-> \ template allocate_rc<typename details::voc_node<Type,op1<Type> > > \ (v, c); \ @@ -30716,7 +36049,6 @@ namespace exprtk case details::e_sf##op : return details::T0oT1oT2oT3_sf4ext<Type,T0,T1,T2,T3,details::sf##op##_op<Type> >:: \ allocate(*(expr_gen.node_allocator_), t0, t1, t2, t3); \ - #define case_stmt1(op) \ case details::e_sf4ext##op : return details::T0oT1oT2oT3_sf4ext<Type,T0,T1,T2,T3,details::sfext##op##_op<Type> >:: \ allocate(*(expr_gen.node_allocator_), t0, t1, t2, t3); \ @@ -30917,9 +36249,6 @@ namespace exprtk const details::operator_type o0 = vov->operation(); const details::operator_type o1 = operation; - binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); - binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); - details::free_node(*(expr_gen.node_allocator_),branch[0]); expression_node_ptr result = error_node(); @@ -30931,7 +36260,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<vtype,vtype,vtype>(expr_gen, "t/(t*t)", v0, v1, v2, result); + template compile<vtype, vtype, vtype>(expr_gen, "t/(t*t)", v0, v1, v2, result); exprtk_debug(("(v0 / v1) / v2 --> (vovov) v0 / (v1 * v2)\n")); @@ -30945,7 +36274,11 @@ namespace exprtk if (synthesis_result) return result; - else if (!expr_gen.valid_operator(o0,f0)) + + binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); + binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); + + if (!expr_gen.valid_operator(o0,f0)) return error_node(); else if (!expr_gen.valid_operator(o1,f1)) return error_node(); @@ -30954,12 +36287,13 @@ namespace exprtk } static inline std::string id(expression_generator<Type>& expr_gen, - const details::operator_type o0, const details::operator_type o1) + const details::operator_type o0, + const details::operator_type o1) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t"; + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t"; } }; @@ -30980,9 +36314,6 @@ namespace exprtk const details::operator_type o0 = operation; const details::operator_type o1 = vov->operation(); - binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); - binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); - details::free_node(*(expr_gen.node_allocator_),branch[1]); expression_node_ptr result = error_node(); @@ -30994,7 +36325,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<vtype,vtype,vtype>(expr_gen, "(t*t)/t", v0, v2, v1, result); + template compile<vtype, vtype, vtype>(expr_gen, "(t*t)/t", v0, v2, v1, result); exprtk_debug(("v0 / (v1 / v2) --> (vovov) (v0 * v2) / v1\n")); @@ -31008,7 +36339,11 @@ namespace exprtk if (synthesis_result) return result; - else if (!expr_gen.valid_operator(o0,f0)) + + binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); + binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); + + if (!expr_gen.valid_operator(o0,f0)) return error_node(); else if (!expr_gen.valid_operator(o1,f1)) return error_node(); @@ -31017,12 +36352,13 @@ namespace exprtk } static inline std::string id(expression_generator<Type>& expr_gen, - const details::operator_type o0, const details::operator_type o1) + const details::operator_type o0, + const details::operator_type o1) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "t)"; + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)"; } }; @@ -31043,9 +36379,6 @@ namespace exprtk const details::operator_type o0 = vov->operation(); const details::operator_type o1 = operation; - binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); - binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); - details::free_node(*(expr_gen.node_allocator_),branch[0]); details::free_node(*(expr_gen.node_allocator_),branch[1]); @@ -31058,7 +36391,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<vtype,vtype,ctype>(expr_gen, "t/(t*t)", v0, v1, c, result); + template compile<vtype, vtype, ctype>(expr_gen, "t/(t*t)", v0, v1, c, result); exprtk_debug(("(v0 / v1) / c --> (vovoc) v0 / (v1 * c)\n")); @@ -31072,7 +36405,11 @@ namespace exprtk if (synthesis_result) return result; - else if (!expr_gen.valid_operator(o0,f0)) + + binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); + binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); + + if (!expr_gen.valid_operator(o0,f0)) return error_node(); else if (!expr_gen.valid_operator(o1,f1)) return error_node(); @@ -31081,12 +36418,13 @@ namespace exprtk } static inline std::string id(expression_generator<Type>& expr_gen, - const details::operator_type o0, const details::operator_type o1) + const details::operator_type o0, + const details::operator_type o1) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t"; + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t"; } }; @@ -31107,9 +36445,6 @@ namespace exprtk const details::operator_type o0 = operation; const details::operator_type o1 = voc->operation(); - binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); - binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); - details::free_node(*(expr_gen.node_allocator_),branch[1]); expression_node_ptr result = error_node(); @@ -31121,7 +36456,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<vtype,ctype,vtype>(expr_gen, "(t*t)/t", v0, c, v1, result); + template compile<vtype, ctype, vtype>(expr_gen, "(t*t)/t", v0, c, v1, result); exprtk_debug(("v0 / (v1 / c) --> (vocov) (v0 * c) / v1\n")); @@ -31135,7 +36470,11 @@ namespace exprtk if (synthesis_result) return result; - else if (!expr_gen.valid_operator(o0,f0)) + + binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); + binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); + + if (!expr_gen.valid_operator(o0,f0)) return error_node(); else if (!expr_gen.valid_operator(o1,f1)) return error_node(); @@ -31144,12 +36483,13 @@ namespace exprtk } static inline std::string id(expression_generator<Type>& expr_gen, - const details::operator_type o0, const details::operator_type o1) + const details::operator_type o0, + const details::operator_type o1) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "t)"; + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)"; } }; @@ -31170,9 +36510,6 @@ namespace exprtk const details::operator_type o0 = voc->operation(); const details::operator_type o1 = operation; - binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); - binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); - details::free_node(*(expr_gen.node_allocator_),branch[0]); expression_node_ptr result = error_node(); @@ -31184,7 +36521,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<vtype,vtype,ctype>(expr_gen, "t/(t*t)", v0, v1, c, result); + template compile<vtype, vtype, ctype>(expr_gen, "t/(t*t)", v0, v1, c, result); exprtk_debug(("(v0 / c) / v1 --> (vovoc) v0 / (v1 * c)\n")); @@ -31198,7 +36535,11 @@ namespace exprtk if (synthesis_result) return result; - else if (!expr_gen.valid_operator(o0,f0)) + + binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); + binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); + + if (!expr_gen.valid_operator(o0,f0)) return error_node(); else if (!expr_gen.valid_operator(o1,f1)) return error_node(); @@ -31207,12 +36548,13 @@ namespace exprtk } static inline std::string id(expression_generator<Type>& expr_gen, - const details::operator_type o0, const details::operator_type o1) + const details::operator_type o0, + const details::operator_type o1) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t"; + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t"; } }; @@ -31233,9 +36575,6 @@ namespace exprtk const details::operator_type o0 = operation; const details::operator_type o1 = cov->operation(); - binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); - binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); - details::free_node(*(expr_gen.node_allocator_),branch[1]); expression_node_ptr result = error_node(); @@ -31261,7 +36600,11 @@ namespace exprtk if (synthesis_result) return result; - else if (!expr_gen.valid_operator(o0,f0)) + + binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); + binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); + + if (!expr_gen.valid_operator(o0,f0)) return error_node(); else if (!expr_gen.valid_operator(o1,f1)) return error_node(); @@ -31270,12 +36613,13 @@ namespace exprtk } static inline std::string id(expression_generator<Type>& expr_gen, - const details::operator_type o0, const details::operator_type o1) + const details::operator_type o0, + const details::operator_type o1) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "t)"; + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)"; } }; @@ -31296,9 +36640,6 @@ namespace exprtk const details::operator_type o0 = cov->operation(); const details::operator_type o1 = operation; - binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); - binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); - details::free_node(*(expr_gen.node_allocator_),branch[0]); expression_node_ptr result = error_node(); @@ -31324,7 +36665,11 @@ namespace exprtk if (synthesis_result) return result; - else if (!expr_gen.valid_operator(o0,f0)) + + binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); + binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); + + if (!expr_gen.valid_operator(o0,f0)) return error_node(); else if (!expr_gen.valid_operator(o1,f1)) return error_node(); @@ -31333,12 +36678,13 @@ namespace exprtk } static inline std::string id(expression_generator<Type>& expr_gen, - const details::operator_type o0, const details::operator_type o1) + const details::operator_type o0, + const details::operator_type o1) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t"; + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t"; } }; @@ -31359,9 +36705,6 @@ namespace exprtk const details::operator_type o0 = operation; const details::operator_type o1 = vov->operation(); - binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); - binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); - details::free_node(*(expr_gen.node_allocator_),branch[0]); details::free_node(*(expr_gen.node_allocator_),branch[1]); @@ -31388,7 +36731,11 @@ namespace exprtk if (synthesis_result) return result; - else if (!expr_gen.valid_operator(o0,f0)) + + binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); + binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); + + if (!expr_gen.valid_operator(o0,f0)) return error_node(); else if (!expr_gen.valid_operator(o1,f1)) return error_node(); @@ -31396,12 +36743,14 @@ namespace exprtk return node_type::allocate(*(expr_gen.node_allocator_), c, v0, v1, f0, f1); } - static inline std::string id(expression_generator<Type>& expr_gen, const details::operator_type o0, const details::operator_type o1) + static inline std::string id(expression_generator<Type>& expr_gen, + const details::operator_type o0, + const details::operator_type o1) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "t)"; + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)"; } }; @@ -31422,9 +36771,6 @@ namespace exprtk const details::operator_type o0 = cov->operation(); const details::operator_type o1 = operation; - binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); - binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); - details::free_node(*(expr_gen.node_allocator_),branch[0]); details::free_node(*(expr_gen.node_allocator_),branch[1]); @@ -31504,7 +36850,11 @@ namespace exprtk if (synthesis_result) return result; - else if (!expr_gen.valid_operator(o0,f0)) + + binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); + binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); + + if (!expr_gen.valid_operator(o0,f0)) return error_node(); else if (!expr_gen.valid_operator(o1,f1)) return error_node(); @@ -31513,12 +36863,13 @@ namespace exprtk } static inline std::string id(expression_generator<Type>& expr_gen, - const details::operator_type o0, const details::operator_type o1) + const details::operator_type o0, + const details::operator_type o1) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t"; + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t"; } }; @@ -31539,9 +36890,6 @@ namespace exprtk const details::operator_type o0 = operation; const details::operator_type o1 = voc->operation(); - binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); - binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); - details::free_node(*(expr_gen.node_allocator_),branch[0]); details::free_node(*(expr_gen.node_allocator_),branch[1]); @@ -31621,7 +36969,11 @@ namespace exprtk if (synthesis_result) return result; - else if (!expr_gen.valid_operator(o0,f0)) + + binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); + binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); + + if (!expr_gen.valid_operator(o0,f0)) return error_node(); else if (!expr_gen.valid_operator(o1,f1)) return error_node(); @@ -31630,19 +36982,22 @@ namespace exprtk } static inline std::string id(expression_generator<Type>& expr_gen, - const details::operator_type o0, const details::operator_type o1) + const details::operator_type o0, + const details::operator_type o1) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "t)"; + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)"; } }; struct synthesize_cocov_expression0 { typedef typename cocov_t::type0 node_type; - static inline expression_node_ptr process(expression_generator<Type>&, const details::operator_type&, expression_node_ptr (&)[2]) + static inline expression_node_ptr process(expression_generator<Type>&, + const details::operator_type&, + expression_node_ptr (&)[2]) { // (c0 o0 c1) o1 (v) - Not possible. return error_node(); @@ -31666,9 +37021,6 @@ namespace exprtk const details::operator_type o0 = operation; const details::operator_type o1 = cov->operation(); - binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); - binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); - details::free_node(*(expr_gen.node_allocator_),branch[0]); details::free_node(*(expr_gen.node_allocator_),branch[1]); @@ -31748,7 +37100,11 @@ namespace exprtk if (synthesis_result) return result; - else if (!expr_gen.valid_operator(o0,f0)) + + binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); + binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); + + if (!expr_gen.valid_operator(o0,f0)) return error_node(); else if (!expr_gen.valid_operator(o1,f1)) return error_node(); @@ -31756,12 +37112,14 @@ namespace exprtk return node_type::allocate(*(expr_gen.node_allocator_), c0, c1, v, f0, f1); } - static inline std::string id(expression_generator<Type>& expr_gen, const details::operator_type o0, const details::operator_type o1) + static inline std::string id(expression_generator<Type>& expr_gen, + const details::operator_type o0, + const details::operator_type o1) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "t)"; + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)"; } }; @@ -31782,9 +37140,6 @@ namespace exprtk const details::operator_type o0 = voc->operation(); const details::operator_type o1 = operation; - binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); - binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); - details::free_node(*(expr_gen.node_allocator_),branch[0]); details::free_node(*(expr_gen.node_allocator_),branch[1]); @@ -31872,7 +37227,11 @@ namespace exprtk if (synthesis_result) return result; - else if (!expr_gen.valid_operator(o0,f0)) + + binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); + binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); + + if (!expr_gen.valid_operator(o0,f0)) return error_node(); else if (!expr_gen.valid_operator(o1,f1)) return error_node(); @@ -31881,12 +37240,13 @@ namespace exprtk } static inline std::string id(expression_generator<Type>& expr_gen, - const details::operator_type o0, const details::operator_type o1) + const details::operator_type o0, + const details::operator_type o1) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t"; + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t"; } }; @@ -31894,7 +37254,9 @@ namespace exprtk { typedef typename vococ_t::type0 node_type; - static inline expression_node_ptr process(expression_generator<Type>&, const details::operator_type&, expression_node_ptr (&)[2]) + static inline expression_node_ptr process(expression_generator<Type>&, + const details::operator_type&, + expression_node_ptr (&)[2]) { // (v) o0 (c0 o1 c1) - Not possible. exprtk_debug(("(v) o0 (c0 o1 c1) - Not possible.\n")); @@ -31926,10 +37288,6 @@ namespace exprtk const details::operator_type o1 = operation; const details::operator_type o2 = vov1->operation(); - binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); - binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); - binary_functor_t f2 = reinterpret_cast<binary_functor_t>(0); - details::free_node(*(expr_gen.node_allocator_),branch[0]); details::free_node(*(expr_gen.node_allocator_),branch[1]); @@ -31942,7 +37300,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf4ext_expression:: - template compile<vtype,vtype,vtype,vtype>(expr_gen, "(t*t)/(t*t)", v0, v2, v1, v3, result); + template compile<vtype, vtype, vtype, vtype>(expr_gen, "(t*t)/(t*t)", v0, v2, v1, v3, result); exprtk_debug(("(v0 / v1) * (v2 / v3) --> (vovovov) (v0 * v2) / (v1 * v3)\n")); @@ -31953,7 +37311,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf4ext_expression:: - template compile<vtype,vtype,vtype,vtype>(expr_gen, "(t*t)/(t*t)", v0, v3, v1, v2, result); + template compile<vtype, vtype, vtype, vtype>(expr_gen, "(t*t)/(t*t)", v0, v3, v1, v2, result); exprtk_debug(("(v0 / v1) / (v2 / v3) --> (vovovov) (v0 * v3) / (v1 * v2)\n")); @@ -31964,7 +37322,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf4ext_expression:: - template compile<vtype,vtype,vtype,vtype>(expr_gen, "(t+t)*(t/t)", v0, v1, v3, v2, result); + template compile<vtype, vtype, vtype, vtype>(expr_gen, "(t+t)*(t/t)", v0, v1, v3, v2, result); exprtk_debug(("(v0 + v1) / (v2 / v3) --> (vovovov) (v0 + v1) * (v3 / v2)\n")); @@ -31975,7 +37333,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf4ext_expression:: - template compile<vtype,vtype,vtype,vtype>(expr_gen, "(t-t)*(t/t)", v0, v1, v3, v2, result); + template compile<vtype, vtype, vtype, vtype>(expr_gen, "(t-t)*(t/t)", v0, v1, v3, v2, result); exprtk_debug(("(v0 - v1) / (v2 / v3) --> (vovovov) (v0 - v1) * (v3 / v2)\n")); @@ -31986,7 +37344,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf4ext_expression:: - template compile<vtype,vtype,vtype,vtype>(expr_gen, "((t*t)*t)/t", v0, v1, v3, v2, result); + template compile<vtype, vtype, vtype, vtype>(expr_gen, "((t*t)*t)/t", v0, v1, v3, v2, result); exprtk_debug(("(v0 * v1) / (v2 / v3) --> (vovovov) ((v0 * v1) * v3) / v2\n")); @@ -32000,7 +37358,12 @@ namespace exprtk if (synthesis_result) return result; - else if (!expr_gen.valid_operator(o0,f0)) + + binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); + binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); + binary_functor_t f2 = reinterpret_cast<binary_functor_t>(0); + + if (!expr_gen.valid_operator(o0,f0)) return error_node(); else if (!expr_gen.valid_operator(o1,f1)) return error_node(); @@ -32016,10 +37379,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t)"; + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; } }; @@ -32047,10 +37410,6 @@ namespace exprtk const details::operator_type o1 = operation; const details::operator_type o2 = voc->operation(); - binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); - binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); - binary_functor_t f2 = reinterpret_cast<binary_functor_t>(0); - details::free_node(*(expr_gen.node_allocator_),branch[0]); details::free_node(*(expr_gen.node_allocator_),branch[1]); @@ -32063,7 +37422,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf4ext_expression:: - template compile<vtype,vtype,vtype,ctype>(expr_gen, "(t*t)/(t*t)", v0, v2, v1, c, result); + template compile<vtype, vtype, vtype, ctype>(expr_gen, "(t*t)/(t*t)", v0, v2, v1, c, result); exprtk_debug(("(v0 / v1) * (v2 / c) --> (vovovoc) (v0 * v2) / (v1 * c)\n")); @@ -32074,7 +37433,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf4ext_expression:: - template compile<vtype,ctype,vtype,vtype>(expr_gen, "(t*t)/(t*t)", v0, c, v1, v2, result); + template compile<vtype, ctype, vtype, vtype>(expr_gen, "(t*t)/(t*t)", v0, c, v1, v2, result); exprtk_debug(("(v0 / v1) / (v2 / c) --> (vocovov) (v0 * c) / (v1 * v2)\n")); @@ -32088,7 +37447,12 @@ namespace exprtk if (synthesis_result) return result; - else if (!expr_gen.valid_operator(o0,f0)) + + binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); + binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); + binary_functor_t f2 = reinterpret_cast<binary_functor_t>(0); + + if (!expr_gen.valid_operator(o0,f0)) return error_node(); else if (!expr_gen.valid_operator(o1,f1)) return error_node(); @@ -32104,10 +37468,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t)"; + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; } }; @@ -32135,10 +37499,6 @@ namespace exprtk const details::operator_type o1 = operation; const details::operator_type o2 = cov->operation(); - binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); - binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); - binary_functor_t f2 = reinterpret_cast<binary_functor_t>(0); - details::free_node(*(expr_gen.node_allocator_),branch[0]); details::free_node(*(expr_gen.node_allocator_),branch[1]); @@ -32151,7 +37511,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf4ext_expression:: - template compile<vtype,ctype,vtype,vtype>(expr_gen, "(t*t)/(t*t)", v0, c, v1, v2, result); + template compile<vtype, ctype, vtype, vtype>(expr_gen, "(t*t)/(t*t)", v0, c, v1, v2, result); exprtk_debug(("(v0 / v1) * (c / v2) --> (vocovov) (v0 * c) / (v1 * v2)\n")); @@ -32162,7 +37522,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf4ext_expression:: - template compile<vtype,vtype,vtype,ctype>(expr_gen, "(t*t)/(t*t)", v0, v2, v1, c, result); + template compile<vtype, vtype, vtype, ctype>(expr_gen, "(t*t)/(t*t)", v0, v2, v1, c, result); exprtk_debug(("(v0 / v1) / (c / v2) --> (vovovoc) (v0 * v2) / (v1 * c)\n")); @@ -32176,7 +37536,12 @@ namespace exprtk if (synthesis_result) return result; - else if (!expr_gen.valid_operator(o0,f0)) + + binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); + binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); + binary_functor_t f2 = reinterpret_cast<binary_functor_t>(0); + + if (!expr_gen.valid_operator(o0,f0)) return error_node(); else if (!expr_gen.valid_operator(o1,f1)) return error_node(); @@ -32192,10 +37557,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t)"; + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; } }; @@ -32223,10 +37588,6 @@ namespace exprtk const details::operator_type o1 = operation; const details::operator_type o2 = vov->operation(); - binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); - binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); - binary_functor_t f2 = reinterpret_cast<binary_functor_t>(0); - details::free_node(*(expr_gen.node_allocator_),branch[0]); details::free_node(*(expr_gen.node_allocator_),branch[1]); @@ -32239,7 +37600,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf4ext_expression:: - template compile<vtype,vtype,ctype,vtype>(expr_gen, "(t*t)/(t*t)", v0, v1, c, v2, result); + template compile<vtype, vtype, ctype, vtype>(expr_gen, "(t*t)/(t*t)", v0, v1, c, v2, result); exprtk_debug(("(v0 / c) * (v1 / v2) --> (vovocov) (v0 * v1) / (c * v2)\n")); @@ -32250,7 +37611,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf4ext_expression:: - template compile<vtype,vtype,ctype,vtype>(expr_gen, "(t*t)/(t*t)", v0, v2, c, v1, result); + template compile<vtype, vtype, ctype, vtype>(expr_gen, "(t*t)/(t*t)", v0, v2, c, v1, result); exprtk_debug(("(v0 / c) / (v1 / v2) --> (vovocov) (v0 * v2) / (c * v1)\n")); @@ -32264,7 +37625,12 @@ namespace exprtk if (synthesis_result) return result; - else if (!expr_gen.valid_operator(o0,f0)) + + binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); + binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); + binary_functor_t f2 = reinterpret_cast<binary_functor_t>(0); + + if (!expr_gen.valid_operator(o0,f0)) return error_node(); else if (!expr_gen.valid_operator(o1,f1)) return error_node(); @@ -32280,10 +37646,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t)"; + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; } }; @@ -32311,10 +37677,6 @@ namespace exprtk const details::operator_type o1 = operation; const details::operator_type o2 = vov->operation(); - binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); - binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); - binary_functor_t f2 = reinterpret_cast<binary_functor_t>(0); - details::free_node(*(expr_gen.node_allocator_),branch[0]); details::free_node(*(expr_gen.node_allocator_),branch[1]); @@ -32327,7 +37689,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf4ext_expression:: - template compile<ctype,vtype,vtype,vtype>(expr_gen, "(t*t)/(t*t)", c, v1, v0, v2, result); + template compile<ctype, vtype, vtype, vtype>(expr_gen, "(t*t)/(t*t)", c, v1, v0, v2, result); exprtk_debug(("(c / v0) * (v1 / v2) --> (covovov) (c * v1) / (v0 * v2)\n")); @@ -32338,7 +37700,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf4ext_expression:: - template compile<ctype,vtype,vtype,vtype>(expr_gen, "(t*t)/(t*t)", c, v2, v0, v1, result); + template compile<ctype, vtype, vtype, vtype>(expr_gen, "(t*t)/(t*t)", c, v2, v0, v1, result); exprtk_debug(("(c / v0) / (v1 / v2) --> (covovov) (c * v2) / (v0 * v1)\n")); @@ -32352,7 +37714,12 @@ namespace exprtk if (synthesis_result) return result; - else if (!expr_gen.valid_operator(o0,f0)) + + binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); + binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); + binary_functor_t f2 = reinterpret_cast<binary_functor_t>(0); + + if (!expr_gen.valid_operator(o0,f0)) return error_node(); else if (!expr_gen.valid_operator(o1,f1)) return error_node(); @@ -32368,10 +37735,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t)"; + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; } }; @@ -32399,10 +37766,6 @@ namespace exprtk const details::operator_type o1 = operation; const details::operator_type o2 = cov1->operation(); - binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); - binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); - binary_functor_t f2 = reinterpret_cast<binary_functor_t>(0); - details::free_node(*(expr_gen.node_allocator_),branch[0]); details::free_node(*(expr_gen.node_allocator_),branch[1]); @@ -32415,7 +37778,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen, "(t+t)+t", (c0 + c1), v0, v1, result); + template compile<ctype, vtype, vtype>(expr_gen, "(t+t)+t", (c0 + c1), v0, v1, result); exprtk_debug(("(c0 + v0) + (c1 + v1) --> (covov) (c0 + c1) + v0 + v1\n")); @@ -32426,7 +37789,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen, "(t+t)-t", (c0 - c1), v0, v1, result); + template compile<ctype, vtype, vtype>(expr_gen, "(t+t)-t", (c0 - c1), v0, v1, result); exprtk_debug(("(c0 + v0) - (c1 + v1) --> (covov) (c0 - c1) + v0 - v1\n")); @@ -32437,7 +37800,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen, "(t-t)+t", (c0 - c1), v0, v1, result); + template compile<ctype, vtype, vtype>(expr_gen, "(t-t)+t", (c0 - c1), v0, v1, result); exprtk_debug(("(c0 - v0) - (c1 - v1) --> (covov) (c0 - c1) - v0 + v1\n")); @@ -32448,7 +37811,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen, "(t*t)*t", (c0 * c1), v0, v1, result); + template compile<ctype, vtype, vtype>(expr_gen, "(t*t)*t", (c0 * c1), v0, v1, result); exprtk_debug(("(c0 * v0) * (c1 * v1) --> (covov) (c0 * c1) * v0 * v1\n")); @@ -32459,7 +37822,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen, "(t*t)/t", (c0 / c1), v0, v1, result); + template compile<ctype, vtype, vtype>(expr_gen, "(t*t)/t", (c0 / c1), v0, v1, result); exprtk_debug(("(c0 * v0) / (c1 * v1) --> (covov) (c0 / c1) * (v0 / v1)\n")); @@ -32470,7 +37833,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen, "t/(t*t)", (c0 * c1), v0, v1, result); + template compile<ctype, vtype, vtype>(expr_gen, "t/(t*t)", (c0 * c1), v0, v1, result); exprtk_debug(("(c0 / v0) * (c1 / v1) --> (covov) (c0 * c1) / (v0 * v1)\n")); @@ -32481,7 +37844,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen, "(t*t)/t", (c0 / c1), v1, v0, result); + template compile<ctype, vtype, vtype>(expr_gen, "(t*t)/t", (c0 / c1), v1, v0, result); exprtk_debug(("(c0 / v0) / (c1 / v1) --> (covov) ((c0 / c1) * v1) / v0\n")); @@ -32492,7 +37855,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen, "t*(t*t)", (c0 / c1), v0, v1, result); + template compile<ctype, vtype, vtype>(expr_gen, "t*(t*t)", (c0 / c1), v0, v1, result); exprtk_debug(("(c0 * v0) / (c1 / v1) --> (covov) (c0 / c1) * (v0 * v1)\n")); @@ -32503,7 +37866,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen, "t/(t*t)", (c0 / c1), v0, v1, result); + template compile<ctype, vtype, vtype>(expr_gen, "t/(t*t)", (c0 / c1), v0, v1, result); exprtk_debug(("(c0 / v0) / (c1 * v1) --> (covov) (c0 / c1) / (v0 * v1)\n")); @@ -32545,7 +37908,12 @@ namespace exprtk if (synthesis_result) return result; - else if (!expr_gen.valid_operator(o0,f0)) + + binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); + binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); + binary_functor_t f2 = reinterpret_cast<binary_functor_t>(0); + + if (!expr_gen.valid_operator(o0,f0)) return error_node(); else if (!expr_gen.valid_operator(o1,f1)) return error_node(); @@ -32561,10 +37929,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t)"; + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; } }; @@ -32592,10 +37960,6 @@ namespace exprtk const details::operator_type o1 = operation; const details::operator_type o2 = voc1->operation(); - binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); - binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); - binary_functor_t f2 = reinterpret_cast<binary_functor_t>(0); - details::free_node(*(expr_gen.node_allocator_),branch[0]); details::free_node(*(expr_gen.node_allocator_),branch[1]); @@ -32608,7 +37972,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen, "(t+t)+t", (c0 + c1), v0, v1, result); + template compile<ctype, vtype, vtype>(expr_gen, "(t+t)+t", (c0 + c1), v0, v1, result); exprtk_debug(("(v0 + c0) + (v1 + c1) --> (covov) (c0 + c1) + v0 + v1\n")); @@ -32619,7 +37983,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen, "(t+t)-t", (c0 - c1), v0, v1, result); + template compile<ctype, vtype, vtype>(expr_gen, "(t+t)-t", (c0 - c1), v0, v1, result); exprtk_debug(("(v0 + c0) - (v1 + c1) --> (covov) (c0 - c1) + v0 - v1\n")); @@ -32630,7 +37994,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen, "(t+t)-t", (c1 - c0), v0, v1, result); + template compile<ctype, vtype, vtype>(expr_gen, "(t+t)-t", (c1 - c0), v0, v1, result); exprtk_debug(("(v0 - c0) - (v1 - c1) --> (covov) (c1 - c0) + v0 - v1\n")); @@ -32641,7 +38005,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen, "(t*t)*t", (c0 * c1), v0, v1, result); + template compile<ctype, vtype, vtype>(expr_gen, "(t*t)*t", (c0 * c1), v0, v1, result); exprtk_debug(("(v0 * c0) * (v1 * c1) --> (covov) (c0 * c1) * v0 * v1\n")); @@ -32652,7 +38016,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen, "(t*t)/t", (c0 / c1), v0, v1, result); + template compile<ctype, vtype, vtype>(expr_gen, "(t*t)/t", (c0 / c1), v0, v1, result); exprtk_debug(("(v0 * c0) / (v1 * c1) --> (covov) (c0 / c1) * (v0 / v1)\n")); @@ -32663,7 +38027,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen, "(t*t)*t", Type(1) / (c0 * c1), v0, v1, result); + template compile<ctype, vtype, vtype>(expr_gen, "(t*t)*t", Type(1) / (c0 * c1), v0, v1, result); exprtk_debug(("(v0 / c0) * (v1 / c1) --> (covov) (1 / (c0 * c1)) * v0 * v1\n")); @@ -32674,7 +38038,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen, "(t*t)/t", (c1 / c0), v0, v1, result); + template compile<ctype, vtype, vtype>(expr_gen, "(t*t)/t", (c1 / c0), v0, v1, result); exprtk_debug(("(v0 / c0) / (v1 / c1) --> (covov) ((c1 / c0) * v0) / v1\n")); @@ -32685,7 +38049,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen, "t*(t/t)", (c0 * c1), v0, v1, result); + template compile<ctype, vtype, vtype>(expr_gen, "t*(t/t)", (c0 * c1), v0, v1, result); exprtk_debug(("(v0 * c0) / (v1 / c1) --> (covov) (c0 * c1) * (v0 / v1)\n")); @@ -32696,7 +38060,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen, "t*(t/t)", Type(1) / (c0 * c1), v0, v1, result); + template compile<ctype, vtype, vtype>(expr_gen, "t*(t/t)", Type(1) / (c0 * c1), v0, v1, result); exprtk_debug(("(v0 / c0) / (v1 * c1) --> (covov) (1 / (c0 * c1)) * v0 / v1\n")); @@ -32707,7 +38071,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf4ext_expression:: - template compile<vtype,ctype,vtype,ctype>(expr_gen, "(t*t)*(t+t)", v0, T(1) / c0, v1, c1, result); + template compile<vtype, ctype, vtype, ctype>(expr_gen, "(t*t)*(t+t)", v0, T(1) / c0, v1, c1, result); exprtk_debug(("(v0 / c0) * (v1 + c1) --> (vocovoc) (v0 * (1 / c0)) * (v1 + c1)\n")); @@ -32718,7 +38082,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf4ext_expression:: - template compile<vtype,ctype,vtype,ctype>(expr_gen, "(t*t)*(t-t)", v0, T(1) / c0, v1, c1, result); + template compile<vtype, ctype, vtype, ctype>(expr_gen, "(t*t)*(t-t)", v0, T(1) / c0, v1, c1, result); exprtk_debug(("(v0 / c0) * (v1 - c1) --> (vocovoc) (v0 * (1 / c0)) * (v1 - c1)\n")); @@ -32746,7 +38110,7 @@ namespace exprtk const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen, specfunc, c0, v0, v1, result); + template compile<ctype, vtype, vtype>(expr_gen, specfunc, c0, v0, v1, result); exprtk_debug(("(v0 * c) +/- (v1 * c) --> (covov) c * (v0 +/- v1)\n")); @@ -32774,7 +38138,7 @@ namespace exprtk const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<vtype,vtype,ctype>(expr_gen, specfunc, v0, v1, c0, result); + template compile<vtype, vtype, ctype>(expr_gen, specfunc, v0, v1, c0, result); exprtk_debug(("(v0 / c) +/- (v1 / c) --> (vovoc) (v0 +/- v1) / c\n")); @@ -32788,7 +38152,12 @@ namespace exprtk if (synthesis_result) return result; - else if (!expr_gen.valid_operator(o0,f0)) + + binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); + binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); + binary_functor_t f2 = reinterpret_cast<binary_functor_t>(0); + + if (!expr_gen.valid_operator(o0,f0)) return error_node(); else if (!expr_gen.valid_operator(o1,f1)) return error_node(); @@ -32804,10 +38173,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t)"; + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; } }; @@ -32835,10 +38204,6 @@ namespace exprtk const details::operator_type o1 = operation; const details::operator_type o2 = voc->operation(); - binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); - binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); - binary_functor_t f2 = reinterpret_cast<binary_functor_t>(0); - details::free_node(*(expr_gen.node_allocator_),branch[0]); details::free_node(*(expr_gen.node_allocator_),branch[1]); @@ -32851,7 +38216,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen, "(t+t)+t", (c0 + c1), v0, v1, result); + template compile<ctype, vtype, vtype>(expr_gen, "(t+t)+t", (c0 + c1), v0, v1, result); exprtk_debug(("(c0 + v0) + (v1 + c1) --> (covov) (c0 + c1) + v0 + v1\n")); @@ -32862,7 +38227,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen, "(t+t)-t", (c0 - c1), v0, v1, result); + template compile<ctype, vtype, vtype>(expr_gen, "(t+t)-t", (c0 - c1), v0, v1, result); exprtk_debug(("(c0 + v0) - (v1 + c1) --> (covov) (c0 - c1) + v0 - v1\n")); @@ -32873,7 +38238,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen, "t-(t+t)", (c0 + c1), v0, v1, result); + template compile<ctype, vtype, vtype>(expr_gen, "t-(t+t)", (c0 + c1), v0, v1, result); exprtk_debug(("(c0 - v0) - (v1 - c1) --> (covov) (c0 + c1) - v0 - v1\n")); @@ -32884,7 +38249,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen, "(t*t)*t", (c0 * c1), v0, v1, result); + template compile<ctype, vtype, vtype>(expr_gen, "(t*t)*t", (c0 * c1), v0, v1, result); exprtk_debug(("(c0 * v0) * (v1 * c1) --> (covov) (c0 * c1) * v0 * v1\n")); @@ -32895,7 +38260,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen, "(t*t)/t", (c0 / c1), v0, v1, result); + template compile<ctype, vtype, vtype>(expr_gen, "(t*t)/t", (c0 / c1), v0, v1, result); exprtk_debug(("(c0 * v0) / (v1 * c1) --> (covov) (c0 / c1) * (v0 / v1)\n")); @@ -32906,7 +38271,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen, "t*(t/t)", (c0 / c1), v1, v0, result); + template compile<ctype, vtype, vtype>(expr_gen, "t*(t/t)", (c0 / c1), v1, v0, result); exprtk_debug(("(c0 / v0) * (v1 / c1) --> (covov) (c0 / c1) * (v1 / v0)\n")); @@ -32917,7 +38282,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen, "t/(t*t)", (c0 * c1), v0, v1, result); + template compile<ctype, vtype, vtype>(expr_gen, "t/(t*t)", (c0 * c1), v0, v1, result); exprtk_debug(("(c0 / v0) / (v1 / c1) --> (covov) (c0 * c1) / (v0 * v1)\n")); @@ -32928,7 +38293,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen, "(t*t)/t", (c0 * c1), v0, v1, result); + template compile<ctype, vtype, vtype>(expr_gen, "(t*t)/t", (c0 * c1), v0, v1, result); exprtk_debug(("(c0 * v0) / (v1 / c1) --> (covov) (c0 * c1) * (v0 / v1)\n")); @@ -32939,7 +38304,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen, "t/(t*t)", (c0 / c1), v0, v1, result); + template compile<ctype, vtype, vtype>(expr_gen, "t/(t*t)", (c0 / c1), v0, v1, result); exprtk_debug(("(c0 / v0) / (v1 * c1) --> (covov) (c0 / c1) / (v0 * v1)\n")); @@ -32967,7 +38332,7 @@ namespace exprtk const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen,specfunc, c0, v0, v1, result); + template compile<ctype, vtype, vtype>(expr_gen, specfunc, c0, v0, v1, result); exprtk_debug(("(c * v0) +/- (v1 * c) --> (covov) c * (v0 +/- v1)\n")); @@ -32981,7 +38346,12 @@ namespace exprtk if (synthesis_result) return result; - else if (!expr_gen.valid_operator(o0,f0)) + + binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); + binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); + binary_functor_t f2 = reinterpret_cast<binary_functor_t>(0); + + if (!expr_gen.valid_operator(o0,f0)) return error_node(); else if (!expr_gen.valid_operator(o1,f1)) return error_node(); @@ -32997,10 +38367,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t)"; + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; } }; @@ -33028,10 +38398,6 @@ namespace exprtk const details::operator_type o1 = operation; const details::operator_type o2 = cov->operation(); - binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); - binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); - binary_functor_t f2 = reinterpret_cast<binary_functor_t>(0); - details::free_node(*(expr_gen.node_allocator_),branch[0]); details::free_node(*(expr_gen.node_allocator_),branch[1]); @@ -33044,7 +38410,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen, "(t+t)+t", (c0 + c1), v0, v1, result); + template compile<ctype, vtype, vtype>(expr_gen, "(t+t)+t", (c0 + c1), v0, v1, result); exprtk_debug(("(v0 + c0) + (c1 + v1) --> (covov) (c0 + c1) + v0 + v1\n")); @@ -33055,7 +38421,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen, "(t+t)-t", (c0 - c1), v0, v1, result); + template compile<ctype, vtype, vtype>(expr_gen, "(t+t)-t", (c0 - c1), v0, v1, result); exprtk_debug(("(v0 + c0) - (c1 + v1) --> (covov) (c0 - c1) + v0 - v1\n")); @@ -33066,7 +38432,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<vtype,vtype,ctype>(expr_gen, "(t+t)-t", v0, v1, (c1 + c0), result); + template compile<vtype, vtype, ctype>(expr_gen, "(t+t)-t", v0, v1, (c1 + c0), result); exprtk_debug(("(v0 - c0) - (c1 - v1) --> (vovoc) v0 + v1 - (c1 + c0)\n")); @@ -33077,7 +38443,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen, "(t*t)*t", (c0 * c1), v0, v1, result); + template compile<ctype, vtype, vtype>(expr_gen, "(t*t)*t", (c0 * c1), v0, v1, result); exprtk_debug(("(v0 * c0) * (c1 * v1) --> (covov) (c0 * c1) * v0 * v1\n")); @@ -33088,7 +38454,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen, "(t*t)/t", (c0 / c1), v0, v1, result); + template compile<ctype, vtype, vtype>(expr_gen, "(t*t)/t", (c0 / c1), v0, v1, result); exprtk_debug(("(v0 * c0) / (c1 * v1) --> (covov) (c0 / c1) * (v0 * v1)\n")); @@ -33099,7 +38465,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen, "(t*t)/t", (c1 / c0), v0, v1, result); + template compile<ctype, vtype, vtype>(expr_gen, "(t*t)/t", (c1 / c0), v0, v1, result); exprtk_debug(("(v0 / c0) * (c1 / v1) --> (covov) (c1 / c0) * (v0 / v1)\n")); @@ -33110,7 +38476,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen, "(t*t)*t", (c0 / c1), v0, v1, result); + template compile<ctype, vtype, vtype>(expr_gen, "(t*t)*t", (c0 / c1), v0, v1, result); exprtk_debug(("(v0 * c0) / (c1 / v1) --> (covov) (c0 / c1) * (v0 * v1)\n")); @@ -33121,7 +38487,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen, "(t*t)/t", Type(1) / (c0 * c1), v0, v1, result); + template compile<ctype, vtype, vtype>(expr_gen, "(t*t)/t", Type(1) / (c0 * c1), v0, v1, result); exprtk_debug(("(v0 / c0) / (c1 * v1) --> (covov) (1 / (c0 * c1)) * (v0 / v1)\n")); @@ -33132,7 +38498,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<vtype,vtype,ctype>(expr_gen, "(t*t)*t", v0, v1, Type(1) / (c0 * c1), result); + template compile<vtype, vtype, ctype>(expr_gen, "(t*t)*t", v0, v1, Type(1) / (c0 * c1), result); exprtk_debug(("(v0 / c0) / (c1 / v1) --> (vovoc) (v0 * v1) * (1 / (c0 * c1))\n")); @@ -33159,7 +38525,7 @@ namespace exprtk const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen, specfunc, c0, v0, v1, result); + template compile<ctype, vtype, vtype>(expr_gen, specfunc, c0, v0, v1, result); exprtk_debug(("(v0 * c) +/- (c * v1) --> (covov) c * (v0 +/- v1)\n")); @@ -33173,7 +38539,12 @@ namespace exprtk if (synthesis_result) return result; - else if (!expr_gen.valid_operator(o0,f0)) + + binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0); + binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0); + binary_functor_t f2 = reinterpret_cast<binary_functor_t>(0); + + if (!expr_gen.valid_operator(o0,f0)) return error_node(); else if (!expr_gen.valid_operator(o1,f1)) return error_node(); @@ -33189,10 +38560,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t)"; + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; } }; @@ -33229,14 +38600,18 @@ namespace exprtk expression_node_ptr result = error_node(); - if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,v2,v3,result)) + const bool synthesis_result = + synthesize_sf4ext_expression::template compile<T0, T1, T2, T3> + (expr_gen,id(expr_gen, o0, o1, o2), v0, v1, v2, v3, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); exprtk_debug(("v0 o0 (v1 o1 (v2 o2 v3))\n")); - return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,v3,f0,f1,f2); + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, v3, f0, f1, f2); } static inline std::string id(expression_generator<Type>& expr_gen, @@ -33245,10 +38620,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t))"; + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; } }; @@ -33305,10 +38680,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t))"; + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; } }; @@ -33365,10 +38740,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t))"; + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; } }; @@ -33425,10 +38800,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t))"; + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; } }; @@ -33486,10 +38861,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t))"; + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; } }; @@ -33547,10 +38922,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t))"; + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; } }; @@ -33607,10 +38982,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t))"; + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; } }; @@ -33667,10 +39042,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t))"; + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; } }; @@ -33727,10 +39102,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t))"; + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; } }; @@ -33787,10 +39162,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "((t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t)"; + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; } }; @@ -33847,10 +39222,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "((t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t)"; + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; } }; @@ -33907,10 +39282,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "((t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t)"; + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; } }; @@ -33967,10 +39342,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "((t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t)"; + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; } }; @@ -34028,10 +39403,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "((t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t)"; + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; } }; @@ -34089,10 +39464,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "((t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t)"; + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; } }; @@ -34149,10 +39524,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "((t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t)"; + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; } }; @@ -34210,17 +39585,19 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "t" << expr_gen.to_str(o0) - << "((t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t)"; + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; } }; struct synthesize_vococov_expression2 { typedef typename vococov_t::type2 node_type; - static inline expression_node_ptr process(expression_generator<Type>&, const details::operator_type&, expression_node_ptr (&)[2]) + static inline expression_node_ptr process(expression_generator<Type>&, + const details::operator_type&, + expression_node_ptr (&)[2]) { // v0 o0 ((c0 o1 c1) o2 v1) - Not possible exprtk_debug(("v0 o0 ((c0 o1 c1) o2 v1) - Not possible\n")); @@ -34228,7 +39605,9 @@ namespace exprtk } static inline std::string id(expression_generator<Type>&, - const details::operator_type, const details::operator_type, const details::operator_type) + const details::operator_type, + const details::operator_type, + const details::operator_type) { return "INVALID"; } @@ -34287,10 +39666,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "((t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -34348,10 +39727,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "((t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -34408,10 +39787,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "((t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -34468,10 +39847,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "((t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -34528,10 +39907,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "((t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -34588,10 +39967,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "((t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -34649,10 +40028,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "((t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -34710,10 +40089,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "((t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -34770,10 +40149,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "((t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -34830,10 +40209,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -34891,10 +40270,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -34951,10 +40330,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -35010,10 +40389,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -35070,10 +40449,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -35130,10 +40509,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -35191,10 +40570,10 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -35252,17 +40631,19 @@ namespace exprtk const details::operator_type o2) { return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; struct synthesize_vococov_expression4 { typedef typename vococov_t::type4 node_type; - static inline expression_node_ptr process(expression_generator<Type>&, const details::operator_type&, expression_node_ptr (&)[2]) + static inline expression_node_ptr process(expression_generator<Type>&, + const details::operator_type&, + expression_node_ptr (&)[2]) { // ((v0 o0 (c0 o1 c1)) o2 v1) - Not possible exprtk_debug(("((v0 o0 (c0 o1 c1)) o2 v1) - Not possible\n")); @@ -35270,7 +40651,9 @@ namespace exprtk } static inline std::string id(expression_generator<Type>&, - const details::operator_type, const details::operator_type, const details::operator_type) + const details::operator_type, + const details::operator_type, + const details::operator_type) { return "INVALID"; } @@ -35353,16 +40736,16 @@ namespace exprtk #ifndef exprtk_disable_string_capabilities - #define string_opr_switch_statements \ - case_stmt(details:: e_lt ,details:: lt_op) \ - case_stmt(details:: e_lte ,details:: lte_op) \ - case_stmt(details:: e_gt ,details:: gt_op) \ - case_stmt(details:: e_gte ,details:: gte_op) \ - case_stmt(details:: e_eq ,details:: eq_op) \ - case_stmt(details:: e_ne ,details:: ne_op) \ - case_stmt(details::e_in ,details:: in_op) \ - case_stmt(details::e_like ,details:: like_op) \ - case_stmt(details::e_ilike,details::ilike_op) \ + #define string_opr_switch_statements \ + case_stmt(details::e_lt , details::lt_op ) \ + case_stmt(details::e_lte , details::lte_op ) \ + case_stmt(details::e_gt , details::gt_op ) \ + case_stmt(details::e_gte , details::gte_op ) \ + case_stmt(details::e_eq , details::eq_op ) \ + case_stmt(details::e_ne , details::ne_op ) \ + case_stmt(details::e_in , details::in_op ) \ + case_stmt(details::e_like , details::like_op ) \ + case_stmt(details::e_ilike , details::ilike_op) \ template <typename T0, typename T1> inline expression_node_ptr synthesize_str_xrox_expression_impl(const details::operator_type& opr, @@ -35371,7 +40754,7 @@ namespace exprtk { switch (opr) { - #define case_stmt(op0,op1) \ + #define case_stmt(op0, op1) \ case op0 : return node_allocator_-> \ allocate_ttt<typename details::str_xrox_node<Type,T0,T1,range_t,op1<Type> >,T0,T1> \ (s0, s1, rp0); \ @@ -35389,7 +40772,7 @@ namespace exprtk { switch (opr) { - #define case_stmt(op0,op1) \ + #define case_stmt(op0, op1) \ case op0 : return node_allocator_-> \ allocate_ttt<typename details::str_xoxr_node<Type,T0,T1,range_t,op1<Type> >,T0,T1> \ (s0, s1, rp1); \ @@ -35407,7 +40790,7 @@ namespace exprtk { switch (opr) { - #define case_stmt(op0,op1) \ + #define case_stmt(op0, op1) \ case op0 : return node_allocator_-> \ allocate_tttt<typename details::str_xroxr_node<Type,T0,T1,range_t,op1<Type> >,T0,T1> \ (s0, s1, rp0, rp1); \ @@ -35423,7 +40806,7 @@ namespace exprtk { switch (opr) { - #define case_stmt(op0,op1) \ + #define case_stmt(op0, op1) \ case op0 : return node_allocator_-> \ allocate_tt<typename details::sos_node<Type,T0,T1,op1<Type> >,T0,T1>(s0, s1); \ @@ -35449,7 +40832,7 @@ namespace exprtk static_cast<details::string_range_node<Type>*>(branch[0])->range_ref().clear(); - free_node(*node_allocator_,branch[0]); + details::free_node(*node_allocator_,branch[0]); return synthesize_str_xrox_expression_impl<std::string&,std::string&>(opr, s0, s1, rp0); } @@ -35462,7 +40845,7 @@ namespace exprtk static_cast<details::string_range_node<Type>*>(branch[1])->range_ref().clear(); - free_node(*node_allocator_,branch[1]); + details::free_node(*node_allocator_,branch[1]); return synthesize_str_xoxr_expression_impl<std::string&,std::string&>(opr, s0, s1, rp1); } @@ -35475,7 +40858,7 @@ namespace exprtk static_cast<details::const_string_range_node<Type>*>(branch[1])->range_ref().clear(); - free_node(*node_allocator_,branch[1]); + details::free_node(*node_allocator_,branch[1]); return synthesize_str_xoxr_expression_impl<std::string&, const std::string>(opr, s0, s1, rp1); } @@ -35509,7 +40892,7 @@ namespace exprtk inline expression_node_ptr synthesize_csos_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) { std::string s0 = static_cast<details::string_literal_node<Type>*>(branch[0])->str(); - std::string& s1 = static_cast< details::stringvar_node<Type>*>(branch[1])->ref(); + std::string& s1 = static_cast<details::stringvar_node<Type>* >(branch[1])->ref(); details::free_node(*node_allocator_,branch[0]); @@ -35518,9 +40901,9 @@ namespace exprtk inline expression_node_ptr synthesize_csosr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) { - std::string s0 = static_cast<details::string_literal_node<Type>*>(branch[0])->str (); - std::string& s1 = static_cast<details::string_range_node<Type>*> (branch[1])->ref (); - range_t rp1 = static_cast<details::string_range_node<Type>*> (branch[1])->range(); + std::string s0 = static_cast<details::string_literal_node<Type>*>(branch[0])->str (); + std::string& s1 = static_cast<details::string_range_node<Type>* >(branch[1])->ref (); + range_t rp1 = static_cast<details::string_range_node<Type>* >(branch[1])->range(); static_cast<details::string_range_node<Type>*>(branch[1])->range_ref().clear(); @@ -35532,9 +40915,9 @@ namespace exprtk inline expression_node_ptr synthesize_srocs_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) { - std::string& s0 = static_cast<details::string_range_node<Type>*> (branch[0])->ref (); + std::string& s0 = static_cast<details::string_range_node<Type>* >(branch[0])->ref (); std::string s1 = static_cast<details::string_literal_node<Type>*>(branch[1])->str (); - range_t rp0 = static_cast<details::string_range_node<Type>*> (branch[0])->range(); + range_t rp0 = static_cast<details::string_range_node<Type>* >(branch[0])->range(); static_cast<details::string_range_node<Type>*>(branch[0])->range_ref().clear(); @@ -35546,9 +40929,9 @@ namespace exprtk inline expression_node_ptr synthesize_srocsr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) { - std::string& s0 = static_cast<details::string_range_node<Type>*> (branch[0])->ref (); + std::string& s0 = static_cast<details::string_range_node<Type>* >(branch[0])->ref (); std::string s1 = static_cast<details::const_string_range_node<Type>*>(branch[1])->str (); - range_t rp0 = static_cast<details::string_range_node<Type>*> (branch[0])->range(); + range_t rp0 = static_cast<details::string_range_node<Type>* >(branch[0])->range(); range_t rp1 = static_cast<details::const_string_range_node<Type>*>(branch[1])->range(); static_cast<details::string_range_node<Type>*> (branch[0])->range_ref().clear(); @@ -35593,14 +40976,14 @@ namespace exprtk inline expression_node_ptr synthesize_csocsr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) { - const std::string s0 = static_cast<details::string_literal_node<Type>*> (branch[0])->str (); + const std::string s0 = static_cast<details::string_literal_node<Type>* >(branch[0])->str (); std::string s1 = static_cast<details::const_string_range_node<Type>*>(branch[1])->str (); range_t rp1 = static_cast<details::const_string_range_node<Type>*>(branch[1])->range(); static_cast<details::const_string_range_node<Type>*>(branch[1])->range_ref().clear(); - free_node(*node_allocator_,branch[0]); - free_node(*node_allocator_,branch[1]); + details::free_node(*node_allocator_,branch[0]); + details::free_node(*node_allocator_,branch[1]); return synthesize_str_xoxr_expression_impl<const std::string, const std::string>(opr, s0, s1, rp1); } @@ -35608,12 +40991,12 @@ namespace exprtk inline expression_node_ptr synthesize_csros_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) { std::string s0 = static_cast<details::const_string_range_node<Type>*>(branch[0])->str (); - std::string& s1 = static_cast<details::stringvar_node<Type>*> (branch[1])->ref (); + std::string& s1 = static_cast<details::stringvar_node<Type>* >(branch[1])->ref (); range_t rp0 = static_cast<details::const_string_range_node<Type>*>(branch[0])->range(); static_cast<details::const_string_range_node<Type>*>(branch[0])->range_ref().clear(); - free_node(*node_allocator_,branch[0]); + details::free_node(*node_allocator_,branch[0]); return synthesize_str_xrox_expression_impl<const std::string,std::string&>(opr, s0, s1, rp0); } @@ -35621,15 +41004,15 @@ namespace exprtk inline expression_node_ptr synthesize_csrosr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) { const std::string s0 = static_cast<details::const_string_range_node<Type>*>(branch[0])->str (); - std::string& s1 = static_cast<details::string_range_node<Type>*> (branch[1])->ref (); + std::string& s1 = static_cast<details::string_range_node<Type>* >(branch[1])->ref (); const range_t rp0 = static_cast<details::const_string_range_node<Type>*>(branch[0])->range(); - const range_t rp1 = static_cast<details::string_range_node<Type>*> (branch[1])->range(); + const range_t rp1 = static_cast<details::string_range_node<Type>* >(branch[1])->range(); static_cast<details::const_string_range_node<Type>*>(branch[0])->range_ref().clear(); static_cast<details::string_range_node<Type>*> (branch[1])->range_ref().clear(); - free_node(*node_allocator_,branch[0]); - free_node(*node_allocator_,branch[1]); + details::free_node(*node_allocator_,branch[0]); + details::free_node(*node_allocator_,branch[1]); return synthesize_str_xroxr_expression_impl<const std::string,std::string&>(opr, s0, s1, rp0, rp1); } @@ -35637,7 +41020,7 @@ namespace exprtk inline expression_node_ptr synthesize_csrocs_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) { const std::string s0 = static_cast<details::const_string_range_node<Type>*>(branch[0])->str (); - const std::string s1 = static_cast<details::string_literal_node<Type>*> (branch[1])->str (); + const std::string s1 = static_cast<details::string_literal_node<Type>* >(branch[1])->str (); const range_t rp0 = static_cast<details::const_string_range_node<Type>*>(branch[0])->range(); static_cast<details::const_string_range_node<Type>*>(branch[0])->range_ref().clear(); @@ -35666,7 +41049,7 @@ namespace exprtk { switch (opr) { - #define case_stmt(op0,op1) \ + #define case_stmt(op0, op1) \ case op0 : return node_allocator_-> \ allocate_ttt<typename details::str_sogens_node<Type,op1<Type> > > \ (opr, branch[0], branch[1]); \ @@ -35676,6 +41059,8 @@ namespace exprtk default : return error_node(); } } + + #undef string_opr_switch_statements #endif #ifndef exprtk_disable_string_capabilities @@ -35728,28 +41113,28 @@ namespace exprtk } else if (b0_is_s) { - if (b1_is_s ) return synthesize_sos_expression (opr,branch); + if (b1_is_s ) return synthesize_sos_expression (opr,branch); else if (b1_is_cs ) return synthesize_socs_expression (opr,branch); else if (b1_is_sr ) return synthesize_sosr_expression (opr,branch); else if (b1_is_csr) return synthesize_socsr_expression (opr,branch); } else if (b0_is_cs) { - if (b1_is_s ) return synthesize_csos_expression (opr,branch); + if (b1_is_s ) return synthesize_csos_expression (opr,branch); else if (b1_is_cs ) return synthesize_csocs_expression (opr,branch); else if (b1_is_sr ) return synthesize_csosr_expression (opr,branch); else if (b1_is_csr) return synthesize_csocsr_expression(opr,branch); } else if (b0_is_sr) { - if (b1_is_s ) return synthesize_sros_expression (opr,branch); + if (b1_is_s ) return synthesize_sros_expression (opr,branch); else if (b1_is_sr ) return synthesize_srosr_expression (opr,branch); else if (b1_is_cs ) return synthesize_srocs_expression (opr,branch); else if (b1_is_csr) return synthesize_srocsr_expression(opr,branch); } else if (b0_is_csr) { - if (b1_is_s ) return synthesize_csros_expression (opr,branch); + if (b1_is_s ) return synthesize_csros_expression (opr,branch); else if (b1_is_sr ) return synthesize_csrosr_expression (opr,branch); else if (b1_is_cs ) return synthesize_csrocs_expression (opr,branch); else if (b1_is_csr) return synthesize_csrocsr_expression(opr,branch); @@ -35813,7 +41198,7 @@ namespace exprtk ) { std::string s0 = static_cast<details::string_literal_node<Type>*>(branch[0])->str(); - std::string& s1 = static_cast< details::stringvar_node<Type>*>(branch[1])->ref(); + std::string& s1 = static_cast<details::stringvar_node<Type>* >(branch[1])->ref(); std::string s2 = static_cast<details::string_literal_node<Type>*>(branch[2])->str(); typedef typename details::sosos_node<Type, std::string, std::string&, std::string, details::inrange_op<Type> > inrange_t; @@ -35829,9 +41214,9 @@ namespace exprtk details::is_string_node(branch[2]) ) { - std::string& s0 = static_cast< details::stringvar_node<Type>*>(branch[0])->ref(); + std::string& s0 = static_cast<details::stringvar_node<Type>* >(branch[0])->ref(); std::string s1 = static_cast<details::string_literal_node<Type>*>(branch[1])->str(); - std::string& s2 = static_cast< details::stringvar_node<Type>*>(branch[2])->ref(); + std::string& s2 = static_cast<details::stringvar_node<Type>* >(branch[2])->ref(); typedef typename details::sosos_node<Type, std::string&, std::string, std::string&, details::inrange_op<Type> > inrange_t; @@ -35845,8 +41230,8 @@ namespace exprtk details::is_const_string_node(branch[2]) ) { - std::string& s0 = static_cast< details::stringvar_node<Type>*>(branch[0])->ref(); - std::string& s1 = static_cast< details::stringvar_node<Type>*>(branch[1])->ref(); + std::string& s0 = static_cast<details::stringvar_node<Type>* >(branch[0])->ref(); + std::string& s1 = static_cast<details::stringvar_node<Type>* >(branch[1])->ref(); std::string s2 = static_cast<details::string_literal_node<Type>*>(branch[2])->str(); typedef typename details::sosos_node<Type, std::string&, std::string&, std::string, details::inrange_op<Type> > inrange_t; @@ -35862,8 +41247,8 @@ namespace exprtk ) { std::string s0 = static_cast<details::string_literal_node<Type>*>(branch[0])->str(); - std::string& s1 = static_cast< details::stringvar_node<Type>*>(branch[1])->ref(); - std::string& s2 = static_cast< details::stringvar_node<Type>*>(branch[2])->ref(); + std::string& s1 = static_cast<details::stringvar_node<Type>* >(branch[1])->ref(); + std::string& s2 = static_cast<details::stringvar_node<Type>* >(branch[2])->ref(); typedef typename details::sosos_node<Type, std::string, std::string&, std::string&, details::inrange_op<Type> > inrange_t; @@ -36009,11 +41394,22 @@ namespace exprtk return node_allocator_->allocate<literal_node_t>(v); } - else + + if (expression_point && expression_point->valid()) + { return expression_point; + } + + parser_->set_error(parser_error::make_error( + parser_error::e_parser, + token_t(), + "ERR276 - Failed to synthesize node: NodeType", + exprtk_error_location)); + + details::free_node(*node_allocator_, expression_point); } - else - return error_node(); + + return error_node(); } template <typename NodeType, std::size_t N> @@ -36064,7 +41460,7 @@ namespace exprtk sf3_map_t* sf3_map_; sf4_map_t* sf4_map_; parser_t* parser_; - }; + }; // class expression_generator inline void set_error(const parser_error::type& error_type) { @@ -36093,8 +41489,11 @@ namespace exprtk { scope_element& se = sem_.get_element(i); + exprtk_debug(("register_local_vars() - se[%s]\n", se.name.c_str())); + if ( (scope_element::e_variable == se.type) || + (scope_element::e_literal == se.type) || (scope_element::e_vecelem == se.type) ) { @@ -36154,48 +41553,48 @@ namespace exprtk inline void load_unary_operations_map(unary_op_map_t& m) { - #define register_unary_op(Op,UnaryFunctor) \ + #define register_unary_op(Op, UnaryFunctor) \ m.insert(std::make_pair(Op,UnaryFunctor<T>::process)); \ - register_unary_op(details:: e_abs, details:: abs_op) - register_unary_op(details:: e_acos, details:: acos_op) - register_unary_op(details::e_acosh, details::acosh_op) - register_unary_op(details:: e_asin, details:: asin_op) - register_unary_op(details::e_asinh, details::asinh_op) - register_unary_op(details::e_atanh, details::atanh_op) - register_unary_op(details:: e_ceil, details:: ceil_op) - register_unary_op(details:: e_cos, details:: cos_op) - register_unary_op(details:: e_cosh, details:: cosh_op) - register_unary_op(details:: e_exp, details:: exp_op) - register_unary_op(details::e_expm1, details::expm1_op) - register_unary_op(details::e_floor, details::floor_op) - register_unary_op(details:: e_log, details:: log_op) - register_unary_op(details::e_log10, details::log10_op) - register_unary_op(details:: e_log2, details:: log2_op) - register_unary_op(details::e_log1p, details::log1p_op) - register_unary_op(details:: e_neg, details:: neg_op) - register_unary_op(details:: e_pos, details:: pos_op) - register_unary_op(details::e_round, details::round_op) - register_unary_op(details:: e_sin, details:: sin_op) - register_unary_op(details:: e_sinc, details:: sinc_op) - register_unary_op(details:: e_sinh, details:: sinh_op) - register_unary_op(details:: e_sqrt, details:: sqrt_op) - register_unary_op(details:: e_tan, details:: tan_op) - register_unary_op(details:: e_tanh, details:: tanh_op) - register_unary_op(details:: e_cot, details:: cot_op) - register_unary_op(details:: e_sec, details:: sec_op) - register_unary_op(details:: e_csc, details:: csc_op) - register_unary_op(details:: e_r2d, details:: r2d_op) - register_unary_op(details:: e_d2r, details:: d2r_op) - register_unary_op(details:: e_d2g, details:: d2g_op) - register_unary_op(details:: e_g2d, details:: g2d_op) - register_unary_op(details:: e_notl, details:: notl_op) - register_unary_op(details:: e_sgn, details:: sgn_op) - register_unary_op(details:: e_erf, details:: erf_op) - register_unary_op(details:: e_erfc, details:: erfc_op) - register_unary_op(details:: e_ncdf, details:: ncdf_op) - register_unary_op(details:: e_frac, details:: frac_op) - register_unary_op(details::e_trunc, details::trunc_op) + register_unary_op(details::e_abs , details::abs_op ) + register_unary_op(details::e_acos , details::acos_op ) + register_unary_op(details::e_acosh , details::acosh_op) + register_unary_op(details::e_asin , details::asin_op ) + register_unary_op(details::e_asinh , details::asinh_op) + register_unary_op(details::e_atanh , details::atanh_op) + register_unary_op(details::e_ceil , details::ceil_op ) + register_unary_op(details::e_cos , details::cos_op ) + register_unary_op(details::e_cosh , details::cosh_op ) + register_unary_op(details::e_exp , details::exp_op ) + register_unary_op(details::e_expm1 , details::expm1_op) + register_unary_op(details::e_floor , details::floor_op) + register_unary_op(details::e_log , details::log_op ) + register_unary_op(details::e_log10 , details::log10_op) + register_unary_op(details::e_log2 , details::log2_op ) + register_unary_op(details::e_log1p , details::log1p_op) + register_unary_op(details::e_neg , details::neg_op ) + register_unary_op(details::e_pos , details::pos_op ) + register_unary_op(details::e_round , details::round_op) + register_unary_op(details::e_sin , details::sin_op ) + register_unary_op(details::e_sinc , details::sinc_op ) + register_unary_op(details::e_sinh , details::sinh_op ) + register_unary_op(details::e_sqrt , details::sqrt_op ) + register_unary_op(details::e_tan , details::tan_op ) + register_unary_op(details::e_tanh , details::tanh_op ) + register_unary_op(details::e_cot , details::cot_op ) + register_unary_op(details::e_sec , details::sec_op ) + register_unary_op(details::e_csc , details::csc_op ) + register_unary_op(details::e_r2d , details::r2d_op ) + register_unary_op(details::e_d2r , details::d2r_op ) + register_unary_op(details::e_d2g , details::d2g_op ) + register_unary_op(details::e_g2d , details::g2d_op ) + register_unary_op(details::e_notl , details::notl_op ) + register_unary_op(details::e_sgn , details::sgn_op ) + register_unary_op(details::e_erf , details::erf_op ) + register_unary_op(details::e_erfc , details::erfc_op ) + register_unary_op(details::e_ncdf , details::ncdf_op ) + register_unary_op(details::e_frac , details::frac_op ) + register_unary_op(details::e_trunc , details::trunc_op) #undef register_unary_op } @@ -36203,27 +41602,27 @@ namespace exprtk { typedef typename binary_op_map_t::value_type value_type; - #define register_binary_op(Op,BinaryFunctor) \ + #define register_binary_op(Op, BinaryFunctor) \ m.insert(value_type(Op,BinaryFunctor<T>::process)); \ - register_binary_op(details:: e_add, details:: add_op) - register_binary_op(details:: e_sub, details:: sub_op) - register_binary_op(details:: e_mul, details:: mul_op) - register_binary_op(details:: e_div, details:: div_op) - register_binary_op(details:: e_mod, details:: mod_op) - register_binary_op(details:: e_pow, details:: pow_op) - register_binary_op(details:: e_lt, details:: lt_op) - register_binary_op(details:: e_lte, details:: lte_op) - register_binary_op(details:: e_gt, details:: gt_op) - register_binary_op(details:: e_gte, details:: gte_op) - register_binary_op(details:: e_eq, details:: eq_op) - register_binary_op(details:: e_ne, details:: ne_op) - register_binary_op(details:: e_and, details:: and_op) - register_binary_op(details::e_nand, details::nand_op) - register_binary_op(details:: e_or, details:: or_op) - register_binary_op(details:: e_nor, details:: nor_op) - register_binary_op(details:: e_xor, details:: xor_op) - register_binary_op(details::e_xnor, details::xnor_op) + register_binary_op(details::e_add , details::add_op ) + register_binary_op(details::e_sub , details::sub_op ) + register_binary_op(details::e_mul , details::mul_op ) + register_binary_op(details::e_div , details::div_op ) + register_binary_op(details::e_mod , details::mod_op ) + register_binary_op(details::e_pow , details::pow_op ) + register_binary_op(details::e_lt , details::lt_op ) + register_binary_op(details::e_lte , details::lte_op ) + register_binary_op(details::e_gt , details::gt_op ) + register_binary_op(details::e_gte , details::gte_op ) + register_binary_op(details::e_eq , details::eq_op ) + register_binary_op(details::e_ne , details::ne_op ) + register_binary_op(details::e_and , details::and_op ) + register_binary_op(details::e_nand , details::nand_op) + register_binary_op(details::e_or , details::or_op ) + register_binary_op(details::e_nor , details::nor_op ) + register_binary_op(details::e_xor , details::xor_op ) + register_binary_op(details::e_xnor , details::xnor_op) #undef register_binary_op } @@ -36231,27 +41630,27 @@ namespace exprtk { typedef typename inv_binary_op_map_t::value_type value_type; - #define register_binary_op(Op,BinaryFunctor) \ + #define register_binary_op(Op, BinaryFunctor) \ m.insert(value_type(BinaryFunctor<T>::process,Op)); \ - register_binary_op(details:: e_add, details:: add_op) - register_binary_op(details:: e_sub, details:: sub_op) - register_binary_op(details:: e_mul, details:: mul_op) - register_binary_op(details:: e_div, details:: div_op) - register_binary_op(details:: e_mod, details:: mod_op) - register_binary_op(details:: e_pow, details:: pow_op) - register_binary_op(details:: e_lt, details:: lt_op) - register_binary_op(details:: e_lte, details:: lte_op) - register_binary_op(details:: e_gt, details:: gt_op) - register_binary_op(details:: e_gte, details:: gte_op) - register_binary_op(details:: e_eq, details:: eq_op) - register_binary_op(details:: e_ne, details:: ne_op) - register_binary_op(details:: e_and, details:: and_op) - register_binary_op(details::e_nand, details::nand_op) - register_binary_op(details:: e_or, details:: or_op) - register_binary_op(details:: e_nor, details:: nor_op) - register_binary_op(details:: e_xor, details:: xor_op) - register_binary_op(details::e_xnor, details::xnor_op) + register_binary_op(details::e_add , details::add_op ) + register_binary_op(details::e_sub , details::sub_op ) + register_binary_op(details::e_mul , details::mul_op ) + register_binary_op(details::e_div , details::div_op ) + register_binary_op(details::e_mod , details::mod_op ) + register_binary_op(details::e_pow , details::pow_op ) + register_binary_op(details::e_lt , details::lt_op ) + register_binary_op(details::e_lte , details::lte_op ) + register_binary_op(details::e_gt , details::gt_op ) + register_binary_op(details::e_gte , details::gte_op ) + register_binary_op(details::e_eq , details::eq_op ) + register_binary_op(details::e_ne , details::ne_op ) + register_binary_op(details::e_and , details::and_op ) + register_binary_op(details::e_nand , details::nand_op) + register_binary_op(details::e_or , details::or_op ) + register_binary_op(details::e_nor , details::nor_op ) + register_binary_op(details::e_xor , details::xor_op ) + register_binary_op(details::e_xnor , details::xnor_op) #undef register_binary_op } @@ -36344,8 +41743,8 @@ namespace exprtk private: - parser(const parser<T>&); - parser<T>& operator=(const parser<T>&); + parser(const parser<T>&) exprtk_delete; + parser<T>& operator=(const parser<T>&) exprtk_delete; settings_store settings_; expression_generator<T> expression_generator_; @@ -36367,6 +41766,10 @@ namespace exprtk sf4_map_t sf4_map_; std::string synthesis_error_; scope_element_manager sem_; + std::vector<state_t> current_state_stack_; + + immutable_memory_map_t immutable_memory_map_; + immutable_symtok_map_t immutable_symtok_map_; lexer::helper::helper_assembly helper_assembly_; @@ -36375,15 +41778,19 @@ namespace exprtk lexer::helper::operator_joiner operator_joiner_3_; lexer::helper::symbol_replacer symbol_replacer_; lexer::helper::bracket_checker bracket_checker_; - lexer::helper::numeric_checker numeric_checker_; + lexer::helper::numeric_checker<T> numeric_checker_; lexer::helper::sequence_validator sequence_validator_; lexer::helper::sequence_validator_3tokens sequence_validator_3tkns_; - loop_runtime_check_ptr loop_runtime_check_; + loop_runtime_check_ptr loop_runtime_check_; + vector_access_runtime_check_ptr vector_access_runtime_check_; + compilation_check_ptr compilation_check_ptr_; + assert_check_ptr assert_check_; + std::set<std::string> assert_ids_; template <typename ParserType> friend void details::disable_type_checking(ParserType& p); - }; + }; // class parser namespace details { @@ -36391,22 +41798,24 @@ namespace exprtk struct collector_helper { typedef exprtk::symbol_table<T> symbol_table_t; - typedef exprtk::expression<T> expression_t; - typedef exprtk::parser<T> parser_t; + typedef exprtk::expression<T> expression_t; + typedef exprtk::parser<T> parser_t; typedef typename parser_t::dependent_entity_collector::symbol_t symbol_t; typedef typename parser_t::unknown_symbol_resolver usr_t; - struct resolve_as_vector : public parser_t::unknown_symbol_resolver + struct resolve_as_vector : public usr_t { typedef exprtk::parser<T> parser_t; + using usr_t::process; + resolve_as_vector() : usr_t(usr_t::e_usrmode_extended) {} - virtual bool process(const std::string& unknown_symbol, - symbol_table_t& symbol_table, - std::string&) + bool process(const std::string& unknown_symbol, + symbol_table_t& symbol_table, + std::string&) exprtk_override { static T v[1]; symbol_table.add_vector(unknown_symbol,v); @@ -36618,7 +42027,9 @@ namespace exprtk const symbol_table<T>& sym_table = e.get_symbol_table(); if (!sym_table.valid()) + { return std::numeric_limits<T>::quiet_NaN(); + } details::variable_node<T>* var = sym_table.get_variable(variable_name); @@ -36631,8 +42042,8 @@ namespace exprtk return result; } - else - return std::numeric_limits<T>::quiet_NaN(); + + return std::numeric_limits<T>::quiet_NaN(); } template <typename T> @@ -36645,9 +42056,9 @@ namespace exprtk x = x_init + _2h; const T y0 = e.value(); - x = x_init + h; + x = x_init + h; const T y1 = e.value(); - x = x_init - h; + x = x_init - h; const T y2 = e.value(); x = x_init - _2h; const T y3 = e.value(); @@ -36667,9 +42078,9 @@ namespace exprtk const T y = e.value(); x = x_init + _2h; const T y0 = e.value(); - x = x_init + h; + x = x_init + h; const T y1 = e.value(); - x = x_init - h; + x = x_init - h; const T y2 = e.value(); x = x_init - _2h; const T y3 = e.value(); @@ -36688,9 +42099,9 @@ namespace exprtk x = x_init + _2h; const T y0 = e.value(); - x = x_init + h; + x = x_init + h; const T y1 = e.value(); - x = x_init - h; + x = x_init - h; const T y2 = e.value(); x = x_init - _2h; const T y3 = e.value(); @@ -36722,8 +42133,8 @@ namespace exprtk return result; } - else - return std::numeric_limits<T>::quiet_NaN(); + + return std::numeric_limits<T>::quiet_NaN(); } template <typename T> @@ -36749,8 +42160,8 @@ namespace exprtk return result; } - else - return std::numeric_limits<T>::quiet_NaN(); + + return std::numeric_limits<T>::quiet_NaN(); } template <typename T> @@ -36776,8 +42187,8 @@ namespace exprtk return result; } - else - return std::numeric_limits<T>::quiet_NaN(); + + return std::numeric_limits<T>::quiet_NaN(); } /* @@ -37056,84 +42467,97 @@ namespace exprtk disable_has_side_effects(*this); } - ~polynomial() override = default; + ~polynomial() exprtk_override exprtk_default; #define poly_rtrn(NN) \ return (NN != N) ? std::numeric_limits<T>::quiet_NaN() : - inline virtual T operator() (const T& x, const T& c1, const T& c0) + inline T operator() (const T& x, const T& c1, const T& c0) exprtk_override { poly_rtrn(1) (poly_impl<T,1>::evaluate(x, c1, c0)); } - inline virtual T operator() (const T& x, const T& c2, const T& c1, const T& c0) + inline T operator() (const T& x, const T& c2, const T& c1, const T& c0) exprtk_override { poly_rtrn(2) (poly_impl<T,2>::evaluate(x, c2, c1, c0)); } - inline virtual T operator() (const T& x, const T& c3, const T& c2, const T& c1, const T& c0) + inline T operator() (const T& x, const T& c3, const T& c2, const T& c1, const T& c0) exprtk_override { poly_rtrn(3) (poly_impl<T,3>::evaluate(x, c3, c2, c1, c0)); } - inline virtual T operator() (const T& x, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) + inline T operator() (const T& x, const T& c4, const T& c3, const T& c2, const T& c1, + const T& c0) exprtk_override { poly_rtrn(4) (poly_impl<T,4>::evaluate(x, c4, c3, c2, c1, c0)); } - inline virtual T operator() (const T& x, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) + inline T operator() (const T& x, const T& c5, const T& c4, const T& c3, const T& c2, + const T& c1, const T& c0) exprtk_override { poly_rtrn(5) (poly_impl<T,5>::evaluate(x, c5, c4, c3, c2, c1, c0)); } - inline virtual T operator() (const T& x, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) + inline T operator() (const T& x, const T& c6, const T& c5, const T& c4, const T& c3, + const T& c2, const T& c1, const T& c0) exprtk_override { poly_rtrn(6) (poly_impl<T,6>::evaluate(x, c6, c5, c4, c3, c2, c1, c0)); } - inline virtual T operator() (const T& x, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) + inline T operator() (const T& x, const T& c7, const T& c6, const T& c5, const T& c4, + const T& c3, const T& c2, const T& c1, const T& c0) exprtk_override { poly_rtrn(7) (poly_impl<T,7>::evaluate(x, c7, c6, c5, c4, c3, c2, c1, c0)); } - inline virtual T operator() (const T& x, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) + inline T operator() (const T& x, const T& c8, const T& c7, const T& c6, const T& c5, + const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) exprtk_override { poly_rtrn(8) (poly_impl<T,8>::evaluate(x, c8, c7, c6, c5, c4, c3, c2, c1, c0)); } - inline virtual T operator() (const T& x, const T& c9, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) + inline T operator() (const T& x, const T& c9, const T& c8, const T& c7, const T& c6, + const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, + const T& c0) exprtk_override { poly_rtrn(9) (poly_impl<T,9>::evaluate(x, c9, c8, c7, c6, c5, c4, c3, c2, c1, c0)); } - inline virtual T operator() (const T& x, const T& c10, const T& c9, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) + inline T operator() (const T& x, const T& c10, const T& c9, const T& c8, const T& c7, + const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, + const T& c1, const T& c0) exprtk_override { poly_rtrn(10) (poly_impl<T,10>::evaluate(x, c10, c9, c8, c7, c6, c5, c4, c3, c2, c1, c0)); } - inline virtual T operator() (const T& x, const T& c11, const T& c10, const T& c9, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) + inline T operator() (const T& x, const T& c11, const T& c10, const T& c9, const T& c8, + const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, + const T& c2, const T& c1, const T& c0) exprtk_override { poly_rtrn(11) (poly_impl<T,11>::evaluate(x, c11, c10, c9, c8, c7, c6, c5, c4, c3, c2, c1, c0)); } - inline virtual T operator() (const T& x, const T& c12, const T& c11, const T& c10, const T& c9, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) + inline T operator() (const T& x, const T& c12, const T& c11, const T& c10, const T& c9, + const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, + const T& c3, const T& c2, const T& c1, const T& c0) exprtk_override { poly_rtrn(12) (poly_impl<T,12>::evaluate(x, c12, c11, c10, c9, c8, c7, c6, c5, c4, c3, c2, c1, c0)); } #undef poly_rtrn - inline virtual T operator() () + inline T operator() () exprtk_override { return std::numeric_limits<T>::quiet_NaN(); } - inline virtual T operator() (const T&) + inline T operator() (const T&) exprtk_override { return std::numeric_limits<T>::quiet_NaN(); } - inline virtual T operator() (const T&, const T&) + inline T operator() (const T&, const T&) exprtk_override { return std::numeric_limits<T>::quiet_NaN(); } @@ -37151,7 +42575,7 @@ namespace exprtk struct function { - function() = default; + function() exprtk_default; function(const std::string& n) : name_(n) @@ -37159,15 +42583,15 @@ namespace exprtk function(const std::string& name, const std::string& expression) - : name_(name), - expression_(expression) + : name_(name) + , expression_(expression) {} function(const std::string& name, const std::string& expression, const std::string& v0) - : name_(name), - expression_(expression) + : name_(name) + , expression_(expression) { v_.push_back(v0); } @@ -37175,8 +42599,8 @@ namespace exprtk function(const std::string& name, const std::string& expression, const std::string& v0, const std::string& v1) - : name_(name), - expression_(expression) + : name_(name) + , expression_(expression) { v_.push_back(v0); v_.push_back(v1); } @@ -37185,8 +42609,8 @@ namespace exprtk const std::string& expression, const std::string& v0, const std::string& v1, const std::string& v2) - : name_(name), - expression_(expression) + : name_(name) + , expression_(expression) { v_.push_back(v0); v_.push_back(v1); v_.push_back(v2); @@ -37196,8 +42620,8 @@ namespace exprtk const std::string& expression, const std::string& v0, const std::string& v1, const std::string& v2, const std::string& v3) - : name_(name), - expression_(expression) + : name_(name) + , expression_(expression) { v_.push_back(v0); v_.push_back(v1); v_.push_back(v2); v_.push_back(v3); @@ -37208,8 +42632,8 @@ namespace exprtk const std::string& v0, const std::string& v1, const std::string& v2, const std::string& v3, const std::string& v4) - : name_(name), - expression_(expression) + : name_(name) + , expression_(expression) { v_.push_back(v0); v_.push_back(v1); v_.push_back(v2); v_.push_back(v3); @@ -37234,6 +42658,50 @@ namespace exprtk return (*this); } + inline function& vars(const std::string& v0, + const std::string& v1) + { + v_.push_back(v0); + v_.push_back(v1); + return (*this); + } + + inline function& vars(const std::string& v0, + const std::string& v1, + const std::string& v2) + { + v_.push_back(v0); + v_.push_back(v1); + v_.push_back(v2); + return (*this); + } + + inline function& vars(const std::string& v0, + const std::string& v1, + const std::string& v2, + const std::string& v3) + { + v_.push_back(v0); + v_.push_back(v1); + v_.push_back(v2); + v_.push_back(v3); + return (*this); + } + + inline function& vars(const std::string& v0, + const std::string& v1, + const std::string& v2, + const std::string& v3, + const std::string& v4) + { + v_.push_back(v0); + v_.push_back(v1); + v_.push_back(v2); + v_.push_back(v3); + v_.push_back(v4); + return (*this); + } + std::string name_; std::string expression_; std::deque<std::string> v_; @@ -37243,76 +42711,101 @@ namespace exprtk struct base_func : public exprtk::ifunction<T> { - typedef const T& type; - typedef exprtk::ifunction<T> function_t; - typedef std::vector<T*> varref_t; - typedef std::vector<T> var_t; + typedef const T& type; + typedef exprtk::ifunction<T> function_t; + typedef std::vector<T*> varref_t; + typedef std::vector<T> var_t; + typedef std::vector<std::string> str_t; typedef std::pair<T*,std::size_t> lvarref_t; typedef std::vector<lvarref_t> lvr_vec_t; + typedef std::vector<std::string*> lstr_vec_t; using exprtk::ifunction<T>::operator(); base_func(const std::size_t& pc = 0) - : exprtk::ifunction<T>(pc), - local_var_stack_size(0), - stack_depth(0) + : exprtk::ifunction<T>(pc) + , local_var_stack_size(0) + , stack_depth(0) { v.resize(pc); } - ~base_func() override = default; + ~base_func() exprtk_override exprtk_default; + + #define exprtk_assign(Index) \ + (*v[Index]) = v##Index; \ inline void update(const T& v0) { - (*v[0]) = v0; + exprtk_assign(0) } inline void update(const T& v0, const T& v1) { - (*v[0]) = v0; (*v[1]) = v1; + exprtk_assign(0) exprtk_assign(1) } inline void update(const T& v0, const T& v1, const T& v2) { - (*v[0]) = v0; (*v[1]) = v1; - (*v[2]) = v2; + exprtk_assign(0) exprtk_assign(1) + exprtk_assign(2) } inline void update(const T& v0, const T& v1, const T& v2, const T& v3) { - (*v[0]) = v0; (*v[1]) = v1; - (*v[2]) = v2; (*v[3]) = v3; + exprtk_assign(0) exprtk_assign(1) + exprtk_assign(2) exprtk_assign(3) } inline void update(const T& v0, const T& v1, const T& v2, const T& v3, const T& v4) { - (*v[0]) = v0; (*v[1]) = v1; - (*v[2]) = v2; (*v[3]) = v3; - (*v[4]) = v4; + exprtk_assign(0) exprtk_assign(1) + exprtk_assign(2) exprtk_assign(3) + exprtk_assign(4) } inline void update(const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, const T& v5) { - (*v[0]) = v0; (*v[1]) = v1; - (*v[2]) = v2; (*v[3]) = v3; - (*v[4]) = v4; (*v[5]) = v5; + exprtk_assign(0) exprtk_assign(1) + exprtk_assign(2) exprtk_assign(3) + exprtk_assign(4) exprtk_assign(5) } + #ifdef exprtk_assign + #undef exprtk_assign + #endif + inline function_t& setup(expression_t& expr) { expression = expr; - typedef typename expression_t::control_block::local_data_list_t ldl_t; + typedef typename expression_t::control_block ctrlblk_t; + typedef typename ctrlblk_t::local_data_list_t ldl_t; + typedef typename ctrlblk_t::data_type data_t; + typedef typename ldl_t::value_type ldl_value_type; const ldl_t ldl = expr.local_data_list(); - std::vector<std::size_t> index_list; + std::vector<std::pair<std::size_t,data_t> > index_list; for (std::size_t i = 0; i < ldl.size(); ++i) { + exprtk_debug(("base_func::setup() - element[%02d] type: %s size: %d\n", + static_cast<int>(i), + expression_t::control_block::to_str(ldl[i].type).c_str(), + static_cast<int>(ldl[i].size))); + + switch (ldl[i].type) + { + case ctrlblk_t::e_unknown : continue; + case ctrlblk_t::e_expr : continue; + case ctrlblk_t::e_vecholder : continue; + default : break; + } + if (ldl[i].size) { - index_list.push_back(i); + index_list.push_back(std::make_pair(i,ldl[i].type)); } } @@ -37320,19 +42813,34 @@ namespace exprtk for (std::size_t i = 0; i < index_list.size(); ++i) { - const std::size_t index = index_list[i]; + const std::size_t index = index_list[i].first; + const ldl_value_type& local_var = ldl[index]; + + assert(local_var.pointer); if (i < (index_list.size() - v.size())) { - lv.push_back( - std::make_pair( - reinterpret_cast<T*>(ldl[index].pointer), - ldl[index].size)); + if (local_var.type == ctrlblk_t::e_string) + { + local_str_vars.push_back( + reinterpret_cast<std::string*>(local_var.pointer)); + } + else if ( + (local_var.type == ctrlblk_t::e_data ) || + (local_var.type == ctrlblk_t::e_vecdata) + ) + { + local_vars.push_back(std::make_pair( + reinterpret_cast<T*>(local_var.pointer), + local_var.size)); - local_var_stack_size += ldl[index].size; + local_var_stack_size += local_var.size; + } } else - v[input_param_count++] = reinterpret_cast<T*>(ldl[index].pointer); + { + v[input_param_count++] = reinterpret_cast<T*>(local_var.pointer); + } } clear_stack(); @@ -37348,14 +42856,21 @@ namespace exprtk { var_t var_stack(v.size(),T(0)); copy(v,var_stack); - param_stack.push_back(var_stack); + input_params_stack.push_back(var_stack); + } + + if (!local_vars.empty()) + { + var_t local_vec_frame(local_var_stack_size,T(0)); + copy(local_vars,local_vec_frame); + local_var_stack.push_back(local_vec_frame); } - if (!lv.empty()) + if (!local_str_vars.empty()) { - var_t local_var_stack(local_var_stack_size,T(0)); - copy(lv,local_var_stack); - local_stack.push_back(local_var_stack); + str_t local_str_frame(local_str_vars.size()); + copy(local_str_vars,local_str_frame); + local_str_stack.push_back(local_str_frame); } } } @@ -37366,14 +42881,20 @@ namespace exprtk { if (!v.empty()) { - copy(param_stack.back(),v); - param_stack.pop_back(); + copy(input_params_stack.back(), v); + input_params_stack.pop_back(); + } + + if (!local_vars.empty()) + { + copy(local_var_stack.back(), local_vars); + local_var_stack.pop_back(); } - if (!lv.empty()) + if (!local_str_vars.empty()) { - copy(local_stack.back(),lv); - local_stack.pop_back(); + copy(local_str_stack.back(), local_str_vars); + local_str_stack.pop_back(); } } } @@ -37386,6 +42907,14 @@ namespace exprtk } } + void copy(const lstr_vec_t& src_v, str_t& dest_v) + { + for (std::size_t i = 0; i < src_v.size(); ++i) + { + dest_v[i] = (*src_v[i]); + } + } + void copy(const var_t& src_v, varref_t& dest_v) { for (std::size_t i = 0; i < src_v.size(); ++i) @@ -37418,9 +42947,12 @@ namespace exprtk typename var_t::const_iterator itr = src_v.begin(); typedef typename std::iterator_traits<typename var_t::iterator>::difference_type diff_t; - for (std::size_t i = 0; i < src_v.size(); ++i) + for (std::size_t i = 0; i < dest_v.size(); ++i) { - lvarref_t vr = dest_v[i]; + lvarref_t& vr = dest_v[i]; + + assert(vr.first != 0); + assert(vr.second > 0); if (1 == vr.second) (*vr.first) = *itr++; @@ -37432,6 +42964,16 @@ namespace exprtk } } + void copy(const str_t& src_str, lstr_vec_t& dest_str) + { + assert(src_str.size() == dest_str.size()); + + for (std::size_t i = 0; i < dest_str.size(); ++i) + { + *dest_str[i] = src_str[i]; + } + } + inline void clear_stack() { for (std::size_t i = 0; i < v.size(); ++i) @@ -37445,29 +42987,19 @@ namespace exprtk return e.value(); } - expression_t expression; - varref_t v; - lvr_vec_t lv; - std::size_t local_var_stack_size; - std::size_t stack_depth; - std::deque<var_t> param_stack; - std::deque<var_t> local_stack; + expression_t expression; + varref_t v; + lvr_vec_t local_vars; + lstr_vec_t local_str_vars; + std::size_t local_var_stack_size; + std::size_t stack_depth; + std::deque<var_t> input_params_stack; + std::deque<var_t> local_var_stack; + std::deque<str_t> local_str_stack; }; typedef std::map<std::string,base_func*> funcparam_t; - struct func_0param : public base_func - { - using exprtk::ifunction<T>::operator(); - - func_0param() : base_func(0) {} - - inline T operator() () - { - return this->value(base_func::expression); - } - }; - typedef const T& type; template <typename BaseFuncType> @@ -37488,8 +43020,21 @@ namespace exprtk private: - scoped_bft(scoped_bft&); - scoped_bft& operator=(scoped_bft&); + scoped_bft(const scoped_bft&) exprtk_delete; + scoped_bft& operator=(const scoped_bft&) exprtk_delete; + }; + + struct func_0param : public base_func + { + using exprtk::ifunction<T>::operator(); + + func_0param() : base_func(0) {} + + inline T operator() () exprtk_override + { + scoped_bft<func_0param> sb(*this); + return this->value(base_func::expression); + } }; struct func_1param : public base_func @@ -37498,7 +43043,7 @@ namespace exprtk func_1param() : base_func(1) {} - inline T operator() (type v0) + inline T operator() (type v0) exprtk_override { scoped_bft<func_1param> sb(*this); base_func::update(v0); @@ -37512,7 +43057,7 @@ namespace exprtk func_2param() : base_func(2) {} - inline T operator() (type v0, type v1) + inline T operator() (type v0, type v1) exprtk_override { scoped_bft<func_2param> sb(*this); base_func::update(v0, v1); @@ -37526,7 +43071,7 @@ namespace exprtk func_3param() : base_func(3) {} - inline T operator() (type v0, type v1, type v2) + inline T operator() (type v0, type v1, type v2) exprtk_override { scoped_bft<func_3param> sb(*this); base_func::update(v0, v1, v2); @@ -37540,7 +43085,7 @@ namespace exprtk func_4param() : base_func(4) {} - inline T operator() (type v0, type v1, type v2, type v3) + inline T operator() (type v0, type v1, type v2, type v3) exprtk_override { scoped_bft<func_4param> sb(*this); base_func::update(v0, v1, v2, v3); @@ -37554,7 +43099,7 @@ namespace exprtk func_5param() : base_func(5) {} - inline T operator() (type v0, type v1, type v2, type v3, type v4) + inline T operator() (type v0, type v1, type v2, type v3, type v4) exprtk_override { scoped_bft<func_5param> sb(*this); base_func::update(v0, v1, v2, v3, v4); @@ -37568,7 +43113,7 @@ namespace exprtk func_6param() : base_func(6) {} - inline T operator() (type v0, type v1, type v2, type v3, type v4, type v5) + inline T operator() (type v0, type v1, type v2, type v3, type v4, type v5) exprtk_override { scoped_bft<func_6param> sb(*this); base_func::update(v0, v1, v2, v3, v4, v5); @@ -37595,14 +43140,14 @@ namespace exprtk return result; } - #define def_fp_retval(N) \ - struct func_##N##param_retval : public func_##N##param \ - { \ - inline T value(expression_t& e) \ - { \ - return return_value(e); \ - } \ - }; \ + #define def_fp_retval(N) \ + struct func_##N##param_retval exprtk_final : public func_##N##param \ + { \ + inline T value(expression_t& e) exprtk_override \ + { \ + return return_value(e); \ + } \ + }; \ def_fp_retval(0) def_fp_retval(1) @@ -37612,18 +43157,20 @@ namespace exprtk def_fp_retval(5) def_fp_retval(6) + #undef def_fp_retval + template <typename Allocator, template <typename, typename> class Sequence> inline bool add(const std::string& name, const std::string& expression, const Sequence<std::string,Allocator>& var_list, - const bool override = false) + const bool allow_override = false) { const typename std::map<std::string,expression_t>::iterator itr = expr_map_.find(name); if (expr_map_.end() != itr) { - if (!override) + if (!allow_override) { exprtk_debug(("Compositor error(add): function '%s' already defined\n", name.c_str())); @@ -37634,7 +43181,7 @@ namespace exprtk remove(name, var_list.size()); } - if (compile_expression(name,expression,var_list)) + if (compile_expression(name, expression, var_list)) { const std::size_t n = var_list.size(); @@ -37654,16 +43201,20 @@ namespace exprtk public: function_compositor() - : parser_(settings_t::compile_all_opts + - settings_t::e_disable_zero_return), - fp_map_(7) + : parser_(settings_t::default_compile_all_opts + + settings_t::e_disable_zero_return) + , fp_map_(7) + , load_variables_(false) + , load_vectors_(false) {} - function_compositor(const symbol_table_t& st) - : symbol_table_(st), - parser_(settings_t::compile_all_opts + - settings_t::e_disable_zero_return), - fp_map_(7) + explicit function_compositor(const symbol_table_t& st) + : symbol_table_(st) + , parser_(settings_t::default_compile_all_opts + + settings_t::e_disable_zero_return) + , fp_map_(7) + , load_variables_(false) + , load_vectors_(false) {} ~function_compositor() @@ -37686,6 +43237,46 @@ namespace exprtk auxiliary_symtab_list_.push_back(&symtab); } + void load_variables(const bool load = true) + { + load_variables_ = load; + } + + void load_vectors(const bool load = true) + { + load_vectors_ = load; + } + + inline void register_loop_runtime_check(loop_runtime_check& lrtchk) + { + parser_.register_loop_runtime_check(lrtchk); + } + + inline void register_vector_access_runtime_check(vector_access_runtime_check& vartchk) + { + parser_.register_vector_access_runtime_check(vartchk); + } + + inline void register_compilation_timeout_check(compilation_check& compchk) + { + parser_.register_compilation_timeout_check(compchk); + } + + inline void clear_loop_runtime_check() + { + parser_.clear_loop_runtime_check(); + } + + inline void clear_vector_access_runtime_check() + { + parser_.clear_vector_access_runtime_check(); + } + + inline void clear_compilation_timeout_check() + { + parser_.clear_compilation_timeout_check(); + } + void clear() { symbol_table_.clear(); @@ -37704,11 +43295,40 @@ namespace exprtk fp_map_[i].clear(); } + + clear_loop_runtime_check (); + clear_vector_access_runtime_check(); + clear_compilation_timeout_check (); } - inline bool add(const function& f, const bool override = false) + inline bool add(const function& f, const bool allow_override = false) { - return add(f.name_, f.expression_, f.v_,override); + return add(f.name_, f.expression_, f.v_, allow_override); + } + + inline std::string error() const + { + if (!error_list_.empty()) + { + return error_list_[0].diagnostic; + } + else + return std::string("No Error"); + } + + inline std::size_t error_count() const + { + return error_list_.size(); + } + + inline parser_error::type get_error(const std::size_t& index) const + { + if (index < error_list_.size()) + { + return error_list_[index]; + } + + throw std::invalid_argument("compositor::get_error() - Invalid error index specified"); } private: @@ -37726,8 +43346,30 @@ namespace exprtk local_symbol_table.load_from(symbol_table_); local_symbol_table.add_constants(); + if (load_variables_) + { + local_symbol_table.load_variables_from(symbol_table_); + } + + if (load_vectors_) + { + local_symbol_table.load_vectors_from(symbol_table_); + } + + error_list_.clear(); + if (!valid(name,input_var_list.size())) + { + parser_error::type error = + parser_error::make_error( + parser_error::e_parser, + lexer::token(), + "ERR277 - Function '" + name + "' is an invalid overload", + exprtk_error_location); + + error_list_.push_back(error); return false; + } if (!forward(name, input_var_list.size(), @@ -37759,18 +43401,22 @@ namespace exprtk if (!parser_.compile(mod_expression,compiled_expression)) { - exprtk_debug(("Compositor Error: %s\n",parser_.error().c_str())); - exprtk_debug(("Compositor modified expression: \n%s\n",mod_expression.c_str())); + exprtk_debug(("Compositor Error: %s\n", parser_.error().c_str())); + exprtk_debug(("Compositor modified expression: \n%s\n", mod_expression.c_str())); remove(name,input_var_list.size()); + for (std::size_t err_index = 0; err_index < parser_.error_count(); ++err_index) + { + error_list_.push_back(parser_.get_error(err_index)); + } + return false; } if (!return_present && parser_.dec().return_present()) { remove(name,input_var_list.size()); - return compile_expression(name, expression, input_var_list, true); } @@ -37891,206 +43537,14 @@ namespace exprtk std::map<std::string,expression_t> expr_map_; std::vector<funcparam_t> fp_map_; std::vector<symbol_table_t*> auxiliary_symtab_list_; - }; - - template <typename T> - inline bool pgo_primer() - { - static const std::string expression_list[] = - { - "(y + x)", - "2 * (y + x)", - "(2 * y + 2 * x)", - "(y + x / y) * (x - y / x)", - "x / ((x + y) * (x - y)) / y", - "1 - ((x * y) + (y / x)) - 3", - "sin(2 * x) + cos(pi / y)", - "1 - sin(2 * x) + cos(pi / y)", - "sqrt(1 - sin(2 * x) + cos(pi / y) / 3)", - "(x^2 / sin(2 * pi / y)) -x / 2", - "x + (cos(y - sin(2 / x * pi)) - sin(x - cos(2 * y / pi))) - y", - "clamp(-1.0, sin(2 * pi * x) + cos(y / 2 * pi), +1.0)", - "iclamp(-1.0, sin(2 * pi * x) + cos(y / 2 * pi), +1.0)", - "max(3.33, min(sqrt(1 - sin(2 * x) + cos(pi / y) / 3), 1.11))", - "if(avg(x,y) <= x + y, x - y, x * y) + 2 * pi / x", - "1.1x^1 + 2.2y^2 - 3.3x^3 + 4.4y^4 - 5.5x^5 + 6.6y^6 - 7.7x^27 + 8.8y^55", - "(yy + xx)", - "2 * (yy + xx)", - "(2 * yy + 2 * xx)", - "(yy + xx / yy) * (xx - yy / xx)", - "xx / ((xx + yy) * (xx - yy)) / yy", - "1 - ((xx * yy) + (yy / xx)) - 3", - "sin(2 * xx) + cos(pi / yy)", - "1 - sin(2 * xx) + cos(pi / yy)", - "sqrt(1 - sin(2 * xx) + cos(pi / yy) / 3)", - "(xx^2 / sin(2 * pi / yy)) -xx / 2", - "xx + (cos(yy - sin(2 / xx * pi)) - sin(xx - cos(2 * yy / pi))) - yy", - "clamp(-1.0, sin(2 * pi * xx) + cos(yy / 2 * pi), +1.0)", - "max(3.33, min(sqrt(1 - sin(2 * xx) + cos(pi / yy) / 3), 1.11))", - "if(avg(xx,yy) <= xx + yy, xx - yy, xx * yy) + 2 * pi / xx", - "1.1xx^1 + 2.2yy^2 - 3.3xx^3 + 4.4yy^4 - 5.5xx^5 + 6.6yy^6 - 7.7xx^27 + 8.8yy^55", - "(1.1*(2.2*(3.3*(4.4*(5.5*(6.6*(7.7*(8.8*(9.9+x)))))))))", - "(((((((((x+9.9)*8.8)*7.7)*6.6)*5.5)*4.4)*3.3)*2.2)*1.1)", - "(x + y) * z", "x + (y * z)", "(x + y) * 7", "x + (y * 7)", - "(x + 7) * y", "x + (7 * y)", "(7 + x) * y", "7 + (x * y)", - "(2 + x) * 3", "2 + (x * 3)", "(2 + 3) * x", "2 + (3 * x)", - "(x + 2) * 3", "x + (2 * 3)", - "(x + y) * (z / w)", "(x + y) * (z / 7)", "(x + y) * (7 / z)", "(x + 7) * (y / z)", - "(7 + x) * (y / z)", "(2 + x) * (y / z)", "(x + 2) * (y / 3)", "(2 + x) * (y / 3)", - "(x + 2) * (3 / y)", "x + (y * (z / w))", "x + (y * (z / 7))", "x + (y * (7 / z))", - "x + (7 * (y / z))", "7 + (x * (y / z))", "2 + (x * (3 / y))", "x + (2 * (y / 4))", - "2 + (x * (y / 3))", "x + (2 * (3 / y))", - "x + ((y * z) / w)", "x + ((y * z) / 7)", "x + ((y * 7) / z)", "x + ((7 * y) / z)", - "7 + ((y * z) / w)", "2 + ((x * 3) / y)", "x + ((2 * y) / 3)", "2 + ((x * y) / 3)", - "x + ((2 * 3) / y)", "(((x + y) * z) / w)", - "(((x + y) * z) / 7)", "(((x + y) * 7) / z)", "(((x + 7) * y) / z)", "(((7 + x) * y) / z)", - "(((2 + x) * 3) / y)", "(((x + 2) * y) / 3)", "(((2 + x) * y) / 3)", "(((x + 2) * 3) / y)", - "((x + (y * z)) / w)", "((x + (y * z)) / 7)", "((x + (y * 7)) / y)", "((x + (7 * y)) / z)", - "((7 + (x * y)) / z)", "((2 + (x * 3)) / y)", "((x + (2 * y)) / 3)", "((2 + (x * y)) / 3)", - "((x + (2 * 3)) / y)", - "(xx + yy) * zz", "xx + (yy * zz)", - "(xx + yy) * 7", "xx + (yy * 7)", - "(xx + 7) * yy", "xx + (7 * yy)", - "(7 + xx) * yy", "7 + (xx * yy)", - "(2 + x) * 3", "2 + (x * 3)", - "(2 + 3) * x", "2 + (3 * x)", - "(x + 2) * 3", "x + (2 * 3)", - "(xx + yy) * (zz / ww)", "(xx + yy) * (zz / 7)", - "(xx + yy) * (7 / zz)", "(xx + 7) * (yy / zz)", - "(7 + xx) * (yy / zz)", "(2 + xx) * (yy / zz)", - "(xx + 2) * (yy / 3)", "(2 + xx) * (yy / 3)", - "(xx + 2) * (3 / yy)", "xx + (yy * (zz / ww))", - "xx + (yy * (zz / 7))", "xx + (yy * (7 / zz))", - "xx + (7 * (yy / zz))", "7 + (xx * (yy / zz))", - "2 + (xx * (3 / yy))", "xx + (2 * (yy / 4))", - "2 + (xx * (yy / 3))", "xx + (2 * (3 / yy))", - "xx + ((yy * zz) / ww)", "xx + ((yy * zz) / 7)", - "xx + ((yy * 7) / zz)", "xx + ((7 * yy) / zz)", - "7 + ((yy * zz) / ww)", "2 + ((xx * 3) / yy)", - "xx + ((2 * yy) / 3)", "2 + ((xx * yy) / 3)", - "xx + ((2 * 3) / yy)", "(((xx + yy) * zz) / ww)", - "(((xx + yy) * zz) / 7)", "(((xx + yy) * 7) / zz)", - "(((xx + 7) * yy) / zz)", "(((7 + xx) * yy) / zz)", - "(((2 + xx) * 3) / yy)", "(((xx + 2) * yy) / 3)", - "(((2 + xx) * yy) / 3)", "(((xx + 2) * 3) / yy)", - "((xx + (yy * zz)) / ww)", "((xx + (yy * zz)) / 7)", - "((xx + (yy * 7)) / yy)", "((xx + (7 * yy)) / zz)", - "((7 + (xx * yy)) / zz)", "((2 + (xx * 3)) / yy)", - "((xx + (2 * yy)) / 3)", "((2 + (xx * yy)) / 3)", - "((xx + (2 * 3)) / yy)" - }; - - static const std::size_t expression_list_size = sizeof(expression_list) / sizeof(std::string); - - T x = T(0); - T y = T(0); - T z = T(0); - T w = T(0); - T xx = T(0); - T yy = T(0); - T zz = T(0); - T ww = T(0); - - exprtk::symbol_table<T> symbol_table; - symbol_table.add_constants(); - symbol_table.add_variable( "x", x); - symbol_table.add_variable( "y", y); - symbol_table.add_variable( "z", z); - symbol_table.add_variable( "w", w); - symbol_table.add_variable("xx",xx); - symbol_table.add_variable("yy",yy); - symbol_table.add_variable("zz",zz); - symbol_table.add_variable("ww",ww); - - typedef typename std::deque<exprtk::expression<T> > expr_list_t; - expr_list_t expr_list; - - const std::size_t rounds = 50; - - { - for (std::size_t r = 0; r < rounds; ++r) - { - expr_list.clear(); - exprtk::parser<T> parser; - - for (std::size_t i = 0; i < expression_list_size; ++i) - { - exprtk::expression<T> expression; - expression.register_symbol_table(symbol_table); - - if (!parser.compile(expression_list[i],expression)) - { - return false; - } - - expr_list.push_back(expression); - } - } - } - - struct execute - { - static inline T process(T& x, T& y, expression<T>& expression) - { - static const T lower_bound = T(-20); - static const T upper_bound = T(+20); - static const T delta = T(0.1); - - T total = T(0); - - for (x = lower_bound; x <= upper_bound; x += delta) - { - for (y = lower_bound; y <= upper_bound; y += delta) - { - total += expression.value(); - } - } - - return total; - } - }; - - for (std::size_t i = 0; i < expr_list.size(); ++i) - { - execute::process( x, y, expr_list[i]); - execute::process(xx, yy, expr_list[i]); - } - - { - for (std::size_t i = 0; i < 10000; ++i) - { - const T v = T(123.456 + i); - - if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T, 1>::result(v),details::numeric::pow(v,T( 1))))) - return false; - - #define else_stmt(N) \ - else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,N>::result(v),details::numeric::pow(v,T(N))))) \ - return false; \ - - else_stmt( 2) else_stmt( 3) else_stmt( 4) else_stmt( 5) - else_stmt( 6) else_stmt( 7) else_stmt( 8) else_stmt( 9) - else_stmt(10) else_stmt(11) else_stmt(12) else_stmt(13) - else_stmt(14) else_stmt(15) else_stmt(16) else_stmt(17) - else_stmt(18) else_stmt(19) else_stmt(20) else_stmt(21) - else_stmt(22) else_stmt(23) else_stmt(24) else_stmt(25) - else_stmt(26) else_stmt(27) else_stmt(28) else_stmt(29) - else_stmt(30) else_stmt(31) else_stmt(32) else_stmt(33) - else_stmt(34) else_stmt(35) else_stmt(36) else_stmt(37) - else_stmt(38) else_stmt(39) else_stmt(40) else_stmt(41) - else_stmt(42) else_stmt(43) else_stmt(44) else_stmt(45) - else_stmt(46) else_stmt(47) else_stmt(48) else_stmt(49) - else_stmt(50) else_stmt(51) else_stmt(52) else_stmt(53) - else_stmt(54) else_stmt(55) else_stmt(56) else_stmt(57) - else_stmt(58) else_stmt(59) else_stmt(60) else_stmt(61) - } - } + std::deque<parser_error::type> error_list_; + bool load_variables_; + bool load_vectors_; + }; // class function_compositor - return true; - } -} +} // namespace exprtk -#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) +#if defined(_MSC_VER) || defined(_WIN32) || defined(__WIN32__) || defined(WIN32) # ifndef NOMINMAX # define NOMINMAX # endif @@ -38111,9 +43565,11 @@ namespace exprtk { public: - #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) + #if defined(_MSC_VER) || defined(_WIN32) || defined(__WIN32__) || defined(WIN32) timer() : in_use_(false) + , start_time_{ {0, 0} } + , stop_time_ { {0, 0} } { QueryPerformanceFrequency(&clock_frequency_); } @@ -38142,6 +43598,7 @@ namespace exprtk { start_time_.tv_sec = 0; start_time_.tv_usec = 0; + stop_time_.tv_sec = 0; stop_time_.tv_usec = 0; } @@ -38190,7 +43647,7 @@ namespace exprtk bool in_use_; - #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) + #if defined(_MSC_VER) || defined(_WIN32) || defined(__WIN32__) || defined(WIN32) LARGE_INTEGER start_time_; LARGE_INTEGER stop_time_; LARGE_INTEGER clock_frequency_; @@ -38200,6 +43657,17 @@ namespace exprtk #endif }; + template <typename T> + struct type_defs + { + typedef symbol_table<T> symbol_table_t; + typedef expression<T> expression_t; + typedef parser<T> parser_t; + typedef parser_error::type error_t; + typedef function_compositor<T> compositor_t; + typedef typename compositor_t::function function_t; + }; + } // namespace exprtk #ifndef exprtk_disable_rtl_io @@ -38212,7 +43680,23 @@ namespace exprtk const T v, exprtk::details::numeric::details::real_type_tag) { - printf(fmt.c_str(),v); + #if defined(__clang__) + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wformat-nonliteral" + #elif defined(__GNUC__) || defined(__GNUG__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wformat-nonliteral" + #elif defined(_MSC_VER) + #endif + + printf(fmt.c_str(), v); + + #if defined(__clang__) + #pragma clang diagnostic pop + #elif defined(__GNUC__) || defined(__GNUG__) + #pragma GCC diagnostic pop + #elif defined(_MSC_VER) + #endif } template <typename T> @@ -38272,19 +43756,19 @@ namespace exprtk } // namespace exprtk::rtl::io::details template <typename T> - struct print : public exprtk::igeneric_function<T> + struct print exprtk_final : public exprtk::igeneric_function<T> { typedef typename igeneric_function<T>::parameter_list_t parameter_list_t; using exprtk::igeneric_function<T>::operator(); - print(const std::string& scalar_format = "%10.5f") + explicit print(const std::string& scalar_format = "%10.5f") : scalar_format_(scalar_format) { exprtk::enable_zero_parameters(*this); } - inline T operator() (parameter_list_t parameters) + inline T operator() (parameter_list_t parameters) exprtk_override { details::print_impl<T>::process(scalar_format_,parameters); return T(0); @@ -38294,19 +43778,19 @@ namespace exprtk }; template <typename T> - struct println : public exprtk::igeneric_function<T> + struct println exprtk_final : public exprtk::igeneric_function<T> { typedef typename igeneric_function<T>::parameter_list_t parameter_list_t; using exprtk::igeneric_function<T>::operator(); - println(const std::string& scalar_format = "%10.5f") + explicit println(const std::string& scalar_format = "%10.5f") : scalar_format_(scalar_format) { exprtk::enable_zero_parameters(*this); } - inline T operator() (parameter_list_t parameters) + inline T operator() (parameter_list_t parameters) exprtk_override { details::print_impl<T>::process(scalar_format_,parameters); printf("\n"); @@ -38324,7 +43808,7 @@ namespace exprtk bool register_package(exprtk::symbol_table<T>& symtab) { - #define exprtk_register_function(FunctionName,FunctionType) \ + #define exprtk_register_function(FunctionName, FunctionType) \ if (!symtab.add_function(FunctionName,FunctionType)) \ { \ exprtk_debug(( \ @@ -38333,7 +43817,7 @@ namespace exprtk return false; \ } \ - exprtk_register_function("print" , p) + exprtk_register_function("print" , p ) exprtk_register_function("println", pl) #undef exprtk_register_function @@ -38352,6 +43836,9 @@ namespace exprtk { namespace rtl { namespace io { namespace file { namespace details { + using ::exprtk::details::char_ptr; + using ::exprtk::details::char_cptr; + enum file_mode { e_error = 0, @@ -38363,9 +43850,9 @@ namespace exprtk struct file_descriptor { file_descriptor(const std::string& fname, const std::string& access) - : stream_ptr(0), - mode(get_file_mode(access)), - file_name(fname) + : stream_ptr(0) + , mode(get_file_mode(access)) + , file_name(fname) {} void* stream_ptr; @@ -38385,8 +43872,8 @@ namespace exprtk return false; } - else - stream_ptr = stream; + + stream_ptr = stream; return true; } @@ -38401,8 +43888,8 @@ namespace exprtk return false; } - else - stream_ptr = stream; + + stream_ptr = stream; return true; } @@ -38417,13 +43904,13 @@ namespace exprtk return false; } - else - stream_ptr = stream; + + stream_ptr = stream; return true; } - else - return false; + + return false; } template <typename Stream, typename Ptr> @@ -38460,11 +43947,11 @@ namespace exprtk switch (mode) { case e_write : reinterpret_cast<std::ofstream*>(stream_ptr)-> - write(reinterpret_cast<const char*>(view.begin() + offset), amount * sizeof(typename View::value_t)); + write(reinterpret_cast<char_cptr>(view.begin() + offset), amount * sizeof(typename View::value_t)); break; case e_rdwrt : reinterpret_cast<std::fstream*>(stream_ptr)-> - write(reinterpret_cast<const char*>(view.begin() + offset) , amount * sizeof(typename View::value_t)); + write(reinterpret_cast<char_cptr>(view.begin() + offset) , amount * sizeof(typename View::value_t)); break; default : return false; @@ -38479,11 +43966,11 @@ namespace exprtk switch (mode) { case e_read : reinterpret_cast<std::ifstream*>(stream_ptr)-> - read(reinterpret_cast<char*>(view.begin() + offset), amount * sizeof(typename View::value_t)); + read(reinterpret_cast<char_ptr>(view.begin() + offset), amount * sizeof(typename View::value_t)); break; case e_rdwrt : reinterpret_cast<std::fstream*>(stream_ptr)-> - read(reinterpret_cast<char*>(view.begin() + offset) , amount * sizeof(typename View::value_t)); + read(reinterpret_cast<char_ptr>(view.begin() + offset) , amount * sizeof(typename View::value_t)); break; default : return false; @@ -38547,11 +44034,12 @@ namespace exprtk template <typename T> file_descriptor* make_handle(T v) { - file_descriptor* fd = reinterpret_cast<file_descriptor*>(0); + const std::size_t fd_size = sizeof(details::file_descriptor*); + details::file_descriptor* fd = reinterpret_cast<file_descriptor*>(0); - std::memcpy(reinterpret_cast<char*>(&fd), - reinterpret_cast<const char*>(&v), - sizeof(void*)); + std::memcpy(reinterpret_cast<char_ptr >(&fd), + reinterpret_cast<char_cptr>(&v ), + fd_size); return fd; } @@ -38569,12 +44057,13 @@ namespace exprtk #ifdef _MSC_VER #pragma warning(pop) #endif + assert(sizeof(T) <= sizeof(void*)); } } // namespace exprtk::rtl::io::file::details template <typename T> - class open : public exprtk::igeneric_function<T> + class open exprtk_final : public exprtk::igeneric_function<T> { public: @@ -38583,26 +44072,28 @@ namespace exprtk typedef typename igfun_t::generic_type generic_type; typedef typename generic_type::string_view string_t; - using exprtk::igeneric_function<T>::operator(); + using igfun_t::operator(); open() : exprtk::igeneric_function<T>("S|SS") { details::perform_check<T>(); } - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { - std::string file_name = to_str(string_t(parameters[0])); - std::string access; + const std::string file_name = to_str(string_t(parameters[0])); if (file_name.empty()) + { return T(0); + } - if (0 == ps_index) - access = "r"; - else if (0 == string_t(parameters[1]).size()) + if ((1 == ps_index) && (0 == string_t(parameters[1]).size())) + { return T(0); - else - access = to_str(string_t(parameters[1])); + } + + const std::string access = + (0 == ps_index) ? "r" : to_str(string_t(parameters[1])); details::file_descriptor* fd = new details::file_descriptor(file_name,access); @@ -38610,9 +44101,11 @@ namespace exprtk { T t = T(0); + const std::size_t fd_size = sizeof(details::file_descriptor*); + std::memcpy(reinterpret_cast<char*>(&t ), reinterpret_cast<char*>(&fd), - sizeof(void*)); + fd_size); return t; } else @@ -38624,7 +44117,7 @@ namespace exprtk }; template <typename T> - struct close : public exprtk::ifunction<T> + struct close exprtk_final : public exprtk::ifunction<T> { using exprtk::ifunction<T>::operator(); @@ -38632,7 +44125,7 @@ namespace exprtk : exprtk::ifunction<T>(1) { details::perform_check<T>(); } - inline T operator() (const T& v) + inline T operator() (const T& v) exprtk_override { details::file_descriptor* fd = details::make_handle(v); @@ -38646,7 +44139,7 @@ namespace exprtk }; template <typename T> - class write : public exprtk::igeneric_function<T> + class write exprtk_final : public exprtk::igeneric_function<T> { public: @@ -38657,42 +44150,42 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function<T>::operator(); + using igfun_t::operator(); write() : igfun_t("TS|TST|TV|TVT") { details::perform_check<T>(); } - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { details::file_descriptor* fd = details::make_handle(scalar_t(parameters[0])()); - std::size_t amount = 0; - switch (ps_index) { case 0 : { const string_t buffer(parameters[1]); - amount = buffer.size(); + const std::size_t amount = buffer.size(); return T(fd->write(buffer, amount) ? 1 : 0); } case 1 : { const string_t buffer(parameters[1]); - amount = std::min(buffer.size(), + const std::size_t amount = + std::min(buffer.size(), static_cast<std::size_t>(scalar_t(parameters[2])())); return T(fd->write(buffer, amount) ? 1 : 0); } case 2 : { const vector_t vec(parameters[1]); - amount = vec.size(); + const std::size_t amount = vec.size(); return T(fd->write(vec, amount) ? 1 : 0); } case 3 : { const vector_t vec(parameters[1]); - amount = std::min(vec.size(), + const std::size_t amount = + std::min(vec.size(), static_cast<std::size_t>(scalar_t(parameters[2])())); return T(fd->write(vec, amount) ? 1 : 0); } @@ -38703,7 +44196,7 @@ namespace exprtk }; template <typename T> - class read : public exprtk::igeneric_function<T> + class read exprtk_final : public exprtk::igeneric_function<T> { public: @@ -38714,42 +44207,42 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function<T>::operator(); + using igfun_t::operator(); read() : igfun_t("TS|TST|TV|TVT") { details::perform_check<T>(); } - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { details::file_descriptor* fd = details::make_handle(scalar_t(parameters[0])()); - std::size_t amount = 0; - switch (ps_index) { case 0 : { string_t buffer(parameters[1]); - amount = buffer.size(); + const std::size_t amount = buffer.size(); return T(fd->read(buffer,amount) ? 1 : 0); } case 1 : { string_t buffer(parameters[1]); - amount = std::min(buffer.size(), + const std::size_t amount = + std::min(buffer.size(), static_cast<std::size_t>(scalar_t(parameters[2])())); return T(fd->read(buffer,amount) ? 1 : 0); } case 2 : { vector_t vec(parameters[1]); - amount = vec.size(); + const std::size_t amount = vec.size(); return T(fd->read(vec,amount) ? 1 : 0); } case 3 : { vector_t vec(parameters[1]); - amount = std::min(vec.size(), + const std::size_t amount = + std::min(vec.size(), static_cast<std::size_t>(scalar_t(parameters[2])())); return T(fd->read(vec,amount) ? 1 : 0); } @@ -38760,7 +44253,7 @@ namespace exprtk }; template <typename T> - class getline : public exprtk::igeneric_function<T> + class getline exprtk_final : public exprtk::igeneric_function<T> { public: @@ -38770,14 +44263,13 @@ namespace exprtk typedef typename generic_type::string_view string_t; typedef typename generic_type::scalar_view scalar_t; - using exprtk::igeneric_function<T>::operator(); + using igfun_t::operator(); getline() : igfun_t("T",igfun_t::e_rtrn_string) { details::perform_check<T>(); } - inline T operator() (std::string& result, - parameter_list_t parameters) + inline T operator() (std::string& result, parameter_list_t parameters) exprtk_override { details::file_descriptor* fd = details::make_handle(scalar_t(parameters[0])()); return T(fd->getline(result) ? 1 : 0); @@ -38785,7 +44277,7 @@ namespace exprtk }; template <typename T> - struct eof : public exprtk::ifunction<T> + struct eof exprtk_final : public exprtk::ifunction<T> { using exprtk::ifunction<T>::operator(); @@ -38793,10 +44285,9 @@ namespace exprtk : exprtk::ifunction<T>(1) { details::perform_check<T>(); } - inline T operator() (const T& v) + inline T operator() (const T& v) exprtk_override { details::file_descriptor* fd = details::make_handle(v); - return (fd->eof() ? T(1) : T(0)); } }; @@ -38813,7 +44304,7 @@ namespace exprtk bool register_package(exprtk::symbol_table<T>& symtab) { - #define exprtk_register_function(FunctionName,FunctionType) \ + #define exprtk_register_function(FunctionName, FunctionType) \ if (!symtab.add_function(FunctionName,FunctionType)) \ { \ exprtk_debug(( \ @@ -38822,12 +44313,12 @@ namespace exprtk return false; \ } \ - exprtk_register_function("open" ,o) - exprtk_register_function("close" ,c) - exprtk_register_function("write" ,w) - exprtk_register_function("read" ,r) - exprtk_register_function("getline",g) - exprtk_register_function("eof" ,e) + exprtk_register_function("open" , o) + exprtk_register_function("close" , c) + exprtk_register_function("write" , w) + exprtk_register_function("read" , r) + exprtk_register_function("getline" , g) + exprtk_register_function("eof" , e) #undef exprtk_register_function return true; @@ -38906,44 +44397,61 @@ namespace exprtk } // namespace exprtk::rtl::details template <typename T> - class all_true : public exprtk::igeneric_function<T> + class all_true exprtk_final : public exprtk::igeneric_function<T> { public: typedef typename exprtk::igeneric_function<T> igfun_t; typedef typename igfun_t::parameter_list_t parameter_list_t; typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function<T>::operator(); + using igfun_t::operator(); all_true() - : exprtk::igeneric_function<T>("V|VTT") + : exprtk::igeneric_function<T>("V|VTT|T*") /* Overloads: 0. V - vector 1. VTT - vector, r0, r1 + 2. T* - T....T */ {} - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { - const vector_t vec(parameters[0]); + if (2 == ps_index) + { + for (std::size_t i = 0; i < parameters.size(); ++i) + { + if (scalar_t(parameters[i])() == T(0)) + { + return T(0); + } + } + } + else + { + const vector_t vec(parameters[0]); - std::size_t r0 = 0; - std::size_t r1 = vec.size() - 1; + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; - if ( - (1 == ps_index) && - !helper::load_vector_range<T>::process(parameters, r0, r1, 1, 2, 0) - ) - return std::numeric_limits<T>::quiet_NaN(); + if ( + (1 == ps_index) && + !helper::load_vector_range<T>::process(parameters, r0, r1, 1, 2, 0) + ) + { + return std::numeric_limits<T>::quiet_NaN(); + } - for (std::size_t i = r0; i <= r1; ++i) - { - if (vec[i] == T(0)) + for (std::size_t i = r0; i <= r1; ++i) { - return T(0); + if (vec[i] == T(0)) + { + return T(0); + } } } @@ -38952,44 +44460,61 @@ namespace exprtk }; template <typename T> - class all_false : public exprtk::igeneric_function<T> + class all_false exprtk_final : public exprtk::igeneric_function<T> { public: typedef typename exprtk::igeneric_function<T> igfun_t; typedef typename igfun_t::parameter_list_t parameter_list_t; typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function<T>::operator(); + using igfun_t::operator(); all_false() - : exprtk::igeneric_function<T>("V|VTT") + : exprtk::igeneric_function<T>("V|VTT|T*") /* Overloads: 0. V - vector 1. VTT - vector, r0, r1 + 2. T* - T....T */ {} - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { - const vector_t vec(parameters[0]); + if (2 == ps_index) + { + for (std::size_t i = 0; i < parameters.size(); ++i) + { + if (scalar_t(parameters[i])() != T(0)) + { + return T(0); + } + } + } + else + { + const vector_t vec(parameters[0]); - std::size_t r0 = 0; - std::size_t r1 = vec.size() - 1; + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; - if ( - (1 == ps_index) && - !helper::load_vector_range<T>::process(parameters, r0, r1, 1, 2, 0) - ) - return std::numeric_limits<T>::quiet_NaN(); + if ( + (1 == ps_index) && + !helper::load_vector_range<T>::process(parameters, r0, r1, 1, 2, 0) + ) + { + return std::numeric_limits<T>::quiet_NaN(); + } - for (std::size_t i = r0; i <= r1; ++i) - { - if (vec[i] != T(0)) + for (std::size_t i = r0; i <= r1; ++i) { - return T(0); + if (vec[i] != T(0)) + { + return T(0); + } } } @@ -38998,44 +44523,61 @@ namespace exprtk }; template <typename T> - class any_true : public exprtk::igeneric_function<T> + class any_true exprtk_final : public exprtk::igeneric_function<T> { public: typedef typename exprtk::igeneric_function<T> igfun_t; typedef typename igfun_t::parameter_list_t parameter_list_t; typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function<T>::operator(); + using igfun_t::operator(); any_true() - : exprtk::igeneric_function<T>("V|VTT") + : exprtk::igeneric_function<T>("V|VTT|T*") /* Overloads: 0. V - vector 1. VTT - vector, r0, r1 + 2. T* - T....T */ {} - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { - const vector_t vec(parameters[0]); + if (2 == ps_index) + { + for (std::size_t i = 0; i < parameters.size(); ++i) + { + if (scalar_t(parameters[i])() != T(0)) + { + return T(1); + } + } + } + else + { + const vector_t vec(parameters[0]); - std::size_t r0 = 0; - std::size_t r1 = vec.size() - 1; + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; - if ( - (1 == ps_index) && - !helper::load_vector_range<T>::process(parameters, r0, r1, 1, 2, 0) - ) - return std::numeric_limits<T>::quiet_NaN(); + if ( + (1 == ps_index) && + !helper::load_vector_range<T>::process(parameters, r0, r1, 1, 2, 0) + ) + { + return std::numeric_limits<T>::quiet_NaN(); + } - for (std::size_t i = r0; i <= r1; ++i) - { - if (vec[i] != T(0)) + for (std::size_t i = r0; i <= r1; ++i) { - return T(1); + if (vec[i] != T(0)) + { + return T(1); + } } } @@ -39044,44 +44586,61 @@ namespace exprtk }; template <typename T> - class any_false : public exprtk::igeneric_function<T> + class any_false exprtk_final : public exprtk::igeneric_function<T> { public: typedef typename exprtk::igeneric_function<T> igfun_t; typedef typename igfun_t::parameter_list_t parameter_list_t; typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function<T>::operator(); + using igfun_t::operator(); any_false() - : exprtk::igeneric_function<T>("V|VTT") + : exprtk::igeneric_function<T>("V|VTT|T*") /* Overloads: 0. V - vector 1. VTT - vector, r0, r1 + 2. T* - T....T */ {} - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { - const vector_t vec(parameters[0]); + if (2 == ps_index) + { + for (std::size_t i = 0; i < parameters.size(); ++i) + { + if (scalar_t(parameters[i])() == T(0)) + { + return T(1); + } + } + } + else + { + const vector_t vec(parameters[0]); - std::size_t r0 = 0; - std::size_t r1 = vec.size() - 1; + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; - if ( - (1 == ps_index) && - !helper::load_vector_range<T>::process(parameters, r0, r1, 1, 2, 0) - ) - return std::numeric_limits<T>::quiet_NaN(); + if ( + (1 == ps_index) && + !helper::load_vector_range<T>::process(parameters, r0, r1, 1, 2, 0) + ) + { + return std::numeric_limits<T>::quiet_NaN(); + } - for (std::size_t i = r0; i <= r1; ++i) - { - if (vec[i] == T(0)) + for (std::size_t i = r0; i <= r1; ++i) { - return T(1); + if (vec[i] == T(0)) + { + return T(1); + } } } @@ -39090,44 +44649,58 @@ namespace exprtk }; template <typename T> - class count : public exprtk::igeneric_function<T> + class count exprtk_final : public exprtk::igeneric_function<T> { public: typedef typename exprtk::igeneric_function<T> igfun_t; typedef typename igfun_t::parameter_list_t parameter_list_t; typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function<T>::operator(); + using igfun_t::operator(); count() - : exprtk::igeneric_function<T>("V|VTT") + : exprtk::igeneric_function<T>("V|VTT|T*") /* Overloads: 0. V - vector 1. VTT - vector, r0, r1 + 2. T* - T....T */ {} - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { - const vector_t vec(parameters[0]); + std::size_t cnt = 0; - std::size_t r0 = 0; - std::size_t r1 = vec.size() - 1; + if (2 == ps_index) + { + for (std::size_t i = 0; i < parameters.size(); ++i) + { + if (scalar_t(parameters[i])() != T(0)) ++cnt; + } + } + else + { + const vector_t vec(parameters[0]); - if ( - (1 == ps_index) && - !helper::load_vector_range<T>::process(parameters, r0, r1, 1, 2, 0) - ) - return std::numeric_limits<T>::quiet_NaN(); + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; - std::size_t cnt = 0; + if ( + (1 == ps_index) && + !helper::load_vector_range<T>::process(parameters, r0, r1, 1, 2, 0) + ) + { + return std::numeric_limits<T>::quiet_NaN(); + } - for (std::size_t i = r0; i <= r1; ++i) - { - if (vec[i] != T(0)) ++cnt; + for (std::size_t i = r0; i <= r1; ++i) + { + if (vec[i] != T(0)) ++cnt; + } } return T(cnt); @@ -39135,7 +44708,7 @@ namespace exprtk }; template <typename T> - class copy : public exprtk::igeneric_function<T> + class copy exprtk_final : public exprtk::igeneric_function<T> { public: @@ -39145,7 +44718,7 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function<T>::operator(); + using igfun_t::operator(); copy() : exprtk::igeneric_function<T>("VV|VTTVTT") @@ -39156,7 +44729,7 @@ namespace exprtk */ {} - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { const vector_t x(parameters[0]); vector_t y(parameters[(0 == ps_index) ? 1 : 3]); @@ -39178,14 +44751,17 @@ namespace exprtk const std::size_t n = std::min(xr1 - xr0 + 1, yr1 - yr0 + 1); - std::copy(x.begin() + xr0, x.begin() + xr0 + n, y.begin() + yr0); + std::copy( + x.begin() + xr0, + x.begin() + xr0 + n, + y.begin() + yr0); return T(n); } }; template <typename T> - class rol : public exprtk::igeneric_function<T> + class rol exprtk_final : public exprtk::igeneric_function<T> { public: @@ -39195,7 +44771,7 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function<T>::operator(); + using igfun_t::operator(); rol() : exprtk::igeneric_function<T>("VT|VTTT") @@ -39206,7 +44782,7 @@ namespace exprtk */ {} - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { vector_t vec(parameters[0]); @@ -39236,7 +44812,7 @@ namespace exprtk }; template <typename T> - class ror : public exprtk::igeneric_function<T> + class ror exprtk_final : public exprtk::igeneric_function<T> { public: @@ -39246,7 +44822,7 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function<T>::operator(); + using igfun_t::operator(); ror() : exprtk::igeneric_function<T>("VT|VTTT") @@ -39257,7 +44833,7 @@ namespace exprtk */ {} - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { vector_t vec(parameters[0]); @@ -39274,8 +44850,8 @@ namespace exprtk ) return T(0); - std::size_t dist = r1 - r0 + 1; - std::size_t shift = (dist - (n % dist)) % dist; + const std::size_t dist = r1 - r0 + 1; + const std::size_t shift = (dist - (n % dist)) % dist; std::rotate( vec.begin() + r0, @@ -39287,7 +44863,7 @@ namespace exprtk }; template <typename T> - class shift_left : public exprtk::igeneric_function<T> + class reverse exprtk_final : public exprtk::igeneric_function<T> { public: @@ -39297,7 +44873,48 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function<T>::operator(); + using igfun_t::operator(); + + reverse() + : exprtk::igeneric_function<T>("V|VTT") + /* + Overloads: + 0. V - vector + 1. VTT - vector, r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override + { + vector_t vec(parameters[0]); + + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if ( + (1 == ps_index) && + !helper::load_vector_range<T>::process(parameters, r0, r1, 1, 2, 0) + ) + return T(0); + + std::reverse(vec.begin() + r0, vec.begin() + r1 + 1); + + return T(1); + } + }; + + template <typename T> + class shift_left exprtk_final : public exprtk::igeneric_function<T> + { + public: + + typedef typename exprtk::igeneric_function<T> igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using igfun_t::operator(); shift_left() : exprtk::igeneric_function<T>("VT|VTTT") @@ -39308,7 +44925,7 @@ namespace exprtk */ {} - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { vector_t vec(parameters[0]); @@ -39325,7 +44942,7 @@ namespace exprtk ) return T(0); - const std::size_t dist = r1 - r0 + 1; + const std::size_t dist = r1 - r0 + 1; if (n > dist) return T(0); @@ -39335,7 +44952,7 @@ namespace exprtk vec.begin() + r0 + n, vec.begin() + r1 + 1); - for (std::size_t i = r1 - n + 1; i <= r1; ++i) + for (std::size_t i = r1 - n + 1ULL; i <= r1; ++i) { vec[i] = T(0); } @@ -39345,7 +44962,7 @@ namespace exprtk }; template <typename T> - class shift_right : public exprtk::igeneric_function<T> + class shift_right exprtk_final : public exprtk::igeneric_function<T> { public: @@ -39355,7 +44972,7 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function<T>::operator(); + using igfun_t::operator(); shift_right() : exprtk::igeneric_function<T>("VT|VTTT") @@ -39366,7 +44983,7 @@ namespace exprtk */ {} - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { vector_t vec(parameters[0]); @@ -39383,7 +45000,7 @@ namespace exprtk ) return T(0); - const std::size_t dist = r1 - r0 + 1; + const std::size_t dist = r1 - r0 + 1; if (n > dist) return T(0); @@ -39405,7 +45022,7 @@ namespace exprtk }; template <typename T> - class sort : public exprtk::igeneric_function<T> + class sort exprtk_final : public exprtk::igeneric_function<T> { public: @@ -39415,7 +45032,7 @@ namespace exprtk typedef typename generic_type::string_view string_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function<T>::operator(); + using igfun_t::operator(); sort() : exprtk::igeneric_function<T>("V|VTT|VS|VSTT") @@ -39428,7 +45045,7 @@ namespace exprtk */ {} - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { vector_t vec(parameters[0]); @@ -39453,16 +45070,22 @@ namespace exprtk } if (ascending) - std::sort(vec.begin() + r0, vec.begin() + r1 + 1, std::less<T> ()); + std::sort( + vec.begin() + r0, + vec.begin() + r1 + 1, + std::less<T>()); else - std::sort(vec.begin() + r0, vec.begin() + r1 + 1, std::greater<T>()); + std::sort( + vec.begin() + r0, + vec.begin() + r1 + 1, + std::greater<T>()); return T(1); } }; template <typename T> - class nthelement : public exprtk::igeneric_function<T> + class nthelement exprtk_final : public exprtk::igeneric_function<T> { public: @@ -39472,7 +45095,7 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function<T>::operator(); + using igfun_t::operator(); nthelement() : exprtk::igeneric_function<T>("VT|VTTT") @@ -39483,7 +45106,7 @@ namespace exprtk */ {} - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { vector_t vec(parameters[0]); @@ -39495,16 +45118,21 @@ namespace exprtk return T(0); if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters, r0, r1, 2, 3, 0)) + { return std::numeric_limits<T>::quiet_NaN(); + } - std::nth_element(vec.begin() + r0, vec.begin() + r0 + n , vec.begin() + r1 + 1); + std::nth_element( + vec.begin() + r0, + vec.begin() + r0 + n , + vec.begin() + r1 + 1); return T(1); } }; template <typename T> - class iota : public exprtk::igeneric_function<T> + class assign exprtk_final : public exprtk::igeneric_function<T> { public: @@ -39514,41 +45142,101 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function<T>::operator(); + using igfun_t::operator(); + + assign() + : exprtk::igeneric_function<T>("VT|VTTT|VTTTT") + /* + Overloads: + 0. VT - vector, V + 1. VTTT - vector, V, r0, r1 + 2. VTTTT - vector, V, r0, r1, SS + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override + { + vector_t vec(parameters[0]); + + const T assign_value = scalar_t(parameters[1]); + + const std::size_t step_size = (2 != ps_index) ? 1 : + static_cast<std::size_t>(scalar_t(parameters.back())()); + + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if ( + ((ps_index == 1) || (ps_index == 2)) && + !helper::load_vector_range<T>::process(parameters, r0, r1, 2, 3, 0) + ) + { + return T(0); + } + + for (std::size_t i = r0; i <= r1; i += step_size) + { + vec[i] = assign_value; + } + + return T(1); + } + }; + + template <typename T> + class iota exprtk_final : public exprtk::igeneric_function<T> + { + public: + + typedef typename exprtk::igeneric_function<T> igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using igfun_t::operator(); iota() - : exprtk::igeneric_function<T>("VT|VTT|VTTT|VTTTT") + : exprtk::igeneric_function<T>("VTT|VT|VTTTT|VTTT") /* Overloads: - 0. VT - vector, increment - 1. VTT - vector, increment, base - 2. VTTTT - vector, increment, r0, r1 - 3. VTTTT - vector, increment, base, r0, r1 + 0. VTT - vector, SV, SS + 1. VT - vector, SV, SS (+1) + 2. VTTT - vector, r0, r1, SV, SS + 3. VTT - vector, r0, r1, SV, SS (+1) + + Where: + 1. SV - Start value + 2. SS - Step size */ {} - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { vector_t vec(parameters[0]); - T increment = scalar_t(parameters[1])(); - T base = ((1 == ps_index) || (3 == ps_index)) ? scalar_t(parameters[2])() : T(0); + const T start_value = (ps_index <= 1) ? + scalar_t(parameters[1]) : + scalar_t(parameters[3]) ; + + const T step_size = ((0 == ps_index) || (2 == ps_index)) ? + scalar_t(parameters.back())() : + T(1) ; std::size_t r0 = 0; std::size_t r1 = vec.size() - 1; - if ((2 == ps_index) && !helper::load_vector_range<T>::process(parameters, r0, r1, 2, 3, 0)) - return std::numeric_limits<T>::quiet_NaN(); - else if ((3 == ps_index) && !helper::load_vector_range<T>::process(parameters, r0, r1, 3, 4, 0)) - return std::numeric_limits<T>::quiet_NaN(); - else + if ( + ((ps_index == 2) || (ps_index == 3)) && + !helper::load_vector_range<T>::process(parameters, r0, r1, 1, 2, 0) + ) { - long long j = 0; + return T(0); + } - for (std::size_t i = r0; i <= r1; ++i, ++j) - { - vec[i] = base + (increment * j); - } + for (std::size_t i = r0; i <= r1; ++i) + { + vec[i] = start_value + ((i - r0) * step_size); } return T(1); @@ -39556,40 +45244,50 @@ namespace exprtk }; template <typename T> - class sumk : public exprtk::igeneric_function<T> + class sumk exprtk_final : public exprtk::igeneric_function<T> { public: typedef typename exprtk::igeneric_function<T> igfun_t; typedef typename igfun_t::parameter_list_t parameter_list_t; typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function<T>::operator(); + using igfun_t::operator(); sumk() - : exprtk::igeneric_function<T>("V|VTT") + : exprtk::igeneric_function<T>("V|VTT|VTTT") /* Overloads: - 0. V - vector - 1. VTT - vector, r0, r1 + 0. V - vector + 1. VTT - vector, r0, r1 + 2. VTTT - vector, r0, r1, stride */ {} - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { const vector_t vec(parameters[0]); + const std::size_t stride = (2 != ps_index) ? 1 : + static_cast<std::size_t>(scalar_t(parameters[3])()); + std::size_t r0 = 0; std::size_t r1 = vec.size() - 1; - if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters, r0, r1, 1, 2, 0)) + if ( + ((1 == ps_index) || (2 == ps_index)) && + !helper::load_vector_range<T>::process(parameters, r0, r1, 1, 2, 0) + ) + { return std::numeric_limits<T>::quiet_NaN(); + } T result = T(0); T error = T(0); - for (std::size_t i = r0; i <= r1; ++i) + for (std::size_t i = r0; i <= r1; i += stride) { details::kahan_sum(result, error, vec[i]); } @@ -39599,7 +45297,7 @@ namespace exprtk }; template <typename T> - class axpy : public exprtk::igeneric_function<T> + class axpy exprtk_final : public exprtk::igeneric_function<T> { public: @@ -39609,7 +45307,7 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function<T>::operator(); + using igfun_t::operator(); axpy() : exprtk::igeneric_function<T>("TVV|TVVTT") @@ -39621,7 +45319,7 @@ namespace exprtk */ {} - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { const vector_t x(parameters[1]); vector_t y(parameters[2]); @@ -39646,7 +45344,7 @@ namespace exprtk }; template <typename T> - class axpby : public exprtk::igeneric_function<T> + class axpby exprtk_final : public exprtk::igeneric_function<T> { public: @@ -39656,7 +45354,7 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function<T>::operator(); + using igfun_t::operator(); axpby() : exprtk::igeneric_function<T>("TVTV|TVTVTT") @@ -39668,7 +45366,7 @@ namespace exprtk */ {} - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { const vector_t x(parameters[1]); vector_t y(parameters[3]); @@ -39694,7 +45392,7 @@ namespace exprtk }; template <typename T> - class axpyz : public exprtk::igeneric_function<T> + class axpyz exprtk_final : public exprtk::igeneric_function<T> { public: @@ -39704,7 +45402,7 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function<T>::operator(); + using igfun_t::operator(); axpyz() : exprtk::igeneric_function<T>("TVVV|TVVVTT") @@ -39716,7 +45414,7 @@ namespace exprtk */ {} - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { const vector_t x(parameters[1]); const vector_t y(parameters[2]); @@ -39725,7 +45423,7 @@ namespace exprtk std::size_t r0 = 0; std::size_t r1 = std::min(x.size(),y.size()) - 1; - if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters, r0, r1, 3, 4, 1)) + if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters, r0, r1, 4, 5, 1)) return std::numeric_limits<T>::quiet_NaN(); else if (helper::invalid_range(y, r0, r1)) return std::numeric_limits<T>::quiet_NaN(); @@ -39744,7 +45442,7 @@ namespace exprtk }; template <typename T> - class axpbyz : public exprtk::igeneric_function<T> + class axpbyz exprtk_final : public exprtk::igeneric_function<T> { public: @@ -39754,7 +45452,7 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function<T>::operator(); + using igfun_t::operator(); axpbyz() : exprtk::igeneric_function<T>("TVTVV|TVTVVTT") @@ -39766,7 +45464,7 @@ namespace exprtk */ {} - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { const vector_t x(parameters[1]); const vector_t y(parameters[3]); @@ -39775,7 +45473,7 @@ namespace exprtk std::size_t r0 = 0; std::size_t r1 = std::min(x.size(),y.size()) - 1; - if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters, r0, r1, 4, 5, 1)) + if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters, r0, r1, 5, 6, 1)) return std::numeric_limits<T>::quiet_NaN(); else if (helper::invalid_range(y, r0, r1)) return std::numeric_limits<T>::quiet_NaN(); @@ -39795,7 +45493,7 @@ namespace exprtk }; template <typename T> - class axpbz : public exprtk::igeneric_function<T> + class axpbsy exprtk_final : public exprtk::igeneric_function<T> { public: @@ -39805,7 +45503,110 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function<T>::operator(); + using igfun_t::operator(); + + axpbsy() + : exprtk::igeneric_function<T>("TVTTV|TVTTVTT") + /* + y <- ax + by + Overloads: + 0. TVTVV - a, x(vector), b, shift, y(vector), z(vector) + 1. TVTVVTT - a, x(vector), b, shift, y(vector), z(vector), r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override + { + const vector_t x(parameters[1]); + vector_t y(parameters[4]); + + std::size_t r0 = 0; + std::size_t r1 = std::min(x.size(),y.size()) - 1; + + if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters, r0, r1, 5, 6, 1)) + return std::numeric_limits<T>::quiet_NaN(); + else if (helper::invalid_range(y, r0, r1)) + return std::numeric_limits<T>::quiet_NaN(); + + const T a = scalar_t(parameters[0])(); + const T b = scalar_t(parameters[2])(); + + const std::size_t s = static_cast<std::size_t>(scalar_t(parameters[3])()); + + for (std::size_t i = r0; i <= r1; ++i) + { + y[i] = (a * x[i]) + (b * y[i + s]); + } + + return T(1); + } + }; + + template <typename T> + class axpbsyz exprtk_final : public exprtk::igeneric_function<T> + { + public: + + typedef typename exprtk::igeneric_function<T> igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using igfun_t::operator(); + + axpbsyz() + : exprtk::igeneric_function<T>("TVTTVV|TVTTVVTT") + /* + z <- ax + by + Overloads: + 0. TVTVV - a, x(vector), b, shift, y(vector), z(vector) + 1. TVTVVTT - a, x(vector), b, shift, y(vector), z(vector), r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override + { + const vector_t x(parameters[1]); + const vector_t y(parameters[4]); + vector_t z(parameters[5]); + + std::size_t r0 = 0; + std::size_t r1 = std::min(x.size(),y.size()) - 1; + + if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters, r0, r1, 6, 7, 1)) + return std::numeric_limits<T>::quiet_NaN(); + else if (helper::invalid_range(y, r0, r1)) + return std::numeric_limits<T>::quiet_NaN(); + else if (helper::invalid_range(z, r0, r1)) + return std::numeric_limits<T>::quiet_NaN(); + + const T a = scalar_t(parameters[0])(); + const T b = scalar_t(parameters[2])(); + + const std::size_t s = static_cast<std::size_t>(scalar_t(parameters[3])()); + + for (std::size_t i = r0; i <= r1; ++i) + { + z[i] = (a * x[i]) + (b * y[i + s]); + } + + return T(1); + } + }; + + template <typename T> + class axpbz exprtk_final : public exprtk::igeneric_function<T> + { + public: + + typedef typename exprtk::igeneric_function<T> igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using igfun_t::operator(); axpbz() : exprtk::igeneric_function<T>("TVTV|TVTVTT") @@ -39817,7 +45618,7 @@ namespace exprtk */ {} - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { const vector_t x(parameters[1]); vector_t z(parameters[3]); @@ -39843,7 +45644,7 @@ namespace exprtk }; template <typename T> - class dot : public exprtk::igeneric_function<T> + class diff exprtk_final : public exprtk::igeneric_function<T> { public: @@ -39853,7 +45654,55 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function<T>::operator(); + using igfun_t::operator(); + + diff() + : exprtk::igeneric_function<T>("VV|VVT") + /* + x_(i - stride) - x_i + Overloads: + 0. VV - x(vector), y(vector) + 1. VVT - x(vector), y(vector), stride + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override + { + const vector_t x(parameters[0]); + vector_t y(parameters[1]); + + const std::size_t r0 = 0; + const std::size_t r1 = std::min(x.size(),y.size()) - 1; + + const std::size_t stride = (1 != ps_index) ? 1 : + std::min(r1,static_cast<std::size_t>(scalar_t(parameters[2])())); + + for (std::size_t i = 0; i < stride; ++i) + { + y[i] = std::numeric_limits<T>::quiet_NaN(); + } + + for (std::size_t i = (r0 + stride); i <= r1; ++i) + { + y[i] = x[i] - x[i - stride]; + } + + return T(1); + } + }; + + template <typename T> + class dot exprtk_final : public exprtk::igeneric_function<T> + { + public: + + typedef typename exprtk::igeneric_function<T> igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using igfun_t::operator(); dot() : exprtk::igeneric_function<T>("VV|VVTT") @@ -39864,7 +45713,7 @@ namespace exprtk */ {} - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { const vector_t x(parameters[0]); const vector_t y(parameters[1]); @@ -39889,7 +45738,7 @@ namespace exprtk }; template <typename T> - class dotk : public exprtk::igeneric_function<T> + class dotk exprtk_final : public exprtk::igeneric_function<T> { public: @@ -39899,7 +45748,7 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function<T>::operator(); + using igfun_t::operator(); dotk() : exprtk::igeneric_function<T>("VV|VVTT") @@ -39910,7 +45759,7 @@ namespace exprtk */ {} - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override { const vector_t x(parameters[0]); const vector_t y(parameters[1]); @@ -39935,34 +45784,159 @@ namespace exprtk } }; + template <typename T> + class threshold_below exprtk_final : public exprtk::igeneric_function<T> + { + public: + + typedef typename exprtk::igeneric_function<T> igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using igfun_t::operator(); + + threshold_below() + : exprtk::igeneric_function<T>("VTT|VTTTT") + /* + Overloads: + 0. VTT - vector, TV, SV + 1. VTTTT - vector, r0, r1, TV, SV + + Where: + TV - Threshold value + SV - Snap-to value + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override + { + vector_t vec(parameters[0]); + + const T threshold_value = (0 == ps_index) ? + scalar_t(parameters[1]) : + scalar_t(parameters[3]) ; + + const T snap_value = scalar_t(parameters.back()); + + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if ( + (1 == ps_index) && + !helper::load_vector_range<T>::process(parameters, r0, r1, 1, 2, 0) + ) + { + return T(0); + } + + for (std::size_t i = r0; i <= r1; ++i) + { + if (vec[i] < threshold_value) + { + vec[i] = snap_value; + } + } + + return T(1); + } + }; + + template <typename T> + class threshold_above exprtk_final : public exprtk::igeneric_function<T> + { + public: + + typedef typename exprtk::igeneric_function<T> igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using igfun_t::operator(); + + threshold_above() + : exprtk::igeneric_function<T>("VTT|VTTTT") + /* + Overloads: + 0. VTT - vector, TV, SV + 1. VTTTT - vector, r0, r1, TV, SV + + Where: + TV - Threshold value + SV - Snap-to value + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override + { + vector_t vec(parameters[0]); + + const T threshold_value = (0 == ps_index) ? + scalar_t(parameters[1]) : + scalar_t(parameters[3]) ; + + const T snap_value = scalar_t(parameters.back()); + + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if ( + (1 == ps_index) && + !helper::load_vector_range<T>::process(parameters, r0, r1, 1, 2, 0) + ) + { + return T(0); + } + + for (std::size_t i = r0; i <= r1; ++i) + { + if (vec[i] > threshold_value) + { + vec[i] = snap_value; + } + } + + return T(1); + } + }; + template <typename T> struct package { - all_true <T> at; - all_false <T> af; - any_true <T> nt; - any_false <T> nf; - count <T> c; - copy <T> cp; - rol <T> rl; - ror <T> rr; - shift_left <T> sl; - shift_right<T> sr; - sort <T> st; - nthelement <T> ne; - iota <T> ia; - sumk <T> sk; - axpy <T> b1_axpy; - axpby <T> b1_axpby; - axpyz <T> b1_axpyz; - axpbyz <T> b1_axpbyz; - axpbz <T> b1_axpbz; - dot <T> dt; - dotk <T> dtk; + all_true <T> at; + all_false <T> af; + any_true <T> nt; + any_false <T> nf; + count <T> c; + copy <T> cp; + rol <T> rl; + ror <T> rr; + reverse <T> rev; + shift_left <T> sl; + shift_right <T> sr; + sort <T> st; + nthelement <T> ne; + assign <T> an; + iota <T> ia; + sumk <T> sk; + axpy <T> b1_axpy; + axpby <T> b1_axpby; + axpyz <T> b1_axpyz; + axpbyz <T> b1_axpbyz; + axpbsy <T> b1_axpbsy; + axpbsyz <T> b1_axpbsyz; + axpbz <T> b1_axpbz; + diff <T> df; + dot <T> dt; + dotk <T> dtk; + threshold_above<T> ta; + threshold_below<T> tb; bool register_package(exprtk::symbol_table<T>& symtab) { - #define exprtk_register_function(FunctionName,FunctionType) \ + #define exprtk_register_function(FunctionName, FunctionType) \ if (!symtab.add_function(FunctionName,FunctionType)) \ { \ exprtk_debug(( \ @@ -39971,29 +45945,36 @@ namespace exprtk return false; \ } \ - exprtk_register_function("all_true" ,at) - exprtk_register_function("all_false" ,af) - exprtk_register_function("any_true" ,nt) - exprtk_register_function("any_false" ,nf) - exprtk_register_function("count" , c) - exprtk_register_function("copy" ,cp) - exprtk_register_function("rotate_left" ,rl) - exprtk_register_function("rol" ,rl) - exprtk_register_function("rotate_right" ,rr) - exprtk_register_function("ror" ,rr) - exprtk_register_function("shftl" ,sl) - exprtk_register_function("shftr" ,sr) - exprtk_register_function("sort" ,st) - exprtk_register_function("nth_element" ,ne) - exprtk_register_function("iota" ,ia) - exprtk_register_function("sumk" ,sk) - exprtk_register_function("axpy" ,b1_axpy) - exprtk_register_function("axpby" ,b1_axpby) - exprtk_register_function("axpyz" ,b1_axpyz) - exprtk_register_function("axpbyz",b1_axpbyz) - exprtk_register_function("axpbz" ,b1_axpbz) - exprtk_register_function("dot" ,dt) - exprtk_register_function("dotk" ,dtk) + exprtk_register_function("all_true" , at ) + exprtk_register_function("all_false" , af ) + exprtk_register_function("any_true" , nt ) + exprtk_register_function("any_false" , nf ) + exprtk_register_function("count" , c ) + exprtk_register_function("copy" , cp ) + exprtk_register_function("rotate_left" , rl ) + exprtk_register_function("rol" , rl ) + exprtk_register_function("rotate_right" , rr ) + exprtk_register_function("ror" , rr ) + exprtk_register_function("reverse" , rev ) + exprtk_register_function("shftl" , sl ) + exprtk_register_function("shftr" , sr ) + exprtk_register_function("sort" , st ) + exprtk_register_function("nth_element" , ne ) + exprtk_register_function("assign" , an ) + exprtk_register_function("iota" , ia ) + exprtk_register_function("sumk" , sk ) + exprtk_register_function("axpy" , b1_axpy ) + exprtk_register_function("axpby" , b1_axpby ) + exprtk_register_function("axpyz" , b1_axpyz ) + exprtk_register_function("axpbyz" , b1_axpbyz ) + exprtk_register_function("axpbsy" , b1_axpbsy ) + exprtk_register_function("axpbsyz" , b1_axpbsyz) + exprtk_register_function("axpbz" , b1_axpbz ) + exprtk_register_function("diff" , df ) + exprtk_register_function("dot" , dt ) + exprtk_register_function("dotk" , dtk ) + exprtk_register_function("threshold_above" , ta ) + exprtk_register_function("threshold_below" , tb ) #undef exprtk_register_function return true; @@ -40009,18 +45990,22 @@ namespace exprtk { namespace information { - static const char* library = "Mathematical Expression Toolkit"; - static const char* version = "2.718281828459045235360287471352" - "66249775724709369995957496696762" - "77240766303535475945713821785251" - "66427427466391932003059921817413"; - static const char* date = "20210101"; + using ::exprtk::details::char_cptr; + + static char_cptr library = "Mathematical Expression Toolkit"; + static char_cptr version = "2.718281828459045235360287471352662497757" + "24709369995957496696762772407663035354759" + "45713821785251664274274663919320030599218" + "17413596629043572900334295260595630738132"; + static char_cptr date = "20240101"; + static char_cptr min_cpp = "199711L"; static inline std::string data() { static const std::string info_str = std::string(library) + std::string(" v") + std::string(version) + - std::string(" (") + date + std::string(")"); + std::string(" (") + date + std::string(")") + + std::string(" (") + min_cpp + std::string(")"); return info_str; } @@ -40034,16 +46019,28 @@ namespace exprtk #undef exprtk_error_location #endif - #ifdef exprtk_disable_fallthrough_begin - #undef exprtk_disable_fallthrough_begin + #ifdef exprtk_fallthrough + #undef exprtk_fallthrough + #endif + + #ifdef exprtk_override + #undef exprtk_override + #endif + + #ifdef exprtk_final + #undef exprtk_final + #endif + + #ifdef exprtk_delete + #undef exprtk_delete #endif - #ifdef exprtk_disable_fallthrough_end - #undef exprtk_disable_fallthrough_end + #ifdef exprtk_default + #undef exprtk_default #endif } // namespace exprtk -//NOLINTEND(modernize-use-nullptr) +//NOLINTEND(modernize-*,readability-*,performance-no-int-to-ptr,bugprone-empty-catch,bugprone-inc-dec-in-conditions) #endif diff --git a/src/gpu/FieldIndexing.impl.h b/src/gpu/FieldIndexing.impl.h index a8c9feccfbed0e12b015fe37dadac4aeaa803450..7ec1bb86a00d265c4158f3d37f170caa9b09735d 100644 --- a/src/gpu/FieldIndexing.impl.h +++ b/src/gpu/FieldIndexing.impl.h @@ -48,11 +48,11 @@ FieldIndexing<T>::FieldIndexing ( const GPUField<T> & field, { gpuDeviceProp prop; int count; - gpuGetDeviceCount(&count); + WALBERLA_GPU_CHECK(gpuGetDeviceCount(&count)); int threadsPerBlock = std::numeric_limits< int >::max(); for (int i = 0; i < count; i++) { - gpuGetDeviceProperties(&prop, i); + WALBERLA_GPU_CHECK(gpuGetDeviceProperties(&prop, i)); threadsPerBlock = std::min(prop.maxThreadsPerBlock, threadsPerBlock); } WALBERLA_ASSERT_LESS(int_c(blockDim_.x), threadsPerBlock, diff --git a/src/gpu/GPUWrapper.h b/src/gpu/GPUWrapper.h index d4893da8b7ed123596fe18be62186670f990491d..7d103c298f691488817441132d3f0413b26d9ac9 100644 --- a/src/gpu/GPUWrapper.h +++ b/src/gpu/GPUWrapper.h @@ -35,6 +35,7 @@ #define gpuMalloc cudaMalloc #define gpuMallocHost cudaMallocHost + #define gpuMallocManaged cudaMallocManaged #define gpuHostAllocDefault cudaHostAllocDefault #define gpuHostAlloc cudaHostAlloc #define gpuMemcpyHostToDevice cudaMemcpyHostToDevice @@ -45,6 +46,7 @@ #define gpuMemcpy3D cudaMemcpy3D #define gpuMemcpy3DParms cudaMemcpy3DParms #define gpuMemcpy3DAsync cudaMemcpy3DAsync + #define gpuMemset cudaMemset #define gpuMemset cudaMemset #define gpuMemsetAsync cudaMemsetAsync @@ -99,6 +101,7 @@ #define gpuMalloc hipMalloc #define gpuMallocHost hipHostMalloc + #define gpuMallocManaged hipMallocManaged #define gpuHostAllocDefault hipHostMallocDefault // warning: 'hipHostAlloc' is deprecated: use hipHostMalloc insteadwarning: 'hipHostAlloc' is deprecated: use hipHostMalloc instead #define gpuHostAlloc hipHostMalloc @@ -110,6 +113,7 @@ #define gpuMemcpy3D hipMemcpy3D #define gpuMemcpy3DParms hipMemcpy3DParms #define gpuMemcpy3DAsync hipMemcpy3DAsync + #define gpuMemset hipMemset #define gpuMemset hipMemset #define gpuMemsetAsync hipMemsetAsync @@ -144,7 +148,7 @@ #define gpuGetDeviceCount hipGetDeviceCount #define gpuSetDevice hipSetDevice - #define gpuDeviceProp hipDeviceProp + #define gpuDeviceProp hipDeviceProp_t #define gpuGetDeviceProperties hipGetDeviceProperties #define gpuLaunchKernel hipLaunchKernel diff --git a/src/gpu/Kernel.h b/src/gpu/Kernel.h index f6c2eb687a1d54e6aea2b21f80bfd200d05b371f..59366e5bc6d2bcdbd990cfd8d968a07121efb904 100644 --- a/src/gpu/Kernel.h +++ b/src/gpu/Kernel.h @@ -145,6 +145,18 @@ namespace gpu CHECK_PARAMETER_FUNC(5) CHECK_PARAMETER_FUNC(6) CHECK_PARAMETER_FUNC(7) + CHECK_PARAMETER_FUNC(8) + CHECK_PARAMETER_FUNC(9) + CHECK_PARAMETER_FUNC(10) + CHECK_PARAMETER_FUNC(11) + CHECK_PARAMETER_FUNC(12) + CHECK_PARAMETER_FUNC(13) + CHECK_PARAMETER_FUNC(14) + CHECK_PARAMETER_FUNC(15) + CHECK_PARAMETER_FUNC(16) + CHECK_PARAMETER_FUNC(17) + CHECK_PARAMETER_FUNC(18) + CHECK_PARAMETER_FUNC(19) #undef CHECK_PARAMETER_FUNC @@ -256,6 +268,18 @@ namespace gpu case 5: return checkParameter5<T>(); case 6: return checkParameter6<T>(); case 7: return checkParameter7<T>(); + case 8: return checkParameter8<T>(); + case 9: return checkParameter9<T>(); + case 10: return checkParameter10<T>(); + case 11: return checkParameter11<T>(); + case 12: return checkParameter12<T>(); + case 13: return checkParameter13<T>(); + case 14: return checkParameter14<T>(); + case 15: return checkParameter15<T>(); + case 16: return checkParameter16<T>(); + case 17: return checkParameter17<T>(); + case 18: return checkParameter18<T>(); + case 19: return checkParameter19<T>(); default: WALBERLA_ABORT("Too many parameters passed to kernel") } diff --git a/src/lbm/PerformanceLogger.h b/src/lbm/PerformanceLogger.h index 337cf6832e13ab68adb17697ffa1a9f17ab0f7de..13b2a4601cb306bbd2a870381c7a9b0164bd482f 100644 --- a/src/lbm/PerformanceLogger.h +++ b/src/lbm/PerformanceLogger.h @@ -167,7 +167,9 @@ void PerformanceLogger<FlagField_T>::getBestResultsForSQLOnRoot( std::map< std:: std::map< std::string, double > & realProperties, std::map< std::string, std::string > & stringProperties ) { + timer_.end(); performanceEvaluation_.getResultsForSQLOnRoot( integerProperties, realProperties, stringProperties, interval_, getTiming( MAX ) ); + timer_.start(); } diff --git a/src/lbm_mesapd_coupling/CMakeLists.txt b/src/lbm_mesapd_coupling/CMakeLists.txt index bde22da3f4a2f4b4f6edcaadc6de8f562292b54f..1e04ba7fd21b3dcf4e4ffc3518c833a4460205ed 100644 --- a/src/lbm_mesapd_coupling/CMakeLists.txt +++ b/src/lbm_mesapd_coupling/CMakeLists.txt @@ -12,8 +12,20 @@ target_sources( lbm_mesapd_coupling DataTypes.h ) +# Maximum number of particles that may overlap with a cell. For fully resolved particles, 2 should normally be +# sufficient (for a sufficiently high stiffness in the DEM). +set(MAX_PARTICLES_PER_CELL 2) +add_custom_target(MAX_PARTICLES_PER_CELL) # Make it a target such that the code generation runs again if changed +target_sources( lbm_mesapd_coupling + PRIVATE + DataTypesCodegen.h + ) +target_compile_definitions(lbm_mesapd_coupling PUBLIC MAX_PARTICLES_PER_CELL=${MAX_PARTICLES_PER_CELL}) + + add_subdirectory( amr ) add_subdirectory( momentum_exchange_method ) +add_subdirectory( overlapping ) add_subdirectory( partially_saturated_cells_method ) add_subdirectory( utility ) add_subdirectory( mapping ) diff --git a/src/lbm_mesapd_coupling/DataTypesCodegen.h b/src/lbm_mesapd_coupling/DataTypesCodegen.h new file mode 100644 index 0000000000000000000000000000000000000000..99583a6131a846193826d968e9b8695c5d51d4f6 --- /dev/null +++ b/src/lbm_mesapd_coupling/DataTypesCodegen.h @@ -0,0 +1,132 @@ +//====================================================================================================================== +// +// This file is part of waLBerla. waLBerla 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. +// +// waLBerla 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 waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file DataTypesGPU.h +//! \ingroup lbm_mesapd_coupling +//! \author Samuel Kemmler <samuel.kemmler@fau.de> +// +//====================================================================================================================== + +#pragma once + +#include "core/DataTypes.h" + +#include "field/AddToStorage.h" +#include "field/GhostLayerField.h" + +#ifdef WALBERLA_BUILD_WITH_GPU_SUPPORT +# include "gpu/AddGPUFieldToStorage.h" +# include "gpu/GPUField.h" +#endif + +namespace walberla +{ +namespace lbm_mesapd_coupling +{ +namespace psm +{ +namespace gpu +{ + +const uint MaxParticlesPerCell = MAX_PARTICLES_PER_CELL; // MAX_PARTICLES_PER_CELL comes from CMake + +// nOverlappingParticlesField is used to store the amount of overlapping particles per cell +// B denotes the local weighting factor and is calculated by taking the sum of all local particle +// weighting factor Bs. The naming of the variables is based on the following paper: +// https://doi.org/10.1016/j.compfluid.2017.05.033 +// idxField is used to store the indices of the overlapping particles +// particleVelocitiesField is used to store the velocities of the overlapping particles evaluated at the cell center +// particleForcesField is used to store the hydrodynamic forces of the cell acting on the overlapping particles + +using nOverlappingParticlesField_T = GhostLayerField< uint_t, 1 >; +using BsField_T = GhostLayerField< real_t, MaxParticlesPerCell >; +using idxField_T = GhostLayerField< size_t, MaxParticlesPerCell >; +using BField_T = GhostLayerField< real_t, 1 >; +using particleVelocitiesField_T = GhostLayerField< real_t, MaxParticlesPerCell * 3 >; +using particleForcesField_T = GhostLayerField< real_t, MaxParticlesPerCell * 3 >; +#ifdef WALBERLA_BUILD_WITH_GPU_SUPPORT +using nOverlappingParticlesFieldGPU_T = walberla::gpu::GPUField< uint_t >; +using BsFieldGPU_T = walberla::gpu::GPUField< real_t >; +using idxFieldGPU_T = walberla::gpu::GPUField< size_t >; +using BFieldGPU_T = walberla::gpu::GPUField< real_t >; +using particleVelocitiesFieldGPU_T = walberla::gpu::GPUField< real_t >; +using particleForcesFieldGPU_T = walberla::gpu::GPUField< real_t >; +#endif + +// The ParticleAndVolumeFractionSoA encapsulates the data needed by the routines involved in the coupling +template< int Weighting_T > +struct ParticleAndVolumeFractionSoA_T +{ + BlockDataID nOverlappingParticlesFieldID; + BlockDataID BsFieldID; + BlockDataID idxFieldID; + BlockDataID BFieldID; + BlockDataID particleVelocitiesFieldID; + BlockDataID particleForcesFieldID; + // relaxation rate omega is used for Weighting_T != 1 + real_t omega_; + // UIDs of the particles are stored during mapping, and it is checked that they are the same during the PSM kernel. + // This prevents running into troubles due to changed indices + std::vector< walberla::id_t > mappingUIDs; + // Store positions globally to avoid copying them from CPU to GPU in multiple sweeps + real_t* positions = nullptr; + + // nrOfGhostLayers is also 1 for the fields that do not need a ghost layer since the generated sweeps can only handle + // fields with the same number of ghost layerserated kernels) + ParticleAndVolumeFractionSoA_T(const shared_ptr< StructuredBlockStorage >& bs, const real_t omega) + { +#ifdef WALBERLA_BUILD_WITH_GPU_SUPPORT + nOverlappingParticlesFieldID = walberla::gpu::addGPUFieldToStorage< nOverlappingParticlesFieldGPU_T >( + bs, "number of overlapping particles field GPU", uint_t(1), field::fzyx, uint_t(1), true); + BsFieldID = walberla::gpu::addGPUFieldToStorage< BsFieldGPU_T >(bs, "Bs field GPU", MaxParticlesPerCell, + field::fzyx, uint_t(1), true); + idxFieldID = walberla::gpu::addGPUFieldToStorage< idxFieldGPU_T >(bs, "idx field GPU", MaxParticlesPerCell, + field::fzyx, uint_t(1), true); + BFieldID = walberla::gpu::addGPUFieldToStorage< BFieldGPU_T >(bs, "B field GPU", 1, field::fzyx, uint_t(1), true); + particleVelocitiesFieldID = walberla::gpu::addGPUFieldToStorage< particleVelocitiesFieldGPU_T >( + bs, "particle velocities field GPU", uint_t(MaxParticlesPerCell * 3), field::fzyx, uint_t(1), true); + particleForcesFieldID = walberla::gpu::addGPUFieldToStorage< particleForcesFieldGPU_T >( + bs, "particle forces field GPU", uint_t(MaxParticlesPerCell * 3), field::fzyx, uint_t(1), true); +#else + nOverlappingParticlesFieldID = field::addToStorage< nOverlappingParticlesField_T >( + bs, "number of overlapping particles field CPU", uint_t(0), field::fzyx, uint_t(1), true); + BsFieldID = field::addToStorage< BsField_T >(bs, "Bs field CPU", real_t(0), field::fzyx, uint_t(1), true); + idxFieldID = field::addToStorage< idxField_T >(bs, "idx field CPU", uint_t(0), field::fzyx, uint_t(1), true); + BFieldID = field::addToStorage< BField_T >(bs, "B field CPU", real_t(0), field::fzyx, uint_t(1), true); + particleVelocitiesFieldID = field::addToStorage< particleVelocitiesField_T >( + bs, "particle velocities field CPU", real_t(0), field::fzyx, uint_t(1), true); + particleForcesFieldID = field::addToStorage< particleForcesField_T >(bs, "particle forces field CPU", real_t(0), + field::fzyx, uint_t(1), true); +#endif + omega_ = omega; + } + + ~ParticleAndVolumeFractionSoA_T() + { + if (positions != nullptr) + { +#ifdef WALBERLA_BUILD_WITH_GPU_SUPPORT + WALBERLA_GPU_CHECK(gpuFree(positions)); +#else + free(positions); +#endif + } + } +}; + +} // namespace gpu +} // namespace psm +} // namespace lbm_mesapd_coupling +} // namespace walberla diff --git a/src/lbm_mesapd_coupling/overlapping/CMakeLists.txt b/src/lbm_mesapd_coupling/overlapping/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..1dfa6dc12d91a77a01f15baa8200835fc78c2fbb --- /dev/null +++ b/src/lbm_mesapd_coupling/overlapping/CMakeLists.txt @@ -0,0 +1,4 @@ +target_sources(lbm_mesapd_coupling + PRIVATE + OverlapFraction.h + ) diff --git a/src/lbm_mesapd_coupling/overlapping/OverlapFraction.h b/src/lbm_mesapd_coupling/overlapping/OverlapFraction.h index 3dbf68e039af2494020a8ec045f60189a318fd9c..c1fa9d7c99583356f122595d8d8df4190f3e82ad 100644 --- a/src/lbm_mesapd_coupling/overlapping/OverlapFraction.h +++ b/src/lbm_mesapd_coupling/overlapping/OverlapFraction.h @@ -16,7 +16,7 @@ //! \file OverlapFraction.h //! \ingroup lbm_mesapd_coupling //! \author Samuel Kemmler <samuel.kemmler@fau.de> -//! \brief Functor that provides overlap fraction computations for different MESA-PD shapes (used for SingleCast) +//! \brief Functor that provides overlap fraction computations for different MESA-PD shapes (used by SingleCast) // //====================================================================================================================== diff --git a/src/lbm_mesapd_coupling/partially_saturated_cells_method/CMakeLists.txt b/src/lbm_mesapd_coupling/partially_saturated_cells_method/CMakeLists.txt index 65b1c468c80828ea27ca30c9cc8f712e137803cb..4a87ce81e6dc56c3a5f3bbeb1b6d988ca2bed00c 100644 --- a/src/lbm_mesapd_coupling/partially_saturated_cells_method/CMakeLists.txt +++ b/src/lbm_mesapd_coupling/partially_saturated_cells_method/CMakeLists.txt @@ -4,3 +4,5 @@ target_sources( lbm_mesapd_coupling ParticleAndVolumeFractionMapping.h PSMUtility.h ) + +add_subdirectory(codegen) diff --git a/src/lbm_mesapd_coupling/partially_saturated_cells_method/PSMSweep.h b/src/lbm_mesapd_coupling/partially_saturated_cells_method/PSMSweep.h index 8ad996ba8c1a5b4ea61a4add9e29f1a9de67196b..d056e2e76ab010cd2732297778a0e4d6750560cd 100644 --- a/src/lbm_mesapd_coupling/partially_saturated_cells_method/PSMSweep.h +++ b/src/lbm_mesapd_coupling/partially_saturated_cells_method/PSMSweep.h @@ -221,7 +221,7 @@ void PSMSweep< LatticeModel_T, Filter_T, DensityVelocityIn_T, DensityVelocityOut // total coverage ratio in the cell real_t Bn = real_t(0); - // averaged solid collision operator for all intersecting bodies s + // averaged solid collision operator for all intersecting particles s // = \sum_s B_s * \Omega_s_i std::vector< real_t > omega_n(Stencil_T::Size, real_t(0)); @@ -398,7 +398,7 @@ void PSMSweep< LatticeModel_T, Filter_T, DensityVelocityIn_T, DensityVelocityOut // total coverage ratio in the cell real_t Bn = real_t(0); - // averaged solid collision operator for all intersecting bodies s + // averaged solid collision operator for all intersecting particles s // = \sum_s B_s * \Omega_s_i std::vector< real_t > omega_n(Stencil_T::Size, real_t(0)); diff --git a/src/lbm_mesapd_coupling/partially_saturated_cells_method/PSMUtility.h b/src/lbm_mesapd_coupling/partially_saturated_cells_method/PSMUtility.h index 854d27f99afd0b40c4eab0ed843ad951a2323cec..aaacd683ee7b50f88ae638fcabb3f547948b6561 100644 --- a/src/lbm_mesapd_coupling/partially_saturated_cells_method/PSMUtility.h +++ b/src/lbm_mesapd_coupling/partially_saturated_cells_method/PSMUtility.h @@ -51,10 +51,10 @@ namespace psm * Weighting_T is like in the PSMSweep. */ template< typename LatticeModel_T, int Weighting_T, typename ParticleAccessor_T > -Vector3< real_t > getPSMMacroscopicVelocity( - const IBlock& block, lbm::PdfField< LatticeModel_T >* pdfField, - GhostLayerField< std::vector< std::pair< walberla::size_t, real_t > >, 1 >* particleAndVolumeFractionField, - StructuredBlockStorage& blockStorage, const Cell& cell, const ParticleAccessor_T& ac) +Vector3< real_t > getPSMMacroscopicVelocity(const IBlock& block, lbm::PdfField< LatticeModel_T >* pdfField, + ParticleAndVolumeFractionField_T* particleAndVolumeFractionField, + StructuredBlockStorage& blockStorage, const Cell& cell, + const ParticleAccessor_T& ac) { static_assert(LatticeModel_T::compressible == false, "Only works with incompressible models!"); WALBERLA_ASSERT_NOT_NULLPTR(pdfField); @@ -87,16 +87,16 @@ Vector3< real_t > getPSMMacroscopicVelocity( return velocity; } -/*!\brief Initializes the PDF field inside the bodies according to the velocities of the bodies. +/*!\brief Initializes the PDF field inside the particles according to the velocities of the particles. * - * As the Partially Saturated Cells method relies on executing the LBM sweep also inside the bodies, it is good practice - * (and for some PSM variants also required) to initialize the PDF field ( i.e. the velocity ) in agreement with - * possible initial velocities of the bodies. This is also the case in the presence of external forces acting on the - * fluid, as these will often shift the macroscopic velocities during the initialization of the PDF field. + * As the Partially Saturated Cells method relies on executing the LBM sweep also inside the particles, it is good + * practice (and for some PSM variants also required) to initialize the PDF field ( i.e. the velocity ) in agreement + * with possible initial velocities of the particles. This is also the case in the presence of external forces acting on + * the fluid, as these will often shift the macroscopic velocities during the initialization of the PDF field. * * Note, that the ParticleAndVolumeFractionMapping for PSM has to be called first to have a valid field. * - * Only the velocity of cells intersecting with bodies is set, pure fluid cells remain unchanged. + * Only the velocity of cells intersecting with particles is set, pure fluid cells remain unchanged. */ template< typename LatticeModel_T, int Weighting_T, typename ParticleAccessor_T > void initializeDomainForPSM(StructuredBlockStorage& blockStorage, const BlockDataID& pdfFieldID, @@ -144,7 +144,7 @@ void initializeDomainForPSM(StructuredBlockStorage& blockStorage, const BlockDat Vector3< real_t > fluidVelocityInCell(real_t(0)); const real_t rho = pdfField->getDensityAndVelocity(fluidVelocityInCell, cell); - // set the PDFs to equilibrium with the density rho and the average velocity of all intersecting bodies + // set the PDFs to equilibrium with the density rho and the average velocity of all intersecting particles pdfField->setToEquilibrium(cell, fluidVelocityInCell * (real_c(1) - totalSolidWeightingInCell) + weightedAverageParticleVelocityInCell, diff --git a/src/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/CMakeLists.txt b/src/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..82b23cd774f80475b781e4bbc092728757277276 --- /dev/null +++ b/src/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/CMakeLists.txt @@ -0,0 +1,35 @@ +target_sources(lbm_mesapd_coupling + PRIVATE + ParticleAndVolumeFractionMappingSweepsCPU.h + PSMSweepCollection.h + PSMWrapperSweepsCPU.h +) +if (WALBERLA_BUILD_WITH_CODEGEN) + foreach (collision_setup srt trt mrt cumulant srt-smagorinsky trt-smagorinsky) + foreach (solid_collision 1 2 3) + set(config ${collision_setup}_sc${solid_collision}) + walberla_generate_target_from_python(NAME PSMCodegenPython_${config} + FILE PSMCodegen.py + CODEGEN_CFG ${config}_${MAX_PARTICLES_PER_CELL} + OUT_FILES LBMSweep.${CODEGEN_FILE_SUFFIX} LBMSweep.h LBMSplitSweep.${CODEGEN_FILE_SUFFIX} LBMSplitSweep.h + PSMSweep.${CODEGEN_FILE_SUFFIX} PSMSweep.h PSMSweepSplit.${CODEGEN_FILE_SUFFIX} PSMSweepSplit.h + PSMPackInfo.${CODEGEN_FILE_SUFFIX} PSMPackInfo.h InitializeDomainForPSM.${CODEGEN_FILE_SUFFIX} InitializeDomainForPSM.h + PSM_NoSlip.${CODEGEN_FILE_SUFFIX} PSM_NoSlip.h PSM_UBB.${CODEGEN_FILE_SUFFIX} PSM_UBB.h PSM_Density.${CODEGEN_FILE_SUFFIX} PSM_Density.h + PSM_FreeSlip.${CODEGEN_FILE_SUFFIX} PSM_FreeSlip.h PSM_InfoHeader.h PSM_MacroGetter.cpp PSM_MacroGetter.h + PSM_MacroSetter.cpp PSM_MacroSetter.h) + add_dependencies(PSMCodegenPython_${config} MAX_PARTICLES_PER_CELL) + endforeach () + endforeach () +endif () +if (WALBERLA_BUILD_WITH_GPU_SUPPORT AND (CMAKE_CUDA_ARCHITECTURES GREATER_EQUAL 60 OR WALBERLA_BUILD_WITH_HIP)) + target_sources(lbm_mesapd_coupling + PRIVATE + ParticleAndVolumeFractionMappingSweepsGPU.h + ParticleAndVolumeFractionMappingKernels.${CODEGEN_FILE_SUFFIX} + ParticleAndVolumeFractionMappingKernels.h + PSMUtilityGPU.h + PSMWrapperKernels.${CODEGEN_FILE_SUFFIX} + PSMWrapperKernels.h + PSMWrapperSweepsGPU.h + ) +endif () diff --git a/src/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/PSMCodegen.py b/src/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/PSMCodegen.py new file mode 100644 index 0000000000000000000000000000000000000000..7564b54db0b76e863990849b0474e1a4f6abfd7d --- /dev/null +++ b/src/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/PSMCodegen.py @@ -0,0 +1,272 @@ +import copy +import sympy as sp +import pystencils as ps +from sympy.core.add import Add +from sympy.codegen.ast import Assignment + +from lbmpy import LBMConfig, LBMOptimisation, LBStencil, Method, Stencil, ForceModel +from lbmpy.partially_saturated_cells import PSMConfig + +from lbmpy.boundaries import NoSlip, UBB, FixedDensity, FreeSlip +from lbmpy.creationfunctions import ( + create_lb_update_rule, + create_lb_method, + create_psm_update_rule, +) + +from lbmpy.macroscopic_value_kernels import ( + macroscopic_values_getter, + macroscopic_values_setter, +) + +from pystencils_walberla import ( + CodeGeneration, + generate_info_header, + generate_sweep, + generate_pack_info_from_kernel, +) + +from lbmpy_walberla import generate_boundary + +# Based on the following paper: https://doi.org/10.1016/j.compfluid.2017.05.033 + +info_header = """ +const char * infoStencil = "{stencil}"; +const char * infoStreamingPattern = "{streaming_pattern}"; +const char * infoCollisionSetup = "{collision_setup}"; +const bool infoCseGlobal = {cse_global}; +const bool infoCsePdfs = {cse_pdfs}; +""" + +with CodeGeneration() as ctx: + data_type = "float64" if ctx.double_accuracy else "float32" + stencil = LBStencil(Stencil.D3Q27) + omega = sp.Symbol("omega") + init_density = sp.Symbol("init_density") + init_velocity = sp.symbols("init_velocity_:3") + pdfs_inter = sp.symbols("pdfs_inter:" + str(stencil.Q)) + layout = "fzyx" + config_tokens = ctx.config.split("_") + MaxParticlesPerCell = int(config_tokens[2]) + methods = { + "srt": Method.SRT, + "trt": Method.TRT, + "mrt": Method.MRT, + "cumulant": Method.MONOMIAL_CUMULANT, + "srt-smagorinsky": Method.SRT, + "trt-smagorinsky": Method.TRT, + } + # Solid collision variant + SC = int(config_tokens[1][2]) + + pdfs, pdfs_tmp, velocity_field, density_field = ps.fields( + f"pdfs({stencil.Q}), pdfs_tmp({stencil.Q}), velocity_field({stencil.D}), density_field({1}): {data_type}[3D]", + layout=layout, + ) + + particle_velocities, particle_forces, Bs = ps.fields( + f"particle_v({MaxParticlesPerCell * stencil.D}), particle_f({MaxParticlesPerCell * stencil.D}), Bs({MaxParticlesPerCell}): {data_type}[3D]", + layout=layout, + ) + + # Solid fraction field + B = ps.fields(f"b({1}): {data_type}[3D]", layout=layout) + + psm_opt = LBMOptimisation( + cse_global=True, + symbolic_field=pdfs, + symbolic_temporary_field=pdfs_tmp, + field_layout=layout, + ) + + psm_config = PSMConfig( + fraction_field=B, + object_velocity_field=particle_velocities, + SC=SC, + MaxParticlesPerCell=MaxParticlesPerCell, + individual_fraction_field=Bs, + particle_force_field=particle_forces, + ) + + lbm_config = LBMConfig( + stencil=stencil, + method=methods[config_tokens[0]], + relaxation_rate=omega, + force=sp.symbols("F_:3"), + force_model=ForceModel.LUO, + compressible=True, + psm_config=psm_config, + ) + + if config_tokens[0] == "srt-smagorinsky" or config_tokens[0] == "trt-smagorinsky": + lbm_config.smagorinsky = True + + # ===================== + # Generate method + # ===================== + + method = create_lb_method(lbm_config=lbm_config) + + node_collection = create_psm_update_rule(lbm_config, psm_opt) + + pdfs_setter = macroscopic_values_setter( + method, init_density, init_velocity, pdfs.center_vector + ) + + # Use average velocity of all intersecting particles when setting PDFs (mandatory for SC=3) + for i, sub_exp in enumerate(pdfs_setter.subexpressions[-3:]): + rhs = [] + for summand in sub_exp.rhs.args: + rhs.append(summand * (1.0 - B.center)) + for p in range(MaxParticlesPerCell): + rhs.append(particle_velocities(p * stencil.D + i) * Bs.center(p)) + pdfs_setter.subexpressions.remove(sub_exp) + pdfs_setter.subexpressions.append(Assignment(sub_exp.lhs, Add(*rhs))) + + # ===================== + # Write method to files + # ===================== + + if ctx.gpu: + target = ps.Target.GPU + else: + target = ps.Target.CPU + + # Generate files + generate_sweep( + ctx, + "PSMSweep", + node_collection, + field_swaps=[(pdfs, pdfs_tmp)], + target=target, + ) + + generate_sweep( + ctx, + "PSMSweepSplit", + node_collection, + field_swaps=[(pdfs, pdfs_tmp)], + target=target, + inner_outer_split=True, + ) + + config_without_psm = LBMConfig( + stencil=stencil, + method=methods[config_tokens[0]], + relaxation_rate=omega, + force=sp.symbols("F_:3"), + force_model=ForceModel.LUO, + compressible=True, + ) + + if config_tokens[0] == "srt-smagorinsky" or config_tokens[0] == "trt-smagorinsky": + config_without_psm.smagorinsky = True + + generate_sweep( + ctx, + "LBMSweep", + create_lb_update_rule(lbm_config=config_without_psm, lbm_optimisation=psm_opt), + field_swaps=[(pdfs, pdfs_tmp)], + target=target, + ) + + generate_sweep( + ctx, + "LBMSplitSweep", + create_lb_update_rule(lbm_config=config_without_psm, lbm_optimisation=psm_opt), + field_swaps=[(pdfs, pdfs_tmp)], + target=target, + inner_outer_split=True, + ) + + generate_pack_info_from_kernel( + ctx, + "PSMPackInfo", + create_lb_update_rule(lbm_config=lbm_config, lbm_optimisation=psm_opt), + target=target, + ) + + generate_sweep(ctx, "InitializeDomainForPSM", pdfs_setter, target=target) + + # Boundary conditions + generate_boundary( + ctx, + "PSM_NoSlip", + NoSlip(), + method, + field_name=pdfs.name, + streaming_pattern="pull", + target=target, + ) + + bc_velocity = sp.symbols("bc_velocity_:3") + generate_boundary( + ctx, + "PSM_UBB", + UBB(bc_velocity), + method, + field_name=pdfs.name, + streaming_pattern="pull", + target=target, + ) + + bc_density = sp.Symbol("bc_density") + generate_boundary( + ctx, + "PSM_Density", + FixedDensity(bc_density), + method, + field_name=pdfs.name, + streaming_pattern="pull", + target=target, + ) + + generate_boundary( + ctx, + "PSM_FreeSlip", + FreeSlip(stencil), + method, + field_name=pdfs.name, + streaming_pattern="pull", + target=target, + ) + + # Info header containing correct template definitions for stencil and fields + infoHeaderParams = { + "stencil": stencil.name, + "streaming_pattern": lbm_config.streaming_pattern, + "collision_setup": config_tokens[0], + "cse_global": int(psm_opt.cse_global), + "cse_pdfs": int(psm_opt.cse_pdfs), + } + + stencil_typedefs = {"Stencil_T": stencil, "CommunicationStencil_T": stencil} + field_typedefs = { + "PdfField_T": pdfs, + "DensityField_T": density_field, + "VelocityField_T": velocity_field, + } + + generate_info_header( + ctx, + "PSM_InfoHeader", + stencil_typedefs=stencil_typedefs, + field_typedefs=field_typedefs, + additional_code=info_header.format(**infoHeaderParams), + ) + + # Getter & setter to compute moments from pdfs + setter_assignments = macroscopic_values_setter( + method, + velocity=velocity_field.center_vector, + pdfs=pdfs.center_vector, + density=1.0, + ) + getter_assignments = macroscopic_values_getter( + method, + density=density_field, + velocity=velocity_field.center_vector, + pdfs=pdfs.center_vector, + ) + generate_sweep(ctx, "PSM_MacroSetter", setter_assignments) + generate_sweep(ctx, "PSM_MacroGetter", getter_assignments) diff --git a/src/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/PSMSweepCollection.h b/src/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/PSMSweepCollection.h new file mode 100644 index 0000000000000000000000000000000000000000..ec0ed85e2ab09b86eee1034d9f9ca8d9c2120b67 --- /dev/null +++ b/src/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/PSMSweepCollection.h @@ -0,0 +1,124 @@ +//====================================================================================================================== +// +// This file is part of waLBerla. waLBerla 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. +// +// waLBerla 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 waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file PSMSweepCollection.h +//! \ingroup lbm_mesapd_coupling +//! \author Samuel Kemmler <samuel.kemmler@fau.de> +// +//====================================================================================================================== + +#pragma once + +#ifdef WALBERLA_BUILD_WITH_GPU_SUPPORT +# include "lbm_mesapd_coupling/partially_saturated_cells_method/codegen/PSMWrapperSweepsGPU.h" +# include "lbm_mesapd_coupling/partially_saturated_cells_method/codegen/ParticleAndVolumeFractionMappingSweepsGPU.h" +#else +# include "lbm_mesapd_coupling/partially_saturated_cells_method/codegen/PSMWrapperSweepsCPU.h" +# include "lbm_mesapd_coupling/partially_saturated_cells_method/codegen/ParticleAndVolumeFractionMappingSweepsCPU.h" +#endif + +namespace walberla +{ +namespace lbm_mesapd_coupling +{ +namespace psm +{ +namespace gpu +{ + +// The deviceSyncWrapper can be used so that the timeloop measures the correct device runtime +auto deviceSyncWrapper = [](std::function< void(IBlock*) > sweep) { + return [sweep](IBlock* b) { + sweep(b); +#ifdef WALBERLA_BUILD_WITH_GPU_SUPPORT + WALBERLA_GPU_CHECK(gpuDeviceSynchronize()); +#endif + }; +}; + +template< typename ParticleAccessor_T, typename ParticleSelector_T, int Weighting_T > +class PSMSweepCollection +{ + public: + PSMSweepCollection(const shared_ptr< StructuredBlockStorage >& bs, const shared_ptr< ParticleAccessor_T >& ac, + const ParticleSelector_T& ps, + ParticleAndVolumeFractionSoA_T< Weighting_T >& particleAndVolumeFractionSoA, + const Vector3< uint_t > particleSubBlockSize = Vector3< uint_t >(10)) + : particleMappingSweep(SphereFractionMappingSweep< ParticleAccessor_T, ParticleSelector_T, Weighting_T >( + bs, ac, ps, particleAndVolumeFractionSoA, particleSubBlockSize)), + setParticleVelocitiesSweep(SetParticleVelocitiesSweep< ParticleAccessor_T, ParticleSelector_T, Weighting_T >( + bs, ac, ps, particleAndVolumeFractionSoA)), + reduceParticleForcesSweep(ReduceParticleForcesSweep< ParticleAccessor_T, ParticleSelector_T, Weighting_T >( + bs, ac, ps, particleAndVolumeFractionSoA)) + {} + SphereFractionMappingSweep< ParticleAccessor_T, ParticleSelector_T, Weighting_T > particleMappingSweep; + SetParticleVelocitiesSweep< ParticleAccessor_T, ParticleSelector_T, Weighting_T > setParticleVelocitiesSweep; + ReduceParticleForcesSweep< ParticleAccessor_T, ParticleSelector_T, Weighting_T > reduceParticleForcesSweep; +}; + +template< typename SweepCollection, typename PSMSweep > +void addPSMSweepsToTimeloop(SweepTimeloop& timeloop, SweepCollection& psmSweepCollection, PSMSweep& psmSweep, + bool synchronize = true) +{ + if (synchronize) + { + timeloop.add() << Sweep(deviceSyncWrapper(psmSweepCollection.particleMappingSweep), "Particle mapping"); + timeloop.add() << Sweep(deviceSyncWrapper(psmSweepCollection.setParticleVelocitiesSweep), + "Set particle velocities"); + timeloop.add() << Sweep(deviceSyncWrapper(psmSweep), "PSM sweep"); + timeloop.add() << Sweep(deviceSyncWrapper(psmSweepCollection.reduceParticleForcesSweep), + "Reduce particle forces"); + } + else + { + timeloop.add() << Sweep(psmSweepCollection.particleMappingSweep, "Particle mapping"); + timeloop.add() << Sweep(psmSweepCollection.setParticleVelocitiesSweep, "Set particle velocities"); + timeloop.add() << Sweep(psmSweep, "PSM sweep"); + timeloop.add() << Sweep(psmSweepCollection.reduceParticleForcesSweep, "Reduce particle forces"); + }; +} + +template< typename SweepCollection, typename PSMSweep, typename Communication > +void addPSMSweepsToTimeloops(SweepTimeloop& commTimeloop, SweepTimeloop& timeloop, Communication& comm, + SweepCollection& psmSweepCollection, PSMSweep& psmSweep, bool synchronize = true) +{ + if (synchronize) + { + commTimeloop.add() << BeforeFunction([&]() { comm.startCommunication(); }) + << Sweep(deviceSyncWrapper(psmSweepCollection.particleMappingSweep), "Particle mapping"); + commTimeloop.add() << Sweep(deviceSyncWrapper(psmSweepCollection.setParticleVelocitiesSweep), + "Set particle velocities"); + commTimeloop.add() << Sweep(deviceSyncWrapper(psmSweep.getInnerSweep()), "PSM inner sweep") + << AfterFunction([&]() { comm.wait(); }, "LBM Communication (wait)"); + timeloop.add() << Sweep(deviceSyncWrapper(psmSweep.getOuterSweep()), "PSM outer sweep"); + timeloop.add() << Sweep(deviceSyncWrapper(psmSweepCollection.reduceParticleForcesSweep), + "Reduce particle forces"); + } + else + { + commTimeloop.add() << BeforeFunction([&]() { comm.startCommunication(); }) + << Sweep(psmSweepCollection.particleMappingSweep, "Particle mapping"); + commTimeloop.add() << Sweep(psmSweepCollection.setParticleVelocitiesSweep, "Set particle velocities"); + commTimeloop.add() << Sweep(psmSweep.getInnerSweep(), "PSM inner sweep") + << AfterFunction([&]() { comm.wait(); }, "LBM Communication (wait)"); + timeloop.add() << Sweep(psmSweep.getOuterSweep(), "PSM outer sweep"); + timeloop.add() << Sweep(psmSweepCollection.reduceParticleForcesSweep, "Reduce particle forces"); + }; +} + +} // namespace gpu +} // namespace psm +} // namespace lbm_mesapd_coupling +} // namespace walberla diff --git a/src/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/PSMUtilityGPU.h b/src/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/PSMUtilityGPU.h new file mode 100644 index 0000000000000000000000000000000000000000..6ac6d0a9a53321b18c964da6bdc5b72df501b788 --- /dev/null +++ b/src/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/PSMUtilityGPU.h @@ -0,0 +1,96 @@ +//====================================================================================================================== +// +// This file is part of waLBerla. waLBerla 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. +// +// waLBerla 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 waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file PSMUtilityGPU.cuh +//! \ingroup lbm_mesapd_coupling +//! \author Samuel Kemmler <samuel.kemmler@fau.de> +// +//====================================================================================================================== + +#pragma once + +#include "gpu/FieldAccessor.h" + +namespace walberla +{ +namespace lbm_mesapd_coupling +{ +namespace psm +{ +namespace gpu +{ + +__device__ void cross(real_t* __restrict__ const crossResult, const real_t* __restrict__ const lhs, + const real_t* __restrict__ const rhs) +{ + crossResult[0] = lhs[1] * rhs[2] - lhs[2] * rhs[1]; + crossResult[1] = lhs[2] * rhs[0] - lhs[0] * rhs[2]; + crossResult[2] = lhs[0] * rhs[1] - lhs[1] * rhs[0]; +} + +__device__ void getVelocityAtWFPoint(real_t* __restrict__ const velocityAtWFPoint, + const real_t* __restrict__ const linearVelocity, + const real_t* __restrict__ const angularVelocity, + const real_t* __restrict__ const position, const real_t* __restrict__ const wf_pt) +{ + real_t crossResult[3]; + real_t rhs[] = { wf_pt[0] - position[0], wf_pt[1] - position[1], wf_pt[2] - position[2] }; + cross(crossResult, angularVelocity, rhs); + velocityAtWFPoint[0] = linearVelocity[0] + crossResult[0]; + velocityAtWFPoint[1] = linearVelocity[1] + crossResult[1]; + velocityAtWFPoint[2] = linearVelocity[2] + crossResult[2]; +} + +__device__ void addHydrodynamicForceTorqueAtWFPosAtomic(real_t* __restrict__ const particleForce, + real_t* __restrict__ const particleTorque, + const real_t* __restrict__ const f, + const real_t* __restrict__ const pos, + const real_t* __restrict__ const wf_pt) +{ +#if defined(WALBERLA_BUILD_WITH_CUDA) + atomicAdd(&(particleForce[0]), f[0]); + atomicAdd(&(particleForce[1]), f[1]); + atomicAdd(&(particleForce[2]), f[2]); +#endif + + // Using unsafeAtomicAdd ensures that HW FP Atomics are used instead of CAS loops, see: + // https://fs.hlrs.de/projects/par/events/2023/GPU-AMD/day3/11.%20AMD_Node_Memory_Model.pdf +#ifdef WALBERLA_BUILD_WITH_HIP + unsafeAtomicAdd(&(particleForce[0]), f[0]); + unsafeAtomicAdd(&(particleForce[1]), f[1]); + unsafeAtomicAdd(&(particleForce[2]), f[2]); +#endif + + real_t torque[] = { 0.0, 0.0, 0.0 }; + real_t lhs[] = { wf_pt[0] - pos[0], wf_pt[1] - pos[1], wf_pt[2] - pos[2] }; + cross(torque, lhs, f); + +#if defined(WALBERLA_BUILD_WITH_CUDA) + atomicAdd(&(particleTorque[0]), torque[0]); + atomicAdd(&(particleTorque[1]), torque[1]); + atomicAdd(&(particleTorque[2]), torque[2]); +#endif + +#ifdef WALBERLA_BUILD_WITH_HIP + unsafeAtomicAdd(&(particleTorque[0]), torque[0]); + unsafeAtomicAdd(&(particleTorque[1]), torque[1]); + unsafeAtomicAdd(&(particleTorque[2]), torque[2]); +#endif +} + +} // namespace gpu +} // namespace psm +} // namespace lbm_mesapd_coupling +} // namespace walberla diff --git a/src/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/PSMWrapperKernels.cpp b/src/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/PSMWrapperKernels.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4bbf4439f56f5e3acae17bef0cc81742437ef5be --- /dev/null +++ b/src/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/PSMWrapperKernels.cpp @@ -0,0 +1,23 @@ +//====================================================================================================================== +// +// This file is part of waLBerla. waLBerla 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. +// +// waLBerla 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 waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file PSMWrapperKernels.cpp +//! \ingroup lbm_mesapd_coupling +//! \author Samuel Kemmler <samuel.kemmler@fau.de> +//! \brief Mirror PSMWrapperKernels.cu to provide a .cpp file for HIP +// +//====================================================================================================================== + +#include "PSMWrapperKernels.cu" diff --git a/src/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/PSMWrapperKernels.cu b/src/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/PSMWrapperKernels.cu new file mode 100644 index 0000000000000000000000000000000000000000..9aacf68d450bc8a6dbd2f8c5288f6116eaed2e0b --- /dev/null +++ b/src/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/PSMWrapperKernels.cu @@ -0,0 +1,101 @@ +//====================================================================================================================== +// +// This file is part of waLBerla. waLBerla 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. +// +// waLBerla 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 waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file PSMWrapperKernels.cu +//! \ingroup lbm_mesapd_coupling +//! \author Samuel Kemmler <samuel.kemmler@fau.de> +//! \brief Provide two kernels that need to be called before and after the PSM kernel +// +//====================================================================================================================== + +#include "PSMUtilityGPU.h" +#include "PSMWrapperKernels.h" + +namespace walberla +{ +namespace lbm_mesapd_coupling +{ +namespace psm +{ +namespace gpu +{ + +__global__ void SetParticleVelocities(walberla::gpu::FieldAccessor< uint_t > nOverlappingParticlesField, + walberla::gpu::FieldAccessor< uint_t > idxField, + walberla::gpu::FieldAccessor< real_t > particleVelocitiesField, + real_t* __restrict__ const linearVelocities, + real_t* __restrict__ const angularVelocities, + real_t* __restrict__ const positions, const double3 blockStart, const real_t dx) +{ + const uint3 blockIdx_uint3 = make_uint3(blockIdx.x, blockIdx.y, blockIdx.z); + const uint3 threadIdx_uint3 = make_uint3(threadIdx.x, threadIdx.y, threadIdx.z); + + nOverlappingParticlesField.set(blockIdx_uint3, threadIdx_uint3); + idxField.set(blockIdx_uint3, threadIdx_uint3); + particleVelocitiesField.set(blockIdx_uint3, threadIdx_uint3); + + // Cell center is needed in order to compute the particle velocity at this WF point + const real_t cellCenter[] = { (blockStart.x + (threadIdx.x + 0.5) * dx), (blockStart.y + (blockIdx.x + 0.5) * dx), + (blockStart.z + (blockIdx.y + 0.5) * dx) }; + + // Compute the particle velocity at the cell center for all overlapping particles + for (uint_t p = 0; p < nOverlappingParticlesField.get(); p++) + { + real_t particleVelocityAtWFPoint[] = { 0.0, 0.0, 0.0 }; + getVelocityAtWFPoint(particleVelocityAtWFPoint, &linearVelocities[idxField.get(p) * 3], + &angularVelocities[idxField.get(p) * 3], &positions[idxField.get(p) * 3], cellCenter); + particleVelocitiesField.get(p * 3 + 0) = particleVelocityAtWFPoint[0]; + particleVelocitiesField.get(p * 3 + 1) = particleVelocityAtWFPoint[1]; + particleVelocitiesField.get(p * 3 + 2) = particleVelocityAtWFPoint[2]; + } +} + +__global__ void ReduceParticleForces(walberla::gpu::FieldAccessor< uint_t > nOverlappingParticlesField, + walberla::gpu::FieldAccessor< id_t > idxField, + walberla::gpu::FieldAccessor< real_t > particleForcesField, + real_t* __restrict__ const hydrodynamicForces, + real_t* __restrict__ const hydrodynamicTorques, + real_t* __restrict__ const positions, const double3 blockStart, const real_t dx, + const real_t forceScalingFactor) +{ + const uint3 blockIdx_uint3 = make_uint3(blockIdx.x, blockIdx.y, blockIdx.z); + const uint3 threadIdx_uint3 = make_uint3(threadIdx.x, threadIdx.y, threadIdx.z); + + nOverlappingParticlesField.set(blockIdx_uint3, threadIdx_uint3); + idxField.set(blockIdx_uint3, threadIdx_uint3); + particleForcesField.set(blockIdx_uint3, threadIdx_uint3); + + // Cell center is needed in order to compute the particle velocity at this WF point + const real_t cellCenter[] = { (blockStart.x + (threadIdx.x + 0.5) * dx), (blockStart.y + (blockIdx.x + 0.5) * dx), + (blockStart.z + (blockIdx.y + 0.5) * dx) }; + + // Reduce the forces for all overlapping particles + for (uint_t p = 0; p < nOverlappingParticlesField.get(); p++) + { + real_t forceOnParticle[] = { particleForcesField.get(p * 3 + 0), particleForcesField.get(p * 3 + 1), + particleForcesField.get(p * 3 + 2) }; + forceOnParticle[0] *= forceScalingFactor; + forceOnParticle[1] *= forceScalingFactor; + forceOnParticle[2] *= forceScalingFactor; + addHydrodynamicForceTorqueAtWFPosAtomic(&hydrodynamicForces[idxField.get(p) * 3], + &hydrodynamicTorques[idxField.get(p) * 3], forceOnParticle, + &positions[idxField.get(p) * 3], cellCenter); + } +} + +} // namespace gpu +} // namespace psm +} // namespace lbm_mesapd_coupling +} // namespace walberla diff --git a/src/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/PSMWrapperKernels.h b/src/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/PSMWrapperKernels.h new file mode 100644 index 0000000000000000000000000000000000000000..d3afc21c7c6d387883e25185ed7a67f7cb03f511 --- /dev/null +++ b/src/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/PSMWrapperKernels.h @@ -0,0 +1,54 @@ +//====================================================================================================================== +// +// This file is part of waLBerla. waLBerla 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. +// +// waLBerla 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 waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file PSMWrapperKernels.h +//! \ingroup lbm_mesapd_coupling +//! \author Samuel Kemmler <samuel.kemmler@fau.de> +// +//====================================================================================================================== + +#pragma once + +#include "gpu/FieldAccessor.h" + +namespace walberla +{ +namespace lbm_mesapd_coupling +{ +namespace psm +{ +namespace gpu +{ + +__global__ void SetParticleVelocities(walberla::gpu::FieldAccessor< uint_t > nOverlappingParticlesField, + walberla::gpu::FieldAccessor< uint_t > idxField, + walberla::gpu::FieldAccessor< real_t > particleVelocitiesField, + real_t* __restrict__ const linearVelocities, + real_t* __restrict__ const angularVelocities, + real_t* __restrict__ const positions, const double3 blockStart, + const real_t dx); + +__global__ void ReduceParticleForces(walberla::gpu::FieldAccessor< uint_t > nOverlappingParticlesField, + walberla::gpu::FieldAccessor< id_t > idxField, + walberla::gpu::FieldAccessor< real_t > particleForcesField, + real_t* __restrict__ const hydrodynamicForces, + real_t* __restrict__ const hydrodynamicTorques, + real_t* __restrict__ const positions, const double3 blockStart, const real_t dx, + const real_t forceScalingFactor); + +} // namespace gpu +} // namespace psm +} // namespace lbm_mesapd_coupling +} // namespace walberla diff --git a/src/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/PSMWrapperSweepsCPU.h b/src/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/PSMWrapperSweepsCPU.h new file mode 100644 index 0000000000000000000000000000000000000000..d4ab73dd4533dd24d0aec203fa772fe734ce08e7 --- /dev/null +++ b/src/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/PSMWrapperSweepsCPU.h @@ -0,0 +1,250 @@ +//====================================================================================================================== +// +// This file is part of waLBerla. waLBerla 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. +// +// waLBerla 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 waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file PSMWrapperSweepsCPU.h +//! \ingroup lbm_mesapd_coupling +//! \author Samuel Kemmler <samuel.kemmler@fau.de> +// +//====================================================================================================================== + +#pragma once + +#include "domain_decomposition/StructuredBlockStorage.h" + +#include "field/GhostLayerField.h" + +#include "lbm/sweeps/StreamPull.h" +#include "lbm/sweeps/SweepBase.h" + +#include "lbm_mesapd_coupling/DataTypesCodegen.h" +#include "lbm_mesapd_coupling/utility/ParticleFunctions.h" + +#include "mesa_pd/common/ParticleFunctions.h" + +#include "timeloop/SweepTimeloop.h" + +#include <cassert> + +namespace walberla +{ +namespace lbm_mesapd_coupling +{ +namespace psm +{ +namespace gpu +{ + +template< typename ParticleAccessor_T, typename ParticleSelector_T, int Weighting_T > +class SetParticleVelocitiesSweep +{ + public: + SetParticleVelocitiesSweep(const shared_ptr< StructuredBlockStorage >& bs, + const shared_ptr< ParticleAccessor_T >& ac, + const ParticleSelector_T& mappingParticleSelector, + ParticleAndVolumeFractionSoA_T< Weighting_T >& particleAndVolumeFractionSoA) + : bs_(bs), ac_(ac), mappingParticleSelector_(mappingParticleSelector), + particleAndVolumeFractionSoA_(particleAndVolumeFractionSoA) + {} + void operator()(IBlock* block) + { + // Check that uids of the particles have not changed since the last mapping to avoid incorrect indices + std::vector< walberla::id_t > currentUIDs; + for (size_t idx = 0; idx < ac_->size(); ++idx) + { + if (mappingParticleSelector_(idx, *ac_)) { currentUIDs.push_back(ac_->getUid(idx)); } + } + WALBERLA_ASSERT(particleAndVolumeFractionSoA_.mappingUIDs == currentUIDs); + + size_t numMappedParticles = 0; + for (size_t idx = 0; idx < ac_->size(); ++idx) + { + if (mappingParticleSelector_(idx, *ac_)) { numMappedParticles++; } + } + + if (numMappedParticles == uint_t(0)) return; + + size_t arraySizes = numMappedParticles * sizeof(real_t) * 3; + + // Allocate unified memory for the particle information required for computing the velocity at a WF point (used in + // the solid collision operator) + real_t* linearVelocities = (real_t*) malloc(arraySizes); + memset(linearVelocities, 0, arraySizes); + real_t* angularVelocities = (real_t*) malloc(arraySizes); + memset(angularVelocities, 0, arraySizes); + + // Store particle information inside memory + size_t idxMapped = 0; + for (size_t idx = 0; idx < ac_->size(); ++idx) + { + if (mappingParticleSelector_(idx, *ac_)) + { + for (size_t d = 0; d < 3; ++d) + { + linearVelocities[idxMapped * 3 + d] = ac_->getLinearVelocity(idx)[d]; + angularVelocities[idxMapped * 3 + d] = ac_->getAngularVelocity(idx)[d]; + } + idxMapped++; + } + } + + auto nOverlappingParticlesField = + block->getData< nOverlappingParticlesField_T >(particleAndVolumeFractionSoA_.nOverlappingParticlesFieldID); + auto idxField = block->getData< idxField_T >(particleAndVolumeFractionSoA_.idxFieldID); + auto particleVelocitiesField = + block->getData< particleVelocitiesField_T >(particleAndVolumeFractionSoA_.particleVelocitiesFieldID); + + // For every cell, compute the particle velocities of the overlapping particles evaluated at the cell center + const real_t dx = block->getAABB().xSize() / real_t(nOverlappingParticlesField->xSize()); + WALBERLA_FOR_ALL_CELLS_XYZ( + particleVelocitiesField, const Vector3< real_t > cellCenter = + Vector3< real_t >(real_t(x) + real_t(0.5) * dx, real_t(y) + real_t(0.5) * dx, + real_t(z) + real_t(0.5) * dx) + + block->getAABB().minCorner(); + for (uint_t p = 0; p < nOverlappingParticlesField->get(x, y, z); p++) { + Vector3< real_t > particleVelocityAtWFPoint = + Vector3< real_t >(linearVelocities[idxField->get(x, y, z, p) * 3 + 0], + linearVelocities[idxField->get(x, y, z, p) * 3 + 1], + linearVelocities[idxField->get(x, y, z, p) * 3 + 2]) + + cross(Vector3< real_t >(angularVelocities[idxField->get(x, y, z, p) * 3 + 0], + angularVelocities[idxField->get(x, y, z, p) * 3 + 1], + angularVelocities[idxField->get(x, y, z, p) * 3 + 2]), + Vector3< real_t >( + cellCenter[0] - particleAndVolumeFractionSoA_.positions[idxField->get(x, y, z, p) * 3 + 0], + cellCenter[1] - particleAndVolumeFractionSoA_.positions[idxField->get(x, y, z, p) * 3 + 1], + cellCenter[2] - particleAndVolumeFractionSoA_.positions[idxField->get(x, y, z, p) * 3 + 2])); + particleVelocitiesField->get(x, y, z, p * 3 + 0) = particleVelocityAtWFPoint[0]; + particleVelocitiesField->get(x, y, z, p * 3 + 1) = particleVelocityAtWFPoint[1]; + particleVelocitiesField->get(x, y, z, p * 3 + 2) = particleVelocityAtWFPoint[2]; + }) + + free(linearVelocities); + free(angularVelocities); + } + + private: + shared_ptr< StructuredBlockStorage > bs_; + const shared_ptr< ParticleAccessor_T > ac_; + const ParticleSelector_T& mappingParticleSelector_; + ParticleAndVolumeFractionSoA_T< Weighting_T >& particleAndVolumeFractionSoA_; +}; + +template< typename ParticleAccessor_T, typename ParticleSelector_T, int Weighting_T > +class ReduceParticleForcesSweep +{ + public: + ReduceParticleForcesSweep(const shared_ptr< StructuredBlockStorage >& bs, const shared_ptr< ParticleAccessor_T >& ac, + const ParticleSelector_T& mappingParticleSelector, + const ParticleAndVolumeFractionSoA_T< Weighting_T >& particleAndVolumeFractionSoA) + : bs_(bs), ac_(ac), mappingParticleSelector_(mappingParticleSelector), + particleAndVolumeFractionSoA_(particleAndVolumeFractionSoA) + {} + void operator()(IBlock* block) + { + // Check that uids of the particles have not changed since the last mapping to avoid incorrect indices + std::vector< walberla::id_t > currentUIDs; + for (size_t idx = 0; idx < ac_->size(); ++idx) + { + if (mappingParticleSelector_(idx, *ac_)) { currentUIDs.push_back(ac_->getUid(idx)); } + } + WALBERLA_ASSERT(particleAndVolumeFractionSoA_.mappingUIDs == currentUIDs); + + const real_t dxCurrentLevel = bs_->dx(bs_->getLevel(*block)); + const real_t lengthScalingFactor = dxCurrentLevel; + const real_t forceScalingFactor = lengthScalingFactor * lengthScalingFactor; + + size_t numMappedParticles = 0; + for (size_t idx = 0; idx < ac_->size(); ++idx) + { + if (mappingParticleSelector_(idx, *ac_)) { numMappedParticles++; } + } + + if (numMappedParticles == uint_t(0)) return; + + size_t arraySizes = numMappedParticles * sizeof(real_t) * 3; + + // Allocate memory for the reduction of the particle forces and torques + real_t* hydrodynamicForces = (real_t*) malloc(arraySizes); + memset(hydrodynamicForces, 0, arraySizes); + real_t* hydrodynamicTorques = (real_t*) malloc(arraySizes); + memset(hydrodynamicTorques, 0, arraySizes); + + auto nOverlappingParticlesField = + block->getData< nOverlappingParticlesField_T >(particleAndVolumeFractionSoA_.nOverlappingParticlesFieldID); + auto idxField = block->getData< idxField_T >(particleAndVolumeFractionSoA_.idxFieldID); + auto particleForcesField = + block->getData< particleForcesField_T >(particleAndVolumeFractionSoA_.particleForcesFieldID); + + // For every cell, reduce the hydrodynamic forces and torques of the overlapping particles + const real_t dx = block->getAABB().xSize() / real_t(nOverlappingParticlesField->xSize()); + WALBERLA_FOR_ALL_CELLS_XYZ( + particleForcesField, const Vector3< real_t > cellCenter = + Vector3< real_t >(real_t(x) + real_t(0.5) * dx, real_t(y) + real_t(0.5) * dx, + real_t(z) + real_t(0.5) * dx) + + block->getAABB().minCorner(); + for (uint_t p = 0; p < nOverlappingParticlesField->get(x, y, z); p++) { + Vector3< real_t > forceOnParticle(particleForcesField->get(x, y, z, p * 3 + 0), + particleForcesField->get(x, y, z, p * 3 + 1), + particleForcesField->get(x, y, z, p * 3 + 2)); + forceOnParticle[0] *= forceScalingFactor; + forceOnParticle[1] *= forceScalingFactor; + forceOnParticle[2] *= forceScalingFactor; + + hydrodynamicForces[idxField->get(x, y, z, p) * 3 + 0] += forceOnParticle[0]; + hydrodynamicForces[idxField->get(x, y, z, p) * 3 + 1] += forceOnParticle[1]; + hydrodynamicForces[idxField->get(x, y, z, p) * 3 + 2] += forceOnParticle[2]; + Vector3< real_t > torqueOnParticle = + cross(Vector3< real_t >( + cellCenter[0] - particleAndVolumeFractionSoA_.positions[idxField->get(x, y, z, p) * 3 + 0], + cellCenter[1] - particleAndVolumeFractionSoA_.positions[idxField->get(x, y, z, p) * 3 + 1], + cellCenter[2] - particleAndVolumeFractionSoA_.positions[idxField->get(x, y, z, p) * 3 + 2]), + forceOnParticle); + + hydrodynamicTorques[idxField->get(x, y, z, p) * 3 + 0] += torqueOnParticle[0]; + hydrodynamicTorques[idxField->get(x, y, z, p) * 3 + 1] += torqueOnParticle[1]; + hydrodynamicTorques[idxField->get(x, y, z, p) * 3 + 2] += torqueOnParticle[2]; + } + + ) + + // Copy forces and torques of particles + size_t idxMapped = 0; + for (size_t idx = 0; idx < ac_->size(); ++idx) + { + if (mappingParticleSelector_(idx, *ac_)) + { + for (size_t d = 0; d < 3; ++d) + { + ac_->getHydrodynamicForceRef(idx)[d] += hydrodynamicForces[idxMapped * 3 + d]; + ac_->getHydrodynamicTorqueRef(idx)[d] += hydrodynamicTorques[idxMapped * 3 + d]; + } + idxMapped++; + } + } + + free(hydrodynamicForces); + free(hydrodynamicTorques); + } + + private: + shared_ptr< StructuredBlockStorage > bs_; + const shared_ptr< ParticleAccessor_T > ac_; + const ParticleSelector_T& mappingParticleSelector_; + const ParticleAndVolumeFractionSoA_T< Weighting_T >& particleAndVolumeFractionSoA_; +}; + +} // namespace gpu +} // namespace psm +} // namespace lbm_mesapd_coupling +} // namespace walberla diff --git a/src/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/PSMWrapperSweepsGPU.h b/src/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/PSMWrapperSweepsGPU.h new file mode 100644 index 0000000000000000000000000000000000000000..863d13fbfa2108668608c83bed2eb2f9ab463f84 --- /dev/null +++ b/src/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/PSMWrapperSweepsGPU.h @@ -0,0 +1,253 @@ +//====================================================================================================================== +// +// This file is part of waLBerla. waLBerla 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. +// +// waLBerla 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 waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file PSMWrapperSweepsGPU.h +//! \ingroup lbm_mesapd_coupling +//! \author Samuel Kemmler <samuel.kemmler@fau.de> +// +//====================================================================================================================== + +#pragma once + +#include "domain_decomposition/StructuredBlockStorage.h" + +#include "field/GhostLayerField.h" + +#include "gpu/FieldIndexing.h" +#include "gpu/GPUField.h" +#include "gpu/Kernel.h" +#include "gpu/sweeps/GPUSweepBase.h" + +#include "lbm/sweeps/StreamPull.h" +#include "lbm/sweeps/SweepBase.h" + +#include "lbm_mesapd_coupling/DataTypesCodegen.h" +#include "lbm_mesapd_coupling/utility/ParticleFunctions.h" + +#include "mesa_pd/common/ParticleFunctions.h" + +#include "timeloop/SweepTimeloop.h" + +#include <cassert> + +#include "PSMWrapperKernels.h" + +namespace walberla +{ +namespace lbm_mesapd_coupling +{ +namespace psm +{ +namespace gpu +{ + +template< typename ParticleAccessor_T, typename ParticleSelector_T, int Weighting_T > +class SetParticleVelocitiesSweep +{ + public: + SetParticleVelocitiesSweep(const shared_ptr< StructuredBlockStorage >& bs, + const shared_ptr< ParticleAccessor_T >& ac, + const ParticleSelector_T& mappingParticleSelector, + ParticleAndVolumeFractionSoA_T< Weighting_T >& particleAndVolumeFractionSoA) + : bs_(bs), ac_(ac), mappingParticleSelector_(mappingParticleSelector), + particleAndVolumeFractionSoA_(particleAndVolumeFractionSoA) + {} + void operator()(IBlock* block) + { + // Check that uids of the particles have not changed since the last mapping to avoid incorrect indices + std::vector< walberla::id_t > currentUIDs; + for (size_t idx = 0; idx < ac_->size(); ++idx) + { + if (mappingParticleSelector_(idx, *ac_)) { currentUIDs.push_back(ac_->getUid(idx)); } + } + WALBERLA_ASSERT(particleAndVolumeFractionSoA_.mappingUIDs == currentUIDs); + + size_t numMappedParticles = 0; + for (size_t idx = 0; idx < ac_->size(); ++idx) + { + if (mappingParticleSelector_(idx, *ac_)) { numMappedParticles++; } + } + + if (numMappedParticles == uint_t(0)) return; + + size_t arraySizes = numMappedParticles * sizeof(real_t) * 3; + + // Allocate memory for the particle information required for computing the velocity at a WF point (used in + // the solid collision operator) + real_t* linearVelocities_h = (real_t*) malloc(arraySizes); + real_t* angularVelocities_h = (real_t*) malloc(arraySizes); + + // Store particle information inside memory to communicate information to the GPU + size_t idxMapped = 0; + for (size_t idx = 0; idx < ac_->size(); ++idx) + { + if (mappingParticleSelector_(idx, *ac_)) + { + for (size_t d = 0; d < 3; ++d) + { + linearVelocities_h[idxMapped * 3 + d] = ac_->getLinearVelocity(idx)[d]; + angularVelocities_h[idxMapped * 3 + d] = ac_->getAngularVelocity(idx)[d]; + } + idxMapped++; + } + } + + real_t* linearVelocities; + WALBERLA_GPU_CHECK(gpuMalloc(&linearVelocities, arraySizes)); + WALBERLA_GPU_CHECK(gpuMemcpy(linearVelocities, linearVelocities_h, arraySizes, gpuMemcpyHostToDevice)); + real_t* angularVelocities; + WALBERLA_GPU_CHECK(gpuMalloc(&angularVelocities, arraySizes)); + WALBERLA_GPU_CHECK(gpuMemcpy(angularVelocities, angularVelocities_h, arraySizes, gpuMemcpyHostToDevice)); + + auto nOverlappingParticlesField = + block->getData< nOverlappingParticlesFieldGPU_T >(particleAndVolumeFractionSoA_.nOverlappingParticlesFieldID); + auto idxField = block->getData< idxFieldGPU_T >(particleAndVolumeFractionSoA_.idxFieldID); + auto particleVelocitiesField = + block->getData< particleVelocitiesFieldGPU_T >(particleAndVolumeFractionSoA_.particleVelocitiesFieldID); + + // For every cell, compute the particle velocities of the overlapping particles evaluated at the cell center + auto velocitiesKernel = walberla::gpu::make_kernel(&(SetParticleVelocities)); + velocitiesKernel.addFieldIndexingParam(walberla::gpu::FieldIndexing< uint_t >::xyz(*nOverlappingParticlesField)); + velocitiesKernel.addFieldIndexingParam(walberla::gpu::FieldIndexing< id_t >::xyz(*idxField)); + velocitiesKernel.addFieldIndexingParam(walberla::gpu::FieldIndexing< real_t >::xyz(*particleVelocitiesField)); + velocitiesKernel.addParam(linearVelocities); + velocitiesKernel.addParam(angularVelocities); + velocitiesKernel.addParam(particleAndVolumeFractionSoA_.positions); + const double3 blockStart = { block->getAABB().minCorner()[0], block->getAABB().minCorner()[1], + block->getAABB().minCorner()[2] }; + velocitiesKernel.addParam(blockStart); + velocitiesKernel.addParam(block->getAABB().xSize() / real_t(nOverlappingParticlesField->xSize())); + velocitiesKernel(); + + WALBERLA_GPU_CHECK(gpuFree(linearVelocities)); + free(linearVelocities_h); + + WALBERLA_GPU_CHECK(gpuFree(angularVelocities)); + free(angularVelocities_h); + } + + private: + shared_ptr< StructuredBlockStorage > bs_; + const shared_ptr< ParticleAccessor_T > ac_; + const ParticleSelector_T& mappingParticleSelector_; + ParticleAndVolumeFractionSoA_T< Weighting_T >& particleAndVolumeFractionSoA_; +}; + +template< typename ParticleAccessor_T, typename ParticleSelector_T, int Weighting_T > +class ReduceParticleForcesSweep +{ + public: + ReduceParticleForcesSweep(const shared_ptr< StructuredBlockStorage >& bs, const shared_ptr< ParticleAccessor_T >& ac, + const ParticleSelector_T& mappingParticleSelector, + const ParticleAndVolumeFractionSoA_T< Weighting_T >& particleAndVolumeFractionSoA) + : bs_(bs), ac_(ac), mappingParticleSelector_(mappingParticleSelector), + particleAndVolumeFractionSoA_(particleAndVolumeFractionSoA) + {} + void operator()(IBlock* block) + { + // Check that uids of the particles have not changed since the last mapping to avoid incorrect indices + std::vector< walberla::id_t > currentUIDs; + for (size_t idx = 0; idx < ac_->size(); ++idx) + { + if (mappingParticleSelector_(idx, *ac_)) { currentUIDs.push_back(ac_->getUid(idx)); } + } + WALBERLA_ASSERT(particleAndVolumeFractionSoA_.mappingUIDs == currentUIDs); + + const real_t dxCurrentLevel = bs_->dx(bs_->getLevel(*block)); + const real_t lengthScalingFactor = dxCurrentLevel; + const real_t forceScalingFactor = lengthScalingFactor * lengthScalingFactor; + + size_t numMappedParticles = 0; + for (size_t idx = 0; idx < ac_->size(); ++idx) + { + if (mappingParticleSelector_(idx, *ac_)) { numMappedParticles++; } + } + + if (numMappedParticles == uint_t(0)) return; + + size_t arraySizes = numMappedParticles * sizeof(real_t) * 3; + + // Allocate memory for the reduction of the particle forces and torques on the GPU + real_t* hydrodynamicForces; + WALBERLA_GPU_CHECK(gpuMalloc(&hydrodynamicForces, arraySizes)); + WALBERLA_GPU_CHECK(gpuMemset(hydrodynamicForces, 0, arraySizes)); + + real_t* hydrodynamicTorques; + WALBERLA_GPU_CHECK(gpuMalloc(&hydrodynamicTorques, arraySizes)); + WALBERLA_GPU_CHECK(gpuMemset(hydrodynamicTorques, 0, arraySizes)); + + auto nOverlappingParticlesField = + block->getData< nOverlappingParticlesFieldGPU_T >(particleAndVolumeFractionSoA_.nOverlappingParticlesFieldID); + auto idxField = block->getData< idxFieldGPU_T >(particleAndVolumeFractionSoA_.idxFieldID); + auto particleForcesField = + block->getData< particleForcesFieldGPU_T >(particleAndVolumeFractionSoA_.particleForcesFieldID); + + const double3 blockStart = { block->getAABB().minCorner()[0], block->getAABB().minCorner()[1], + block->getAABB().minCorner()[2] }; + + // For every cell, reduce the hydrodynamic forces and torques of the overlapping particles + auto forcesKernel = walberla::gpu::make_kernel(&(ReduceParticleForces)); + forcesKernel.addFieldIndexingParam(walberla::gpu::FieldIndexing< uint_t >::xyz(*nOverlappingParticlesField)); + forcesKernel.addFieldIndexingParam(walberla::gpu::FieldIndexing< id_t >::xyz(*idxField)); + forcesKernel.addFieldIndexingParam(walberla::gpu::FieldIndexing< real_t >::xyz(*particleForcesField)); + forcesKernel.addParam(hydrodynamicForces); + forcesKernel.addParam(hydrodynamicTorques); + forcesKernel.addParam(particleAndVolumeFractionSoA_.positions); + forcesKernel.addParam(blockStart); + forcesKernel.addParam(block->getAABB().xSize() / real_t(nOverlappingParticlesField->xSize())); + forcesKernel.addParam(forceScalingFactor); + forcesKernel(); + + WALBERLA_GPU_CHECK(gpuDeviceSynchronize()); + + real_t* hydrodynamicForces_h = (real_t*) malloc(arraySizes); + WALBERLA_GPU_CHECK(gpuMemcpy(hydrodynamicForces_h, hydrodynamicForces, arraySizes, gpuMemcpyDeviceToHost)); + + real_t* hydrodynamicTorques_h = (real_t*) malloc(arraySizes); + WALBERLA_GPU_CHECK(gpuMemcpy(hydrodynamicTorques_h, hydrodynamicTorques, arraySizes, gpuMemcpyDeviceToHost)); + + // Copy forces and torques of particles from GPU to CPU + size_t idxMapped = 0; + for (size_t idx = 0; idx < ac_->size(); ++idx) + { + if (mappingParticleSelector_(idx, *ac_)) + { + for (size_t d = 0; d < 3; ++d) + { + ac_->getHydrodynamicForceRef(idx)[d] += hydrodynamicForces_h[idxMapped * 3 + d]; + ac_->getHydrodynamicTorqueRef(idx)[d] += hydrodynamicTorques_h[idxMapped * 3 + d]; + } + idxMapped++; + } + } + + WALBERLA_GPU_CHECK(gpuFree(hydrodynamicForces)); + free(hydrodynamicForces_h); + + WALBERLA_GPU_CHECK(gpuFree(hydrodynamicTorques)); + free(hydrodynamicTorques_h); + } + + private: + shared_ptr< StructuredBlockStorage > bs_; + const shared_ptr< ParticleAccessor_T > ac_; + const ParticleSelector_T& mappingParticleSelector_; + const ParticleAndVolumeFractionSoA_T< Weighting_T >& particleAndVolumeFractionSoA_; +}; + +} // namespace gpu +} // namespace psm +} // namespace lbm_mesapd_coupling +} // namespace walberla diff --git a/src/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/ParticleAndVolumeFractionMappingKernels.cpp b/src/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/ParticleAndVolumeFractionMappingKernels.cpp new file mode 100644 index 0000000000000000000000000000000000000000..43d8c9786c6153aad985528fc249a69897dd4451 --- /dev/null +++ b/src/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/ParticleAndVolumeFractionMappingKernels.cpp @@ -0,0 +1,23 @@ +//====================================================================================================================== +// +// This file is part of waLBerla. waLBerla 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. +// +// waLBerla 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 waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file ParticleAndVolumeFractionMappingKernels.cpp +//! \ingroup lbm_mesapd_coupling +//! \author Samuel Kemmler <samuel.kemmler@fau.de> +//! \brief Mirror ParticleAndVolumeFractionMappingKernels.cu to provide a .cpp file for HIP +// +//====================================================================================================================== + +#include "ParticleAndVolumeFractionMappingKernels.cu" diff --git a/src/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/ParticleAndVolumeFractionMappingKernels.cu b/src/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/ParticleAndVolumeFractionMappingKernels.cu new file mode 100644 index 0000000000000000000000000000000000000000..fe22d4eb1dd4e1d75eeb7c8c5a7bd137a15a6b64 --- /dev/null +++ b/src/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/ParticleAndVolumeFractionMappingKernels.cu @@ -0,0 +1,313 @@ +//====================================================================================================================== +// +// This file is part of waLBerla. waLBerla 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. +// +// waLBerla 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 waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file ParticleAndVolumeFractionMappingKernels.cu +//! \ingroup lbm_mesapd_coupling +//! \author Samuel Kemmler <samuel.kemmler@fau.de> +// +//====================================================================================================================== + +#include "lbm_mesapd_coupling/DataTypesCodegen.h" + +#include <assert.h> + +#include "ParticleAndVolumeFractionMappingKernels.h" + +namespace walberla +{ +namespace lbm_mesapd_coupling +{ +namespace psm +{ +namespace gpu +{ + +// Functions to calculate Bs +template< int Weighting_T > +__device__ void calculateWeighting(real_t* __restrict__ const weighting, const real_t& /*epsilon*/, + const real_t& /*tau*/) +{ + WALBERLA_STATIC_ASSERT(Weighting_T == 1 || Weighting_T == 2); +} +template<> +__device__ void calculateWeighting< 1 >(real_t* __restrict__ const weighting, const real_t& epsilon, + const real_t& /*tau*/) +{ + *weighting = epsilon; +} +template<> +__device__ void calculateWeighting< 2 >(real_t* __restrict__ const weighting, const real_t& epsilon, const real_t& tau) +{ + *weighting = epsilon * (tau - real_t(0.5)) / ((real_t(1) - epsilon) + (tau - real_t(0.5))); +} + +template< int Weighting_T > +__global__ void superSampling(walberla::gpu::FieldAccessor< uint_t > nOverlappingParticlesField, + walberla::gpu::FieldAccessor< real_t > BsField, + walberla::gpu::FieldAccessor< id_t > idxField, + walberla::gpu::FieldAccessor< real_t > BField, const real_t omega, + const real_t* __restrict__ const spherePositions, + const real_t* __restrict__ const sphereRadii, const double3 blockStart, const real_t dx, + const int3 nSamples, const size_t* __restrict__ const numParticlesSubBlocks, + const size_t* __restrict__ const particleIDsSubBlocks, const uint3 subBlocksPerDim) +{ + const uint3 blockIdx_uint3 = make_uint3(blockIdx.x, blockIdx.y, blockIdx.z); + const uint3 threadIdx_uint3 = make_uint3(threadIdx.x, threadIdx.y, threadIdx.z); + + nOverlappingParticlesField.set(blockIdx_uint3, threadIdx_uint3); + BsField.set(blockIdx_uint3, threadIdx_uint3); + idxField.set(blockIdx_uint3, threadIdx_uint3); + BField.set(blockIdx_uint3, threadIdx_uint3); + + // Clear the fields + for (uint i = 0; i < MaxParticlesPerCell; i++) + { + BsField.get(i) = real_t(0.0); + idxField.get(i) = size_t(0); + } + nOverlappingParticlesField.get() = uint_t(0); + BField.get() = real_t(0.0); + + double3 sampleDistance = { 1.0 / (nSamples.x + 1) * dx, 1.0 / (nSamples.y + 1) * dx, 1.0 / (nSamples.z + 1) * dx }; + double3 startSamplingPoint = { (blockStart.x + threadIdx.x * dx + sampleDistance.x), + (blockStart.y + blockIdx.x * dx + sampleDistance.y), + (blockStart.z + blockIdx.y * dx + sampleDistance.z) }; + const ulong3 subBlockIndex = { size_t(real_t(threadIdx.x) / blockDim.x * real_t(subBlocksPerDim.x)), + size_t(real_t(blockIdx.x) / gridDim.x * real_t(subBlocksPerDim.y)), + size_t(real_t(blockIdx.y) / gridDim.y * real_t(subBlocksPerDim.z)) }; + size_t linearizedSubBlockIndex = + subBlockIndex.z * subBlocksPerDim.x * subBlocksPerDim.y + subBlockIndex.y * subBlocksPerDim.x + subBlockIndex.x; + + for (uint i = 0; i < numParticlesSubBlocks[linearizedSubBlockIndex]; i++) + { + // SoA + size_t idxMapped = + particleIDsSubBlocks[linearizedSubBlockIndex + i * subBlocksPerDim.x * subBlocksPerDim.y * subBlocksPerDim.z]; + double3 currentSamplingPoint = startSamplingPoint; + + double3 minCornerSphere = { spherePositions[idxMapped * 3] - sphereRadii[idxMapped], + spherePositions[idxMapped * 3 + 1] - sphereRadii[idxMapped], + spherePositions[idxMapped * 3 + 2] - sphereRadii[idxMapped] }; + double3 maxCornerSphere = { spherePositions[idxMapped * 3] + sphereRadii[idxMapped], + spherePositions[idxMapped * 3 + 1] + sphereRadii[idxMapped], + spherePositions[idxMapped * 3 + 2] + sphereRadii[idxMapped] }; + + double overlapFraction = 0.0; + + if (startSamplingPoint.x + dx > minCornerSphere.x && startSamplingPoint.x < maxCornerSphere.x && + startSamplingPoint.y + dx > minCornerSphere.y && startSamplingPoint.y < maxCornerSphere.y && + startSamplingPoint.z + dx > minCornerSphere.z && startSamplingPoint.z < maxCornerSphere.z) + { + for (uint_t z = 0; z < nSamples.z; z++) + { + currentSamplingPoint.y = startSamplingPoint.y; + for (uint_t y = 0; y < nSamples.y; y++) + { + currentSamplingPoint.x = startSamplingPoint.x; + for (uint_t x = 0; x < nSamples.x; x++) + { + if ((currentSamplingPoint.x - spherePositions[idxMapped * 3]) * + (currentSamplingPoint.x - spherePositions[idxMapped * 3]) + + (currentSamplingPoint.y - spherePositions[idxMapped * 3 + 1]) * + (currentSamplingPoint.y - spherePositions[idxMapped * 3 + 1]) + + (currentSamplingPoint.z - spherePositions[idxMapped * 3 + 2]) * + (currentSamplingPoint.z - spherePositions[idxMapped * 3 + 2]) <= + sphereRadii[idxMapped] * sphereRadii[idxMapped]) + { + overlapFraction += 1.0; + } + currentSamplingPoint.x += sampleDistance.x; + } + currentSamplingPoint.y += sampleDistance.y; + } + currentSamplingPoint.z += sampleDistance.z; + } + + // store overlap fraction only if there is an intersection + if (overlapFraction > 0.0) + { + assert(nOverlappingParticlesField.get() < MaxParticlesPerCell); + BsField.get(nOverlappingParticlesField.get()) = overlapFraction; + BsField.get(nOverlappingParticlesField.get()) *= 1.0 / (nSamples.x * nSamples.y * nSamples.z); + calculateWeighting< Weighting_T >(&BsField.get(nOverlappingParticlesField.get()), + BsField.get(nOverlappingParticlesField.get()), real_t(1.0) / omega); + idxField.get(nOverlappingParticlesField.get()) = idxMapped; + BField.get() += BsField.get(nOverlappingParticlesField.get()); + nOverlappingParticlesField.get() += 1; + } + } + } + + // Normalize fraction field (Bs) if sum over all fractions (B) > 1 + if (BField.get() > 1) + { + for (uint i = 0; i < nOverlappingParticlesField.get(); i++) + { + BsField.get(i) /= BField.get(); + } + BField.get() = 1.0; + } +} + +// Based on the following paper: https://doi.org/10.1108/EC-02-2016-0052 +template< int Weighting_T > +__global__ void + linearApproximation(walberla::gpu::FieldAccessor< uint_t > nOverlappingParticlesField, + walberla::gpu::FieldAccessor< real_t > BsField, walberla::gpu::FieldAccessor< id_t > idxField, + walberla::gpu::FieldAccessor< real_t > BField, const real_t omega, + const real_t* __restrict__ const spherePositions, const real_t* __restrict__ const sphereRadii, + const real_t* __restrict__ const f_rs, const double3 blockStart, const real_t dx, + const size_t* __restrict__ const numParticlesSubBlocks, + const size_t* __restrict__ const particleIDsSubBlocks, const uint3 subBlocksPerDim) +{ + const uint3 blockIdx_uint3 = make_uint3(blockIdx.x, blockIdx.y, blockIdx.z); + const uint3 threadIdx_uint3 = make_uint3(threadIdx.x, threadIdx.y, threadIdx.z); + + nOverlappingParticlesField.set(blockIdx_uint3, threadIdx_uint3); + BsField.set(blockIdx_uint3, threadIdx_uint3); + idxField.set(blockIdx_uint3, threadIdx_uint3); + BField.set(blockIdx_uint3, threadIdx_uint3); + + // Clear the fields + for (uint i = 0; i < MaxParticlesPerCell; i++) + { + BsField.get(i) = real_t(0.0); + idxField.get(i) = size_t(0); + } + nOverlappingParticlesField.get() = uint_t(0); + BField.get() = real_t(0.0); + + const double3 cellCenter = { (blockStart.x + (threadIdx.x + 0.5) * dx), (blockStart.y + (blockIdx.x + 0.5) * dx), + (blockStart.z + (blockIdx.y + 0.5) * dx) }; + const ulong3 subBlockIndex = { size_t(real_t(threadIdx.x) / blockDim.x * real_t(subBlocksPerDim.x)), + size_t(real_t(blockIdx.x) / gridDim.x * real_t(subBlocksPerDim.y)), + size_t(real_t(blockIdx.y) / gridDim.y * real_t(subBlocksPerDim.z)) }; + size_t linearizedSubBlockIndex = + subBlockIndex.z * subBlocksPerDim.x * subBlocksPerDim.y + subBlockIndex.y * subBlocksPerDim.x + subBlockIndex.x; + + for (uint i = 0; i < numParticlesSubBlocks[linearizedSubBlockIndex]; i++) + { + size_t idxMapped = + particleIDsSubBlocks[linearizedSubBlockIndex + i * subBlocksPerDim.x * subBlocksPerDim.y * subBlocksPerDim.z]; + double3 minCornerSphere = { spherePositions[idxMapped * 3] - sphereRadii[idxMapped], + spherePositions[idxMapped * 3 + 1] - sphereRadii[idxMapped], + spherePositions[idxMapped * 3 + 2] - sphereRadii[idxMapped] }; + double3 maxCornerSphere = { spherePositions[idxMapped * 3] + sphereRadii[idxMapped], + spherePositions[idxMapped * 3 + 1] + sphereRadii[idxMapped], + spherePositions[idxMapped * 3 + 2] + sphereRadii[idxMapped] }; + if (cellCenter.x + dx > minCornerSphere.x && cellCenter.x - dx < maxCornerSphere.x && + cellCenter.y + dx > minCornerSphere.y && cellCenter.y - dx < maxCornerSphere.y && + cellCenter.z + dx > minCornerSphere.z && cellCenter.z - dx < maxCornerSphere.z) + { + const double3 cellSphereVector = { spherePositions[idxMapped * 3] - cellCenter.x, + spherePositions[idxMapped * 3 + 1] - cellCenter.y, + spherePositions[idxMapped * 3 + 2] - cellCenter.z }; + + const real_t D = sqrt(cellSphereVector.x * cellSphereVector.x + cellSphereVector.y * cellSphereVector.y + + cellSphereVector.z * cellSphereVector.z) - + sphereRadii[idxMapped]; + + real_t epsilon = -D + f_rs[idxMapped]; + epsilon = max(epsilon, 0.0); + epsilon = min(epsilon, 1.0); + + // Store overlap fraction only if there is an intersection + if (epsilon > 0.0) + { + // Check that the maximum number of overlapping particles has not yet been reached + assert(nOverlappingParticlesField.get() < MaxParticlesPerCell); + BsField.get(nOverlappingParticlesField.get()) = epsilon; + calculateWeighting< Weighting_T >(&BsField.get(nOverlappingParticlesField.get()), + BsField.get(nOverlappingParticlesField.get()), real_t(1.0) / omega); + idxField.get(nOverlappingParticlesField.get()) = idxMapped; + BField.get() += BsField.get(nOverlappingParticlesField.get()); + nOverlappingParticlesField.get() += 1; + } + } + } + + // Normalize fraction field (Bs) if sum over all fractions (B) > 1 + if (BField.get() > 1) + { + for (uint i = 0; i < nOverlappingParticlesField.get(); i++) + { + BsField.get(i) /= BField.get(); + } + BField.get() = 1.0; + } +} + +template< int Weighting_T > +__global__ void boxMapping(walberla::gpu::FieldAccessor< uint_t > nOverlappingParticlesField, + walberla::gpu::FieldAccessor< real_t > BsField, + walberla::gpu::FieldAccessor< id_t > idxField, walberla::gpu::FieldAccessor< real_t > BField, + const real_t omega, const double3 boxPositionMin, const double3 boxPositionMax, + const double3 blockStart, const real_t dx, const id_t idxMapped) +{ + const uint3 blockIdx_uint3 = make_uint3(blockIdx.x, blockIdx.y, blockIdx.z); + const uint3 threadIdx_uint3 = make_uint3(threadIdx.x, threadIdx.y, threadIdx.z); + + nOverlappingParticlesField.set(blockIdx_uint3, threadIdx_uint3); + BsField.set(blockIdx_uint3, threadIdx_uint3); + idxField.set(blockIdx_uint3, threadIdx_uint3); + BField.set(blockIdx_uint3, threadIdx_uint3); + + const double3 cellCenter = { (blockStart.x + (threadIdx.x + 0.5) * dx), (blockStart.y + (blockIdx.x + 0.5) * dx), + (blockStart.z + (blockIdx.y + 0.5) * dx) }; + const double3 cellMin = { cellCenter.x - dx * real_t(0.5), cellCenter.y - dx * real_t(0.5), + cellCenter.z - dx * real_t(0.5) }; + const double3 cellMax = { cellCenter.x + dx * real_t(0.5), cellCenter.y + dx * real_t(0.5), + cellCenter.z + dx * real_t(0.5) }; + + const real_t xOverlap = max(real_t(0), min(boxPositionMax.x, cellMax.x) - max(boxPositionMin.x, cellMin.x)); + const real_t yOverlap = max(real_t(0), min(boxPositionMax.y, cellMax.y) - max(boxPositionMin.y, cellMin.y)); + const real_t zOverlap = max(real_t(0), min(boxPositionMax.z, cellMax.z) - max(boxPositionMin.z, cellMin.z)); + const real_t overlapFraction = xOverlap * yOverlap * zOverlap / (dx * dx * dx); + + if (overlapFraction > real_t(0)) + { + assert(nOverlappingParticlesField.get() < MaxParticlesPerCell); + + BsField.get(nOverlappingParticlesField.get()) = overlapFraction; + calculateWeighting< Weighting_T >(&BsField.get(nOverlappingParticlesField.get()), + BsField.get(nOverlappingParticlesField.get()), real_t(1.0) / omega); + idxField.get(nOverlappingParticlesField.get()) = idxMapped; + BField.get() += BsField.get(nOverlappingParticlesField.get()); + nOverlappingParticlesField.get() += 1; + + // TODO: it can happen that the BsField for spheres is normalized twice, one here and in the sphere mapping + // Normalize fraction field (Bs) if sum over all fractions (B) > 1 + if (BField.get() > 1) + { + for (uint i = 0; i < nOverlappingParticlesField.get(); i++) + { + BsField.get(i) /= BField.get(); + } + BField.get() = 1.0; + } + } +} + +auto instance0_with_weighting_1 = superSampling< 1 >; +auto instance1_with_weighting_2 = superSampling< 2 >; +auto instance2_with_weighting_1 = linearApproximation< 1 >; +auto instance3_with_weighting_2 = linearApproximation< 2 >; +auto instance4_with_weighting_1 = boxMapping< 1 >; +auto instance5_with_weighting_2 = boxMapping< 2 >; + +} // namespace gpu +} // namespace psm +} // namespace lbm_mesapd_coupling +} // namespace walberla diff --git a/src/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/ParticleAndVolumeFractionMappingKernels.h b/src/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/ParticleAndVolumeFractionMappingKernels.h new file mode 100644 index 0000000000000000000000000000000000000000..32ee62c3bcc87d401f7cc0962e7a25fdf888f22c --- /dev/null +++ b/src/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/ParticleAndVolumeFractionMappingKernels.h @@ -0,0 +1,68 @@ +//====================================================================================================================== +// +// This file is part of waLBerla. waLBerla 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. +// +// waLBerla 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 waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file ParticleAndVolumeFractionMappingKernels.h +//! \ingroup lbm_mesapd_coupling +//! \author Samuel Kemmler <samuel.kemmler@fau.de> +// +//====================================================================================================================== + +#pragma once + +#include "core/DataTypes.h" +#include "core/math/Vector3.h" + +#include "gpu/FieldAccessor.h" + +namespace walberla +{ +namespace lbm_mesapd_coupling +{ +namespace psm +{ +namespace gpu +{ + +template< int Weighting_T > +__global__ void superSampling(walberla::gpu::FieldAccessor< uint_t > nOverlappingParticlesField, + walberla::gpu::FieldAccessor< real_t > BsField, + walberla::gpu::FieldAccessor< id_t > idxField, + walberla::gpu::FieldAccessor< real_t > BField, const real_t omega, + const real_t* __restrict__ const spherePositions, + const real_t* __restrict__ const sphereRadii, const double3 blockStart, const real_t dx, + const int3 nSamples, const size_t* __restrict__ const numParticlesSubBlocks, + const size_t* __restrict__ const particleIDsSubBlocks, const uint3 subBlocksPerDim); + +template< int Weighting_T > +__global__ void + linearApproximation(walberla::gpu::FieldAccessor< uint_t > nOverlappingParticlesField, + walberla::gpu::FieldAccessor< real_t > BsField, walberla::gpu::FieldAccessor< id_t > idxField, + walberla::gpu::FieldAccessor< real_t > BField, const real_t omega, + const real_t* __restrict__ const spherePositions, const real_t* __restrict__ const sphereRadii, + const real_t* __restrict__ const f_rs, const double3 blockStart, const real_t dx, + const size_t* __restrict__ const numParticlesSubBlocks, + const size_t* __restrict__ const particleIDsSubBlocks, const uint3 subBlocksPerDim); + +template< int Weighting_T > +__global__ void boxMapping(walberla::gpu::FieldAccessor< uint_t > nOverlappingParticlesField, + walberla::gpu::FieldAccessor< real_t > BsField, + walberla::gpu::FieldAccessor< id_t > idxField, walberla::gpu::FieldAccessor< real_t > BField, + const real_t omega, const double3 boxPositionMin, const double3 boxPositionMax, + const double3 blockStart, const real_t dx, const id_t idxMapped); + +} // namespace gpu +} // namespace psm +} // namespace lbm_mesapd_coupling +} // namespace walberla diff --git a/src/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/ParticleAndVolumeFractionMappingSweepsCPU.h b/src/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/ParticleAndVolumeFractionMappingSweepsCPU.h new file mode 100644 index 0000000000000000000000000000000000000000..1ab47b344512d165b8e6c7d5718179f5725a3525 --- /dev/null +++ b/src/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/ParticleAndVolumeFractionMappingSweepsCPU.h @@ -0,0 +1,318 @@ +//====================================================================================================================== +// +// This file is part of waLBerla. waLBerla 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. +// +// waLBerla 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 waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file ParticleAndVolumeFractionMappingSweepsCPU.h +//! \ingroup lbm_mesapd_coupling +//! \author Samuel Kemmler <samuel.kemmler@fau.de> +// +//====================================================================================================================== + +#pragma once + +#include "domain_decomposition/StructuredBlockStorage.h" + +#include "field/GhostLayerField.h" + +#include "lbm_mesapd_coupling/DataTypesCodegen.h" +#include "lbm_mesapd_coupling/mapping/ParticleBoundingBox.h" +#include "lbm_mesapd_coupling/utility/ParticleSelector.h" + +#include "mesa_pd/common/AABBConversion.h" +#include "mesa_pd/data/ParticleAccessorWithShape.h" +#include "mesa_pd/data/ParticleStorage.h" +#include "mesa_pd/kernel/SingleCast.h" + +#include <cassert> +#include <functional> +#include <mesa_pd/data/ParticleStorage.h> +#include <mesa_pd/data/shape/Sphere.h> + +namespace walberla +{ +namespace lbm_mesapd_coupling +{ +namespace psm +{ +// The CPU version is on purpose in the gpu namespace to avoid changes in the application codes +namespace gpu +{ + +template< int Weighting_T > +void calculateWeighting(real_t* const weighting, const real_t& /*epsilon*/, const real_t& /*tau*/) +{ + WALBERLA_STATIC_ASSERT(Weighting_T == 1 || Weighting_T == 2); +} + +template<> +void calculateWeighting< 1 >(real_t* const weighting, const real_t& epsilon, const real_t& /*tau*/) +{ + *weighting = epsilon; +} +template<> +void calculateWeighting< 2 >(real_t* const weighting, const real_t& epsilon, const real_t& tau) +{ + *weighting = epsilon * (tau - real_t(0.5)) / ((real_t(1) - epsilon) + (tau - real_t(0.5))); +} + +template< int Weighting_T > +void mapParticles(IBlock& blockIt, const ParticleAndVolumeFractionSoA_T< Weighting_T >& particleAndVolumeFractionSoA, + const real_t* const spherePositions, const real_t* const sphereRadii, const real_t* const f_rs, + const size_t* const numParticlesSubBlocks, const size_t* const particleIDsSubBlocks, + const Vector3< uint_t > subBlocksPerDim) +{ + auto nOverlappingParticlesField = + blockIt.getData< nOverlappingParticlesField_T >(particleAndVolumeFractionSoA.nOverlappingParticlesFieldID); + auto BsField = blockIt.getData< BsField_T >(particleAndVolumeFractionSoA.BsFieldID); + auto idxField = blockIt.getData< idxField_T >(particleAndVolumeFractionSoA.idxFieldID); + auto BField = blockIt.getData< BField_T >(particleAndVolumeFractionSoA.BFieldID); + + real_t dx = blockIt.getAABB().xSize() / real_t(nOverlappingParticlesField->xSize()); + + WALBERLA_FOR_ALL_CELLS_XYZ( + BField, + for (size_t i = 0; i < MaxParticlesPerCell; i++) { + BsField->get(x, y, z, i) = real_t(0.0); + idxField->get(x, y, z, i) = size_t(0); + } nOverlappingParticlesField->get(x, y, z) = uint_t(0); + BField->get(x, y, z) = real_t(0.0); + const Vector3< real_t > cellCenter = + Vector3< real_t >(real_t(x) + real_t(0.5) * dx, real_t(y) + real_t(0.5) * dx, real_t(z) + real_t(0.5) * dx) + + blockIt.getAABB().minCorner(); + const Vector3< size_t > subBlockIndex(size_t(real_t(x) / blockIt.getAABB().xSize() * real_t(subBlocksPerDim[0])), + size_t(real_t(y) / blockIt.getAABB().ySize() * real_t(subBlocksPerDim[1])), + size_t(real_t(z) / blockIt.getAABB().zSize() * real_t(subBlocksPerDim[2]))); + const size_t linearizedSubBlockIndex = subBlockIndex[2] * subBlocksPerDim[0] * subBlocksPerDim[1] + + subBlockIndex[1] * subBlocksPerDim[0] + subBlockIndex[0]; + + for (size_t i = 0; i < numParticlesSubBlocks[linearizedSubBlockIndex]; i++) { + size_t idxMapped = particleIDsSubBlocks[linearizedSubBlockIndex + + i * subBlocksPerDim[0] * subBlocksPerDim[1] * subBlocksPerDim[2]]; + const Vector3< real_t > minCornerSphere(spherePositions[idxMapped * 3] - sphereRadii[idxMapped], + spherePositions[idxMapped * 3 + 1] - sphereRadii[idxMapped], + spherePositions[idxMapped * 3 + 2] - sphereRadii[idxMapped]); + const Vector3< real_t > maxCornerSphere(spherePositions[idxMapped * 3] + sphereRadii[idxMapped], + spherePositions[idxMapped * 3 + 1] + sphereRadii[idxMapped], + spherePositions[idxMapped * 3 + 2] + sphereRadii[idxMapped]); + if (cellCenter[0] + dx > minCornerSphere[0] && cellCenter[0] - dx < maxCornerSphere[0] && + cellCenter[1] + dx > minCornerSphere[1] && cellCenter[1] - dx < maxCornerSphere[1] && + cellCenter[2] + dx > minCornerSphere[2] && cellCenter[2] - dx < maxCornerSphere[2]) + { + const Vector3< real_t > cellSphereVector(spherePositions[idxMapped * 3] - cellCenter[0], + spherePositions[idxMapped * 3 + 1] - cellCenter[1], + spherePositions[idxMapped * 3 + 2] - cellCenter[2]); + + const real_t D = + real_t(sqrt(cellSphereVector[0] * cellSphereVector[0] + cellSphereVector[1] * cellSphereVector[1] + + cellSphereVector[2] * cellSphereVector[2])) - + sphereRadii[idxMapped]; + + real_t epsilon = -D + f_rs[idxMapped]; + epsilon = std::max(epsilon, real_t(0)); + epsilon = std::min(epsilon, real_t(1)); + + // Store overlap fraction only if there is an intersection + if (epsilon > 0.0) + { + // Check that the maximum number of overlapping particles has not yet been reached + assert(nOverlappingParticlesField->get(x, y, z) < MaxParticlesPerCell); + BsField->get(x, y, z, nOverlappingParticlesField->get(x, y, z)) = epsilon; + calculateWeighting< Weighting_T >(&BsField->get(x, y, z, nOverlappingParticlesField->get(x, y, z)), + BsField->get(x, y, z, nOverlappingParticlesField->get(x, y, z)), + real_t(1.0) / particleAndVolumeFractionSoA.omega_); + idxField->get(x, y, z, nOverlappingParticlesField->get(x, y, z)) = idxMapped; + BField->get(x, y, z) += BsField->get(x, y, z, nOverlappingParticlesField->get(x, y, z)); + nOverlappingParticlesField->get(x, y, z) += 1; + } + } + } + + // Normalize fraction field (Bs) if sum over all fractions (B) > 1 + if (BField->get(x, y, z) > 1) { + for (size_t i = 0; i < nOverlappingParticlesField->get(x, y, z); i++) + { + BsField->get(x, y, z, i) /= BField->get(x, y, z); + } + BField->get(x, y, z) = 1.0; + }) +} + +template< typename ParticleAccessor_T, typename ParticleSelector_T, int Weighting_T > +class SphereFractionMappingSweep +{ + public: + SphereFractionMappingSweep(const shared_ptr< StructuredBlockStorage >& blockStorage, + const shared_ptr< ParticleAccessor_T >& ac, + const ParticleSelector_T& mappingParticleSelector, + ParticleAndVolumeFractionSoA_T< Weighting_T >& particleAndVolumeFractionSoA, + const Vector3< uint_t > subBlockSize) + : blockStorage_(blockStorage), ac_(ac), mappingParticleSelector_(mappingParticleSelector), + particleAndVolumeFractionSoA_(particleAndVolumeFractionSoA), subBlockSize_(subBlockSize) + { + static_assert(std::is_base_of< mesa_pd::data::IAccessor, ParticleAccessor_T >::value, + "Provide a valid accessor as template"); + for (auto blockIt = blockStorage_->begin(); blockIt != blockStorage_->end(); ++blockIt) + { + auto aabb = blockIt->getAABB(); + if (size_t(aabb.xSize()) % subBlockSize_[0] != 0 || size_t(aabb.ySize()) % subBlockSize_[1] != 0 || + size_t(aabb.zSize()) % subBlockSize_[2] != 0) + { + WALBERLA_ABORT("Number of cells per block (" << aabb << ") is not divisible by subBlockSize (" + << subBlockSize_ << ").") + } + } + } + + void operator()(IBlock* block) + { + size_t numMappedParticles = 0; + particleAndVolumeFractionSoA_.mappingUIDs.clear(); + for (size_t idx = 0; idx < ac_->size(); ++idx) + { + if (mappingParticleSelector_(idx, *ac_)) + { + numMappedParticles++; + // Store UIDs to make sure that the particles have not changed between the mapping and the PSM sweep + particleAndVolumeFractionSoA_.mappingUIDs.push_back(ac_->getUid(idx)); + } + } + + if (numMappedParticles == uint_t(0)) return; + + // Allocate memory storing the particle information needed for the overlap fraction computations + const size_t scalarArraySize = numMappedParticles * sizeof(real_t); + + if (particleAndVolumeFractionSoA_.positions != nullptr) { free(particleAndVolumeFractionSoA_.positions); } + particleAndVolumeFractionSoA_.positions = (real_t*) malloc(3 * scalarArraySize); + real_t* radii = (real_t*) malloc(scalarArraySize); + real_t* f_r = (real_t*) malloc(scalarArraySize); // f_r is described in https://doi.org/10.1108/EC-02-2016-0052 + + // Store particle information inside the memory + size_t idxMapped = 0; + for (size_t idx = 0; idx < ac_->size(); ++idx) + { + if (mappingParticleSelector_(idx, *ac_)) + { + for (size_t d = 0; d < 3; ++d) + { + particleAndVolumeFractionSoA_.positions[idxMapped * 3 + d] = ac_->getPosition(idx)[d]; + } + // If other shapes than spheres are mapped, ignore them here + if (ac_->getShape(idx)->getShapeType() == mesa_pd::data::Sphere::SHAPE_TYPE) + { + const real_t radius = static_cast< mesa_pd::data::Sphere* >(ac_->getShape(idx))->getRadius(); + radii[idxMapped] = radius; + real_t Va = real_t( + (1.0 / 12.0 - radius * radius) * atan((0.5 * sqrt(radius * radius - 0.5)) / (0.5 - radius * radius)) + + 1.0 / 3.0 * sqrt(radius * radius - 0.5) + + (radius * radius - 1.0 / 12.0) * atan(0.5 / sqrt(radius * radius - 0.5)) - + 4.0 / 3.0 * radius * radius * radius * atan(0.25 / (radius * sqrt(radius * radius - 0.5)))); + f_r[idxMapped] = Va - radius + real_t(0.5); + } + idxMapped++; + } + } + + // Update fraction mapping + // Split the block into sub-blocks and sort the particle indices into each overlapping sub-block. This way, in + // the particle mapping, each iteration only has to check the potentially overlapping particles. + auto blockAABB = block->getAABB(); + const Vector3< uint_t > subBlocksPerDim = + Vector3< uint_t >(uint_t(blockAABB.xSize()) / subBlockSize_[0], uint_t(blockAABB.ySize()) / subBlockSize_[1], + uint_t(blockAABB.zSize()) / subBlockSize_[2]); + const size_t numSubBlocks = subBlocksPerDim[0] * subBlocksPerDim[1] * subBlocksPerDim[2]; + std::vector< std::vector< size_t > > subBlocks(numSubBlocks); + + idxMapped = 0; + for (size_t idx = 0; idx < ac_->size(); ++idx) + { + if (mappingParticleSelector_(idx, *ac_)) + { + if (ac_->getShape(idx)->getShapeType() == mesa_pd::data::Sphere::SHAPE_TYPE) + { + auto sphereAABB = mesa_pd::getParticleAABB(idx, *ac_); + if (blockAABB.intersects(sphereAABB)) + { + auto intersectionAABB = blockAABB.getIntersection(sphereAABB); + intersectionAABB.translate(-blockAABB.minCorner()); + mesa_pd::Vec3 blockScaling = mesa_pd::Vec3(real_t(subBlocksPerDim[0]) / blockAABB.sizes()[0], + real_t(subBlocksPerDim[1]) / blockAABB.sizes()[1], + real_t(subBlocksPerDim[2]) / blockAABB.sizes()[2]); + + for (size_t z = size_t(intersectionAABB.zMin() * blockScaling[2]); + z < size_t(ceil(intersectionAABB.zMax() * blockScaling[2])); ++z) + { + for (size_t y = size_t(intersectionAABB.yMin() * blockScaling[1]); + y < size_t(ceil(intersectionAABB.yMax() * blockScaling[1])); ++y) + { + for (size_t x = size_t(intersectionAABB.xMin() * blockScaling[0]); + x < size_t(ceil(intersectionAABB.xMax() * blockScaling[0])); ++x) + { + size_t index = z * subBlocksPerDim[0] * subBlocksPerDim[1] + y * subBlocksPerDim[0] + x; + subBlocks[index].push_back(idxMapped); + } + } + } + } + } + idxMapped++; + } + } + + size_t maxParticlesPerSubBlock = 0; + std::for_each(subBlocks.begin(), subBlocks.end(), [&maxParticlesPerSubBlock](std::vector< size_t >& subBlock) { + maxParticlesPerSubBlock = std::max(maxParticlesPerSubBlock, subBlock.size()); + }); + + size_t* numParticlesPerSubBlock = (size_t*) malloc(numSubBlocks * sizeof(size_t)); + size_t* particleIDsSubBlocks = (size_t*) malloc(numSubBlocks * maxParticlesPerSubBlock * sizeof(size_t)); + + // Copy data from std::vector to memory + for (size_t z = 0; z < subBlocksPerDim[2]; ++z) + { + for (size_t y = 0; y < subBlocksPerDim[1]; ++y) + { + for (size_t x = 0; x < subBlocksPerDim[0]; ++x) + { + size_t index = z * subBlocksPerDim[0] * subBlocksPerDim[1] + y * subBlocksPerDim[0] + x; + numParticlesPerSubBlock[index] = subBlocks[index].size(); + for (size_t k = 0; k < subBlocks[index].size(); k++) + { + particleIDsSubBlocks[index + k * numSubBlocks] = subBlocks[index][k]; + } + } + } + } + + mapParticles(*block, particleAndVolumeFractionSoA_, particleAndVolumeFractionSoA_.positions, radii, f_r, + numParticlesPerSubBlock, particleIDsSubBlocks, subBlocksPerDim); + + free(numParticlesPerSubBlock); + free(particleIDsSubBlocks); + + free(radii); + free(f_r); + } + + shared_ptr< StructuredBlockStorage > blockStorage_; + const shared_ptr< ParticleAccessor_T > ac_; + const ParticleSelector_T& mappingParticleSelector_; + ParticleAndVolumeFractionSoA_T< Weighting_T >& particleAndVolumeFractionSoA_; + const Vector3< uint_t > subBlockSize_; +}; + +} // namespace gpu +} // namespace psm +} // namespace lbm_mesapd_coupling +} // namespace walberla diff --git a/src/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/ParticleAndVolumeFractionMappingSweepsGPU.h b/src/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/ParticleAndVolumeFractionMappingSweepsGPU.h new file mode 100644 index 0000000000000000000000000000000000000000..7576d9476764d092a5c8c3defa4a85117f34b2d5 --- /dev/null +++ b/src/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/ParticleAndVolumeFractionMappingSweepsGPU.h @@ -0,0 +1,362 @@ +//====================================================================================================================== +// +// This file is part of waLBerla. waLBerla 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. +// +// waLBerla 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 waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file ParticleAndVolumeFractionMappingSweepsGPU.h +//! \ingroup lbm_mesapd_coupling +//! \author Samuel Kemmler <samuel.kemmler@fau.de> +// +//====================================================================================================================== + +#pragma once + +#include "domain_decomposition/StructuredBlockStorage.h" + +#include "field/GhostLayerField.h" + +#include "gpu/AddGPUFieldToStorage.h" +#include "gpu/FieldCopy.h" +#include "gpu/FieldIndexing.h" +#include "gpu/GPUField.h" +#include "gpu/HostFieldAllocator.h" +#include "gpu/Kernel.h" + +#include "lbm_mesapd_coupling/DataTypesCodegen.h" +#include "lbm_mesapd_coupling/mapping/ParticleBoundingBox.h" +#include "lbm_mesapd_coupling/utility/ParticleSelector.h" + +#include "mesa_pd/common/AABBConversion.h" +#include "mesa_pd/data/ParticleAccessorWithShape.h" +#include "mesa_pd/data/ParticleStorage.h" +#include "mesa_pd/kernel/SingleCast.h" + +#include <functional> +#include <mesa_pd/data/ParticleStorage.h> +#include <mesa_pd/data/shape/Sphere.h> + +#include "ParticleAndVolumeFractionMappingKernels.h" + +namespace walberla +{ +namespace lbm_mesapd_coupling +{ +namespace psm +{ +namespace gpu +{ + +template< int Weighting_T > +void mapParticles(const IBlock& blockIt, + const ParticleAndVolumeFractionSoA_T< Weighting_T >& particleAndVolumeFractionSoA, + const real_t* const spherePositions, const real_t* const sphereRadii, const real_t* const f_rs, + const size_t* const numParticlesSubBlocks, const size_t* const particleIDsSubBlocks, + const Vector3< uint_t > subBlocksPerDim) +{ + auto nOverlappingParticlesField = + blockIt.getData< nOverlappingParticlesFieldGPU_T >(particleAndVolumeFractionSoA.nOverlappingParticlesFieldID); + auto BsField = blockIt.getData< BsFieldGPU_T >(particleAndVolumeFractionSoA.BsFieldID); + auto idxField = blockIt.getData< idxFieldGPU_T >(particleAndVolumeFractionSoA.idxFieldID); + auto BField = blockIt.getData< BFieldGPU_T >(particleAndVolumeFractionSoA.BFieldID); + + auto myKernel = walberla::gpu::make_kernel(&(linearApproximation< Weighting_T >) ); + myKernel.addFieldIndexingParam(walberla::gpu::FieldIndexing< uint_t >::xyz(*nOverlappingParticlesField)); + myKernel.addFieldIndexingParam(walberla::gpu::FieldIndexing< real_t >::xyz(*BsField)); + myKernel.addFieldIndexingParam(walberla::gpu::FieldIndexing< id_t >::xyz(*idxField)); + myKernel.addFieldIndexingParam(walberla::gpu::FieldIndexing< real_t >::xyz(*BField)); + myKernel.addParam(particleAndVolumeFractionSoA.omega_); + myKernel.addParam(spherePositions); + myKernel.addParam(sphereRadii); + myKernel.addParam(f_rs); + Vector3< real_t > blockStart = blockIt.getAABB().minCorner(); + myKernel.addParam(double3{ blockStart[0], blockStart[1], blockStart[2] }); + myKernel.addParam(blockIt.getAABB().xSize() / real_t(nOverlappingParticlesField->xSize())); + myKernel.addParam(numParticlesSubBlocks); + myKernel.addParam(particleIDsSubBlocks); + myKernel.addParam(uint3{ uint(subBlocksPerDim[0]), uint(subBlocksPerDim[1]), uint(subBlocksPerDim[2]) }); + myKernel(); +} + +template< typename ParticleAccessor_T, typename ParticleSelector_T, int Weighting_T > +class SphereFractionMappingSweep +{ + public: + SphereFractionMappingSweep(const shared_ptr< StructuredBlockStorage >& blockStorage, + const shared_ptr< ParticleAccessor_T >& ac, + const ParticleSelector_T& mappingParticleSelector, + ParticleAndVolumeFractionSoA_T< Weighting_T >& particleAndVolumeFractionSoA, + const Vector3< uint_t > subBlockSize) + : blockStorage_(blockStorage), ac_(ac), mappingParticleSelector_(mappingParticleSelector), + particleAndVolumeFractionSoA_(particleAndVolumeFractionSoA), subBlockSize_(subBlockSize) + { + static_assert(std::is_base_of< mesa_pd::data::IAccessor, ParticleAccessor_T >::value, + "Provide a valid accessor as template"); + for (auto blockIt = blockStorage_->begin(); blockIt != blockStorage_->end(); ++blockIt) + { + auto aabb = blockIt->getAABB(); + if (size_t(aabb.xSize()) % subBlockSize_[0] != 0 || size_t(aabb.ySize()) % subBlockSize_[1] != 0 || + size_t(aabb.zSize()) % subBlockSize_[2] != 0) + { + WALBERLA_ABORT("Number of cells per block (" << aabb << ") is not divisible by subBlockSize (" + << subBlockSize_ << ").") + } + } + } + + void operator()(IBlock* block) + { + size_t numMappedParticles = 0; + particleAndVolumeFractionSoA_.mappingUIDs.clear(); + for (size_t idx = 0; idx < ac_->size(); ++idx) + { + if (mappingParticleSelector_(idx, *ac_)) + { + numMappedParticles++; + // Store UIDs to make sure that the particles have not changed between the mapping and the PSM sweep + particleAndVolumeFractionSoA_.mappingUIDs.push_back(ac_->getUid(idx)); + } + } + + if (numMappedParticles == uint_t(0)) return; + + // Allocate memory storing the particle information needed for the overlap fraction computations + const size_t scalarArraySize = numMappedParticles * sizeof(real_t); + + if (particleAndVolumeFractionSoA_.positions != nullptr) + { + WALBERLA_GPU_CHECK(gpuFree(particleAndVolumeFractionSoA_.positions)); + } + real_t* positions_h = (real_t*) malloc(3 * scalarArraySize); + real_t* radii_h = (real_t*) malloc(scalarArraySize); + real_t* f_r_h = (real_t*) malloc(scalarArraySize); // f_r is described in https://doi.org/10.1108/EC-02-2016-0052 + + // Store particle information inside the memory + size_t idxMapped = 0; + for (size_t idx = 0; idx < ac_->size(); ++idx) + { + if (mappingParticleSelector_(idx, *ac_)) + { + for (size_t d = 0; d < 3; ++d) + { + positions_h[idxMapped * 3 + d] = ac_->getPosition(idx)[d]; + } + // If other shapes than spheres are mapped, ignore them here + if (ac_->getShape(idx)->getShapeType() == mesa_pd::data::Sphere::SHAPE_TYPE) + { + const real_t radius = static_cast< mesa_pd::data::Sphere* >(ac_->getShape(idx))->getRadius(); + radii_h[idxMapped] = radius; + real_t Va = real_t( + (1.0 / 12.0 - radius * radius) * atan((0.5 * sqrt(radius * radius - 0.5)) / (0.5 - radius * radius)) + + 1.0 / 3.0 * sqrt(radius * radius - 0.5) + + (radius * radius - 1.0 / 12.0) * atan(0.5 / sqrt(radius * radius - 0.5)) - + 4.0 / 3.0 * radius * radius * radius * atan(0.25 / (radius * sqrt(radius * radius - 0.5)))); + f_r_h[idxMapped] = Va - radius + real_t(0.5); + } + idxMapped++; + } + } + + // Update fraction mapping + // Split the block into sub-blocks and sort the particle indices into each overlapping sub-block. This way, in + // the particle mapping, each gpu thread only has to check the potentially overlapping particles. + auto blockAABB = block->getAABB(); + const Vector3< uint_t > subBlocksPerDim = + Vector3< uint_t >(uint_t(blockAABB.xSize()) / subBlockSize_[0], uint_t(blockAABB.ySize()) / subBlockSize_[1], + uint_t(blockAABB.zSize()) / subBlockSize_[2]); + const size_t numSubBlocks = subBlocksPerDim[0] * subBlocksPerDim[1] * subBlocksPerDim[2]; + std::vector< std::vector< size_t > > subBlocks(numSubBlocks); + + idxMapped = 0; + for (size_t idx = 0; idx < ac_->size(); ++idx) + { + if (mappingParticleSelector_(idx, *ac_)) + { + if (ac_->getShape(idx)->getShapeType() == mesa_pd::data::Sphere::SHAPE_TYPE) + { + auto sphereAABB = mesa_pd::getParticleAABB(idx, *ac_); + if (blockAABB.intersects(sphereAABB)) + { + auto intersectionAABB = blockAABB.getIntersection(sphereAABB); + intersectionAABB.translate(-blockAABB.minCorner()); + mesa_pd::Vec3 blockScaling = mesa_pd::Vec3(real_t(subBlocksPerDim[0]) / blockAABB.sizes()[0], + real_t(subBlocksPerDim[1]) / blockAABB.sizes()[1], + real_t(subBlocksPerDim[2]) / blockAABB.sizes()[2]); + + for (size_t z = size_t(intersectionAABB.zMin() * blockScaling[2]); + z < size_t(ceil(intersectionAABB.zMax() * blockScaling[2])); ++z) + { + for (size_t y = size_t(intersectionAABB.yMin() * blockScaling[1]); + y < size_t(ceil(intersectionAABB.yMax() * blockScaling[1])); ++y) + { + for (size_t x = size_t(intersectionAABB.xMin() * blockScaling[0]); + x < size_t(ceil(intersectionAABB.xMax() * blockScaling[0])); ++x) + { + size_t index = z * subBlocksPerDim[0] * subBlocksPerDim[1] + y * subBlocksPerDim[0] + x; + subBlocks[index].push_back(idxMapped); + } + } + } + } + } + idxMapped++; + } + } + + size_t maxParticlesPerSubBlock = 0; + std::for_each(subBlocks.begin(), subBlocks.end(), [&maxParticlesPerSubBlock](std::vector< size_t >& subBlock) { + maxParticlesPerSubBlock = std::max(maxParticlesPerSubBlock, subBlock.size()); + }); + + size_t* numParticlesPerSubBlock_h = (size_t*) malloc(numSubBlocks * sizeof(size_t)); + size_t* particleIDsSubBlocks_h = nullptr; + if (maxParticlesPerSubBlock > uint_t(0)) + { + particleIDsSubBlocks_h = (size_t*) malloc(numSubBlocks * maxParticlesPerSubBlock * sizeof(size_t)); + } + // Copy data from std::vector to memory + for (size_t z = 0; z < subBlocksPerDim[2]; ++z) + { + for (size_t y = 0; y < subBlocksPerDim[1]; ++y) + { + for (size_t x = 0; x < subBlocksPerDim[0]; ++x) + { + size_t index = z * subBlocksPerDim[0] * subBlocksPerDim[1] + y * subBlocksPerDim[0] + x; + numParticlesPerSubBlock_h[index] = subBlocks[index].size(); + for (size_t k = 0; k < subBlocks[index].size(); k++) + { + particleIDsSubBlocks_h[index + k * numSubBlocks] = subBlocks[index][k]; + } + } + } + } + + WALBERLA_GPU_CHECK(gpuMalloc(&(particleAndVolumeFractionSoA_.positions), 3 * scalarArraySize)); + WALBERLA_GPU_CHECK( + gpuMemcpy(particleAndVolumeFractionSoA_.positions, positions_h, 3 * scalarArraySize, gpuMemcpyHostToDevice)); + + real_t* radii; + WALBERLA_GPU_CHECK(gpuMalloc(&radii, scalarArraySize)); + WALBERLA_GPU_CHECK(gpuMemcpy(radii, radii_h, scalarArraySize, gpuMemcpyHostToDevice)); + + real_t* f_r; + WALBERLA_GPU_CHECK(gpuMalloc(&f_r, scalarArraySize)); + WALBERLA_GPU_CHECK(gpuMemcpy(f_r, f_r_h, scalarArraySize, gpuMemcpyHostToDevice)); + + size_t* numParticlesPerSubBlock; + WALBERLA_GPU_CHECK(gpuMalloc(&numParticlesPerSubBlock, numSubBlocks * sizeof(size_t))); + WALBERLA_GPU_CHECK(gpuMemcpy(numParticlesPerSubBlock, numParticlesPerSubBlock_h, numSubBlocks * sizeof(size_t), + gpuMemcpyHostToDevice)); + + size_t* particleIDsSubBlocks; + if (maxParticlesPerSubBlock > uint_t(0)) + { + WALBERLA_GPU_CHECK(gpuMalloc(&particleIDsSubBlocks, numSubBlocks * maxParticlesPerSubBlock * sizeof(size_t))); + WALBERLA_GPU_CHECK(gpuMemcpy(particleIDsSubBlocks, particleIDsSubBlocks_h, + numSubBlocks * maxParticlesPerSubBlock * sizeof(size_t), gpuMemcpyHostToDevice)); + } + + mapParticles(*block, particleAndVolumeFractionSoA_, particleAndVolumeFractionSoA_.positions, radii, f_r, + numParticlesPerSubBlock, particleIDsSubBlocks, subBlocksPerDim); + + WALBERLA_GPU_CHECK(gpuFree(numParticlesPerSubBlock)); + free(numParticlesPerSubBlock_h); + + if (maxParticlesPerSubBlock > uint_t(0)) + { + WALBERLA_GPU_CHECK(gpuFree(particleIDsSubBlocks)); + free(particleIDsSubBlocks_h); + } + + WALBERLA_GPU_CHECK(gpuFree(radii)); + free(radii_h); + + WALBERLA_GPU_CHECK(gpuFree(f_r)); + free(f_r_h); + + free(positions_h); + } + + shared_ptr< StructuredBlockStorage > blockStorage_; + const shared_ptr< ParticleAccessor_T > ac_; + const ParticleSelector_T& mappingParticleSelector_; + ParticleAndVolumeFractionSoA_T< Weighting_T >& particleAndVolumeFractionSoA_; + const Vector3< uint_t > subBlockSize_; +}; + +template< typename ParticleAccessor_T, typename ParticleSelector_T, int Weighting_T > +class BoxFractionMappingSweep +{ + public: + BoxFractionMappingSweep(const shared_ptr< StructuredBlockStorage >& blockStorage, + const shared_ptr< ParticleAccessor_T >& ac, const uint_t boxUid, + const Vector3< real_t > boxEdgeLength, + ParticleAndVolumeFractionSoA_T< Weighting_T >& particleAndVolumeFractionSoA, + const ParticleSelector_T& mappingParticleSelector) + : blockStorage_(blockStorage), ac_(ac), boxUid_(boxUid), boxEdgeLength_(boxEdgeLength), + particleAndVolumeFractionSoA_(particleAndVolumeFractionSoA), mappingParticleSelector_(mappingParticleSelector) + { + static_assert(std::is_base_of< mesa_pd::data::IAccessor, ParticleAccessor_T >::value, + "Provide a valid accessor as template"); + } + + void operator()(IBlock* block) + { + auto nOverlappingParticlesField = + block->getData< nOverlappingParticlesFieldGPU_T >(particleAndVolumeFractionSoA_.nOverlappingParticlesFieldID); + auto BsField = block->getData< BsFieldGPU_T >(particleAndVolumeFractionSoA_.BsFieldID); + auto idxField = block->getData< idxFieldGPU_T >(particleAndVolumeFractionSoA_.idxFieldID); + auto BField = block->getData< BFieldGPU_T >(particleAndVolumeFractionSoA_.BFieldID); + + auto myKernel = walberla::gpu::make_kernel(&(boxMapping< Weighting_T >) ); + myKernel.addFieldIndexingParam(walberla::gpu::FieldIndexing< uint_t >::xyz(*nOverlappingParticlesField)); + myKernel.addFieldIndexingParam(walberla::gpu::FieldIndexing< real_t >::xyz(*BsField)); + myKernel.addFieldIndexingParam(walberla::gpu::FieldIndexing< id_t >::xyz(*idxField)); + myKernel.addFieldIndexingParam(walberla::gpu::FieldIndexing< real_t >::xyz(*BField)); + myKernel.addParam(particleAndVolumeFractionSoA_.omega_); + const Vector3< real_t > boxPosition = ac_->getPosition(ac_->uidToIdx(boxUid_)); + myKernel.addParam(double3{ boxPosition[0] - boxEdgeLength_[0] / real_t(2), + boxPosition[1] - boxEdgeLength_[1] / real_t(2), + boxPosition[2] - boxEdgeLength_[2] / real_t(2) }); + myKernel.addParam(double3{ boxPosition[0] + boxEdgeLength_[0] / real_t(2), + boxPosition[1] + boxEdgeLength_[1] / real_t(2), + boxPosition[2] + boxEdgeLength_[2] / real_t(2) }); + Vector3< real_t > blockStart = block->getAABB().minCorner(); + myKernel.addParam(double3{ blockStart[0], blockStart[1], blockStart[2] }); + myKernel.addParam(block->getAABB().xSize() / real_t(nOverlappingParticlesField->xSize())); + + // Determine the index of the box among the mapped particles + size_t idxMapped = 0; + for (size_t idx = 0; idx < ac_->size(); ++idx) + { + if (mappingParticleSelector_(idx, *ac_)) + { + if (ac_->getUid(idx) == boxUid_) { break; } + idxMapped++; + } + } + myKernel.addParam(idxMapped); + myKernel(); + } + + shared_ptr< StructuredBlockStorage > blockStorage_; + const shared_ptr< ParticleAccessor_T > ac_; + const uint_t boxUid_; + const Vector3< real_t > boxEdgeLength_; + ParticleAndVolumeFractionSoA_T< Weighting_T >& particleAndVolumeFractionSoA_; + const ParticleSelector_T& mappingParticleSelector_; +}; + +} // namespace gpu +} // namespace psm +} // namespace lbm_mesapd_coupling +} // namespace walberla diff --git a/src/mesa_pd/common/ParticleFunctions.h b/src/mesa_pd/common/ParticleFunctions.h index 155ca3af1a8b2fd9627f5005f6def49c8b98092d..14397c39c6c3e8ff89a041bd01bcd556b2374215 100644 --- a/src/mesa_pd/common/ParticleFunctions.h +++ b/src/mesa_pd/common/ParticleFunctions.h @@ -88,23 +88,23 @@ inline Mat3 getInertia(const size_t p_idx, Accessor& ac) template <typename Accessor> inline void addForceAtomic(const size_t p_idx, Accessor& ac, const Vec3& f) { - // Increasing the force and torque on this particle; - ac.getForceRef(p_idx)[0] += f[0];; - ac.getForceRef(p_idx)[1] += f[1];; + // Increasing the force and torque on this particle + ac.getForceRef(p_idx)[0] += f[0]; + ac.getForceRef(p_idx)[1] += f[1]; ac.getForceRef(p_idx)[2] += f[2]; } template <typename Accessor> inline void addForceAtWFPosAtomic(const size_t p_idx, Accessor& ac, const Vec3& f, const Vec3& wf_pt) { - // Increasing the force and torque on this particle; - ac.getForceRef(p_idx)[0] += f[0];; - ac.getForceRef(p_idx)[1] += f[1];; + // Increasing the force and torque on this particle + ac.getForceRef(p_idx)[0] += f[0]; + ac.getForceRef(p_idx)[1] += f[1]; ac.getForceRef(p_idx)[2] += f[2]; - const auto t = cross(( wf_pt - ac.getPosition(p_idx) ), f);; - ac.getTorqueRef(p_idx)[0] += t[0];; - ac.getTorqueRef(p_idx)[1] += t[1];; + const auto t = cross(( wf_pt - ac.getPosition(p_idx) ), f); + ac.getTorqueRef(p_idx)[0] += t[0]; + ac.getTorqueRef(p_idx)[1] += t[1]; ac.getTorqueRef(p_idx)[2] += t[2]; } @@ -114,9 +114,9 @@ inline void addForceAtWFPosAtomic(const size_t p_idx, Accessor& ac, const Vec3& template <typename Accessor> inline void addTorqueAtomic(const size_t p_idx, Accessor& ac, const Vec3& t) { - // Increasing the torque on this particle; - ac.getTorqueRef(p_idx)[0] += t[0];; - ac.getTorqueRef(p_idx)[1] += t[1];; + // Increasing the torque on this particle + ac.getTorqueRef(p_idx)[0] += t[0]; + ac.getTorqueRef(p_idx)[1] += t[1]; ac.getTorqueRef(p_idx)[2] += t[2]; } diff --git a/src/mesa_pd/data/ParticleAccessor.h b/src/mesa_pd/data/ParticleAccessor.h index f18c0105a00ea1b45a2a97c4f0c2eb2803b74a93..ea82d84f93fc49a4400720aebfcde5bbcac93b8b 100644 --- a/src/mesa_pd/data/ParticleAccessor.h +++ b/src/mesa_pd/data/ParticleAccessor.h @@ -88,6 +88,10 @@ public: walberla::mesa_pd::Vec3& getOldForceRef(const size_t p_idx) {return ps_->getOldForceRef(p_idx);} void setOldForce(const size_t p_idx, walberla::mesa_pd::Vec3 const & v) { ps_->setOldForce(p_idx, v);} + walberla::real_t const & getCharge(const size_t p_idx) const {return ps_->getCharge(p_idx);} + walberla::real_t& getChargeRef(const size_t p_idx) {return ps_->getChargeRef(p_idx);} + void setCharge(const size_t p_idx, walberla::real_t const & v) { ps_->setCharge(p_idx, v);} + size_t const & getShapeID(const size_t p_idx) const {return ps_->getShapeID(p_idx);} size_t& getShapeIDRef(const size_t p_idx) {return ps_->getShapeIDRef(p_idx);} void setShapeID(const size_t p_idx, size_t const & v) { ps_->setShapeID(p_idx, v);} @@ -172,6 +176,18 @@ public: walberla::mesa_pd::Vec3& getOldHydrodynamicTorqueRef(const size_t p_idx) {return ps_->getOldHydrodynamicTorqueRef(p_idx);} void setOldHydrodynamicTorque(const size_t p_idx, walberla::mesa_pd::Vec3 const & v) { ps_->setOldHydrodynamicTorque(p_idx, v);} + walberla::mesa_pd::Vec3 const & getElectrostaticForce(const size_t p_idx) const {return ps_->getElectrostaticForce(p_idx);} + walberla::mesa_pd::Vec3& getElectrostaticForceRef(const size_t p_idx) {return ps_->getElectrostaticForceRef(p_idx);} + void setElectrostaticForce(const size_t p_idx, walberla::mesa_pd::Vec3 const & v) { ps_->setElectrostaticForce(p_idx, v);} + + walberla::real_t const & getTotalDisplacement(const size_t p_idx) const {return ps_->getTotalDisplacement(p_idx);} + walberla::real_t& getTotalDisplacementRef(const size_t p_idx) {return ps_->getTotalDisplacementRef(p_idx);} + void setTotalDisplacement(const size_t p_idx, walberla::real_t const & v) { ps_->setTotalDisplacement(p_idx, v);} + + walberla::real_t const & getCollisionForceNorm(const size_t p_idx) const {return ps_->getCollisionForceNorm(p_idx);} + walberla::real_t& getCollisionForceNormRef(const size_t p_idx) {return ps_->getCollisionForceNormRef(p_idx);} + void setCollisionForceNorm(const size_t p_idx, walberla::real_t const & v) { ps_->setCollisionForceNorm(p_idx, v);} + walberla::real_t const & getVirtualMass(const size_t p_idx) const {return ps_->getVirtualMass(p_idx);} walberla::real_t& getVirtualMassRef(const size_t p_idx) {return ps_->getVirtualMassRef(p_idx);} void setVirtualMass(const size_t p_idx, walberla::real_t const & v) { ps_->setVirtualMass(p_idx, v);} @@ -297,6 +313,10 @@ public: void setOldForce(const size_t /*p_idx*/, walberla::mesa_pd::Vec3 const & v) { oldForce_ = v;} walberla::mesa_pd::Vec3& getOldForceRef(const size_t /*p_idx*/) {return oldForce_;} + walberla::real_t const & getCharge(const size_t /*p_idx*/) const {return charge_;} + void setCharge(const size_t /*p_idx*/, walberla::real_t const & v) { charge_ = v;} + walberla::real_t& getChargeRef(const size_t /*p_idx*/) {return charge_;} + size_t const & getShapeID(const size_t /*p_idx*/) const {return shapeID_;} void setShapeID(const size_t /*p_idx*/, size_t const & v) { shapeID_ = v;} size_t& getShapeIDRef(const size_t /*p_idx*/) {return shapeID_;} @@ -381,6 +401,18 @@ public: void setOldHydrodynamicTorque(const size_t /*p_idx*/, walberla::mesa_pd::Vec3 const & v) { oldHydrodynamicTorque_ = v;} walberla::mesa_pd::Vec3& getOldHydrodynamicTorqueRef(const size_t /*p_idx*/) {return oldHydrodynamicTorque_;} + walberla::mesa_pd::Vec3 const & getElectrostaticForce(const size_t /*p_idx*/) const {return electrostaticForce_;} + void setElectrostaticForce(const size_t /*p_idx*/, walberla::mesa_pd::Vec3 const & v) { electrostaticForce_ = v;} + walberla::mesa_pd::Vec3& getElectrostaticForceRef(const size_t /*p_idx*/) {return electrostaticForce_;} + + walberla::real_t const & getTotalDisplacement(const size_t /*p_idx*/) const {return totalDisplacement_;} + void setTotalDisplacement(const size_t /*p_idx*/, walberla::real_t const & v) { totalDisplacement_ = v;} + walberla::real_t& getTotalDisplacementRef(const size_t /*p_idx*/) {return totalDisplacement_;} + + walberla::real_t const & getCollisionForceNorm(const size_t /*p_idx*/) const {return collisionForceNorm_;} + void setCollisionForceNorm(const size_t /*p_idx*/, walberla::real_t const & v) { collisionForceNorm_ = v;} + walberla::real_t& getCollisionForceNormRef(const size_t /*p_idx*/) {return collisionForceNorm_;} + walberla::real_t const & getVirtualMass(const size_t /*p_idx*/) const {return virtualMass_;} void setVirtualMass(const size_t /*p_idx*/, walberla::real_t const & v) { virtualMass_ = v;} walberla::real_t& getVirtualMassRef(const size_t /*p_idx*/) {return virtualMass_;} @@ -442,6 +474,7 @@ private: walberla::real_t invMass_; walberla::mesa_pd::Vec3 force_; walberla::mesa_pd::Vec3 oldForce_; + walberla::real_t charge_; size_t shapeID_; std::shared_ptr<walberla::mesa_pd::data::BaseShape> baseShape_; walberla::mesa_pd::Rot3 rotation_; @@ -463,6 +496,9 @@ private: walberla::mesa_pd::Vec3 hydrodynamicTorque_; walberla::mesa_pd::Vec3 oldHydrodynamicForce_; walberla::mesa_pd::Vec3 oldHydrodynamicTorque_; + walberla::mesa_pd::Vec3 electrostaticForce_; + walberla::real_t totalDisplacement_; + walberla::real_t collisionForceNorm_; walberla::real_t virtualMass_; walberla::real_t invMassIncludingVirtual_; walberla::mesa_pd::Vec3 oldLinearAcceleration_; diff --git a/src/mesa_pd/data/ParticleStorage.h b/src/mesa_pd/data/ParticleStorage.h index a25c9d29e0ccf2c5e4eb53e554a004116b7428c0..ef37bbe0303d22f5069dc54558d4c3c7acd2d37c 100644 --- a/src/mesa_pd/data/ParticleStorage.h +++ b/src/mesa_pd/data/ParticleStorage.h @@ -82,6 +82,7 @@ public: using invMass_type = walberla::real_t; using force_type = walberla::mesa_pd::Vec3; using oldForce_type = walberla::mesa_pd::Vec3; + using charge_type = walberla::real_t; using shapeID_type = size_t; using baseShape_type = std::shared_ptr<walberla::mesa_pd::data::BaseShape>; using rotation_type = walberla::mesa_pd::Rot3; @@ -103,6 +104,9 @@ public: using hydrodynamicTorque_type = walberla::mesa_pd::Vec3; using oldHydrodynamicForce_type = walberla::mesa_pd::Vec3; using oldHydrodynamicTorque_type = walberla::mesa_pd::Vec3; + using electrostaticForce_type = walberla::mesa_pd::Vec3; + using totalDisplacement_type = walberla::real_t; + using collisionForceNorm_type = walberla::real_t; using virtualMass_type = walberla::real_t; using invMassIncludingVirtual_type = walberla::real_t; using oldLinearAcceleration_type = walberla::mesa_pd::Vec3; @@ -155,6 +159,10 @@ public: oldForce_type& getOldForceRef() {return storage_.getOldForceRef(i_);} void setOldForce(oldForce_type const & v) { storage_.setOldForce(i_, v);} + charge_type const & getCharge() const {return storage_.getCharge(i_);} + charge_type& getChargeRef() {return storage_.getChargeRef(i_);} + void setCharge(charge_type const & v) { storage_.setCharge(i_, v);} + shapeID_type const & getShapeID() const {return storage_.getShapeID(i_);} shapeID_type& getShapeIDRef() {return storage_.getShapeIDRef(i_);} void setShapeID(shapeID_type const & v) { storage_.setShapeID(i_, v);} @@ -239,6 +247,18 @@ public: oldHydrodynamicTorque_type& getOldHydrodynamicTorqueRef() {return storage_.getOldHydrodynamicTorqueRef(i_);} void setOldHydrodynamicTorque(oldHydrodynamicTorque_type const & v) { storage_.setOldHydrodynamicTorque(i_, v);} + electrostaticForce_type const & getElectrostaticForce() const {return storage_.getElectrostaticForce(i_);} + electrostaticForce_type& getElectrostaticForceRef() {return storage_.getElectrostaticForceRef(i_);} + void setElectrostaticForce(electrostaticForce_type const & v) { storage_.setElectrostaticForce(i_, v);} + + totalDisplacement_type const & getTotalDisplacement() const {return storage_.getTotalDisplacement(i_);} + totalDisplacement_type& getTotalDisplacementRef() {return storage_.getTotalDisplacementRef(i_);} + void setTotalDisplacement(totalDisplacement_type const & v) { storage_.setTotalDisplacement(i_, v);} + + collisionForceNorm_type const & getCollisionForceNorm() const {return storage_.getCollisionForceNorm(i_);} + collisionForceNorm_type& getCollisionForceNormRef() {return storage_.getCollisionForceNormRef(i_);} + void setCollisionForceNorm(collisionForceNorm_type const & v) { storage_.setCollisionForceNorm(i_, v);} + virtualMass_type const & getVirtualMass() const {return storage_.getVirtualMass(i_);} virtualMass_type& getVirtualMassRef() {return storage_.getVirtualMassRef(i_);} void setVirtualMass(virtualMass_type const & v) { storage_.setVirtualMass(i_, v);} @@ -349,6 +369,7 @@ public: using invMass_type = walberla::real_t; using force_type = walberla::mesa_pd::Vec3; using oldForce_type = walberla::mesa_pd::Vec3; + using charge_type = walberla::real_t; using shapeID_type = size_t; using baseShape_type = std::shared_ptr<walberla::mesa_pd::data::BaseShape>; using rotation_type = walberla::mesa_pd::Rot3; @@ -370,6 +391,9 @@ public: using hydrodynamicTorque_type = walberla::mesa_pd::Vec3; using oldHydrodynamicForce_type = walberla::mesa_pd::Vec3; using oldHydrodynamicTorque_type = walberla::mesa_pd::Vec3; + using electrostaticForce_type = walberla::mesa_pd::Vec3; + using totalDisplacement_type = walberla::real_t; + using collisionForceNorm_type = walberla::real_t; using virtualMass_type = walberla::real_t; using invMassIncludingVirtual_type = walberla::real_t; using oldLinearAcceleration_type = walberla::mesa_pd::Vec3; @@ -422,6 +446,10 @@ public: oldForce_type& getOldForceRef(const size_t idx) {return oldForce_[idx];} void setOldForce(const size_t idx, oldForce_type const & v) { oldForce_[idx] = v; } + charge_type const & getCharge(const size_t idx) const {return charge_[idx];} + charge_type& getChargeRef(const size_t idx) {return charge_[idx];} + void setCharge(const size_t idx, charge_type const & v) { charge_[idx] = v; } + shapeID_type const & getShapeID(const size_t idx) const {return shapeID_[idx];} shapeID_type& getShapeIDRef(const size_t idx) {return shapeID_[idx];} void setShapeID(const size_t idx, shapeID_type const & v) { shapeID_[idx] = v; } @@ -506,6 +534,18 @@ public: oldHydrodynamicTorque_type& getOldHydrodynamicTorqueRef(const size_t idx) {return oldHydrodynamicTorque_[idx];} void setOldHydrodynamicTorque(const size_t idx, oldHydrodynamicTorque_type const & v) { oldHydrodynamicTorque_[idx] = v; } + electrostaticForce_type const & getElectrostaticForce(const size_t idx) const {return electrostaticForce_[idx];} + electrostaticForce_type& getElectrostaticForceRef(const size_t idx) {return electrostaticForce_[idx];} + void setElectrostaticForce(const size_t idx, electrostaticForce_type const & v) { electrostaticForce_[idx] = v; } + + totalDisplacement_type const & getTotalDisplacement(const size_t idx) const {return totalDisplacement_[idx];} + totalDisplacement_type& getTotalDisplacementRef(const size_t idx) {return totalDisplacement_[idx];} + void setTotalDisplacement(const size_t idx, totalDisplacement_type const & v) { totalDisplacement_[idx] = v; } + + collisionForceNorm_type const & getCollisionForceNorm(const size_t idx) const {return collisionForceNorm_[idx];} + collisionForceNorm_type& getCollisionForceNormRef(const size_t idx) {return collisionForceNorm_[idx];} + void setCollisionForceNorm(const size_t idx, collisionForceNorm_type const & v) { collisionForceNorm_[idx] = v; } + virtualMass_type const & getVirtualMass(const size_t idx) const {return virtualMass_[idx];} virtualMass_type& getVirtualMassRef(const size_t idx) {return virtualMass_[idx];} void setVirtualMass(const size_t idx, virtualMass_type const & v) { virtualMass_[idx] = v; } @@ -647,6 +687,7 @@ public: std::vector<invMass_type> invMass_ {}; std::vector<force_type> force_ {}; std::vector<oldForce_type> oldForce_ {}; + std::vector<charge_type> charge_ {}; std::vector<shapeID_type> shapeID_ {}; std::vector<baseShape_type> baseShape_ {}; std::vector<rotation_type> rotation_ {}; @@ -668,6 +709,9 @@ public: std::vector<hydrodynamicTorque_type> hydrodynamicTorque_ {}; std::vector<oldHydrodynamicForce_type> oldHydrodynamicForce_ {}; std::vector<oldHydrodynamicTorque_type> oldHydrodynamicTorque_ {}; + std::vector<electrostaticForce_type> electrostaticForce_ {}; + std::vector<totalDisplacement_type> totalDisplacement_ {}; + std::vector<collisionForceNorm_type> collisionForceNorm_ {}; std::vector<virtualMass_type> virtualMass_ {}; std::vector<invMassIncludingVirtual_type> invMassIncludingVirtual_ {}; std::vector<oldLinearAcceleration_type> oldLinearAcceleration_ {}; @@ -697,6 +741,7 @@ ParticleStorage::Particle& ParticleStorage::Particle::operator=(const ParticleSt getInvMassRef() = rhs.getInvMass(); getForceRef() = rhs.getForce(); getOldForceRef() = rhs.getOldForce(); + getChargeRef() = rhs.getCharge(); getShapeIDRef() = rhs.getShapeID(); getBaseShapeRef() = rhs.getBaseShape(); getRotationRef() = rhs.getRotation(); @@ -718,6 +763,9 @@ ParticleStorage::Particle& ParticleStorage::Particle::operator=(const ParticleSt getHydrodynamicTorqueRef() = rhs.getHydrodynamicTorque(); getOldHydrodynamicForceRef() = rhs.getOldHydrodynamicForce(); getOldHydrodynamicTorqueRef() = rhs.getOldHydrodynamicTorque(); + getElectrostaticForceRef() = rhs.getElectrostaticForce(); + getTotalDisplacementRef() = rhs.getTotalDisplacement(); + getCollisionForceNormRef() = rhs.getCollisionForceNorm(); getVirtualMassRef() = rhs.getVirtualMass(); getInvMassIncludingVirtualRef() = rhs.getInvMassIncludingVirtual(); getOldLinearAccelerationRef() = rhs.getOldLinearAcceleration(); @@ -744,6 +792,7 @@ ParticleStorage::Particle& ParticleStorage::Particle::operator=(ParticleStorage: getInvMassRef() = std::move(rhs.getInvMassRef()); getForceRef() = std::move(rhs.getForceRef()); getOldForceRef() = std::move(rhs.getOldForceRef()); + getChargeRef() = std::move(rhs.getChargeRef()); getShapeIDRef() = std::move(rhs.getShapeIDRef()); getBaseShapeRef() = std::move(rhs.getBaseShapeRef()); getRotationRef() = std::move(rhs.getRotationRef()); @@ -765,6 +814,9 @@ ParticleStorage::Particle& ParticleStorage::Particle::operator=(ParticleStorage: getHydrodynamicTorqueRef() = std::move(rhs.getHydrodynamicTorqueRef()); getOldHydrodynamicForceRef() = std::move(rhs.getOldHydrodynamicForceRef()); getOldHydrodynamicTorqueRef() = std::move(rhs.getOldHydrodynamicTorqueRef()); + getElectrostaticForceRef() = std::move(rhs.getElectrostaticForceRef()); + getTotalDisplacementRef() = std::move(rhs.getTotalDisplacementRef()); + getCollisionForceNormRef() = std::move(rhs.getCollisionForceNormRef()); getVirtualMassRef() = std::move(rhs.getVirtualMassRef()); getInvMassIncludingVirtualRef() = std::move(rhs.getInvMassIncludingVirtualRef()); getOldLinearAccelerationRef() = std::move(rhs.getOldLinearAccelerationRef()); @@ -792,6 +844,7 @@ void swap(ParticleStorage::Particle lhs, ParticleStorage::Particle rhs) std::swap(lhs.getInvMassRef(), rhs.getInvMassRef()); std::swap(lhs.getForceRef(), rhs.getForceRef()); std::swap(lhs.getOldForceRef(), rhs.getOldForceRef()); + std::swap(lhs.getChargeRef(), rhs.getChargeRef()); std::swap(lhs.getShapeIDRef(), rhs.getShapeIDRef()); std::swap(lhs.getBaseShapeRef(), rhs.getBaseShapeRef()); std::swap(lhs.getRotationRef(), rhs.getRotationRef()); @@ -813,6 +866,9 @@ void swap(ParticleStorage::Particle lhs, ParticleStorage::Particle rhs) std::swap(lhs.getHydrodynamicTorqueRef(), rhs.getHydrodynamicTorqueRef()); std::swap(lhs.getOldHydrodynamicForceRef(), rhs.getOldHydrodynamicForceRef()); std::swap(lhs.getOldHydrodynamicTorqueRef(), rhs.getOldHydrodynamicTorqueRef()); + std::swap(lhs.getElectrostaticForceRef(), rhs.getElectrostaticForceRef()); + std::swap(lhs.getTotalDisplacementRef(), rhs.getTotalDisplacementRef()); + std::swap(lhs.getCollisionForceNormRef(), rhs.getCollisionForceNormRef()); std::swap(lhs.getVirtualMassRef(), rhs.getVirtualMassRef()); std::swap(lhs.getInvMassIncludingVirtualRef(), rhs.getInvMassIncludingVirtualRef()); std::swap(lhs.getOldLinearAccelerationRef(), rhs.getOldLinearAccelerationRef()); @@ -840,6 +896,7 @@ std::ostream& operator<<( std::ostream& os, const ParticleStorage::Particle& p ) "invMass : " << p.getInvMass() << "\n" << "force : " << p.getForce() << "\n" << "oldForce : " << p.getOldForce() << "\n" << + "charge : " << p.getCharge() << "\n" << "shapeID : " << p.getShapeID() << "\n" << "baseShape : " << p.getBaseShape() << "\n" << "rotation : " << p.getRotation() << "\n" << @@ -861,6 +918,9 @@ std::ostream& operator<<( std::ostream& os, const ParticleStorage::Particle& p ) "hydrodynamicTorque : " << p.getHydrodynamicTorque() << "\n" << "oldHydrodynamicForce: " << p.getOldHydrodynamicForce() << "\n" << "oldHydrodynamicTorque: " << p.getOldHydrodynamicTorque() << "\n" << + "electrostaticForce : " << p.getElectrostaticForce() << "\n" << + "totalDisplacement : " << p.getTotalDisplacement() << "\n" << + "collisionForceNorm : " << p.getCollisionForceNorm() << "\n" << "virtualMass : " << p.getVirtualMass() << "\n" << "invMassIncludingVirtual: " << p.getInvMassIncludingVirtual() << "\n" << "oldLinearAcceleration: " << p.getOldLinearAcceleration() << "\n" << @@ -958,6 +1018,7 @@ inline ParticleStorage::iterator ParticleStorage::create(const id_t& uid) invMass_.emplace_back(real_t(1)); force_.emplace_back(real_t(0)); oldForce_.emplace_back(real_t(0)); + charge_.emplace_back(real_t(0)); shapeID_.emplace_back(); baseShape_.emplace_back(make_shared<walberla::mesa_pd::data::BaseShape>()); rotation_.emplace_back(); @@ -979,6 +1040,9 @@ inline ParticleStorage::iterator ParticleStorage::create(const id_t& uid) hydrodynamicTorque_.emplace_back(real_t(0)); oldHydrodynamicForce_.emplace_back(real_t(0)); oldHydrodynamicTorque_.emplace_back(real_t(0)); + electrostaticForce_.emplace_back(real_t(0)); + totalDisplacement_.emplace_back(real_t(0)); + collisionForceNorm_.emplace_back(real_t(0)); virtualMass_.emplace_back(real_t(0)); invMassIncludingVirtual_.emplace_back(real_t(0)); oldLinearAcceleration_.emplace_back(real_t(0)); @@ -1031,6 +1095,7 @@ inline ParticleStorage::iterator ParticleStorage::erase(iterator& it) invMass_.pop_back(); force_.pop_back(); oldForce_.pop_back(); + charge_.pop_back(); shapeID_.pop_back(); baseShape_.pop_back(); rotation_.pop_back(); @@ -1052,6 +1117,9 @@ inline ParticleStorage::iterator ParticleStorage::erase(iterator& it) hydrodynamicTorque_.pop_back(); oldHydrodynamicForce_.pop_back(); oldHydrodynamicTorque_.pop_back(); + electrostaticForce_.pop_back(); + totalDisplacement_.pop_back(); + collisionForceNorm_.pop_back(); virtualMass_.pop_back(); invMassIncludingVirtual_.pop_back(); oldLinearAcceleration_.pop_back(); @@ -1091,6 +1159,7 @@ inline void ParticleStorage::reserve(const size_t size) invMass_.reserve(size); force_.reserve(size); oldForce_.reserve(size); + charge_.reserve(size); shapeID_.reserve(size); baseShape_.reserve(size); rotation_.reserve(size); @@ -1112,6 +1181,9 @@ inline void ParticleStorage::reserve(const size_t size) hydrodynamicTorque_.reserve(size); oldHydrodynamicForce_.reserve(size); oldHydrodynamicTorque_.reserve(size); + electrostaticForce_.reserve(size); + totalDisplacement_.reserve(size); + collisionForceNorm_.reserve(size); virtualMass_.reserve(size); invMassIncludingVirtual_.reserve(size); oldLinearAcceleration_.reserve(size); @@ -1136,6 +1208,7 @@ inline void ParticleStorage::clear() invMass_.clear(); force_.clear(); oldForce_.clear(); + charge_.clear(); shapeID_.clear(); baseShape_.clear(); rotation_.clear(); @@ -1157,6 +1230,9 @@ inline void ParticleStorage::clear() hydrodynamicTorque_.clear(); oldHydrodynamicForce_.clear(); oldHydrodynamicTorque_.clear(); + electrostaticForce_.clear(); + totalDisplacement_.clear(); + collisionForceNorm_.clear(); virtualMass_.clear(); invMassIncludingVirtual_.clear(); oldLinearAcceleration_.clear(); @@ -1182,6 +1258,7 @@ inline size_t ParticleStorage::size() const //WALBERLA_ASSERT_EQUAL( uid_.size(), invMass.size() ); //WALBERLA_ASSERT_EQUAL( uid_.size(), force.size() ); //WALBERLA_ASSERT_EQUAL( uid_.size(), oldForce.size() ); + //WALBERLA_ASSERT_EQUAL( uid_.size(), charge.size() ); //WALBERLA_ASSERT_EQUAL( uid_.size(), shapeID.size() ); //WALBERLA_ASSERT_EQUAL( uid_.size(), baseShape.size() ); //WALBERLA_ASSERT_EQUAL( uid_.size(), rotation.size() ); @@ -1203,6 +1280,9 @@ inline size_t ParticleStorage::size() const //WALBERLA_ASSERT_EQUAL( uid_.size(), hydrodynamicTorque.size() ); //WALBERLA_ASSERT_EQUAL( uid_.size(), oldHydrodynamicForce.size() ); //WALBERLA_ASSERT_EQUAL( uid_.size(), oldHydrodynamicTorque.size() ); + //WALBERLA_ASSERT_EQUAL( uid_.size(), electrostaticForce.size() ); + //WALBERLA_ASSERT_EQUAL( uid_.size(), totalDisplacement.size() ); + //WALBERLA_ASSERT_EQUAL( uid_.size(), collisionForceNorm.size() ); //WALBERLA_ASSERT_EQUAL( uid_.size(), virtualMass.size() ); //WALBERLA_ASSERT_EQUAL( uid_.size(), invMassIncludingVirtual.size() ); //WALBERLA_ASSERT_EQUAL( uid_.size(), oldLinearAcceleration.size() ); @@ -1469,6 +1549,15 @@ public: walberla::mesa_pd::Vec3 const & operator()(const data::Particle& p) const {return p.getOldForce();} }; ///Predicate that selects a certain property from a Particle +class SelectParticleCharge +{ +public: + using return_type = walberla::real_t; + walberla::real_t& operator()(data::Particle& p) const {return p.getChargeRef();} + walberla::real_t& operator()(data::Particle&& p) const {return p.getChargeRef();} + walberla::real_t const & operator()(const data::Particle& p) const {return p.getCharge();} +}; +///Predicate that selects a certain property from a Particle class SelectParticleShapeID { public: @@ -1658,6 +1747,33 @@ public: walberla::mesa_pd::Vec3 const & operator()(const data::Particle& p) const {return p.getOldHydrodynamicTorque();} }; ///Predicate that selects a certain property from a Particle +class SelectParticleElectrostaticForce +{ +public: + using return_type = walberla::mesa_pd::Vec3; + walberla::mesa_pd::Vec3& operator()(data::Particle& p) const {return p.getElectrostaticForceRef();} + walberla::mesa_pd::Vec3& operator()(data::Particle&& p) const {return p.getElectrostaticForceRef();} + walberla::mesa_pd::Vec3 const & operator()(const data::Particle& p) const {return p.getElectrostaticForce();} +}; +///Predicate that selects a certain property from a Particle +class SelectParticleTotalDisplacement +{ +public: + using return_type = walberla::real_t; + walberla::real_t& operator()(data::Particle& p) const {return p.getTotalDisplacementRef();} + walberla::real_t& operator()(data::Particle&& p) const {return p.getTotalDisplacementRef();} + walberla::real_t const & operator()(const data::Particle& p) const {return p.getTotalDisplacement();} +}; +///Predicate that selects a certain property from a Particle +class SelectParticleCollisionForceNorm +{ +public: + using return_type = walberla::real_t; + walberla::real_t& operator()(data::Particle& p) const {return p.getCollisionForceNormRef();} + walberla::real_t& operator()(data::Particle&& p) const {return p.getCollisionForceNormRef();} + walberla::real_t const & operator()(const data::Particle& p) const {return p.getCollisionForceNorm();} +}; +///Predicate that selects a certain property from a Particle class SelectParticleVirtualMass { public: diff --git a/src/mesa_pd/kernel/LinearSpringDashpot.h b/src/mesa_pd/kernel/LinearSpringDashpot.h index db9ca2e902bbf53ebba37a850875a5cf04bde4a8..5907132172d45aa0a9f58685fde5c1ba9aebd124 100644 --- a/src/mesa_pd/kernel/LinearSpringDashpot.h +++ b/src/mesa_pd/kernel/LinearSpringDashpot.h @@ -344,7 +344,8 @@ inline void LinearSpringDashpot::operator()(const size_t p_idx1, const real_t fTabs( std::min( fTLS.length(), fFrictionAbs) ); const Vec3 fT ( fTabs * t ); - //TODO check if tangential spring displacement is same for symmetric case + // TODO check if tangential spring displacement is same for symmetric case + // TODO: check why exactly this critical section is needed auto& ch1 = ac.getNewContactHistoryRef(p_idx1)[ac.getUid(p_idx2)]; ch1.setTangentialSpringDisplacement(newTangentialSpringDisplacement); ch1.setIsSticking(isSticking); diff --git a/src/mesa_pd/mpi/notifications/CMakeLists.txt b/src/mesa_pd/mpi/notifications/CMakeLists.txt index c50238b775c0bc00aa6986c8c471ab237ba296f0..16e1bac3779869d71835a318d0ba9b758bd47a35 100644 --- a/src/mesa_pd/mpi/notifications/CMakeLists.txt +++ b/src/mesa_pd/mpi/notifications/CMakeLists.txt @@ -17,5 +17,6 @@ target_sources( mesa_pd HydrodynamicForceTorqueNotification.h reset.h ForceTorqueNotification.h - NotificationType.h + NotificationType.h + ElectrostaticForceNotification.h ) diff --git a/src/mesa_pd/mpi/notifications/ElectrostaticForceNotification.h b/src/mesa_pd/mpi/notifications/ElectrostaticForceNotification.h new file mode 100644 index 0000000000000000000000000000000000000000..91eb0d71c7f4afbe9978fd14910cab83a06516bc --- /dev/null +++ b/src/mesa_pd/mpi/notifications/ElectrostaticForceNotification.h @@ -0,0 +1,114 @@ +//====================================================================================================================== +// +// This file is part of waLBerla. waLBerla 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. +// +// waLBerla 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 waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file +//! \author Sebastian Eibl <sebastian.eibl@fau.de> +// +//====================================================================================================================== + +//====================================================================================================================== +// +// THIS FILE IS GENERATED - PLEASE CHANGE THE TEMPLATE !!! +// +//====================================================================================================================== + +#pragma once + +#include <mesa_pd/data/DataTypes.h> +#include <mesa_pd/data/ParticleStorage.h> +#include <mesa_pd/mpi/notifications/NotificationType.h> +#include <mesa_pd/mpi/notifications/reset.h> + +#include <core/mpi/Datatype.h> +#include <core/mpi/RecvBuffer.h> +#include <core/mpi/SendBuffer.h> + +namespace walberla { +namespace mesa_pd { + +/** + * Transmits force and torque information. + */ +class ElectrostaticForceNotification +{ +public: + struct Parameters + { + id_t uid_; + mesa_pd::Vec3 electrostaticForce_; + }; + + inline explicit ElectrostaticForceNotification( const data::Particle& p ) : p_(p) {} + + const data::Particle& p_; +}; + +template <> +void reset<ElectrostaticForceNotification>(data::Particle& p) +{ + p.setElectrostaticForce( Vec3(real_t(0)) ); +} + +void reduce(data::Particle&& p, const ElectrostaticForceNotification::Parameters& objparam) +{ + p.getElectrostaticForceRef() += objparam.electrostaticForce_; +} + +void update(data::Particle&& p, const ElectrostaticForceNotification::Parameters& objparam) +{ + p.setElectrostaticForce( objparam.electrostaticForce_ ); +} + +} // namespace mesa_pd +} // namespace walberla + +//====================================================================================================================== +// +// Send/Recv Buffer Serialization Specialization +// +//====================================================================================================================== + +namespace walberla { +namespace mpi { + +template< typename T, // Element type of SendBuffer + typename G> // Growth policy of SendBuffer +mpi::GenericSendBuffer<T,G>& operator<<( mpi::GenericSendBuffer<T,G> & buf, const mesa_pd::ElectrostaticForceNotification& obj ) +{ + buf.addDebugMarker( "pn" ); + buf << obj.p_.getUid(); + buf << obj.p_.getElectrostaticForce(); + return buf; +} + +template< typename T> // Element type of RecvBuffer +mpi::GenericRecvBuffer<T>& operator>>( mpi::GenericRecvBuffer<T> & buf, mesa_pd::ElectrostaticForceNotification::Parameters& objparam ) +{ + buf.readDebugMarker( "pn" ); + buf >> objparam.uid_; + buf >> objparam.electrostaticForce_; + return buf; +} + +template< > +struct BufferSizeTrait< mesa_pd::ElectrostaticForceNotification > { + static const bool constantSize = true; + static const uint_t size = BufferSizeTrait<id_t>::size + + BufferSizeTrait<mesa_pd::Vec3>::size + + mpi::BUFFER_DEBUG_OVERHEAD; +}; + +} // mpi +} // walberla \ No newline at end of file diff --git a/src/mesa_pd/mpi/notifications/ParseMessage.h b/src/mesa_pd/mpi/notifications/ParseMessage.h index ed3124bf252166d98114bc90d640531ebc002d91..082b02909d7068c79846b0a1a0776c99b4fc68ae 100644 --- a/src/mesa_pd/mpi/notifications/ParseMessage.h +++ b/src/mesa_pd/mpi/notifications/ParseMessage.h @@ -115,6 +115,7 @@ void ParseMessage::operator()(int sender, pIt->setUid(objparam.uid); pIt->setPosition(objparam.position); pIt->setLinearVelocity(objparam.linearVelocity); + pIt->setCharge(objparam.charge); pIt->setRotation(objparam.rotation); pIt->setAngularVelocity(objparam.angularVelocity); pIt->setRadiusAtTemperature(objparam.radiusAtTemperature); @@ -153,6 +154,9 @@ void ParseMessage::operator()(int sender, pIt->setHydrodynamicTorque(objparam.hydrodynamicTorque_); pIt->setOldHydrodynamicForce(objparam.oldHydrodynamicForce_); pIt->setOldHydrodynamicTorque(objparam.oldHydrodynamicTorque_); + pIt->setElectrostaticForce(objparam.electrostaticForce_); + pIt->setTotalDisplacement(objparam.totalDisplacement_); + pIt->setCollisionForceNorm(objparam.collisionForceNorm_); pIt->setVirtualMass(objparam.virtualMass_); pIt->setInvMassIncludingVirtual(objparam.invMassIncludingVirtual_); pIt->setOldLinearAcceleration(objparam.oldLinearAcceleration_); diff --git a/src/mesa_pd/mpi/notifications/ParticleCopyNotification.h b/src/mesa_pd/mpi/notifications/ParticleCopyNotification.h index 78de9c6eaee587fe1a1fffca9a193dfcba4a6354..23d085b51440a2db1da7ca731530072378816372 100644 --- a/src/mesa_pd/mpi/notifications/ParticleCopyNotification.h +++ b/src/mesa_pd/mpi/notifications/ParticleCopyNotification.h @@ -57,6 +57,7 @@ public: walberla::mesa_pd::Vec3 linearVelocity {real_t(0)}; walberla::real_t invMass {real_t(1)}; walberla::mesa_pd::Vec3 oldForce {real_t(0)}; + walberla::real_t charge {real_t(0)}; size_t shapeID {}; std::shared_ptr<walberla::mesa_pd::data::BaseShape> baseShape {make_shared<walberla::mesa_pd::data::BaseShape>()}; walberla::mesa_pd::Rot3 rotation {}; @@ -70,6 +71,9 @@ public: walberla::mesa_pd::Vec3 hydrodynamicTorque {real_t(0)}; walberla::mesa_pd::Vec3 oldHydrodynamicForce {real_t(0)}; walberla::mesa_pd::Vec3 oldHydrodynamicTorque {real_t(0)}; + walberla::mesa_pd::Vec3 electrostaticForce {real_t(0)}; + walberla::real_t totalDisplacement {real_t(0)}; + walberla::real_t collisionForceNorm {real_t(0)}; walberla::real_t virtualMass {real_t(0)}; walberla::real_t invMassIncludingVirtual {real_t(0)}; walberla::mesa_pd::Vec3 oldLinearAcceleration {real_t(0)}; @@ -99,6 +103,7 @@ inline data::ParticleStorage::iterator createNewParticle(data::ParticleStorage& pIt->setLinearVelocity(data.linearVelocity); pIt->setInvMass(data.invMass); pIt->setOldForce(data.oldForce); + pIt->setCharge(data.charge); pIt->setShapeID(data.shapeID); pIt->setBaseShape(data.baseShape); pIt->setRotation(data.rotation); @@ -112,6 +117,9 @@ inline data::ParticleStorage::iterator createNewParticle(data::ParticleStorage& pIt->setHydrodynamicTorque(data.hydrodynamicTorque); pIt->setOldHydrodynamicForce(data.oldHydrodynamicForce); pIt->setOldHydrodynamicTorque(data.oldHydrodynamicTorque); + pIt->setElectrostaticForce(data.electrostaticForce); + pIt->setTotalDisplacement(data.totalDisplacement); + pIt->setCollisionForceNorm(data.collisionForceNorm); pIt->setVirtualMass(data.virtualMass); pIt->setInvMassIncludingVirtual(data.invMassIncludingVirtual); pIt->setOldLinearAcceleration(data.oldLinearAcceleration); @@ -156,6 +164,7 @@ mpi::GenericSendBuffer<T,G>& operator<<( mpi::GenericSendBuffer<T,G> & buf, cons buf << obj.particle_.getLinearVelocity(); buf << obj.particle_.getInvMass(); buf << obj.particle_.getOldForce(); + buf << obj.particle_.getCharge(); buf << obj.particle_.getShapeID(); buf << obj.particle_.getBaseShape(); buf << obj.particle_.getRotation(); @@ -169,6 +178,9 @@ mpi::GenericSendBuffer<T,G>& operator<<( mpi::GenericSendBuffer<T,G> & buf, cons buf << obj.particle_.getHydrodynamicTorque(); buf << obj.particle_.getOldHydrodynamicForce(); buf << obj.particle_.getOldHydrodynamicTorque(); + buf << obj.particle_.getElectrostaticForce(); + buf << obj.particle_.getTotalDisplacement(); + buf << obj.particle_.getCollisionForceNorm(); buf << obj.particle_.getVirtualMass(); buf << obj.particle_.getInvMassIncludingVirtual(); buf << obj.particle_.getOldLinearAcceleration(); @@ -194,6 +206,7 @@ mpi::GenericRecvBuffer<T>& operator>>( mpi::GenericRecvBuffer<T> & buf, mesa_pd: buf >> objparam.linearVelocity; buf >> objparam.invMass; buf >> objparam.oldForce; + buf >> objparam.charge; buf >> objparam.shapeID; buf >> objparam.baseShape; buf >> objparam.rotation; @@ -207,6 +220,9 @@ mpi::GenericRecvBuffer<T>& operator>>( mpi::GenericRecvBuffer<T> & buf, mesa_pd: buf >> objparam.hydrodynamicTorque; buf >> objparam.oldHydrodynamicForce; buf >> objparam.oldHydrodynamicTorque; + buf >> objparam.electrostaticForce; + buf >> objparam.totalDisplacement; + buf >> objparam.collisionForceNorm; buf >> objparam.virtualMass; buf >> objparam.invMassIncludingVirtual; buf >> objparam.oldLinearAcceleration; diff --git a/src/mesa_pd/mpi/notifications/ParticleGhostCopyNotification.h b/src/mesa_pd/mpi/notifications/ParticleGhostCopyNotification.h index fa87d8571fd11db5aa83b881a9461d9befb7bc3b..12ee33efad8e64abfeee2250226525b848381d4d 100644 --- a/src/mesa_pd/mpi/notifications/ParticleGhostCopyNotification.h +++ b/src/mesa_pd/mpi/notifications/ParticleGhostCopyNotification.h @@ -55,6 +55,7 @@ public: int owner {-1}; walberla::mesa_pd::Vec3 linearVelocity {real_t(0)}; walberla::real_t invMass {real_t(1)}; + walberla::real_t charge {real_t(0)}; size_t shapeID {}; std::shared_ptr<walberla::mesa_pd::data::BaseShape> baseShape {make_shared<walberla::mesa_pd::data::BaseShape>()}; walberla::mesa_pd::Rot3 rotation {}; @@ -83,6 +84,7 @@ inline data::ParticleStorage::iterator createNewParticle(data::ParticleStorage& pIt->setOwner(data.owner); pIt->setLinearVelocity(data.linearVelocity); pIt->setInvMass(data.invMass); + pIt->setCharge(data.charge); pIt->setShapeID(data.shapeID); pIt->setBaseShape(data.baseShape); pIt->setRotation(data.rotation); @@ -126,6 +128,7 @@ mpi::GenericSendBuffer<T,G>& operator<<( mpi::GenericSendBuffer<T,G> & buf, cons buf << obj.particle_.getOwner(); buf << obj.particle_.getLinearVelocity(); buf << obj.particle_.getInvMass(); + buf << obj.particle_.getCharge(); buf << obj.particle_.getShapeID(); buf << obj.particle_.getBaseShape(); buf << obj.particle_.getRotation(); @@ -150,6 +153,7 @@ mpi::GenericRecvBuffer<T>& operator>>( mpi::GenericRecvBuffer<T> & buf, mesa_pd: buf >> objparam.owner; buf >> objparam.linearVelocity; buf >> objparam.invMass; + buf >> objparam.charge; buf >> objparam.shapeID; buf >> objparam.baseShape; buf >> objparam.rotation; diff --git a/src/mesa_pd/mpi/notifications/ParticleMigrationNotification.h b/src/mesa_pd/mpi/notifications/ParticleMigrationNotification.h index d7cf2b54d86bc57b5875130e5f7edf3c0f8d98b0..efaf5ff61897b6548fe2b0e47abfcc159ca9cbd6 100644 --- a/src/mesa_pd/mpi/notifications/ParticleMigrationNotification.h +++ b/src/mesa_pd/mpi/notifications/ParticleMigrationNotification.h @@ -52,6 +52,9 @@ public: walberla::mesa_pd::Vec3 hydrodynamicTorque_ {real_t(0)}; walberla::mesa_pd::Vec3 oldHydrodynamicForce_ {real_t(0)}; walberla::mesa_pd::Vec3 oldHydrodynamicTorque_ {real_t(0)}; + walberla::mesa_pd::Vec3 electrostaticForce_ {real_t(0)}; + walberla::real_t totalDisplacement_ {real_t(0)}; + walberla::real_t collisionForceNorm_ {real_t(0)}; walberla::real_t virtualMass_ {real_t(0)}; walberla::real_t invMassIncludingVirtual_ {real_t(0)}; walberla::mesa_pd::Vec3 oldLinearAcceleration_ {real_t(0)}; @@ -96,6 +99,9 @@ mpi::GenericSendBuffer<T,G>& operator<<( mpi::GenericSendBuffer<T,G> & buf, cons buf << obj.particle_.getHydrodynamicTorque(); buf << obj.particle_.getOldHydrodynamicForce(); buf << obj.particle_.getOldHydrodynamicTorque(); + buf << obj.particle_.getElectrostaticForce(); + buf << obj.particle_.getTotalDisplacement(); + buf << obj.particle_.getCollisionForceNorm(); buf << obj.particle_.getVirtualMass(); buf << obj.particle_.getInvMassIncludingVirtual(); buf << obj.particle_.getOldLinearAcceleration(); @@ -118,6 +124,9 @@ mpi::GenericRecvBuffer<T>& operator>>( mpi::GenericRecvBuffer<T> & buf, mesa_pd: buf >> objparam.hydrodynamicTorque_; buf >> objparam.oldHydrodynamicForce_; buf >> objparam.oldHydrodynamicTorque_; + buf >> objparam.electrostaticForce_; + buf >> objparam.totalDisplacement_; + buf >> objparam.collisionForceNorm_; buf >> objparam.virtualMass_; buf >> objparam.invMassIncludingVirtual_; buf >> objparam.oldLinearAcceleration_; diff --git a/src/mesa_pd/mpi/notifications/ParticleUpdateNotification.h b/src/mesa_pd/mpi/notifications/ParticleUpdateNotification.h index 95d0d7e37acc742b4cff1fce9442398f9a3a3042..73bc47acfc62602e7d3130c9ad09362efd18500f 100644 --- a/src/mesa_pd/mpi/notifications/ParticleUpdateNotification.h +++ b/src/mesa_pd/mpi/notifications/ParticleUpdateNotification.h @@ -48,6 +48,7 @@ public: walberla::id_t uid {UniqueID<data::Particle>::invalidID()}; walberla::mesa_pd::Vec3 position {real_t(0)}; walberla::mesa_pd::Vec3 linearVelocity {real_t(0)}; + walberla::real_t charge {real_t(0)}; walberla::mesa_pd::Rot3 rotation {}; walberla::mesa_pd::Vec3 angularVelocity {real_t(0)}; walberla::real_t radiusAtTemperature {real_t(0)}; @@ -85,6 +86,7 @@ mpi::GenericSendBuffer<T,G>& operator<<( mpi::GenericSendBuffer<T,G> & buf, cons buf << obj.particle_.getUid(); buf << obj.particle_.getPosition(); buf << obj.particle_.getLinearVelocity(); + buf << obj.particle_.getCharge(); buf << obj.particle_.getRotation(); buf << obj.particle_.getAngularVelocity(); buf << obj.particle_.getRadiusAtTemperature(); @@ -100,6 +102,7 @@ mpi::GenericRecvBuffer<T>& operator>>( mpi::GenericRecvBuffer<T> & buf, mesa_pd: buf >> objparam.uid; buf >> objparam.position; buf >> objparam.linearVelocity; + buf >> objparam.charge; buf >> objparam.rotation; buf >> objparam.angularVelocity; buf >> objparam.radiusAtTemperature; diff --git a/tests/lbm_mesapd_coupling/CMakeLists.txt b/tests/lbm_mesapd_coupling/CMakeLists.txt index 94438a2d9863101d05ea984eb59ff3f58f6aad2c..b6c8f15397a1317a5643d488b8b685f0fe37e43a 100644 --- a/tests/lbm_mesapd_coupling/CMakeLists.txt +++ b/tests/lbm_mesapd_coupling/CMakeLists.txt @@ -7,13 +7,13 @@ waLBerla_compile_test( NAME LBM_MESAPD_COUPLING_Mapping FILES mapping/ParticleMapping.cpp DEPENDS core mesa_pd lbm lbm_mesapd_coupling domain_decomposition field ) waLBerla_execute_test( NAME LBM_MESAPD_COUPLING_Mapping PROCESSES 3) -waLBerla_compile_test( NAME LBM_MESAPD_COUPLING_MEM_MovingMapping FILES momentum_exchange_method/MovingParticleMapping.cpp DEPENDS core mesa_pd lbm lbm_mesapd_coupling domain_decomposition field vtk) +waLBerla_compile_test( NAME LBM_MESAPD_COUPLING_MEM_MovingMapping FILES momentum_exchange_method/MovingParticleMappingMEM.cpp DEPENDS core mesa_pd lbm lbm_mesapd_coupling domain_decomposition field vtk) waLBerla_execute_test( NAME LBM_MESAPD_COUPLING_MEM_MovingMapping PROCESSES 3) -waLBerla_compile_test( NAME LBM_MESAPD_COUPLING_MEM_DragForceSphere FILES momentum_exchange_method/DragForceSphere.cpp DEPENDS core mesa_pd lbm lbm_mesapd_coupling domain_decomposition field vtk ) +waLBerla_compile_test( NAME LBM_MESAPD_COUPLING_MEM_DragForceSphere FILES momentum_exchange_method/DragForceSphereMEM.cpp DEPENDS core mesa_pd lbm lbm_mesapd_coupling domain_decomposition field vtk ) waLBerla_execute_test( NAME LBM_MESAPD_COUPLING_MEM_DragForceSphere COMMAND $<TARGET_FILE:LBM_MESAPD_COUPLING_MEM_DragForceSphere> --funcTest PROCESSES 2) -waLBerla_compile_test( NAME LBM_MESAPD_COUPLING_MEM_ForceTwoStatObjs FILES momentum_exchange_method/ForceBetweenTwoStationaryObjects.cpp DEPENDS core mesa_pd lbm lbm_mesapd_coupling domain_decomposition field vtk ) +waLBerla_compile_test( NAME LBM_MESAPD_COUPLING_MEM_ForceTwoStatObjs FILES momentum_exchange_method/ForceBetweenTwoStationaryObjectsMEM.cpp DEPENDS core mesa_pd lbm lbm_mesapd_coupling domain_decomposition field vtk ) waLBerla_execute_test( NAME LBM_MESAPD_COUPLING_MEM_ForceTwoStatObjsSS1 COMMAND $<TARGET_FILE:LBM_MESAPD_COUPLING_MEM_ForceTwoStatObjs> PROCESSES 1) waLBerla_execute_test( NAME LBM_MESAPD_COUPLING_MEM_ForceTwoStatObjsSS2 COMMAND $<TARGET_FILE:LBM_MESAPD_COUPLING_MEM_ForceTwoStatObjs> --useSBB PROCESSES 1) waLBerla_execute_test( NAME LBM_MESAPD_COUPLING_MEM_ForceTwoStatObjsSS3 COMMAND $<TARGET_FILE:LBM_MESAPD_COUPLING_MEM_ForceTwoStatObjs> --useCompressible PROCESSES 1) @@ -23,13 +23,13 @@ waLBerla_execute_test( NAME LBM_MESAPD_COUPLING_MEM_ForceTwoStatObjsSW2 COMMAND waLBerla_execute_test( NAME LBM_MESAPD_COUPLING_MEM_ForceTwoStatObjsSW3 COMMAND $<TARGET_FILE:LBM_MESAPD_COUPLING_MEM_ForceTwoStatObjs> --useSphereWallSetup --useCompressible PROCESSES 1) waLBerla_execute_test( NAME LBM_MESAPD_COUPLING_MEM_ForceTwoStatObjsSW4 COMMAND $<TARGET_FILE:LBM_MESAPD_COUPLING_MEM_ForceTwoStatObjs> --useSphereWallSetup --systemVelocity 0.1 PROCESSES 1) -waLBerla_compile_test( NAME LBM_MESAPD_COUPLING_MEM_SettlingSphere FILES momentum_exchange_method/SettlingSphere.cpp DEPENDS core mesa_pd lbm lbm_mesapd_coupling domain_decomposition field vtk ) +waLBerla_compile_test( NAME LBM_MESAPD_COUPLING_MEM_SettlingSphere FILES momentum_exchange_method/SettlingSphereMEM.cpp DEPENDS core mesa_pd lbm lbm_mesapd_coupling domain_decomposition field vtk ) waLBerla_execute_test( NAME LBM_MESAPD_COUPLING_MEM_SettlingSphere COMMAND $<TARGET_FILE:LBM_MESAPD_COUPLING_MEM_SettlingSphere> --funcTest PROCESSES 4) -waLBerla_compile_test( NAME LBM_MESAPD_COUPLING_MEM_PdfReconstruction FILES momentum_exchange_method/PdfReconstruction.cpp DEPENDS core mesa_pd lbm lbm_mesapd_coupling domain_decomposition field vtk) +waLBerla_compile_test( NAME LBM_MESAPD_COUPLING_MEM_PdfReconstruction FILES momentum_exchange_method/PdfReconstructionMEM.cpp DEPENDS core mesa_pd lbm lbm_mesapd_coupling domain_decomposition field vtk) waLBerla_execute_test( NAME LBM_MESAPD_COUPLING_MEM_PdfReconstruction PROCESSES 3) -waLBerla_compile_test( NAME LBM_MESAPD_COUPLING_MEM_UpdateParticleMapping FILES momentum_exchange_method/UpdateParticleMapping.cpp DEPENDS core mesa_pd lbm lbm_mesapd_coupling domain_decomposition field vtk) +waLBerla_compile_test( NAME LBM_MESAPD_COUPLING_MEM_UpdateParticleMapping FILES momentum_exchange_method/UpdateParticleMappingMEM.cpp DEPENDS core mesa_pd lbm lbm_mesapd_coupling domain_decomposition field vtk) waLBerla_execute_test( NAME LBM_MESAPD_COUPLING_MEM_UpdateParticleMapping PROCESSES 1) waLBerla_compile_test( NAME LBM_MESAPD_COUPLING_UTIL_LubricationCorrection FILES utility/LubricationCorrection.cpp DEPENDS mesa_pd lbm_mesapd_coupling ) @@ -47,18 +47,21 @@ waLBerla_execute_test( NAME LBM_MESAPD_COUPLING_UTIL_HydForceMultBlocks_VVAvg CO waLBerla_execute_test( NAME LBM_MESAPD_COUPLING_UTIL_HydForceMultBlocks_EulerNoAvg COMMAND $<TARGET_FILE:LBM_MESAPD_COUPLING_UTIL_HydForceMultBlocks> --noForceAveraging PROCESSES 4 ) waLBerla_execute_test( NAME LBM_MESAPD_COUPLING_UTIL_HydForceMultBlocks_VVNoAvg COMMAND $<TARGET_FILE:LBM_MESAPD_COUPLING_UTIL_HydForceMultBlocks> --noForceAveraging --useVV PROCESSES 4 ) -waLBerla_compile_test( NAME LBM_MESAPD_COUPLING_PSM_BodyAndVolumeFractionMapping FILES partially_saturated_cells_method/ParticleAndVolumeFractionMapping.cpp DEPENDS blockforest boundary core field lbm_mesapd_coupling stencil mesa_pd ) -waLBerla_execute_test( NAME LBM_MESAPD_COUPLING_PSM_BodyAndVolumeFractionMapping PROCESSES 27 ) +waLBerla_compile_test( NAME LBM_MESAPD_COUPLING_PSM_ParticleAndVolumeFractionMapping FILES partially_saturated_cells_method/ParticleAndVolumeFractionMappingPSM.cpp DEPENDS blockforest boundary core field lbm_mesapd_coupling stencil mesa_pd ) +waLBerla_execute_test( NAME LBM_MESAPD_COUPLING_PSM_ParticleAndVolumeFractionMapping COMMAND $<TARGET_FILE:LBM_MESAPD_COUPLING_PSM_ParticleAndVolumeFractionMapping> PROCESSES 27 ) -waLBerla_compile_test( NAME LBM_MESAPD_COUPLING_PSM_DragForceSphere FILES partially_saturated_cells_method/DragForceSphere.cpp DEPENDS blockforest boundary core field lbm lbm_mesapd_coupling timeloop mesa_pd ) +waLBerla_compile_test( NAME LBM_MESAPD_COUPLING_PSM_ParticleAndVolumeFractionMapping_CPU_GPU FILES partially_saturated_cells_method/codegen/ParticleAndVolumeFractionMapping.cpp DEPENDS blockforest boundary core gpu field lbm_mesapd_coupling stencil mesa_pd ) +waLBerla_execute_test( NAME LBM_MESAPD_COUPLING_PSM_ParticleAndVolumeFractionMapping_CPU_GPU COMMAND $<TARGET_FILE:LBM_MESAPD_COUPLING_PSM_ParticleAndVolumeFractionMapping_CPU_GPU> PROCESSES 27 ) + +waLBerla_compile_test( NAME LBM_MESAPD_COUPLING_PSM_DragForceSphere FILES partially_saturated_cells_method/DragForceSpherePSM.cpp DEPENDS blockforest boundary core field lbm lbm_mesapd_coupling timeloop mesa_pd ) waLBerla_execute_test( NAME LBM_MESAPD_COUPLING_PSM_DragForceSphereFuncTest COMMAND $<TARGET_FILE:LBM_MESAPD_COUPLING_PSM_DragForceSphere> --funcTest PROCESSES 8 ) waLBerla_execute_test( NAME LBM_MESAPD_COUPLING_PSM_DragForceSphere COMMAND $<TARGET_FILE:LBM_MESAPD_COUPLING_PSM_DragForceSphere> PROCESSES 8 LABELS longrun CONFIGURATIONS Release RelWithDbgInfo) -waLBerla_compile_test( NAME LBM_MESAPD_COUPLING_PSM_SettlingSphere FILES partially_saturated_cells_method/SettlingSphere.cpp DEPENDS blockforest boundary core domain_decomposition field lbm lbm_mesapd_coupling timeloop mesa_pd ) +waLBerla_compile_test( NAME LBM_MESAPD_COUPLING_PSM_SettlingSphere FILES partially_saturated_cells_method/SettlingSpherePSM.cpp DEPENDS blockforest boundary core domain_decomposition field lbm lbm_mesapd_coupling timeloop mesa_pd ) waLBerla_execute_test( NAME LBM_MESAPD_COUPLING_PSM_SettlingSphereFuncTest COMMAND $<TARGET_FILE:LBM_MESAPD_COUPLING_PSM_SettlingSphere> --funcTest PROCESSES 4 ) waLBerla_execute_test( NAME LBM_MESAPD_COUPLING_PSM_SettlingSphere COMMAND $<TARGET_FILE:LBM_MESAPD_COUPLING_PSM_SettlingSphere> --resolution 70 PROCESSES 4 LABELS longrun CONFIGURATIONS Release RelWithDbgInfo ) -waLBerla_compile_test( NAME LBM_MESAPD_COUPLING_PSM_TorqueSphere FILES partially_saturated_cells_method/TorqueSphere.cpp DEPENDS blockforest boundary core domain_decomposition field lbm stencil timeloop ) +waLBerla_compile_test( NAME LBM_MESAPD_COUPLING_PSM_TorqueSphere FILES partially_saturated_cells_method/TorqueSpherePSM.cpp DEPENDS blockforest boundary core domain_decomposition field lbm stencil timeloop ) waLBerla_execute_test( NAME LBM_MESAPD_COUPLING_PSM_TorqueSphereSC1W1FuncTest COMMAND $<TARGET_FILE:LBM_MESAPD_COUPLING_PSM_TorqueSphere> --funcTest --SC1W1 PROCESSES 1 ) waLBerla_execute_test( NAME LBM_MESAPD_COUPLING_PSM_TorqueSphereSC1W1SingleTest COMMAND $<TARGET_FILE:LBM_MESAPD_COUPLING_PSM_TorqueSphere> --SC1W1 PROCESSES 1 LABELS longrun CONFIGURATIONS Release RelWithDbgInfo ) waLBerla_execute_test( NAME LBM_MESAPD_COUPLING_PSM_TorqueSphereSC1W1ParallelTest COMMAND $<TARGET_FILE:LBM_MESAPD_COUPLING_PSM_TorqueSphere> --SC1W1 PROCESSES 8 LABELS verylongrun CONFIGURATIONS Release RelWithDbgInfo ) @@ -72,3 +75,28 @@ waLBerla_execute_test( NAME LBM_MESAPD_COUPLING_PSM_TorqueSphereSC2W2FuncTest waLBerla_execute_test( NAME LBM_MESAPD_COUPLING_PSM_TorqueSphereSC2W2SingleTest COMMAND $<TARGET_FILE:LBM_MESAPD_COUPLING_PSM_TorqueSphere> --SC2W2 PROCESSES 1 LABELS longrun CONFIGURATIONS Release RelWithDbgInfo ) waLBerla_execute_test( NAME LBM_MESAPD_COUPLING_PSM_TorqueSphereSC3W2FuncTest COMMAND $<TARGET_FILE:LBM_MESAPD_COUPLING_PSM_TorqueSphere> --funcTest --SC3W2 PROCESSES 1 ) waLBerla_execute_test( NAME LBM_MESAPD_COUPLING_PSM_TorqueSphereSC3W2SingleTest COMMAND $<TARGET_FILE:LBM_MESAPD_COUPLING_PSM_TorqueSphere> --SC3W2 PROCESSES 1 LABELS longrun CONFIGURATIONS Release RelWithDbgInfo ) + +if (WALBERLA_BUILD_WITH_CODEGEN) + if (NOT WALBERLA_BUILD_WITH_GPU_SUPPORT OR (WALBERLA_BUILD_WITH_GPU_SUPPORT AND (CMAKE_CUDA_ARCHITECTURES GREATER_EQUAL 60 OR WALBERLA_BUILD_WITH_HIP))) + waLBerla_compile_test(NAME LBM_MESAPD_COUPLING_PSM_DragForceSphere_CPU_GPU FILES partially_saturated_cells_method/codegen/DragForceSpherePSM.cpp DEPENDS blockforest core gpu field lbm_mesapd_coupling mesa_pd PSMCodegenPython_srt_sc1) + waLBerla_execute_test(NAME LBM_MESAPD_COUPLING_PSM_DragForceSphere_CPU_GPU_FuncTest COMMAND $<TARGET_FILE:LBM_MESAPD_COUPLING_PSM_DragForceSphere_CPU_GPU> --funcTest PROCESSES 1) + waLBerla_execute_test(NAME LBM_MESAPD_COUPLING_PSM_DragForceSphere_CPU_GPU COMMAND $<TARGET_FILE:LBM_MESAPD_COUPLING_PSM_DragForceSphere_CPU_GPU> PROCESSES 8 LABELS verylongrun CONFIGURATIONS Release RelWithDbgInfo) + + foreach (collision_setup srt trt-smagorinsky) + foreach (solid_collision 1 2 3) + foreach (weighting 1 2) + set(config ${collision_setup}_sc${solid_collision}_w${weighting}) + waLBerla_compile_test(NAME LBM_MESAPD_COUPLING_PSM_TorqueSphere_CPU_GPU_${config} FILES partially_saturated_cells_method/codegen/TorqueSpherePSM.cpp DEPENDS blockforest core gpu field lbm_mesapd_coupling mesa_pd PSMCodegenPython_${collision_setup}_sc${solid_collision}) + target_compile_definitions(LBM_MESAPD_COUPLING_PSM_TorqueSphere_CPU_GPU_${config} PRIVATE SC=${solid_collision}) + target_compile_definitions(LBM_MESAPD_COUPLING_PSM_TorqueSphere_CPU_GPU_${config} PRIVATE Weighting=${weighting}) + waLBerla_execute_test(NAME LBM_MESAPD_COUPLING_PSM_TorqueSphere_CPU_GPU_${config}_FuncTest COMMAND $<TARGET_FILE:LBM_MESAPD_COUPLING_PSM_TorqueSphere_CPU_GPU_${config}> --funcTest PROCESSES 1) + waLBerla_execute_test(NAME LBM_MESAPD_COUPLING_PSM_TorqueSphere_CPU_GPU_${config} COMMAND $<TARGET_FILE:LBM_MESAPD_COUPLING_PSM_TorqueSphere_CPU_GPU_${config}> PROCESSES 8 LABELS longrun CONFIGURATIONS Release RelWithDbgInfo) + endforeach () + endforeach () + endforeach () + + waLBerla_compile_test(NAME LBM_MESAPD_COUPLING_PSM_SettlingSphere_CPU_GPU FILES partially_saturated_cells_method/codegen/SettlingSpherePSM.cpp DEPENDS blockforest core gpu field lbm lbm_mesapd_coupling mesa_pd timeloop vtk PSMCodegenPython_trt-smagorinsky_sc2) + waLBerla_execute_test(NAME LBM_MESAPD_COUPLING_PSM_SettlingSphere_CPU_GPU_FuncTest COMMAND $<TARGET_FILE:LBM_MESAPD_COUPLING_PSM_SettlingSphere_CPU_GPU> --funcTest PROCESSES 1) + waLBerla_execute_test(NAME LBM_MESAPD_COUPLING_PSM_SettlingSphere_CPU_GPU COMMAND $<TARGET_FILE:LBM_MESAPD_COUPLING_PSM_SettlingSphere_CPU_GPU> PROCESSES 8 LABELS verylongrun CONFIGURATIONS Release RelWithDbgInfo) + endif () +endif () diff --git a/tests/lbm_mesapd_coupling/momentum_exchange_method/DragForceSphere.cpp b/tests/lbm_mesapd_coupling/momentum_exchange_method/DragForceSphereMEM.cpp similarity index 100% rename from tests/lbm_mesapd_coupling/momentum_exchange_method/DragForceSphere.cpp rename to tests/lbm_mesapd_coupling/momentum_exchange_method/DragForceSphereMEM.cpp diff --git a/tests/lbm_mesapd_coupling/momentum_exchange_method/ForceBetweenTwoStationaryObjects.cpp b/tests/lbm_mesapd_coupling/momentum_exchange_method/ForceBetweenTwoStationaryObjectsMEM.cpp similarity index 100% rename from tests/lbm_mesapd_coupling/momentum_exchange_method/ForceBetweenTwoStationaryObjects.cpp rename to tests/lbm_mesapd_coupling/momentum_exchange_method/ForceBetweenTwoStationaryObjectsMEM.cpp diff --git a/tests/lbm_mesapd_coupling/momentum_exchange_method/MovingParticleMapping.cpp b/tests/lbm_mesapd_coupling/momentum_exchange_method/MovingParticleMappingMEM.cpp similarity index 100% rename from tests/lbm_mesapd_coupling/momentum_exchange_method/MovingParticleMapping.cpp rename to tests/lbm_mesapd_coupling/momentum_exchange_method/MovingParticleMappingMEM.cpp diff --git a/tests/lbm_mesapd_coupling/momentum_exchange_method/PdfReconstruction.cpp b/tests/lbm_mesapd_coupling/momentum_exchange_method/PdfReconstructionMEM.cpp similarity index 100% rename from tests/lbm_mesapd_coupling/momentum_exchange_method/PdfReconstruction.cpp rename to tests/lbm_mesapd_coupling/momentum_exchange_method/PdfReconstructionMEM.cpp diff --git a/tests/lbm_mesapd_coupling/momentum_exchange_method/SettlingSphere.cpp b/tests/lbm_mesapd_coupling/momentum_exchange_method/SettlingSphereMEM.cpp similarity index 100% rename from tests/lbm_mesapd_coupling/momentum_exchange_method/SettlingSphere.cpp rename to tests/lbm_mesapd_coupling/momentum_exchange_method/SettlingSphereMEM.cpp diff --git a/tests/lbm_mesapd_coupling/momentum_exchange_method/UpdateParticleMapping.cpp b/tests/lbm_mesapd_coupling/momentum_exchange_method/UpdateParticleMappingMEM.cpp similarity index 100% rename from tests/lbm_mesapd_coupling/momentum_exchange_method/UpdateParticleMapping.cpp rename to tests/lbm_mesapd_coupling/momentum_exchange_method/UpdateParticleMappingMEM.cpp diff --git a/tests/lbm_mesapd_coupling/partially_saturated_cells_method/DragForceSphere.cpp b/tests/lbm_mesapd_coupling/partially_saturated_cells_method/DragForceSpherePSM.cpp similarity index 90% rename from tests/lbm_mesapd_coupling/partially_saturated_cells_method/DragForceSphere.cpp rename to tests/lbm_mesapd_coupling/partially_saturated_cells_method/DragForceSpherePSM.cpp index 151b109c07e083b7d5adc55cb28a1dd0fce0e4eb..12bc2a240dd37765d161ebc3556c78d370546fa1 100644 --- a/tests/lbm_mesapd_coupling/partially_saturated_cells_method/DragForceSphere.cpp +++ b/tests/lbm_mesapd_coupling/partially_saturated_cells_method/DragForceSpherePSM.cpp @@ -36,6 +36,7 @@ #include "core/timing/RemainingTimeLogger.h" #include "field/AddToStorage.h" +#include "field/vtk/VTKWriter.h" #include "lbm/communication/PdfFieldPackInfo.h" #include "lbm/field/AddToStorage.h" @@ -43,10 +44,9 @@ #include "lbm/lattice_model/D3Q19.h" #include "lbm/lattice_model/ForceModel.h" #include "lbm/sweeps/SweepWrappers.h" +#include "lbm/vtk/Velocity.h" #include "lbm_mesapd_coupling/DataTypes.h" -#include "lbm_mesapd_coupling/momentum_exchange_method/MovingParticleMapping.h" -#include "lbm_mesapd_coupling/momentum_exchange_method/boundary/SimpleBB.h" #include "lbm_mesapd_coupling/partially_saturated_cells_method/PSMSweep.h" #include "lbm_mesapd_coupling/partially_saturated_cells_method/PSMUtility.h" #include "lbm_mesapd_coupling/partially_saturated_cells_method/ParticleAndVolumeFractionMapping.h" @@ -103,9 +103,10 @@ class DragForceEvaluator { public: DragForceEvaluator(SweepTimeloop* timeloop, Setup* setup, const shared_ptr< StructuredBlockStorage >& blocks, - const BlockDataID& pdfFieldID, const shared_ptr< ParticleAccessor_T >& ac, - walberla::id_t sphereID) - : timeloop_(timeloop), setup_(setup), blocks_(blocks), pdfFieldID_(pdfFieldID), ac_(ac), sphereID_(sphereID), + const BlockDataID& pdfFieldID, const BlockDataID& particleAndVolumeFractionFieldID, + const shared_ptr< ParticleAccessor_T >& ac, walberla::id_t sphereID) + : timeloop_(timeloop), setup_(setup), blocks_(blocks), pdfFieldID_(pdfFieldID), + particleAndVolumeFractionFieldID_(particleAndVolumeFractionFieldID), ac_(ac), sphereID_(sphereID), normalizedDragOld_(0.0), normalizedDragNew_(0.0) { // calculate the analytical drag force value based on the series expansion of chi @@ -198,13 +199,18 @@ class DragForceEvaluator { // retrieve the pdf field and the flag field from the block PdfField_T* pdfField = blockIt->getData< PdfField_T >(pdfFieldID_); + lbm_mesapd_coupling::psm::ParticleAndVolumeFractionField_T* particleAndVolumeFractionField = + blockIt->getData< lbm_mesapd_coupling::psm::ParticleAndVolumeFractionField_T >( + particleAndVolumeFractionFieldID_); // get the flag that marks a cell as being fluid auto xyzField = pdfField->xyzSize(); for (auto cell : xyzField) { - velocity_sum += pdfField->getVelocity(cell)[0]; + // TODO: weighting is fixed to 1 + velocity_sum += lbm_mesapd_coupling::psm::getPSMMacroscopicVelocity< LatticeModel_T, 1 >( + *blockIt, pdfField, particleAndVolumeFractionField, *blocks_, cell, *ac_)[0]; } } @@ -219,6 +225,7 @@ class DragForceEvaluator shared_ptr< StructuredBlockStorage > blocks_; const BlockDataID pdfFieldID_; + const BlockDataID particleAndVolumeFractionFieldID_; shared_ptr< ParticleAccessor_T > ac_; const walberla::id_t sphereID_; @@ -278,11 +285,12 @@ int main(int argc, char** argv) // Customization // /////////////////// - bool shortrun = false; - bool funcTest = false; - bool logging = false; - real_t tau = real_c(1.5); - uint_t length = uint_c(32); + bool shortrun = false; + bool funcTest = false; + bool logging = false; + uint_t vtkFrequency = uint_c(0); + real_t tau = real_c(1.5); + uint_t length = uint_c(32); for (int i = 1; i < argc; ++i) { @@ -311,6 +319,11 @@ int main(int argc, char** argv) length = uint_c(std::atof(argv[++i])); continue; } + if (std::strcmp(argv[i], "--vtkFrequency") == 0) + { + vtkFrequency = uint_c(std::atof(argv[++i])); + continue; + } WALBERLA_ABORT("Unrecognized command line argument found: " << argv[i]); } @@ -440,7 +453,8 @@ int main(int argc, char** argv) // add LBM communication function and streaming & force evaluation using DragForceEval_T = DragForceEvaluator< ParticleAccessor_T >; - auto forceEval = make_shared< DragForceEval_T >(&timeloop, &setup, blocks, pdfFieldID, accessor, sphereID); + auto forceEval = make_shared< DragForceEval_T >(&timeloop, &setup, blocks, pdfFieldID, + particleAndVolumeFractionFieldID, accessor, sphereID); timeloop.add() << BeforeFunction(optimizedPDFCommunicationScheme, "LBM Communication") << Sweep(lbm::makeStreamSweep(sweep), "cell-wise LB sweep (stream)") << AfterFunction(SharedFunctor< DragForceEval_T >(forceEval), "drag force evaluation"); @@ -454,7 +468,17 @@ int main(int argc, char** argv) "reset force on sphere"); timeloop.addFuncAfterTimeStep(RemainingTimeLogger(timeloop.getNrOfTimeSteps()), "Remaining Time Logger"); + if (vtkFrequency > 0) + { + const std::string path = "vtk_out/dragForceSphere"; + auto vtkOutput = vtk::createVTKOutput_BlockData(*blocks, "psm_velocity_field", vtkFrequency, 0, false, path, + "simulation_step", false, true, true, false, 0); + + auto velWriter = make_shared< walberla::lbm::VelocityVTKWriter< LatticeModel_T > >(pdfFieldID, "Velocity"); + vtkOutput->addCellDataWriter(velWriter); + timeloop.addFuncBeforeTimeStep(vtk::writeFiles(vtkOutput), "VTK Output"); + } //////////////////////// // EXECUTE SIMULATION // //////////////////////// diff --git a/tests/lbm_mesapd_coupling/partially_saturated_cells_method/ParticleAndVolumeFractionMapping.cpp b/tests/lbm_mesapd_coupling/partially_saturated_cells_method/ParticleAndVolumeFractionMappingPSM.cpp similarity index 98% rename from tests/lbm_mesapd_coupling/partially_saturated_cells_method/ParticleAndVolumeFractionMapping.cpp rename to tests/lbm_mesapd_coupling/partially_saturated_cells_method/ParticleAndVolumeFractionMappingPSM.cpp index d1bd029a7fa4109d2390b14f93744d2b8d6b4d75..b49590aedd345de8fd8efa5bfbaaa54a0f75d93c 100644 --- a/tests/lbm_mesapd_coupling/partially_saturated_cells_method/ParticleAndVolumeFractionMapping.cpp +++ b/tests/lbm_mesapd_coupling/partially_saturated_cells_method/ParticleAndVolumeFractionMappingPSM.cpp @@ -146,9 +146,8 @@ int main(int argc, char** argv) // set up synchronization std::function< void(void) > syncCall = [&]() { - const real_t overlap = real_t(1.5) * dx; mesa_pd::mpi::SyncNextNeighbors syncNextNeighborFunc; - syncNextNeighborFunc(*ps, *mesapdDomain, overlap); + syncNextNeighborFunc(*ps, *mesapdDomain); }; // add the sphere in the center of the domain diff --git a/tests/lbm_mesapd_coupling/partially_saturated_cells_method/SettlingSphere.cpp b/tests/lbm_mesapd_coupling/partially_saturated_cells_method/SettlingSpherePSM.cpp similarity index 99% rename from tests/lbm_mesapd_coupling/partially_saturated_cells_method/SettlingSphere.cpp rename to tests/lbm_mesapd_coupling/partially_saturated_cells_method/SettlingSpherePSM.cpp index 8144d27523f2d72c57bc08e735beb2f8f8d6adf7..f0dd609111994eecf7b0d5519ccd9e2da5376c51 100644 --- a/tests/lbm_mesapd_coupling/partially_saturated_cells_method/SettlingSphere.cpp +++ b/tests/lbm_mesapd_coupling/partially_saturated_cells_method/SettlingSpherePSM.cpp @@ -592,9 +592,8 @@ int main(int argc, char** argv) // set up RPD functionality std::function< void(void) > syncCall = [ps, rpdDomain]() { - const real_t overlap = real_t(1.5); mesa_pd::mpi::SyncNextNeighbors syncNextNeighborFunc; - syncNextNeighborFunc(*ps, *rpdDomain, overlap); + syncNextNeighborFunc(*ps, *rpdDomain); }; syncCall(); diff --git a/tests/lbm_mesapd_coupling/partially_saturated_cells_method/TorqueSphere.cpp b/tests/lbm_mesapd_coupling/partially_saturated_cells_method/TorqueSpherePSM.cpp similarity index 98% rename from tests/lbm_mesapd_coupling/partially_saturated_cells_method/TorqueSphere.cpp rename to tests/lbm_mesapd_coupling/partially_saturated_cells_method/TorqueSpherePSM.cpp index f0db14fe5d902f80b1e5f293ef6dc0b5a50f64ca..419897653e391094f62a668e2ec3602395fd4165 100644 --- a/tests/lbm_mesapd_coupling/partially_saturated_cells_method/TorqueSphere.cpp +++ b/tests/lbm_mesapd_coupling/partially_saturated_cells_method/TorqueSpherePSM.cpp @@ -57,8 +57,6 @@ #include "mesa_pd/domain/BlockForestDomain.h" #include "mesa_pd/mpi/SyncNextNeighbors.h" -#include "stencil/D3Q27.h" - #include "timeloop/SweepTimeloop.h" #include <iostream> @@ -392,11 +390,10 @@ int main(int argc, char** argv) sphereParticle->setInteractionRadius(setup.radius); } - // synchronize often enough for large bodies + // synchronize often enough for large particles std::function< void(void) > syncCall = [&]() { - // const real_t overlap = real_t(1.5) * dx; mesa_pd::mpi::SyncNextNeighbors syncNextNeighborFunc; - syncNextNeighborFunc(*ps, *mesapdDomain, overlap); + syncNextNeighborFunc(*ps, *mesapdDomain); }; syncCall(); @@ -418,7 +415,7 @@ int main(int argc, char** argv) field::addToStorage< lbm_mesapd_coupling::psm::ParticleAndVolumeFractionField_T >( blocks, "particle and volume fraction field", std::vector< lbm_mesapd_coupling::psm::ParticleAndVolumeFraction_T >(), field::fzyx, 0); - // map bodies and calculate solid volume fraction initially + // map particles and calculate solid volume fraction initially lbm_mesapd_coupling::psm::ParticleAndVolumeFractionMapping particleMapping( blocks, accessor, lbm_mesapd_coupling::RegularParticlesSelector(), particleAndVolumeFractionFieldID, 4); particleMapping(); @@ -445,7 +442,7 @@ int main(int argc, char** argv) // setup of the LBM communication for synchronizing the pdf field between neighboring blocks std::function< void() > commFunction; - blockforest::communication::UniformBufferedScheme< stencil::D3Q27 > scheme(blocks); + blockforest::communication::UniformBufferedScheme< Stencil_T > scheme(blocks); scheme.addPackInfo(make_shared< field::communication::PackInfo< PdfField_T > >(pdfFieldID)); commFunction = scheme; diff --git a/tests/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/DragForceSpherePSM.cpp b/tests/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/DragForceSpherePSM.cpp new file mode 100644 index 0000000000000000000000000000000000000000..84edc556741f33c130d5160f5e2dac06eb24cf2d --- /dev/null +++ b/tests/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/DragForceSpherePSM.cpp @@ -0,0 +1,552 @@ +//====================================================================================================================== +// +// This file is part of waLBerla. waLBerla 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. +// +// waLBerla 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 waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file DragForceSpherePSMCPUGPU.cpp +//! \ingroup lbm_mesapd_coupling +//! \author Samuel Kemmler <samuel.kemmler@fau.de> +//! \author Christoph Rettinger <christoph.rettinger@fau.de> +//! \brief Modification of partially_saturated_cells_method/DragForceSphere.cpp +// +//====================================================================================================================== + +#include "blockforest/Initialization.h" +#include "blockforest/communication/UniformBufferedScheme.h" + +#include "core/Environment.h" +#include "core/SharedFunctor.h" +#include "core/debug/TestSubsystem.h" +#include "core/logging/Logging.h" +#include "core/mpi/MPIManager.h" +#include "core/mpi/Reduce.h" +#include "core/timing/RemainingTimeLogger.h" + +#include "field/vtk/VTKWriter.h" + +#include "gpu/AddGPUFieldToStorage.h" +#include "gpu/DeviceSelectMPI.h" +#include "gpu/communication/UniformGPUScheme.h" + +#include "lbm_mesapd_coupling/DataTypesCodegen.h" +#include "lbm_mesapd_coupling/partially_saturated_cells_method/codegen/PSMSweepCollection.h" +#include "lbm_mesapd_coupling/utility/ResetHydrodynamicForceTorqueKernel.h" + +#include "mesa_pd/data/ParticleAccessorWithShape.h" +#include "mesa_pd/data/ParticleStorage.h" +#include "mesa_pd/data/ShapeStorage.h" +#include "mesa_pd/domain/BlockForestDomain.h" +#include "mesa_pd/kernel/ParticleSelector.h" + +#include <iostream> + +// codegen +#include "InitializeDomainForPSM.h" +#include "PSMPackInfo.h" +#include "PSMSweep.h" +#include "PSM_InfoHeader.h" +#include "PSM_MacroGetter.h" + +namespace drag_force_sphere_psm +{ + +/////////// +// USING // +/////////// + +using namespace walberla; +using walberla::uint_t; +using namespace lbm_mesapd_coupling::psm::gpu; + +typedef pystencils::PSMPackInfo PackInfo_T; + +//////////////// +// PARAMETERS // +//////////////// + +struct Setup +{ + uint_t checkFrequency; + real_t visc; + real_t tau; + real_t radius; + uint_t length; + real_t chi; + real_t extForce; + real_t analyticalDrag; +}; + +template< typename ParticleAccessor_T > +class DragForceEvaluator +{ + public: + DragForceEvaluator(SweepTimeloop* timeloop, Setup* setup, const shared_ptr< StructuredBlockStorage >& blocks, + const BlockDataID& velocityFieldID, const shared_ptr< ParticleAccessor_T >& ac, + walberla::id_t sphereID) + : timeloop_(timeloop), setup_(setup), blocks_(blocks), velocityFieldID_(velocityFieldID), ac_(ac), + sphereID_(sphereID), normalizedDragOld_(0.0), normalizedDragNew_(0.0) + { + // calculate the analytical drag force value based on the series expansion of chi + // see also Sangani - Slow flow through a periodic array of spheres, IJMF 1982. Eq. 60 and Table 1 + real_t analyticalDrag = real_c(0); + real_t tempChiPowS = real_c(1); + + // coefficients to calculate the drag in a series expansion + real_t dragCoefficients[31] = { real_c(1.000000), real_c(1.418649), real_c(2.012564), real_c(2.331523), + real_c(2.564809), real_c(2.584787), real_c(2.873609), real_c(3.340163), + real_c(3.536763), real_c(3.504092), real_c(3.253622), real_c(2.689757), + real_c(2.037769), real_c(1.809341), real_c(1.877347), real_c(1.534685), + real_c(0.9034708), real_c(0.2857896), real_c(-0.5512626), real_c(-1.278724), + real_c(1.013350), real_c(5.492491), real_c(4.615388), real_c(-0.5736023), + real_c(-2.865924), real_c(-4.709215), real_c(-6.870076), real_c(0.1455304), + real_c(12.51891), real_c(9.742811), real_c(-5.566269) }; + + for (uint_t s = 0; s <= uint_t(30); ++s) + { + analyticalDrag += dragCoefficients[s] * tempChiPowS; + tempChiPowS *= setup->chi; + } + setup_->analyticalDrag = analyticalDrag; + } + + // evaluate the acting drag force + void operator()() + { + const uint_t timestep(timeloop_->getCurrentTimeStep() + 1); + + if (timestep % setup_->checkFrequency != 0) return; + + // get force in x-direction acting on the sphere + real_t forceX = computeDragForce(); + // get average volumetric flowrate in the domain + real_t uBar = computeAverageVel(); + + // f_total = f_drag + f_buoyancy + real_t totalForce = + forceX + real_c(4.0 / 3.0) * math::pi * setup_->radius * setup_->radius * setup_->radius * setup_->extForce; + + real_t normalizedDragForce = totalForce / real_c(6.0 * math::pi * setup_->visc * setup_->radius * uBar); + + // update drag force values + normalizedDragOld_ = normalizedDragNew_; + normalizedDragNew_ = normalizedDragForce; + } + + // return the relative temporal change in the normalized drag + real_t getDragForceDiff() const { return std::fabs((normalizedDragNew_ - normalizedDragOld_) / normalizedDragNew_); } + + // return the drag force + real_t getDragForce() const { return normalizedDragNew_; } + + void logResultToFile(const std::string& filename) const + { + // write to file if desired + // format: length tau viscosity simulatedDrag analyticalDrag\n + WALBERLA_ROOT_SECTION() + { + std::ofstream file; + file.open(filename.c_str(), std::ofstream::app); + file.precision(8); + file << setup_->length << " " << setup_->tau << " " << setup_->visc << " " << normalizedDragNew_ << " " + << setup_->analyticalDrag << "\n"; + file.close(); + } + } + + private: + // obtain the drag force acting on the sphere by summing up all the process local parts of fX + real_t computeDragForce() + { + size_t idx = ac_->uidToIdx(sphereID_); + WALBERLA_ASSERT_UNEQUAL(idx, ac_->getInvalidIdx(), "Index of particle is invalid!"); + real_t force = real_t(0); + if (idx != ac_->getInvalidIdx()) { force = ac_->getHydrodynamicForce(idx)[0]; } + + WALBERLA_MPI_SECTION() { mpi::allReduceInplace(force, mpi::SUM); } + + return force; + } + + // calculate the average velocity in forcing direction (here: x) inside the domain (assuming dx=1) + real_t computeAverageVel() + { + auto velocity_sum = real_t(0); + // iterate all blocks stored locally on this process + for (auto blockIt = blocks_->begin(); blockIt != blocks_->end(); ++blockIt) + { + // retrieve the pdf field and the flag field from the block + VelocityField_T* velocityField = blockIt->getData< VelocityField_T >(velocityFieldID_); + + // get the flag that marks a cell as being fluid + + auto xyzField = velocityField->xyzSize(); + for (auto cell : xyzField) + { + // TODO: fix velocity computation by using getPSMMacroscopicVelocity + velocity_sum += velocityField->get(cell, 0); + } + } + + WALBERLA_MPI_SECTION() { mpi::allReduceInplace(velocity_sum, mpi::SUM); } + + return velocity_sum / real_c(setup_->length * setup_->length * setup_->length); + } + + SweepTimeloop* timeloop_; + + Setup* setup_; + + shared_ptr< StructuredBlockStorage > blocks_; + const BlockDataID velocityFieldID_; + + shared_ptr< ParticleAccessor_T > ac_; + const walberla::id_t sphereID_; + + // drag coefficient + real_t normalizedDragOld_; + real_t normalizedDragNew_; +}; + +////////// +// MAIN // +////////// + +//******************************************************************************************************************* +/*!\brief Testcase that checks the drag force acting on a fixed sphere in the center of a cubic domain in Stokes flow + * + * The drag force for this problem (often denoted as Simple Cubic setup) is given by a semi-analytical series expansion. + * The cubic domain is periodic in all directions, making it a physically infinite periodic array of spheres. + \verbatim + _______________ + ->| |-> + ->| ___ |-> + W ->| / \ |-> E + E ->| | x | |-> A + S ->| \___/ |-> S + T ->| |-> T + ->|_______________|-> + + \endverbatim + * + * The collision model used for the LBM is TRT with a relaxation parameter tau=1.5 and the magic parameter 3/16. + * The Stokes approximation of the equilibrium PDFs is used. + * The flow is driven by a constant particle force of 1e-5. + * The domain is 32x32x32, and the sphere has a diameter of 16 cells ( chi * domainlength ) + * The simulation is run until the relative change in the dragforce between 100 time steps is less than 1e-5. + * The RPD is not used since the sphere is kept fixed and the force is explicitly reset after each time step. + * To avoid periodicity constrain problems, the sphere is set as global. + * + */ +//******************************************************************************************************************* + +int main(int argc, char** argv) +{ + debug::enterTestMode(); + + mpi::Environment env(argc, argv); + + logging::Logging::instance()->setLogLevel(logging::Logging::INFO); + + auto processes = MPIManager::instance()->numProcesses(); + + if (processes != 1 && processes != 2 && processes != 4 && processes != 8) + { + std::cerr << "Number of processes must be equal to either 1, 2, 4, or 8!" << std::endl; + return EXIT_FAILURE; + } + + /////////////////// + // Customization // + /////////////////// + + bool shortrun = false; + bool funcTest = false; + bool logging = false; + uint_t vtkFrequency = uint_c(0); + real_t tau = real_c(1.5); + uint_t length = uint_c(32); + + for (int i = 1; i < argc; ++i) + { + if (std::strcmp(argv[i], "--shortrun") == 0) + { + shortrun = true; + continue; + } + if (std::strcmp(argv[i], "--funcTest") == 0) + { + funcTest = true; + continue; + } + if (std::strcmp(argv[i], "--logging") == 0) + { + logging = true; + continue; + } + if (std::strcmp(argv[i], "--tau") == 0) + { + tau = real_c(std::atof(argv[++i])); + continue; + } + if (std::strcmp(argv[i], "--length") == 0) + { + length = uint_c(std::atof(argv[++i])); + continue; + } + if (std::strcmp(argv[i], "--vtkFrequency") == 0) + { + vtkFrequency = uint_c(std::atof(argv[++i])); + continue; + } + WALBERLA_ABORT("Unrecognized command line argument found: " << argv[i]); + } + + /////////////////////////// + // SIMULATION PROPERTIES // + /////////////////////////// + + Setup setup; + + setup.length = length; // length of the cubic domain in lattice cells + setup.chi = real_c(0.5); // porosity parameter: diameter / length + setup.tau = tau; // relaxation time + setup.extForce = real_c(1e-7); // constant particle force in lattice units + setup.checkFrequency = uint_t(100); // evaluate the drag force only every checkFrequency time steps + setup.radius = real_c(0.5) * setup.chi * real_c(setup.length); // sphere radius + setup.visc = (setup.tau - real_c(0.5)) / real_c(3); // viscosity in lattice units + const real_t omega = real_c(1) / setup.tau; // relaxation rate + const real_t dx = real_c(1); // lattice dx + const real_t convergenceLimit = real_c(1e-7); // tolerance for relative change in drag force + const uint_t timesteps = + funcTest ? 1 : (shortrun ? uint_c(150) : uint_c(50000)); // maximum number of time steps for the whole simulation + + /////////////////////////// + // BLOCK STRUCTURE SETUP // + /////////////////////////// + + const uint_t XBlocks = (processes >= 2) ? uint_t(2) : uint_t(1); + const uint_t YBlocks = (processes >= 4) ? uint_t(2) : uint_t(1); + const uint_t ZBlocks = (processes == 8) ? uint_t(2) : uint_t(1); + const uint_t XCells = setup.length / XBlocks; + const uint_t YCells = setup.length / YBlocks; + const uint_t ZCells = setup.length / ZBlocks; + + // create fully periodic domain + auto blocks = blockforest::createUniformBlockGrid(XBlocks, YBlocks, ZBlocks, XCells, YCells, ZCells, dx, true, true, + true, true); + + ///////// + // RPD // + ///////// + + mesa_pd::domain::BlockForestDomain domain(blocks->getBlockForestPointer()); + + // init data structures + auto ps = std::make_shared< mesa_pd::data::ParticleStorage >(1); + auto ss = std::make_shared< mesa_pd::data::ShapeStorage >(); + using ParticleAccessor_T = mesa_pd::data::ParticleAccessorWithShape; + auto accessor = make_shared< ParticleAccessor_T >(ps, ss); + auto sphereShape = ss->create< mesa_pd::data::Sphere >(setup.radius); + + ////////////////// + // RPD COUPLING // + ////////////////// + + // connect to pe + const real_t overlap = real_t(1.5) * dx; + + if (setup.radius > real_c(setup.length) * real_t(0.5) - overlap) + { + std::cerr << "Periodic sphere is too large and would lead to incorrect mapping!" << std::endl; + // solution: create the periodic copies explicitly + return EXIT_FAILURE; + } + + // create the sphere in the middle of the domain + // it is global and thus present on all processes + Vector3< real_t > position(real_c(setup.length) * real_c(0.5)); + walberla::id_t sphereID; + { + mesa_pd::data::Particle&& p = *ps->create(true); + p.setPosition(position); + p.setInteractionRadius(setup.radius); + p.setOwner(mpi::MPIManager::instance()->rank()); + p.setShapeID(sphereShape); + sphereID = p.getUid(); + } + + /////////////////////// + // ADD DATA TO BLOCKS // + //////////////////////// + + // add fields +#ifdef WALBERLA_BUILD_WITH_GPU_SUPPORT + BlockDataID pdfFieldID = + field::addToStorage< PdfField_T >(blocks, "pdf field (fzyx)", real_c(std::nan("")), field::fzyx); + BlockDataID BFieldID = field::addToStorage< BField_T >(blocks, "B", real_t(0), field::fzyx); + BlockDataID pdfFieldCPUGPUID = gpu::addGPUFieldToStorage< PdfField_T >(blocks, pdfFieldID, "pdf field GPU"); +#else + BlockDataID pdfFieldCPUGPUID = + field::addToStorage< PdfField_T >(blocks, "pdf field CPU", real_c(std::nan("")), field::fzyx); +#endif + + BlockDataID densityFieldID = field::addToStorage< DensityField_T >(blocks, "Density", real_t(0), field::fzyx); + BlockDataID velFieldID = field::addToStorage< VelocityField_T >(blocks, "Velocity", real_t(0), field::fzyx); + + /////////////// + // TIME LOOP // + /////////////// + + // create the timeloop + SweepTimeloop timeloop(blocks->getBlockStorage(), timesteps); + + // setup of the LBM communication for synchronizing the pdf field between neighboring blocks +#ifdef WALBERLA_BUILD_WITH_GPU_SUPPORT + gpu::communication::UniformGPUScheme< Stencil_T > com(blocks, 0, false); +#else + walberla::blockforest::communication::UniformBufferedScheme< Stencil_T > com(blocks); +#endif + com.addPackInfo(make_shared< PackInfo_T >(pdfFieldCPUGPUID)); + auto communication = std::function< void() >([&]() { com.communicate(); }); + + // add particle and volume fraction data structures + ParticleAndVolumeFractionSoA_T< 1 > particleAndVolumeFractionSoA(blocks, omega); + + // map particles and calculate solid volume fraction initially + PSMSweepCollection psmSweepCollection(blocks, accessor, lbm_mesapd_coupling::GlobalParticlesSelector(), + particleAndVolumeFractionSoA, Vector3(8)); + for (auto blockIt = blocks->begin(); blockIt != blocks->end(); ++blockIt) + { + psmSweepCollection.particleMappingSweep(&(*blockIt)); + } + + pystencils::InitializeDomainForPSM pdfSetter( + particleAndVolumeFractionSoA.BsFieldID, particleAndVolumeFractionSoA.BFieldID, + particleAndVolumeFractionSoA.particleVelocitiesFieldID, pdfFieldCPUGPUID, real_t(0), real_t(0), real_t(0), + real_t(1.0), real_t(0), real_t(0), real_t(0)); + + for (auto blockIt = blocks->begin(); blockIt != blocks->end(); ++blockIt) + { + // pdfSetter requires particle velocities at cell centers + psmSweepCollection.setParticleVelocitiesSweep(&(*blockIt)); + pdfSetter(&(*blockIt)); + } + + // since external forcing is applied, the evaluation of the velocity has to be carried out directly after the + // streaming step however, the default sweep is a stream - collide step, i.e. after the sweep, the velocity + // evaluation is not correct solution: split the sweep explicitly into collide and stream + pystencils::PSMSweep PSMSweep(particleAndVolumeFractionSoA.BsFieldID, particleAndVolumeFractionSoA.BFieldID, + particleAndVolumeFractionSoA.particleForcesFieldID, + particleAndVolumeFractionSoA.particleVelocitiesFieldID, pdfFieldCPUGPUID, + setup.extForce, real_t(0.0), real_t(0.0), omega); + +#ifdef WALBERLA_BUILD_WITH_GPU_SUPPORT + pystencils::PSM_MacroGetter getterSweep(BFieldID, densityFieldID, pdfFieldID, velFieldID, setup.extForce, + real_t(0.0), real_t(0.0)); +#else + pystencils::PSM_MacroGetter getterSweep(particleAndVolumeFractionSoA.BFieldID, densityFieldID, pdfFieldCPUGPUID, + velFieldID, setup.extForce, real_t(0.0), real_t(0.0)); +#endif + + // add LBM communication function and streaming & force evaluation + using DragForceEval_T = DragForceEvaluator< ParticleAccessor_T >; + auto forceEval = make_shared< DragForceEval_T >(&timeloop, &setup, blocks, velFieldID, accessor, sphereID); + timeloop.add() << BeforeFunction(communication, "LBM Communication") + << Sweep(deviceSyncWrapper(psmSweepCollection.setParticleVelocitiesSweep), "Set particle velocities"); + timeloop.add() << Sweep(deviceSyncWrapper(PSMSweep), "cell-wise PSM sweep"); + timeloop.add() << Sweep(deviceSyncWrapper(psmSweepCollection.reduceParticleForcesSweep), "Reduce particle forces"); +#ifdef WALBERLA_BUILD_WITH_GPU_SUPPORT + timeloop.add() << Sweep(gpu::fieldCpyFunctor< PdfField_T, gpu::GPUField< real_t > >(pdfFieldID, pdfFieldCPUGPUID), + "copy pdf from GPU to CPU"); + timeloop.add() << Sweep( + gpu::fieldCpyFunctor< BField_T, gpu::GPUField< real_t > >(BFieldID, particleAndVolumeFractionSoA.BFieldID), + "copy B field from GPU to CPU"); +#endif + timeloop.add() << Sweep(getterSweep, "compute velocity") + << AfterFunction(SharedFunctor< DragForceEval_T >(forceEval), "drag force evaluation"); + + // resetting force + timeloop.addFuncAfterTimeStep( + [ps, accessor]() { + ps->forEachParticle(false, mesa_pd::kernel::SelectAll(), *accessor, + lbm_mesapd_coupling::ResetHydrodynamicForceTorqueKernel(), *accessor); + }, + "reset force on sphere"); + + timeloop.addFuncAfterTimeStep(RemainingTimeLogger(timeloop.getNrOfTimeSteps()), "Remaining Time Logger"); + + if (vtkFrequency > 0) + { + const std::string path = "vtk_out/dragForceSphereCPUGPU"; + auto vtkOutput = vtk::createVTKOutput_BlockData(*blocks, "psm_velocity_fieldCPUGPU", vtkFrequency, 0, false, path, + "simulation_step", false, true, true, false, 0); + + vtkOutput->addBeforeFunction([&]() { +#ifdef WALBERLA_BUILD_WITH_GPU_SUPPORT + gpu::fieldCpy< PdfField_T, gpu::GPUField< real_t > >(blocks, pdfFieldID, pdfFieldCPUGPUID); + gpu::fieldCpy< BField_T, gpu::GPUField< real_t > >(blocks, BFieldID, particleAndVolumeFractionSoA.BFieldID); +#endif + for (auto& block : *blocks) + getterSweep(&block); + }); + vtkOutput->addCellDataWriter(make_shared< field::VTKWriter< VelocityField_T > >(velFieldID, "Velocity")); + + timeloop.addFuncBeforeTimeStep(vtk::writeFiles(vtkOutput), "VTK Output"); + } + + //////////////////////// + // EXECUTE SIMULATION // + //////////////////////// + + WcTimingPool timeloopTiming; + + // time loop + for (uint_t i = 0; i < timesteps; ++i) + { + // perform a single simulation step + timeloop.singleStep(timeloopTiming); + + // check if the relative change in the normalized drag force is below the specified convergence criterion + if (i > setup.checkFrequency && forceEval->getDragForceDiff() < convergenceLimit) + { + // if simulation has converged, terminate simulation + break; + } + } + + timeloopTiming.logResultOnRoot(); + + if (!funcTest && !shortrun) + { + // check the result + real_t relErr = std::fabs((setup.analyticalDrag - forceEval->getDragForce()) / setup.analyticalDrag); + if (logging) + { + WALBERLA_ROOT_SECTION() + { + std::cout << "Analytical drag: " << setup.analyticalDrag << "\n" + << "Simulated drag: " << forceEval->getDragForce() << "\n" + << "Relative error: " << relErr << "\n"; + } + forceEval->logResultToFile("log_DragForceSphere.txt"); + } + // the relative error has to be below 10% + WALBERLA_CHECK_LESS(relErr, real_c(0.1)); + } + + return 0; +} + +} // namespace drag_force_sphere_psm + +int main(int argc, char** argv) { drag_force_sphere_psm::main(argc, argv); } diff --git a/tests/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/ParticleAndVolumeFractionMapping.cpp b/tests/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/ParticleAndVolumeFractionMapping.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d71062655a4e4b4bffaa325bb040654d9e603900 --- /dev/null +++ b/tests/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/ParticleAndVolumeFractionMapping.cpp @@ -0,0 +1,311 @@ +//====================================================================================================================== +// +// This file is part of waLBerla. waLBerla 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. +// +// waLBerla 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 waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file ParticleAndVolumeFractionMappingPSMCPUGPU.cpp +//! \ingroup lbm_mesapd_coupling +//! \author Samuel Kemmler <samuel.kemmler@fau.de> +// +//====================================================================================================================== + +#include "blockforest/Initialization.h" + +#include "core/DataTypes.h" +#include "core/Environment.h" +#include "core/debug/TestSubsystem.h" + +#include "field/AddToStorage.h" + +#ifdef WALBERLA_BUILD_WITH_GPU_SUPPORT +# include "gpu/FieldCopy.h" +# include "gpu/GPUField.h" +#endif + +#include "lbm_mesapd_coupling/partially_saturated_cells_method/codegen/PSMSweepCollection.h" +#include "lbm_mesapd_coupling/utility/ParticleSelector.h" + +#include "mesa_pd/data/ParticleAccessorWithShape.h" +#include "mesa_pd/data/ParticleStorage.h" +#include "mesa_pd/data/ShapeStorage.h" +#include "mesa_pd/domain/BlockForestDomain.h" +#include "mesa_pd/kernel/SemiImplicitEuler.h" +#include "mesa_pd/mpi/SyncNextNeighbors.h" + +#include <memory> + +namespace particle_volume_fraction_check +{ + +/////////// +// USING // +/////////// + +using namespace walberla; +using namespace walberla::lbm_mesapd_coupling::psm::gpu; + +//******************************************************************************************************************* +/*!\brief Calculating the sum over all fraction values. This can be used as a sanity check since it has to be roughly + * equal to the volume of all particles. + * + */ +//******************************************************************************************************************* +class FractionFieldSum +{ + public: + FractionFieldSum(const shared_ptr< StructuredBlockStorage >& blockStorage, + const BlockDataID& nOverlappingParticlesFieldID, const BlockDataID& BsFieldID) + : blockStorage_(blockStorage), nOverlappingParticlesFieldID_(nOverlappingParticlesFieldID), BsFieldID_(BsFieldID) + {} + + real_t operator()() + { + real_t sum = 0.0; + + for (auto blockIt = blockStorage_->begin(); blockIt != blockStorage_->end(); ++blockIt) + { + auto nOverlappingParticlesField = + blockIt->getData< nOverlappingParticlesField_T >(nOverlappingParticlesFieldID_); + auto BsField = blockIt->getData< BsField_T >(BsFieldID_); + + const cell_idx_t xSize = cell_idx_c(BsField->xSize()); + const cell_idx_t ySize = cell_idx_c(BsField->ySize()); + const cell_idx_t zSize = cell_idx_c(BsField->zSize()); + + for (cell_idx_t z = 0; z < zSize; ++z) + { + for (cell_idx_t y = 0; y < ySize; ++y) + { + for (cell_idx_t x = 0; x < xSize; ++x) + { + for (uint_t n = 0; n < nOverlappingParticlesField->get(x, y, z); ++n) + { + sum += BsField->get(x, y, z, n); + } + } + } + } + } + + WALBERLA_MPI_SECTION() { mpi::allReduceInplace(sum, mpi::SUM); } + + return sum; + } + + private: + shared_ptr< StructuredBlockStorage > blockStorage_; + BlockDataID nOverlappingParticlesFieldID_; + BlockDataID BsFieldID_; +}; + +//////////////// +// Parameters // +//////////////// + +struct Setup +{ + // domain size (in lattice cells) in x, y and z direction + uint_t xlength; + uint_t ylength; + uint_t zlength; + + // number of block in x, y and z, direction + Vector3< uint_t > nBlocks; + + // cells per block in x, y and z direction + Vector3< uint_t > cellsPerBlock; + + real_t sphereDiam; + + uint_t timesteps; +}; + +////////// +// MAIN // +////////// + +//******************************************************************************************************************* +/*!\brief Testcase that checks if ParticleAndVolumeFractionMapping.h works as intended + * + * A sphere particle is placed inside the domain and is moving with a constant velocity. The overlap fraction is + * computed for all cells in each time step. If the mapping is correct, the sum over all fractions should be roughly + * equivalent to the volume of the sphere. + * + */ +//******************************************************************************************************************* + +int main(int argc, char** argv) +{ + debug::enterTestMode(); + + mpi::Environment env(argc, argv); + + logging::Logging::instance()->setLogLevel(logging::Logging::INFO); + + auto processes = MPIManager::instance()->numProcesses(); + + if (processes != 27) + { + std::cerr << "Number of processes must be 27!" << std::endl; + return EXIT_FAILURE; + } + + /////////////////////////// + // SIMULATION PROPERTIES // + /////////////////////////// + + Setup setup; + + setup.sphereDiam = real_c(12); + setup.zlength = uint_c(4 * setup.sphereDiam); + setup.xlength = setup.zlength; + setup.ylength = setup.zlength; + + const real_t sphereRadius = real_c(0.5) * setup.sphereDiam; + const real_t dx = real_c(1); + + setup.timesteps = 100; + + /////////////////////////// + // BLOCK STRUCTURE SETUP // + /////////////////////////// + + setup.nBlocks[0] = uint_c(3); + setup.nBlocks[1] = uint_c(3); + setup.nBlocks[2] = uint_c(3); + setup.cellsPerBlock[0] = setup.xlength / setup.nBlocks[0]; + setup.cellsPerBlock[1] = setup.ylength / setup.nBlocks[1]; + setup.cellsPerBlock[2] = setup.zlength / setup.nBlocks[2]; + + auto blocks = + blockforest::createUniformBlockGrid(setup.nBlocks[0], setup.nBlocks[1], setup.nBlocks[2], setup.cellsPerBlock[0], + setup.cellsPerBlock[1], setup.cellsPerBlock[2], dx, true, true, true, true); + + //////////// + // MesaPD // + //////////// + + auto mesapdDomain = std::make_shared< mesa_pd::domain::BlockForestDomain >(blocks->getBlockForestPointer()); + auto ps = std::make_shared< mesa_pd::data::ParticleStorage >(1); + auto ss = std::make_shared< mesa_pd::data::ShapeStorage >(); + using ParticleAccessor_T = mesa_pd::data::ParticleAccessorWithShape; + auto accessor = walberla::make_shared< ParticleAccessor_T >(ps, ss); + + // set up synchronization + std::function< void(void) > syncCall = [&]() { + mesa_pd::mpi::SyncNextNeighbors syncNextNeighborFunc; + syncNextNeighborFunc(*ps, *mesapdDomain); + }; + + // add the sphere in the center of the domain + Vector3< real_t > position(real_c(setup.xlength) * real_c(0.5), real_c(setup.ylength) * real_c(0.5), + real_c(setup.zlength) * real_c(0.5)); + Vector3< real_t > velocity(real_c(0.1), real_c(0.1), real_c(0.1)); + auto sphereShape = ss->create< mesa_pd::data::Sphere >(sphereRadius); + + if (mesapdDomain->isContainedInProcessSubdomain(uint_c(walberla::mpi::MPIManager::instance()->rank()), position)) + { + auto sphereParticle = ps->create(); + + sphereParticle->setShapeID(sphereShape); + sphereParticle->setType(0); + sphereParticle->setPosition(position); + sphereParticle->setLinearVelocity(velocity); + sphereParticle->setOwner(walberla::MPIManager::instance()->rank()); + sphereParticle->setInteractionRadius(sphereRadius); + } + + Vector3< real_t > position2(real_c(0.0), real_c(0.0), real_c(0.0)); + Vector3< real_t > velocity2(real_c(0.1), real_c(0.1), real_c(0.1)); + + if (mesapdDomain->isContainedInProcessSubdomain(uint_c(walberla::mpi::MPIManager::instance()->rank()), position2)) + { + auto sphereParticle = ps->create(); + + sphereParticle->setShapeID(sphereShape); + sphereParticle->setType(0); + sphereParticle->setPosition(position2); + sphereParticle->setLinearVelocity(velocity2); + sphereParticle->setOwner(walberla::MPIManager::instance()->rank()); + sphereParticle->setInteractionRadius(sphereRadius); + } + + syncCall(); + + /////////////////////// + // ADD DATA TO BLOCKS // + //////////////////////// + +#ifdef WALBERLA_BUILD_WITH_GPU_SUPPORT + // add particle and volume fraction fields (needed for the PSM) + BlockDataID nOverlappingParticlesFieldID = field::addToStorage< nOverlappingParticlesField_T >( + blocks, "number of overlapping particles field CPU", 0, field::fzyx, 1); + BlockDataID BsFieldID = field::addToStorage< BsField_T >(blocks, "Bs field CPU", 0, field::fzyx, 1); +#endif + + // dummy value for omega since it is not use because Weighting_T == 1 + real_t omega = real_t(42.0); + ParticleAndVolumeFractionSoA_T< 1 > particleAndVolumeFractionSoA(blocks, omega); + + // calculate fraction + PSMSweepCollection psmSweepCollection(blocks, accessor, lbm_mesapd_coupling::RegularParticlesSelector(), + particleAndVolumeFractionSoA, Vector3(16)); + for (auto blockIt = blocks->begin(); blockIt != blocks->end(); ++blockIt) + { + psmSweepCollection.particleMappingSweep(&(*blockIt)); + } + +#ifdef WALBERLA_BUILD_WITH_GPU_SUPPORT + FractionFieldSum fractionFieldSum(blocks, nOverlappingParticlesFieldID, BsFieldID); +#else + FractionFieldSum fractionFieldSum(blocks, particleAndVolumeFractionSoA.nOverlappingParticlesFieldID, + particleAndVolumeFractionSoA.BsFieldID); +#endif + auto selector = mesa_pd::kernel::SelectMaster(); + mesa_pd::kernel::SemiImplicitEuler particleIntegration(1.0); + + for (uint_t i = 0; i < setup.timesteps; ++i) + { +#ifdef WALBERLA_BUILD_WITH_GPU_SUPPORT + // copy data back to perform the check on CPU + for (auto blockIt = blocks->begin(); blockIt != blocks->end(); ++blockIt) + { + gpu::fieldCpySweepFunction< nOverlappingParticlesField_T, nOverlappingParticlesFieldGPU_T >( + nOverlappingParticlesFieldID, particleAndVolumeFractionSoA.nOverlappingParticlesFieldID, &(*blockIt)); + gpu::fieldCpySweepFunction< BsField_T, BsFieldGPU_T >(BsFieldID, particleAndVolumeFractionSoA.BsFieldID, + &(*blockIt)); + } +#endif + + // check that the sum over all fractions is roughly the volume of the sphere + real_t sum = fractionFieldSum(); + WALBERLA_CHECK_LESS(std::fabs(4.0 / 3.0 * math::pi * sphereRadius * sphereRadius * sphereRadius * 2 - sum), + real_c(5)); + + // update position + ps->forEachParticle(false, selector, *accessor, particleIntegration, *accessor); + syncCall(); + + // map particles into field + for (auto blockIt = blocks->begin(); blockIt != blocks->end(); ++blockIt) + { + psmSweepCollection.particleMappingSweep(&(*blockIt)); + } + } + + return EXIT_SUCCESS; +} + +} // namespace particle_volume_fraction_check + +int main(int argc, char** argv) { particle_volume_fraction_check::main(argc, argv); } diff --git a/tests/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/SettlingSpherePSM.cpp b/tests/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/SettlingSpherePSM.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bbcf1a2392322e9e4f45ffeb316240ba3bc0abe4 --- /dev/null +++ b/tests/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/SettlingSpherePSM.cpp @@ -0,0 +1,871 @@ +//====================================================================================================================== +// +// This file is part of waLBerla. waLBerla 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. +// +// waLBerla 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 waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file SettlingSpherePSMGPU.cpp +//! \ingroup lbm_mesapd_coupling +//! \author Samuel Kemmler <samuel.kemmler@fau.de> +//! \author Christoph Rettinger <christoph.rettinger@fau.de> +//! \brief Modification of momentum_exchange_method/SettlingSphere.cpp +// +//====================================================================================================================== + +#include "blockforest/Initialization.h" +#include "blockforest/communication/UniformBufferedScheme.h" + +#include "core/Environment.h" +#include "core/debug/TestSubsystem.h" +#include "core/logging/all.h" +#include "core/math/all.h" +#include "core/timing/RemainingTimeLogger.h" + +#include "field/AddToStorage.h" +#include "field/vtk/all.h" + +#include "geometry/InitBoundaryHandling.h" + +#include "gpu/AddGPUFieldToStorage.h" +#include "gpu/DeviceSelectMPI.h" +#include "gpu/communication/UniformGPUScheme.h" + +#include "lbm/field/AddToStorage.h" +#include "lbm/vtk/all.h" + +#include "lbm_mesapd_coupling/DataTypesCodegen.h" +#include "lbm_mesapd_coupling/partially_saturated_cells_method/codegen/PSMSweepCollection.h" +#include "lbm_mesapd_coupling/utility/AddForceOnParticlesKernel.h" +#include "lbm_mesapd_coupling/utility/AddHydrodynamicInteractionKernel.h" +#include "lbm_mesapd_coupling/utility/AverageHydrodynamicForceTorqueKernel.h" +#include "lbm_mesapd_coupling/utility/InitializeHydrodynamicForceTorqueForAveragingKernel.h" +#include "lbm_mesapd_coupling/utility/LubricationCorrectionKernel.h" +#include "lbm_mesapd_coupling/utility/ParticleSelector.h" +#include "lbm_mesapd_coupling/utility/ResetHydrodynamicForceTorqueKernel.h" + +#include "mesa_pd/collision_detection/AnalyticContactDetection.h" +#include "mesa_pd/data/DataTypes.h" +#include "mesa_pd/data/ParticleAccessorWithShape.h" +#include "mesa_pd/data/ParticleStorage.h" +#include "mesa_pd/data/ShapeStorage.h" +#include "mesa_pd/data/shape/HalfSpace.h" +#include "mesa_pd/data/shape/Sphere.h" +#include "mesa_pd/domain/BlockForestDomain.h" +#include "mesa_pd/kernel/DoubleCast.h" +#include "mesa_pd/kernel/ExplicitEuler.h" +#include "mesa_pd/kernel/ParticleSelector.h" +#include "mesa_pd/kernel/SpringDashpot.h" +#include "mesa_pd/kernel/VelocityVerlet.h" +#include "mesa_pd/mpi/ContactFilter.h" +#include "mesa_pd/mpi/ReduceProperty.h" +#include "mesa_pd/mpi/SyncNextNeighbors.h" +#include "mesa_pd/mpi/notifications/ForceTorqueNotification.h" +#include "mesa_pd/mpi/notifications/HydrodynamicForceTorqueNotification.h" +#include "mesa_pd/vtk/ParticleVtkOutput.h" + +#include "vtk/all.h" + +#include <functional> + +#include "InitializeDomainForPSM.h" +#include "PSMPackInfo.h" +#include "PSMSweep.h" +#include "PSM_InfoHeader.h" +#include "PSM_MacroGetter.h" +#include "PSM_NoSlip.h" + +namespace settling_sphere +{ + +/////////// +// USING // +/////////// + +using namespace walberla; +using walberla::uint_t; +using namespace lbm_mesapd_coupling::psm::gpu; + +using flag_t = walberla::uint8_t; +using FlagField_T = FlagField< flag_t >; + +typedef pystencils::PSMPackInfo PackInfo_T; + +/////////// +// FLAGS // +/////////// + +const FlagUID Fluid_Flag("Fluid"); +const FlagUID NoSlip_Flag("NoSlip"); + +//******************************************************************************************************************* +/*!\brief Evaluating the position and velocity of the sphere + * + */ +//******************************************************************************************************************* +template< typename ParticleAccessor_T > +class SpherePropertyLogger +{ + public: + SpherePropertyLogger(const shared_ptr< ParticleAccessor_T >& ac, walberla::id_t sphereUid, + const std::string& fileName, bool fileIO, real_t dx_SI, real_t dt_SI, real_t diameter, + real_t gravitationalForceMag) + : ac_(ac), sphereUid_(sphereUid), fileName_(fileName), fileIO_(fileIO), dx_SI_(dx_SI), dt_SI_(dt_SI), + diameter_(diameter), gravitationalForceMag_(gravitationalForceMag), position_(real_t(0)), + maxVelocity_(real_t(0)) + { + if (fileIO_) + { + WALBERLA_ROOT_SECTION() + { + std::ofstream file; + file.open(fileName_.c_str()); + file << "#\t t\t posX\t posY\t gapZ\t velX\t velY\t velZ\n"; + file.close(); + } + } + } + + void operator()(const uint_t timestep) + { + Vector3< real_t > pos(real_t(0)); + Vector3< real_t > transVel(real_t(0)); + Vector3< real_t > hydForce(real_t(0)); + + size_t idx = ac_->uidToIdx(sphereUid_); + if (idx != ac_->getInvalidIdx()) + { + if (!mesa_pd::data::particle_flags::isSet(ac_->getFlags(idx), mesa_pd::data::particle_flags::GHOST)) + { + pos = ac_->getPosition(idx); + transVel = ac_->getLinearVelocity(idx); + hydForce = ac_->getHydrodynamicForce(idx); + } + } + + WALBERLA_MPI_SECTION() + { + mpi::allReduceInplace(pos[0], mpi::SUM); + mpi::allReduceInplace(pos[1], mpi::SUM); + mpi::allReduceInplace(pos[2], mpi::SUM); + + mpi::allReduceInplace(transVel[0], mpi::SUM); + mpi::allReduceInplace(transVel[1], mpi::SUM); + mpi::allReduceInplace(transVel[2], mpi::SUM); + + mpi::allReduceInplace(hydForce[0], mpi::SUM); + mpi::allReduceInplace(hydForce[1], mpi::SUM); + mpi::allReduceInplace(hydForce[2], mpi::SUM); + } + + position_ = pos[2]; + maxVelocity_ = std::max(maxVelocity_, -transVel[2]); + + if (fileIO_) writeToFile(timestep, pos, transVel, hydForce); + } + + real_t getPosition() const { return position_; } + + real_t getMaxVelocity() const { return maxVelocity_; } + + private: + void writeToFile(const uint_t timestep, const Vector3< real_t >& position, const Vector3< real_t >& velocity, + const Vector3< real_t >& hydForce) + { + WALBERLA_ROOT_SECTION() + { + std::ofstream file; + file.open(fileName_.c_str(), std::ofstream::app); + + auto scaledPosition = position / diameter_; + auto velocity_SI = velocity * dx_SI_ / dt_SI_; + auto normalizedHydForce = hydForce / gravitationalForceMag_; + + file << timestep << "\t" << real_c(timestep) * dt_SI_ << "\t" << "\t" << scaledPosition[0] << "\t" + << scaledPosition[1] << "\t" << scaledPosition[2] - real_t(0.5) << "\t" << velocity_SI[0] << "\t" + << velocity_SI[1] << "\t" << velocity_SI[2] << "\t" << normalizedHydForce[0] << "\t" + << normalizedHydForce[1] << "\t" << normalizedHydForce[2] << "\n"; + file.close(); + } + } + + shared_ptr< ParticleAccessor_T > ac_; + const walberla::id_t sphereUid_; + std::string fileName_; + bool fileIO_; + real_t dx_SI_, dt_SI_, diameter_, gravitationalForceMag_; + + real_t position_; + real_t maxVelocity_; +}; + +void createPlaneSetup(const shared_ptr< mesa_pd::data::ParticleStorage >& ps, + const shared_ptr< mesa_pd::data::ShapeStorage >& ss, const math::AABB& simulationDomain) +{ + // create bounding planes + mesa_pd::data::Particle p0 = *ps->create(true); + p0.setPosition(simulationDomain.minCorner()); + p0.setInteractionRadius(std::numeric_limits< real_t >::infinity()); + p0.setShapeID(ss->create< mesa_pd::data::HalfSpace >(Vector3< real_t >(0, 0, 1))); + p0.setOwner(mpi::MPIManager::instance()->rank()); + p0.setType(0); + mesa_pd::data::particle_flags::set(p0.getFlagsRef(), mesa_pd::data::particle_flags::INFINITE); + mesa_pd::data::particle_flags::set(p0.getFlagsRef(), mesa_pd::data::particle_flags::FIXED); + + mesa_pd::data::Particle p1 = *ps->create(true); + p1.setPosition(simulationDomain.maxCorner()); + p1.setInteractionRadius(std::numeric_limits< real_t >::infinity()); + p1.setShapeID(ss->create< mesa_pd::data::HalfSpace >(Vector3< real_t >(0, 0, -1))); + p1.setOwner(mpi::MPIManager::instance()->rank()); + p1.setType(0); + mesa_pd::data::particle_flags::set(p1.getFlagsRef(), mesa_pd::data::particle_flags::INFINITE); + mesa_pd::data::particle_flags::set(p1.getFlagsRef(), mesa_pd::data::particle_flags::FIXED); + + mesa_pd::data::Particle p2 = *ps->create(true); + p2.setPosition(simulationDomain.minCorner()); + p2.setInteractionRadius(std::numeric_limits< real_t >::infinity()); + p2.setShapeID(ss->create< mesa_pd::data::HalfSpace >(Vector3< real_t >(1, 0, 0))); + p2.setOwner(mpi::MPIManager::instance()->rank()); + p2.setType(0); + mesa_pd::data::particle_flags::set(p2.getFlagsRef(), mesa_pd::data::particle_flags::INFINITE); + mesa_pd::data::particle_flags::set(p2.getFlagsRef(), mesa_pd::data::particle_flags::FIXED); + + mesa_pd::data::Particle p3 = *ps->create(true); + p3.setPosition(simulationDomain.maxCorner()); + p3.setInteractionRadius(std::numeric_limits< real_t >::infinity()); + p3.setShapeID(ss->create< mesa_pd::data::HalfSpace >(Vector3< real_t >(-1, 0, 0))); + p3.setOwner(mpi::MPIManager::instance()->rank()); + p3.setType(0); + mesa_pd::data::particle_flags::set(p3.getFlagsRef(), mesa_pd::data::particle_flags::INFINITE); + mesa_pd::data::particle_flags::set(p3.getFlagsRef(), mesa_pd::data::particle_flags::FIXED); + + mesa_pd::data::Particle p4 = *ps->create(true); + p4.setPosition(simulationDomain.minCorner()); + p4.setInteractionRadius(std::numeric_limits< real_t >::infinity()); + p4.setShapeID(ss->create< mesa_pd::data::HalfSpace >(Vector3< real_t >(0, 1, 0))); + p4.setOwner(mpi::MPIManager::instance()->rank()); + p4.setType(0); + mesa_pd::data::particle_flags::set(p4.getFlagsRef(), mesa_pd::data::particle_flags::INFINITE); + mesa_pd::data::particle_flags::set(p4.getFlagsRef(), mesa_pd::data::particle_flags::FIXED); + + mesa_pd::data::Particle p5 = *ps->create(true); + p5.setPosition(simulationDomain.maxCorner()); + p5.setInteractionRadius(std::numeric_limits< real_t >::infinity()); + p5.setShapeID(ss->create< mesa_pd::data::HalfSpace >(Vector3< real_t >(0, -1, 0))); + p5.setOwner(mpi::MPIManager::instance()->rank()); + p5.setType(0); + mesa_pd::data::particle_flags::set(p5.getFlagsRef(), mesa_pd::data::particle_flags::INFINITE); + mesa_pd::data::particle_flags::set(p5.getFlagsRef(), mesa_pd::data::particle_flags::FIXED); +} + +////////// +// MAIN // +////////// + +//******************************************************************************************************************* +/*!\brief Testcase that simulates the settling of a sphere inside a rectangular column filled with viscous fluid + * + * see: ten Cate, Nieuwstad, Derksen, Van den Akker - "Particle imaging velocimetry experiments and lattice-Boltzmann + * simulations on a single sphere settling under gravity" (2002), Physics of Fluids, doi: 10.1063/1.1512918 + */ +//******************************************************************************************************************* + +int main(int argc, char** argv) +{ + debug::enterTestMode(); + + mpi::Environment env(argc, argv); + + logging::Logging::instance()->setLogLevel(logging::Logging::INFO); + + /////////////////// + // Customization // + /////////////////// + + // simulation control + bool shortrun = false; + bool funcTest = false; + bool fileIO = false; + uint_t vtkIOFreq = 0; + std::string baseFolder = "vtk_out_SettlingSphere_CPU_GPU"; + + // physical setup + uint_t fluidType = 1; + + // numerical parameters + uint_t numberOfCellsInHorizontalDirection = uint_t(135); + bool averageForceTorqueOverTwoTimeSteps = true; + uint_t numRPDSubCycles = uint_t(1); + bool useVelocityVerlet = false; + + for (int i = 1; i < argc; ++i) + { + if (std::strcmp(argv[i], "--shortrun") == 0) + { + shortrun = true; + continue; + } + if (std::strcmp(argv[i], "--funcTest") == 0) + { + funcTest = true; + continue; + } + if (std::strcmp(argv[i], "--fileIO") == 0) + { + fileIO = true; + continue; + } + if (std::strcmp(argv[i], "--vtkIOFreq") == 0) + { + vtkIOFreq = uint_c(std::atof(argv[++i])); + continue; + } + if (std::strcmp(argv[i], "--fluidType") == 0) + { + fluidType = uint_c(std::atof(argv[++i])); + continue; + } + if (std::strcmp(argv[i], "--numRPDSubCycles") == 0) + { + numRPDSubCycles = uint_c(std::atof(argv[++i])); + continue; + } + if (std::strcmp(argv[i], "--resolution") == 0) + { + numberOfCellsInHorizontalDirection = uint_c(std::atof(argv[++i])); + continue; + } + if (std::strcmp(argv[i], "--noForceAveraging") == 0) + { + averageForceTorqueOverTwoTimeSteps = false; + continue; + } + if (std::strcmp(argv[i], "--baseFolder") == 0) + { + baseFolder = argv[++i]; + continue; + } + if (std::strcmp(argv[i], "--useVV") == 0) + { + useVelocityVerlet = true; + continue; + } + WALBERLA_ABORT("Unrecognized command line argument found: " << argv[i]); + } + + if (funcTest) { walberla::logging::Logging::instance()->setLogLevel(logging::Logging::LogLevel::WARNING); } + + if (fileIO) + { + // create base directory if it does not yet exist + filesystem::path tpath(baseFolder); + if (!filesystem::exists(tpath)) filesystem::create_directory(tpath); + } + + ////////////////////////////////////// + // SIMULATION PROPERTIES in SI units// + ////////////////////////////////////// + + // values are mainly taken from the reference paper + const real_t diameter_SI = real_t(15e-3); + const real_t densitySphere_SI = real_t(1120); + + real_t densityFluid_SI, dynamicViscosityFluid_SI; + real_t expectedSettlingVelocity_SI; + switch (fluidType) + { + case 1: + // Re_p around 1.5 + densityFluid_SI = real_t(970); + dynamicViscosityFluid_SI = real_t(373e-3); + expectedSettlingVelocity_SI = real_t(0.035986); + break; + case 2: + // Re_p around 4.1 + densityFluid_SI = real_t(965); + dynamicViscosityFluid_SI = real_t(212e-3); + expectedSettlingVelocity_SI = real_t(0.05718); + break; + case 3: + // Re_p around 11.6 + densityFluid_SI = real_t(962); + dynamicViscosityFluid_SI = real_t(113e-3); + expectedSettlingVelocity_SI = real_t(0.087269); + break; + case 4: + // Re_p around 31.9 + densityFluid_SI = real_t(960); + dynamicViscosityFluid_SI = real_t(58e-3); + expectedSettlingVelocity_SI = real_t(0.12224); + break; + default: + WALBERLA_ABORT("Only four different fluids are supported! Choose type between 1 and 4."); + } + const real_t kinematicViscosityFluid_SI = dynamicViscosityFluid_SI / densityFluid_SI; + + const real_t gravitationalAcceleration_SI = real_t(9.81); + Vector3< real_t > domainSize_SI(real_t(100e-3), real_t(100e-3), real_t(160e-3)); + // shift starting gap a bit upwards to match the reported (plotted) values + const real_t startingGapSize_SI = real_t(120e-3) + real_t(0.25) * diameter_SI; + + WALBERLA_LOG_INFO_ON_ROOT("Setup (in SI units):"); + WALBERLA_LOG_INFO_ON_ROOT(" - fluid type = " << fluidType); + WALBERLA_LOG_INFO_ON_ROOT(" - domain size = " << domainSize_SI); + WALBERLA_LOG_INFO_ON_ROOT(" - sphere: diameter = " << diameter_SI << ", density = " << densitySphere_SI + << ", starting gap size = " << startingGapSize_SI); + WALBERLA_LOG_INFO_ON_ROOT(" - fluid: density = " << densityFluid_SI << ", dyn. visc = " << dynamicViscosityFluid_SI + << ", kin. visc = " << kinematicViscosityFluid_SI); + WALBERLA_LOG_INFO_ON_ROOT(" - expected settling velocity = " + << expectedSettlingVelocity_SI << " --> Re_p = " + << expectedSettlingVelocity_SI * diameter_SI / kinematicViscosityFluid_SI); + + ////////////////////////// + // NUMERICAL PARAMETERS // + ////////////////////////// + + const real_t dx_SI = domainSize_SI[0] / real_c(numberOfCellsInHorizontalDirection); + const Vector3< uint_t > domainSize(uint_c(floor(domainSize_SI[0] / dx_SI + real_t(0.5))), + uint_c(floor(domainSize_SI[1] / dx_SI + real_t(0.5))), + uint_c(floor(domainSize_SI[2] / dx_SI + real_t(0.5)))); + const real_t diameter = diameter_SI / dx_SI; + const real_t sphereVolume = math::pi / real_t(6) * diameter * diameter * diameter; + + const real_t expectedSettlingVelocity = real_t(0.01); + const real_t dt_SI = expectedSettlingVelocity / expectedSettlingVelocity_SI * dx_SI; + + const real_t viscosity = kinematicViscosityFluid_SI * dt_SI / (dx_SI * dx_SI); + const real_t relaxationTime = real_t(1) / lbm::collision_model::omegaFromViscosity(viscosity); + + const real_t gravitationalAcceleration = gravitationalAcceleration_SI * dt_SI * dt_SI / dx_SI; + + const real_t densityFluid = real_t(1); + const real_t densitySphere = densityFluid * densitySphere_SI / densityFluid_SI; + + const real_t dx = real_t(1); + + const uint_t timesteps = funcTest ? 1 : (shortrun ? uint_t(200) : uint_t(250000)); + + WALBERLA_LOG_INFO_ON_ROOT(" - dx_SI = " << dx_SI << ", dt_SI = " << dt_SI); + WALBERLA_LOG_INFO_ON_ROOT("Setup (in simulation, i.e. lattice, units):"); + WALBERLA_LOG_INFO_ON_ROOT(" - domain size = " << domainSize); + WALBERLA_LOG_INFO_ON_ROOT(" - sphere: diameter = " << diameter << ", density = " << densitySphere); + WALBERLA_LOG_INFO_ON_ROOT(" - fluid: density = " << densityFluid << ", relaxation time (tau) = " << relaxationTime + << ", kin. visc = " << viscosity); + WALBERLA_LOG_INFO_ON_ROOT(" - gravitational acceleration = " << gravitationalAcceleration); + WALBERLA_LOG_INFO_ON_ROOT(" - expected settling velocity = " << expectedSettlingVelocity << " --> Re_p = " + << expectedSettlingVelocity * diameter / viscosity); + WALBERLA_LOG_INFO_ON_ROOT(" - integrator = " << (useVelocityVerlet ? "Velocity Verlet" : "Explicit Euler")); + + if (vtkIOFreq > 0) + { + WALBERLA_LOG_INFO_ON_ROOT(" - writing vtk files to folder \"" << baseFolder << "\" with frequency " << vtkIOFreq); + } + + /////////////////////////// + // BLOCK STRUCTURE SETUP // + /////////////////////////// + + Vector3< uint_t > numberOfBlocksPerDirection(uint_t(1), uint_t(1), uint_t(MPIManager::instance()->numProcesses())); + Vector3< uint_t > cellsPerBlockPerDirection(domainSize[0] / numberOfBlocksPerDirection[0], + domainSize[1] / numberOfBlocksPerDirection[1], + domainSize[2] / numberOfBlocksPerDirection[2]); + WALBERLA_CHECK_EQUAL( + numberOfBlocksPerDirection[0] * numberOfBlocksPerDirection[1] * numberOfBlocksPerDirection[2], + uint_t(MPIManager::instance()->numProcesses()), + "When using GPUs, the number of blocks (" + << numberOfBlocksPerDirection[0] * numberOfBlocksPerDirection[1] * numberOfBlocksPerDirection[2] + << ") has to match the number of MPI processes (" << uint_t(MPIManager::instance()->numProcesses()) << ")"); + + for (uint_t i = 0; i < 3; ++i) + { + WALBERLA_CHECK_EQUAL(cellsPerBlockPerDirection[i] * numberOfBlocksPerDirection[i], domainSize[i], + "Unmatching domain decomposition in direction " << i << "!"); + } + + auto blocks = blockforest::createUniformBlockGrid(numberOfBlocksPerDirection[0], numberOfBlocksPerDirection[1], + numberOfBlocksPerDirection[2], cellsPerBlockPerDirection[0], + cellsPerBlockPerDirection[1], cellsPerBlockPerDirection[2], dx, 0, + false, false, false, false, false, // periodicity + false); + + WALBERLA_LOG_INFO_ON_ROOT("Domain decomposition:"); + WALBERLA_LOG_INFO_ON_ROOT(" - blocks per direction = " << numberOfBlocksPerDirection); + WALBERLA_LOG_INFO_ON_ROOT(" - cells per block = " << cellsPerBlockPerDirection); + + // write domain decomposition to file + if (vtkIOFreq > 0) { vtk::writeDomainDecomposition(blocks, "initial_domain_decomposition", baseFolder); } + + ////////////////// + // RPD COUPLING // + ////////////////// + + auto rpdDomain = std::make_shared< mesa_pd::domain::BlockForestDomain >(blocks->getBlockForestPointer()); + + // init data structures + auto ps = walberla::make_shared< mesa_pd::data::ParticleStorage >(1); + auto ss = walberla::make_shared< mesa_pd::data::ShapeStorage >(); + using ParticleAccessor_T = mesa_pd::data::ParticleAccessorWithShape; + auto accessor = walberla::make_shared< ParticleAccessor_T >(ps, ss); + + // bounding planes + createPlaneSetup(ps, ss, blocks->getDomain()); + + // create sphere and store Uid + Vector3< real_t > initialPosition(real_t(0.5) * real_c(domainSize[0]), real_t(0.5) * real_c(domainSize[1]), + startingGapSize_SI / dx_SI + real_t(0.5) * diameter); + auto sphereShape = ss->create< mesa_pd::data::Sphere >(diameter * real_t(0.5)); + ss->shapes[sphereShape]->updateMassAndInertia(densitySphere); + + walberla::id_t sphereUid = 0; + if (rpdDomain->isContainedInProcessSubdomain(uint_c(mpi::MPIManager::instance()->rank()), initialPosition)) + { + mesa_pd::data::Particle&& p = *ps->create(); + p.setPosition(initialPosition); + p.setInteractionRadius(diameter * real_t(0.5)); + p.setOwner(mpi::MPIManager::instance()->rank()); + p.setShapeID(sphereShape); + sphereUid = p.getUid(); + } + mpi::allReduceInplace(sphereUid, mpi::SUM); + + /////////////////////// + // ADD DATA TO BLOCKS // + //////////////////////// + + // add PDF field +#ifdef WALBERLA_BUILD_WITH_GPU_SUPPORT + BlockDataID pdfFieldID = + field::addToStorage< PdfField_T >(blocks, "pdf field (fzyx)", real_c(std::nan("")), field::fzyx); + BlockDataID BFieldID = field::addToStorage< BField_T >(blocks, "B field CPU", 0, field::fzyx, 1); + BlockDataID BsFieldID = field::addToStorage< BsField_T >(blocks, "Bs field CPU", 0, field::fzyx, 1); + BlockDataID pdfFieldCPUGPUID = gpu::addGPUFieldToStorage< PdfField_T >(blocks, pdfFieldID, "pdf field GPU"); +#else + BlockDataID pdfFieldCPUGPUID = + field::addToStorage< PdfField_T >(blocks, "pdf field CPU", real_c(std::nan("")), field::fzyx); +#endif + + BlockDataID densityFieldID = field::addToStorage< DensityField_T >(blocks, "Density", real_t(0), field::fzyx); + BlockDataID velFieldID = field::addToStorage< VelocityField_T >(blocks, "Velocity", real_t(0), field::fzyx); + + // add flag field + BlockDataID flagFieldID = field::addFlagFieldToStorage< FlagField_T >(blocks, "flag field"); + + // set up RPD functionality + std::function< void(void) > syncCall = [ps, rpdDomain]() { + mesa_pd::mpi::SyncNextNeighbors syncNextNeighborFunc; + syncNextNeighborFunc(*ps, *rpdDomain); + }; + + syncCall(); + + mesa_pd::kernel::ExplicitEuler explEulerIntegrator(real_t(1) / real_t(numRPDSubCycles)); + mesa_pd::kernel::VelocityVerletPreForceUpdate vvIntegratorPreForce(real_t(1) / real_t(numRPDSubCycles)); + mesa_pd::kernel::VelocityVerletPostForceUpdate vvIntegratorPostForce(real_t(1) / real_t(numRPDSubCycles)); + + mesa_pd::kernel::SpringDashpot collisionResponse(1); + mesa_pd::mpi::ReduceProperty reduceProperty; + + // set up coupling functionality + lbm_mesapd_coupling::RegularParticlesSelector sphereSelector; + Vector3< real_t > gravitationalForce(real_t(0), real_t(0), + -(densitySphere - densityFluid) * gravitationalAcceleration * sphereVolume); + lbm_mesapd_coupling::AddForceOnParticlesKernel addGravitationalForce(gravitationalForce); + lbm_mesapd_coupling::AddHydrodynamicInteractionKernel addHydrodynamicInteraction; + lbm_mesapd_coupling::ResetHydrodynamicForceTorqueKernel resetHydrodynamicForceTorque; + lbm_mesapd_coupling::AverageHydrodynamicForceTorqueKernel averageHydrodynamicForceTorque; + lbm_mesapd_coupling::LubricationCorrectionKernel lubricationCorrectionKernel( + viscosity, [](real_t r) { return real_t(0.0016) * r; }); + lbm::PSM_NoSlip noSlip(blocks, pdfFieldCPUGPUID); + + /////////////// + // TIME LOOP // + /////////////// + + // map no-slip boundaries into the LBM simulation + std::string boundariesBlockString = " Boundaries" + "{" + "Border { direction T; walldistance -1; flag NoSlip; }" + "Border { direction B; walldistance -1; flag NoSlip; }" + "Border { direction N; walldistance -1; flag NoSlip; }" + "Border { direction S; walldistance -1; flag NoSlip; }" + "Border { direction W; walldistance -1; flag NoSlip; }" + "Border { direction E; walldistance -1; flag NoSlip; }" + "}"; + + WALBERLA_ROOT_SECTION() + { + std::ofstream boundariesFile("boundaries.prm"); + boundariesFile << boundariesBlockString; + boundariesFile.close(); + } + WALBERLA_MPI_BARRIER() + + auto boundariesCfgFile = Config(); + boundariesCfgFile.readParameterFile("boundaries.prm"); + auto boundariesConfig = boundariesCfgFile.getBlock("Boundaries"); + geometry::initBoundaryHandling< FlagField_T >(*blocks, flagFieldID, boundariesConfig); + geometry::setNonBoundaryCellsToDomain< FlagField_T >(*blocks, flagFieldID, Fluid_Flag); + noSlip.fillFromFlagField< FlagField_T >(blocks, flagFieldID, NoSlip_Flag, Fluid_Flag); + + // add particle and volume fraction data structures + ParticleAndVolumeFractionSoA_T< 1 > particleAndVolumeFractionSoA( + blocks, lbm::collision_model::omegaFromViscosity(viscosity)); + // map particles and calculate solid volume fraction initially + PSMSweepCollection psmSweepCollection(blocks, accessor, sphereSelector, particleAndVolumeFractionSoA, Vector3(27)); + for (auto blockIt = blocks->begin(); blockIt != blocks->end(); ++blockIt) + { + psmSweepCollection.particleMappingSweep(&(*blockIt)); + } + + pystencils::InitializeDomainForPSM pdfSetter( + particleAndVolumeFractionSoA.BsFieldID, particleAndVolumeFractionSoA.BFieldID, + particleAndVolumeFractionSoA.particleVelocitiesFieldID, pdfFieldCPUGPUID, real_t(0), real_t(0), real_t(0), + real_t(1.0), real_t(0), real_t(0), real_t(0)); + + for (auto blockIt = blocks->begin(); blockIt != blocks->end(); ++blockIt) + { + // pdfSetter requires particle velocities at cell centers + psmSweepCollection.setParticleVelocitiesSweep(&(*blockIt)); + pdfSetter(&(*blockIt)); + } + + // setup of the LBM communication for synchronizing the pdf field between neighboring blocks +#ifdef WALBERLA_BUILD_WITH_GPU_SUPPORT + gpu::communication::UniformGPUScheme< Stencil_T > com(blocks, 0, false); +#else + walberla::blockforest::communication::UniformBufferedScheme< Stencil_T > com(blocks); +#endif + + com.addPackInfo(make_shared< PackInfo_T >(pdfFieldCPUGPUID)); + auto communication = std::function< void() >([&]() { com.communicate(); }); + + // create the timeloop + SweepTimeloop timeloop(blocks->getBlockStorage(), timesteps); + + pystencils::PSMSweep PSMSweep(particleAndVolumeFractionSoA.BsFieldID, particleAndVolumeFractionSoA.BFieldID, + particleAndVolumeFractionSoA.particleForcesFieldID, + particleAndVolumeFractionSoA.particleVelocitiesFieldID, pdfFieldCPUGPUID, real_t(0.0), + real_t(0.0), real_t(0.0), lbm::collision_model::omegaFromViscosity(viscosity)); + + timeloop.addFuncBeforeTimeStep(RemainingTimeLogger(timeloop.getNrOfTimeSteps()), "Remaining Time Logger"); + +#ifdef WALBERLA_BUILD_WITH_GPU_SUPPORT + pystencils::PSM_MacroGetter getterSweep(BFieldID, densityFieldID, pdfFieldID, velFieldID, real_t(0.0), real_t(0.0), + real_t(0.0)); +#else + pystencils::PSM_MacroGetter getterSweep(particleAndVolumeFractionSoA.BFieldID, densityFieldID, pdfFieldCPUGPUID, + velFieldID, real_t(0.0), real_t(0.0), real_t(0.0)); +#endif + // vtk output + if (vtkIOFreq != uint_t(0)) + { + // spheres + auto particleVtkOutput = make_shared< mesa_pd::vtk::ParticleVtkOutput >(ps); + particleVtkOutput->setParticleSelector([sphereShape](const mesa_pd::data::ParticleStorage::iterator& pIt) { + return pIt->getShapeID() == sphereShape; + }); + particleVtkOutput->addOutput< mesa_pd::data::SelectParticleOwner >("owner"); + particleVtkOutput->addOutput< mesa_pd::data::SelectParticleLinearVelocity >("velocity"); + auto particleVtkWriter = + vtk::createVTKOutput_PointData(particleVtkOutput, "Particles", vtkIOFreq, baseFolder, "simulation_step"); + timeloop.addFuncBeforeTimeStep(vtk::writeFiles(particleVtkWriter), "VTK (sphere data)"); + + // flag field (written only once in the first time step, ghost layers are also written) + // auto flagFieldVTK = vtk::createVTKOutput_BlockData( blocks, "flag_field", timesteps, FieldGhostLayers, false, + // baseFolder ); flagFieldVTK->addCellDataWriter( make_shared< field::VTKWriter< FlagField_T > >( flagFieldID, + // "FlagField" ) ); timeloop.addFuncBeforeTimeStep( vtk::writeFiles( flagFieldVTK ), "VTK (flag field data)" ); + + // pdf field + auto pdfFieldVTK = vtk::createVTKOutput_BlockData(blocks, "fluid_field", vtkIOFreq, 0, false, baseFolder); + + pdfFieldVTK->addBeforeFunction(communication); + + pdfFieldVTK->addBeforeFunction([&]() { +#ifdef WALBERLA_BUILD_WITH_GPU_SUPPORT + gpu::fieldCpy< PdfField_T, gpu::GPUField< real_t > >(blocks, pdfFieldID, pdfFieldCPUGPUID); + gpu::fieldCpy< BField_T, BFieldGPU_T >(blocks, BFieldID, particleAndVolumeFractionSoA.BFieldID); + gpu::fieldCpy< BsField_T, BsFieldGPU_T >(blocks, BsFieldID, particleAndVolumeFractionSoA.BsFieldID); +#endif + for (auto& block : *blocks) + getterSweep(&block); + }); + + field::FlagFieldCellFilter< FlagField_T > fluidFilter(flagFieldID); + fluidFilter.addFlag(Fluid_Flag); + pdfFieldVTK->addCellInclusionFilter(fluidFilter); + + pdfFieldVTK->addCellDataWriter(make_shared< field::VTKWriter< VelocityField_T > >(velFieldID, "Velocity")); + pdfFieldVTK->addCellDataWriter(make_shared< field::VTKWriter< DensityField_T > >(densityFieldID, "Density")); +#ifdef WALBERLA_BUILD_WITH_GPU_SUPPORT + pdfFieldVTK->addCellDataWriter(make_shared< field::VTKWriter< BField_T > >(BFieldID, "Fraction mapping field B")); + pdfFieldVTK->addCellDataWriter( + make_shared< field::VTKWriter< BsField_T > >(BsFieldID, "Fraction mapping field Bs")); +#else + pdfFieldVTK->addCellDataWriter(make_shared< field::VTKWriter< BField_T > >(particleAndVolumeFractionSoA.BFieldID, + "Fraction mapping field B")); + pdfFieldVTK->addCellDataWriter(make_shared< field::VTKWriter< BsField_T > >( + particleAndVolumeFractionSoA.BsFieldID, "Fraction mapping field Bs")); +#endif + + timeloop.addFuncBeforeTimeStep(vtk::writeFiles(pdfFieldVTK), "VTK (fluid field data)"); + } + + // add LBM communication function and boundary handling sweep (does the hydro force calculations and the no-slip + // treatment) + timeloop.add() << BeforeFunction(communication, "LBM Communication") + << Sweep(noSlip.getSweep(), "Boundary Handling"); + + // stream + collide LBM step + addPSMSweepsToTimeloop(timeloop, psmSweepCollection, PSMSweep); + + // evaluation functionality + std::string loggingFileName(baseFolder + "/LoggingSettlingSphereGPU_"); + loggingFileName += std::to_string(fluidType); + loggingFileName += ".txt"; + if (fileIO) { WALBERLA_LOG_INFO_ON_ROOT(" - writing logging output to file \"" << loggingFileName << "\""); } + SpherePropertyLogger< ParticleAccessor_T > logger(accessor, sphereUid, loggingFileName, fileIO, dx_SI, dt_SI, + diameter, -gravitationalForce[2]); + + //////////////////////// + // EXECUTE SIMULATION // + //////////////////////// + + WcTimingPool timeloopTiming; + + real_t terminationPosition = real_t(0.51) * diameter; // right before sphere touches the bottom wall + + const bool useOpenMP = false; + + // time loop + for (uint_t i = 0; i < timesteps; ++i) + { + // perform a single simulation step -> this contains LBM and setting of the hydrodynamic interactions + timeloop.singleStep(timeloopTiming); + + timeloopTiming["RPD"].start(); + + // -> full hydrodynamic force/torque info is available on local particle + reduceProperty.operator()< mesa_pd::HydrodynamicForceTorqueNotification >(*ps); + + if (averageForceTorqueOverTwoTimeSteps) + { + if (i == 0) + { + lbm_mesapd_coupling::InitializeHydrodynamicForceTorqueForAveragingKernel + initializeHydrodynamicForceTorqueForAveragingKernel; + ps->forEachParticle(useOpenMP, mesa_pd::kernel::SelectLocal(), *accessor, + initializeHydrodynamicForceTorqueForAveragingKernel, *accessor); + } + ps->forEachParticle(useOpenMP, mesa_pd::kernel::SelectLocal(), *accessor, averageHydrodynamicForceTorque, + *accessor); + } + + for (auto subCycle = uint_t(0); subCycle < numRPDSubCycles; ++subCycle) + { + if (useVelocityVerlet) + { + ps->forEachParticle(useOpenMP, mesa_pd::kernel::SelectLocal(), *accessor, vvIntegratorPreForce, *accessor); + syncCall(); + } + + ps->forEachParticle(useOpenMP, mesa_pd::kernel::SelectLocal(), *accessor, addHydrodynamicInteraction, + *accessor); + ps->forEachParticle(useOpenMP, mesa_pd::kernel::SelectLocal(), *accessor, addGravitationalForce, *accessor); + + // lubrication correction + ps->forEachParticlePairHalf( + useOpenMP, mesa_pd::kernel::ExcludeInfiniteInfinite(), *accessor, + [&lubricationCorrectionKernel, rpdDomain](const size_t idx1, const size_t idx2, auto& ac) { + // TODO change this to storing copy, not reference + mesa_pd::collision_detection::AnalyticContactDetection acd; + acd.getContactThreshold() = lubricationCorrectionKernel.getNormalCutOffDistance(); + mesa_pd::kernel::DoubleCast double_cast; + mesa_pd::mpi::ContactFilter contact_filter; + if (double_cast(idx1, idx2, ac, acd, ac)) + { + if (contact_filter(acd.getIdx1(), acd.getIdx2(), ac, acd.getContactPoint(), *rpdDomain)) + { + double_cast(idx1, idx2, ac, lubricationCorrectionKernel, ac, acd.getContactNormal(), + acd.getPenetrationDepth()); + } + } + }, + *accessor); + + // one could add linked cells here + + // collision response + ps->forEachParticlePairHalf( + useOpenMP, mesa_pd::kernel::ExcludeInfiniteInfinite(), *accessor, + [collisionResponse, rpdDomain](const size_t idx1, const size_t idx2, auto& ac) { + mesa_pd::collision_detection::AnalyticContactDetection acd; + mesa_pd::kernel::DoubleCast double_cast; + mesa_pd::mpi::ContactFilter contact_filter; + if (double_cast(idx1, idx2, ac, acd, ac)) + { + if (contact_filter(acd.getIdx1(), acd.getIdx2(), ac, acd.getContactPoint(), *rpdDomain)) + { + collisionResponse(acd.getIdx1(), acd.getIdx2(), ac, acd.getContactPoint(), acd.getContactNormal(), + acd.getPenetrationDepth()); + } + } + }, + *accessor); + + reduceProperty.operator()< mesa_pd::ForceTorqueNotification >(*ps); + + if (useVelocityVerlet) + ps->forEachParticle(useOpenMP, mesa_pd::kernel::SelectLocal(), *accessor, vvIntegratorPostForce, *accessor); + else + ps->forEachParticle(useOpenMP, mesa_pd::kernel::SelectLocal(), *accessor, explEulerIntegrator, *accessor); + + syncCall(); + } + + timeloopTiming["RPD"].end(); + + // evaluation + timeloopTiming["Logging"].start(); + logger(i); + timeloopTiming["Logging"].end(); + + // reset after logging here + ps->forEachParticle(useOpenMP, mesa_pd::kernel::SelectAll(), *accessor, resetHydrodynamicForceTorque, *accessor); + + // check for termination + if (logger.getPosition() < terminationPosition) + { + WALBERLA_LOG_INFO_ON_ROOT("Sphere reached terminal position " << logger.getPosition() << " after " << i + << " timesteps!"); + break; + } + } + + timeloopTiming.logResultOnRoot(); + + // check the result + if (!funcTest && !shortrun) + { + real_t relErr = std::fabs(expectedSettlingVelocity - logger.getMaxVelocity()) / expectedSettlingVelocity; + WALBERLA_LOG_INFO_ON_ROOT("Expected maximum settling velocity: " << expectedSettlingVelocity); + WALBERLA_LOG_INFO_ON_ROOT("Simulated maximum settling velocity: " << logger.getMaxVelocity()); + WALBERLA_LOG_INFO_ON_ROOT("Relative error: " << relErr); + + // the relative error has to be below 10% + WALBERLA_CHECK_LESS(relErr, real_t(0.1)); + } + + return EXIT_SUCCESS; +} + +} // namespace settling_sphere + +int main(int argc, char** argv) { settling_sphere::main(argc, argv); } diff --git a/tests/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/TorqueSpherePSM.cpp b/tests/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/TorqueSpherePSM.cpp new file mode 100644 index 0000000000000000000000000000000000000000..194b3eb3a7dfbfc8f356aa9108c4b70694c1241a --- /dev/null +++ b/tests/lbm_mesapd_coupling/partially_saturated_cells_method/codegen/TorqueSpherePSM.cpp @@ -0,0 +1,480 @@ +//====================================================================================================================== +// +// This file is part of waLBerla. waLBerla 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. +// +// waLBerla 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 waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file TorqueSpherePSMGPU.cpp +//! \ingroup lbm_mesapd_coupling +//! \author Samuel Kemmler <samuel.kemmler@fau.de> +//! \author Christoph Rettinger <christoph.rettinger@fau.de> +//! \brief Modification of pe_coupling/partially_saturated_cells_method/TorqueSpherePSM.cpp +// +//====================================================================================================================== + +#include "blockforest/Initialization.h" +#include "blockforest/communication/UniformBufferedScheme.h" + +#include "core/Environment.h" +#include "core/SharedFunctor.h" +#include "core/debug/TestSubsystem.h" +#include "core/logging/Logging.h" +#include "core/mpi/MPIManager.h" +#include "core/mpi/Reduce.h" +#include "core/timing/RemainingTimeLogger.h" + +#include "field/AddToStorage.h" + +#include "gpu/AddGPUFieldToStorage.h" +#include "gpu/DeviceSelectMPI.h" +#include "gpu/communication/UniformGPUScheme.h" + +#include "lbm_mesapd_coupling/DataTypesCodegen.h" +#include "lbm_mesapd_coupling/partially_saturated_cells_method/codegen/PSMSweepCollection.h" +#include "lbm_mesapd_coupling/utility/ResetHydrodynamicForceTorqueKernel.h" + +#include "mesa_pd/data/ParticleAccessorWithShape.h" +#include "mesa_pd/data/ParticleStorage.h" +#include "mesa_pd/data/ShapeStorage.h" +#include "mesa_pd/domain/BlockForestDomain.h" +#include "mesa_pd/mpi/SyncNextNeighbors.h" + +#include <iostream> +// codegen +#include "InitializeDomainForPSM.h" +#include "PSMPackInfo.h" +#include "PSMSweep.h" +#include "PSM_InfoHeader.h" + +namespace torque_sphere_psm +{ + +/////////// +// USING // +/////////// + +using namespace walberla; +using walberla::uint_t; +using namespace lbm_mesapd_coupling::psm::gpu; + +using flag_t = walberla::uint8_t; +using FlagField_T = FlagField< flag_t >; + +typedef pystencils::PSMPackInfo PackInfo_T; + +/////////// +// FLAGS // +/////////// + +const FlagUID Fluid_Flag("fluid"); + +//////////////// +// PARAMETERS // +//////////////// + +struct Setup +{ + uint_t checkFrequency; + real_t visc; + real_t tau; + real_t radius; + uint_t length; + real_t phi; + real_t angularVel; + real_t analyticalTorque; +}; + +//******************************************************************************************************************* +/*!\brief Evaluating the torque on a sphere, rotating with a constant angular velocity + */ +//******************************************************************************************************************* +template< typename ParticleAccessor_T > +class TorqueEval +{ + public: + TorqueEval(SweepTimeloop* timeloop, Setup* setup, const shared_ptr< StructuredBlockStorage >& blocks, + const shared_ptr< ParticleAccessor_T >& ac, bool fileIO) + : timeloop_(timeloop), setup_(setup), blocks_(blocks), ac_(ac), fileIO_(fileIO), torqueOld_(0.0), torqueNew_(0.0) + { + // calculate the (semi)analytical torque value + // see also Hofmann et al. - Hydrodynamic interactions in colloidal crystals:(II). Application to dense cubic and + // tetragonal arrays (1999), Eqs. 5.1 and 5.5 + const real_t S = real_c(1.95708); + setup_->analyticalTorque = + -setup_->visc * + (real_c(6) * setup_->phi / (real_c(1) - setup_->phi - S * std::pow(setup_->phi, real_c(10. / 3.)))) * + setup_->angularVel * real_c(setup_->length * setup_->length * setup_->length); + + if (fileIO_) + { + std::ofstream file; + filename_ = "TorqueSpherePSMGPU.txt"; + WALBERLA_ROOT_SECTION() + { + file.open(filename_.c_str()); + file << "#\t torqueSim\t torqueAnaly\n"; + file.close(); + } + } + } + + // evaluate the acting torque + void operator()() + { + const uint_t timestep(timeloop_->getCurrentTimeStep() + 1); + + if (timestep % setup_->checkFrequency != 0) return; + + // update torque values + torqueOld_ = torqueNew_; + torqueNew_ = calculateTorque(); + + // write to file if desired + WALBERLA_ROOT_SECTION() + { + if (fileIO_) + { + std::ofstream file; + file.open(filename_.c_str(), std::ofstream::app); + file.setf(std::ios::unitbuf); + file.precision(15); + file << timestep << " " << torqueNew_ << " " << setup_->analyticalTorque << "\n"; + file.close(); + } + } + } + + // obtain the torque acting on the sphere by summing up all the process local parts + real_t calculateTorque() + { + real_t torque = real_c(0); + for (auto blockIt = blocks_->begin(); blockIt != blocks_->end(); ++blockIt) + { + for (size_t idx = 0; idx < ac_->size(); ++idx) + { + torque += ac_->getHydrodynamicTorque(idx)[1]; + } + } + + WALBERLA_MPI_SECTION() { mpi::allReduceInplace(torque, mpi::SUM); } + return torque; + } + + // return the relative temporal change in the torque + real_t getTorqueDiff() const { return std::fabs((torqueNew_ - torqueOld_) / torqueNew_); } + + // return the torque + real_t getTorque() const { return torqueNew_; } + + private: + SweepTimeloop* timeloop_; + + Setup* setup_; + + shared_ptr< StructuredBlockStorage > blocks_; + shared_ptr< ParticleAccessor_T > ac_; + + bool fileIO_; + std::string filename_; + + real_t torqueOld_; + real_t torqueNew_; +}; + +////////// +// MAIN // +////////// + +//******************************************************************************************************************* +/*!\brief Testcase that checks the torque acting on a constantly rotating sphere in the center of a cubic domain + * + * The torque for this problem (often denoted as Simple Cubic setup) is given by a semi-analytical formula. + * The cubic domain is periodic in all directions, making it a physically infinite periodic array of spheres. + \verbatim + _______________ + | <- | + | ___ | + | / \ | + | | x | | + | \___/ | + | -> | + |_______________| + + \endverbatim + * + * The collision model used for the LBM is TRT with a relaxation parameter tau=1.5 and the magic parameter 3/16. + * The Stokes approximation of the equilibrium PDFs is used. + * The sphere rotates with a angular velocity of 1e-5. + * The domain is 32x32x32, and the sphere has a diameter of around 27 cells ( chi * domainlength ) + * The simulation is run until the relative change in the torque between 100 time steps is less than 1e-5. + * The pe is not used since the angular velocity is kept constant and the force is explicitly reset after each time + step. + * + */ +//******************************************************************************************************************* + +int main(int argc, char** argv) +{ + debug::enterTestMode(); + + mpi::Environment env(argc, argv); + + logging::Logging::instance()->setLogLevel(logging::Logging::INFO); + + auto processes = MPIManager::instance()->numProcesses(); + + if (processes != 1 && processes != 2 && processes != 4 && processes != 8) + { + std::cerr << "Number of processes must be equal to either 1, 2, 4, or 8!" << std::endl; + return EXIT_FAILURE; + } + + /////////////////// + // Customization // + /////////////////// + + bool shortrun = false; + bool funcTest = false; + bool fileIO = false; + + for (int i = 1; i < argc; ++i) + { + if (std::strcmp(argv[i], "--shortrun") == 0) + { + shortrun = true; + continue; + } + if (std::strcmp(argv[i], "--funcTest") == 0) + { + funcTest = true; + continue; + } + if (std::strcmp(argv[i], "--fileIO") == 0) + { + fileIO = true; + continue; + } + WALBERLA_ABORT("Unrecognized command line argument found: " << argv[i]); + } + + /////////////////////////// + // SIMULATION PROPERTIES // + /////////////////////////// + + Setup setup; + + setup.length = uint_t(32); // length of the cubic domain in lattice cells + const real_t chi = real_c(0.85); // porosity parameter: diameter / length + setup.tau = real_c(1.5); // relaxation time + setup.angularVel = real_c(1e-5); // angular velocity of the sphere + setup.checkFrequency = uint_t(100); // evaluate the torque only every checkFrequency time steps + setup.radius = real_c(0.5) * chi * real_c(setup.length); // sphere radius + setup.visc = (setup.tau - real_c(0.5)) / real_c(3); // viscosity in lattice units + setup.phi = real_c(4.0 / 3.0) * math::pi * setup.radius * setup.radius * setup.radius / + (real_c(setup.length * setup.length * setup.length)); // solid volume fraction + const real_t omega = real_c(1) / setup.tau; // relaxation rate + const real_t dx = real_c(1); // lattice dx + const real_t convergenceLimit = real_c(1e-5); // tolerance for relative change in torque + const uint_t timesteps = + funcTest ? 1 : (shortrun ? uint_c(150) : uint_c(5000)); // maximum number of time steps for the whole simulation + + /////////////////////////// + // BLOCK STRUCTURE SETUP // + /////////////////////////// + + const uint_t XBlocks = (processes >= 2) ? uint_t(2) : uint_t(1); + const uint_t YBlocks = (processes >= 4) ? uint_t(2) : uint_t(1); + const uint_t ZBlocks = (processes == 8) ? uint_t(2) : uint_t(1); + const uint_t XCells = setup.length / XBlocks; + const uint_t YCells = setup.length / YBlocks; + const uint_t ZCells = setup.length / ZBlocks; + + // create fully periodic domain + auto blocks = blockforest::createUniformBlockGrid(XBlocks, YBlocks, ZBlocks, XCells, YCells, ZCells, dx, true, true, + true, true); + + //////// + // PE // + //////// + + auto mesapdDomain = std::make_shared< mesa_pd::domain::BlockForestDomain >(blocks->getBlockForestPointer()); + auto ps = std::make_shared< mesa_pd::data::ParticleStorage >(1); + auto ss = std::make_shared< mesa_pd::data::ShapeStorage >(); + using ParticleAccessor_T = mesa_pd::data::ParticleAccessorWithShape; + auto accessor = walberla::make_shared< ParticleAccessor_T >(ps, ss); + + ///////////////// + // PE COUPLING // + ///////////////// + + // connect to pe + const real_t overlap = real_c(1.5) * dx; + + if (setup.radius > real_c(setup.length) * real_c(0.5) - overlap) + { + std::cerr << "Periodic sphere is too large!" << std::endl; + return EXIT_FAILURE; + } + + // create the sphere in the middle of the domain + Vector3< real_t > position(real_c(setup.length) * real_c(0.5)); + auto sphereShape = ss->create< mesa_pd::data::Sphere >(setup.radius); + + if (mesapdDomain->isContainedInProcessSubdomain(uint_c(walberla::mpi::MPIManager::instance()->rank()), position)) + { + auto sphereParticle = ps->create(); + sphereParticle->setShapeID(sphereShape); + sphereParticle->setType(0); + sphereParticle->setPosition(position); + sphereParticle->setAngularVelocity(Vector3(real_c(0), setup.angularVel, real_c(0))); + sphereParticle->setOwner(walberla::MPIManager::instance()->rank()); + sphereParticle->setInteractionRadius(setup.radius); + } + + // synchronize often enough for large particles + std::function< void(void) > syncCall = [&]() { + mesa_pd::mpi::SyncNextNeighbors syncNextNeighborFunc; + syncNextNeighborFunc(*ps, *mesapdDomain); + }; + + syncCall(); + + /////////////////////// + // ADD DATA TO BLOCKS // + //////////////////////// + + // add fields ( uInit = <0,0,0>, rhoInit = 1 ) +#ifdef WALBERLA_BUILD_WITH_GPU_SUPPORT + BlockDataID pdfFieldID = + field::addToStorage< PdfField_T >(blocks, "pdf field (fzyx)", real_c(std::nan("")), field::fzyx); + BlockDataID pdfFieldCPUGPUID = gpu::addGPUFieldToStorage< PdfField_T >(blocks, pdfFieldID, "pdf field GPU", true); +#else + BlockDataID pdfFieldCPUGPUID = + field::addToStorage< PdfField_T >(blocks, "pdf field CPU", real_c(std::nan("")), field::fzyx); +#endif + + // add particle and volume fraction data structures + ParticleAndVolumeFractionSoA_T< Weighting > particleAndVolumeFractionSoA(blocks, omega); + // map particles and calculate solid volume fraction initially + PSMSweepCollection psmSweepCollection(blocks, accessor, lbm_mesapd_coupling::RegularParticlesSelector(), + particleAndVolumeFractionSoA, Vector3(8)); + for (auto blockIt = blocks->begin(); blockIt != blocks->end(); ++blockIt) + { + psmSweepCollection.particleMappingSweep(&(*blockIt)); + } + + pystencils::InitializeDomainForPSM pdfSetter( + particleAndVolumeFractionSoA.BsFieldID, particleAndVolumeFractionSoA.BFieldID, + particleAndVolumeFractionSoA.particleVelocitiesFieldID, pdfFieldCPUGPUID, real_t(0), real_t(0), real_t(0), + real_t(1.0), real_t(0), real_t(0), real_t(0)); + + for (auto blockIt = blocks->begin(); blockIt != blocks->end(); ++blockIt) + { + // pdfSetter requires particle velocities at cell centers + psmSweepCollection.setParticleVelocitiesSweep(&(*blockIt)); + pdfSetter(&(*blockIt)); + } + + /////////////// + // TIME LOOP // + /////////////// + + // create the timeloop + SweepTimeloop timeloop(blocks->getBlockStorage(), timesteps); + + // setup of the LBM communication for synchronizing the pdf field between neighboring blocks +#ifdef WALBERLA_BUILD_WITH_GPU_SUPPORT + gpu::communication::UniformGPUScheme< Stencil_T > com(blocks, 0, false); +#else + walberla::blockforest::communication::UniformBufferedScheme< Stencil_T > com(blocks); +#endif + com.addPackInfo(make_shared< PackInfo_T >(pdfFieldCPUGPUID)); + auto communication = std::function< void() >([&]() { com.communicate(); }); + + using TorqueEval_T = TorqueEval< ParticleAccessor_T >; + shared_ptr< TorqueEval_T > torqueEval = make_shared< TorqueEval_T >(&timeloop, &setup, blocks, accessor, fileIO); + + pystencils::PSMSweep PSMSweep(particleAndVolumeFractionSoA.BsFieldID, particleAndVolumeFractionSoA.BFieldID, + particleAndVolumeFractionSoA.particleForcesFieldID, + particleAndVolumeFractionSoA.particleVelocitiesFieldID, pdfFieldCPUGPUID, real_t(0.0), + real_t(0.0), real_t(0.0), omega); + + // communication, streaming and force evaluation + timeloop.add() << BeforeFunction(communication, "LBM Communication") + << Sweep(deviceSyncWrapper(psmSweepCollection.setParticleVelocitiesSweep), + "setParticleVelocitiesSweep"); + timeloop.add() << Sweep(deviceSyncWrapper(PSMSweep), "cell-wise LB sweep"); + timeloop.add() << Sweep(deviceSyncWrapper(psmSweepCollection.reduceParticleForcesSweep), "Reduce particle forces"); +#ifdef WALBERLA_BUILD_WITH_GPU_SUPPORT + timeloop.add() << Sweep(gpu::fieldCpyFunctor< PdfField_T, gpu::GPUField< real_t > >(pdfFieldID, pdfFieldCPUGPUID), + "copy pdf from GPU to CPU") +#else + struct emptySweep + { + void operator()(IBlock*) {} + }; + timeloop.add() << Sweep(emptySweep(), "emptySweep") +#endif + << AfterFunction(SharedFunctor< TorqueEval_T >(torqueEval), "torque evaluation"); + + lbm_mesapd_coupling::ResetHydrodynamicForceTorqueKernel resetHydrodynamicForceTorque; + + timeloop.addFuncAfterTimeStep(RemainingTimeLogger(timeloop.getNrOfTimeSteps()), "Remaining Time Logger"); + + //////////////////////// + // EXECUTE SIMULATION // + //////////////////////// + + WcTimingPool timeloopTiming; + + // time loop + for (uint_t i = 0; i < timesteps; ++i) + { + // perform a single simulation step + timeloop.singleStep(timeloopTiming); + + // resetting force + ps->forEachParticle(false, mesa_pd::kernel::SelectAll(), *accessor, resetHydrodynamicForceTorque, *accessor); + + // check if the relative change in the torque is below the specified convergence criterion + if (i > setup.checkFrequency && torqueEval->getTorqueDiff() < convergenceLimit) + { + // if simulation has converged, terminate simulation + break; + } + } + + timeloopTiming.logResultOnRoot(); + + // check the result + if (!funcTest && !shortrun) + { + real_t relErr = std::fabs((setup.analyticalTorque - torqueEval->getTorque()) / setup.analyticalTorque); + if (fileIO) + { + WALBERLA_ROOT_SECTION() + { + std::cout << "Analytical torque: " << setup.analyticalTorque << "\n" + << "Simulated torque: " << torqueEval->getTorque() << "\n" + << "Relative error: " << relErr << "\n"; + } + } + // the relative error has to be below 10% (25% for SC2) + WALBERLA_CHECK_LESS(relErr, (SC == 2) ? real_c(0.25) : real_c(0.1)); + } + + return 0; +} + +} // namespace torque_sphere_psm + +int main(int argc, char** argv) { torque_sphere_psm::main(argc, argv); } diff --git a/tests/mesa_pd/CMakeLists.txt b/tests/mesa_pd/CMakeLists.txt index 423dda6ef8a2811cd5225d8e34ed12752283c07a..7b217a13677f9c56c79a81cccd0ff007e24d99dd 100644 --- a/tests/mesa_pd/CMakeLists.txt +++ b/tests/mesa_pd/CMakeLists.txt @@ -4,6 +4,8 @@ # ################################################################################################### +waLBerla_link_files_to_builddir(*.prm) + waLBerla_compile_test( NAME MESA_PD_COLLISIONDETECTION_AnalyticCollisionFunctions FILES collision_detection/AnalyticCollisionFunctions.cpp DEPENDS core ) waLBerla_execute_test( NAME MESA_PD_COLLISIONDETECTION_AnalyticCollisionFunctions ) @@ -224,6 +226,8 @@ waLBerla_execute_test( NAME MESA_PD_MPI_VelocityCorrectionNotification PROCESS waLBerla_compile_test( NAME MESA_PD_Sorting FILES Sorting.cpp DEPENDS core ) waLBerla_execute_test( NAME MESA_PD_Sorting ) +waLBerla_compile_test( NAME MESA_PD_Stiffness FILES Stiffness.cpp DEPENDS blockforest core mesa_pd ) + waLBerla_compile_test( NAME MESA_PD_VTK_Outputs FILES vtk/VTKOutputs.cpp DEPENDS blockforest core vtk ) waLBerla_execute_test( NAME MESA_PD_VTK_Outputs PROCESSES 8 ) diff --git a/tests/mesa_pd/Stiffness.cpp b/tests/mesa_pd/Stiffness.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0ebf03ba6d74079043f4b70b0d0e4312b52fc52f --- /dev/null +++ b/tests/mesa_pd/Stiffness.cpp @@ -0,0 +1,142 @@ +//====================================================================================================================== +// +// This file is part of waLBerla. waLBerla 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. +// +// waLBerla 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 waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file Stiffness.cpp +//! \author Samuel Kemmler <samuel.kemmler@fau.de> +// +//====================================================================================================================== + +#include "blockforest/Initialization.h" + +#include "core/Environment.h" + +#include "mesa_pd/collision_detection/AnalyticContactDetection.h" +#include "mesa_pd/data/DataTypes.h" +#include "mesa_pd/data/ParticleAccessorWithBaseShape.h" +#include "mesa_pd/data/ParticleStorage.h" +#include "mesa_pd/data/shape/Sphere.h" +#include "mesa_pd/domain/BlockForestDomain.h" +#include "mesa_pd/kernel/DoubleCast.h" +#include "mesa_pd/kernel/LinearSpringDashpot.h" +#include "mesa_pd/kernel/ParticleSelector.h" +#include "mesa_pd/kernel/VelocityVerlet.h" +#include "mesa_pd/mpi/ContactFilter.h" + +namespace walberla +{ + +using namespace mesa_pd; + +int main(int argc, char** argv) +{ + Environment env(argc, argv); + walberla::mpi::MPIManager::instance()->useWorldComm(); + + WALBERLA_CHECK(MPIManager::instance()->numProcesses() == 1) + + // Config + auto cfg = env.config(); + if (cfg == nullptr) WALBERLA_ABORT("No config specified!"); + WALBERLA_LOG_INFO_ON_ROOT(*cfg); + const Config::BlockHandle config = cfg->getBlock("Stiffness"); + + const Vec3 domainSize_SI = config.getParameter< Vec3 >("domainSize_SI"); + const real_t diameter_SI = config.getParameter< real_t >("diameter_SI"); + const real_t densityParticle_SI = config.getParameter< real_t >("densityParticle_SI"); + const real_t dt_SI = config.getParameter< real_t >("dt_SI"); + const uint_t timeSteps = config.getParameter< uint_t >("timeSteps"); + const real_t force_SI = config.getParameter< real_t >("force_SI"); + const real_t normalSpringConstant_SI = config.getParameter< real_t >("normalSpringConstant_SI"); + + // BlockForest + const math::AABB simulationDomain_SI(real_t(0.0), real_t(0.0), real_t(0.0), domainSize_SI[0], domainSize_SI[1], + domainSize_SI[2]); + + shared_ptr< BlockForest > forest = + blockforest::createBlockForest(simulationDomain_SI, Vec3(uint(1)), Vector3< bool >(false)); + auto domain = std::make_shared< mesa_pd::domain::BlockForestDomain >(forest); + + // MesaPD data structures + auto ps = std::make_shared< data::ParticleStorage >(1); + data::ParticleAccessorWithBaseShape accessor(ps); + + // Init sphere 0 + auto p0 = ps->create(); + p0->getPositionRef() = simulationDomain_SI.center() - Vec3(diameter_SI / 2, real_t(0), real_t(0)); + p0->getInteractionRadiusRef() = diameter_SI * real_t(0.5); + p0->getBaseShapeRef() = std::make_shared< data::Sphere >(p0->getInteractionRadius()); + p0->getBaseShapeRef()->updateMassAndInertia(densityParticle_SI); + p0->getOwnerRef() = walberla::mpi::MPIManager::instance()->rank(); + p0->getTypeRef() = 0; + auto idxp0 = p0->getIdx(); + + // Init sphere 1 + auto p1 = ps->create(); + p1->getPositionRef() = simulationDomain_SI.center() + Vec3(diameter_SI / 2, real_t(0), real_t(0)); + p1->getInteractionRadiusRef() = diameter_SI * real_t(0.5); + p1->getBaseShapeRef() = std::make_shared< data::Sphere >(p1->getInteractionRadius()); + p1->getBaseShapeRef()->updateMassAndInertia(densityParticle_SI); + p1->getOwnerRef() = walberla::mpi::MPIManager::instance()->rank(); + p1->getTypeRef() = 0; + auto idxp1 = p1->getIdx(); + + auto overlap = diameter_SI - (accessor.getPosition(idxp1)[0] - accessor.getPosition(idxp0)[0]); + + // Init kernels + mesa_pd::kernel::VelocityVerletPreForceUpdate vvIntegratorPreForce(dt_SI); + mesa_pd::kernel::VelocityVerletPostForceUpdate vvIntegratorPostForce(dt_SI); + kernel::LinearSpringDashpot dem(1); + dem.setStiffnessN(0, 0, normalSpringConstant_SI); + + for (uint_t i = 0; i < timeSteps; ++i) + { + ps->forEachParticle(false, kernel::SelectLocal(), accessor, vvIntegratorPreForce, accessor); + + p0->setForce(Vec3(force_SI * real_t(i) / real_t(timeSteps), real_t(0), real_t(0))); + p1->setForce(Vec3(-force_SI * real_t(i) / real_t(timeSteps), real_t(0), real_t(0))); + + ps->forEachParticlePairHalf( + false, kernel::ExcludeInfiniteInfinite(), accessor, + [domain, &dem, dt_SI](const size_t idx1, const size_t idx2, auto& ac) { + kernel::DoubleCast double_cast; + mesa_pd::mpi::ContactFilter contact_filter; + collision_detection::AnalyticContactDetection acd; + + if (double_cast(idx1, idx2, ac, acd, ac)) + { + if (contact_filter(acd.getIdx1(), acd.getIdx2(), ac, acd.getContactPoint(), *domain)) + { + dem(acd.getIdx1(), acd.getIdx2(), ac, acd.getContactPoint(), acd.getContactNormal(), + acd.getPenetrationDepth(), dt_SI); + } + } + }, + accessor); + + overlap = diameter_SI - (accessor.getPosition(idxp1)[0] - accessor.getPosition(idxp0)[0]); + + ps->forEachParticle(false, kernel::SelectLocal(), accessor, vvIntegratorPostForce, accessor); + } + + WALBERLA_LOG_DEVEL_VAR(overlap) + const real_t expectedOverlap = force_SI / normalSpringConstant_SI; + WALBERLA_LOG_DEVEL_VAR(expectedOverlap) + WALBERLA_CHECK_FLOAT_EQUAL(overlap, expectedOverlap) + + return EXIT_SUCCESS; +} +} // namespace walberla + +int main(int argc, char** argv) { return walberla::main(argc, argv); } diff --git a/tests/mesa_pd/Stiffness.prm b/tests/mesa_pd/Stiffness.prm new file mode 100644 index 0000000000000000000000000000000000000000..e943ae84e8b6395b9f2eb3040131def2d4884368 --- /dev/null +++ b/tests/mesa_pd/Stiffness.prm @@ -0,0 +1,9 @@ +Stiffness{ + domainSize_SI < 1, 1, 1 >; + diameter_SI 0.01; + densityParticle_SI 2500; + dt_SI 5e-5; + timeSteps 1000000; + force_SI 1; + normalSpringConstant_SI 1000; +}