From 3c89fd1f91182b2473105bab8b1c9d53cd6f97d4 Mon Sep 17 00:00:00 2001 From: subhacom Date: Mon, 11 Nov 2024 09:46:21 +0530 Subject: [PATCH] Squashes all updates so far: NeuroML2 support, Windows Build, and github workflow to build on Windows, Linux and MacOS (#491) * Fixed typo in macro check for BOOST * Updates for Windows MSVC build In setup.py and CMakeLists.txt for build - Added switches for compiler flags for Windows/MSVC - Removed possible override of version in CMakeLists.txt: setup.py should be the only source of version info - Archive format set to zip for windows - Using module name moose instead of _moose, the underscore is added as PREFIX - Platform dependent shared lib file name extension - Removed platform name CMAKE from cmake file - Updated setup.py to allow release build on windows In C++ code - Switched all new style logical opeartors (and, or, not)to C style (&&, ||, !) - these are not recognized by MSVC compiler - Added windows port of getopt in external - Removed SocketStreamer conditionally for Win32 build. Win32 does not have socket library. TODO: look at ports. - CylBase uses a constant PI which does not exist in win32 standard library. Replaced it with cmath's M_PI. Hope they are the same. - Corrected cnpy function for checking numpy file header - Minor correction on printf formatting to avoid warning for size_t build updates for windows - Undefine _DEBUG macro for release builds Added build instructions for windows * Squashed commit of the following: commit fc5f053e2377e7ee43a00c385e37f096f0b646cb Merge: 45f4341e8 71598d1ce Author: Subhasis Ray Date: Sun Nov 10 15:14:44 2024 +0530 Merge branch 'master' of https://github.com/BhallaLab/moose-core into windows_build commit 45f4341e810e61a79bc9d4b42e489c3e7f820249 Author: Subhasis Ray Date: Sun Nov 10 15:02:51 2024 +0530 github actions: try to fix gsl availability commit 17f91bb851d7fefea356b0013128b25960db8eaa Author: Subhasis Ray Date: Sun Nov 10 14:01:39 2024 +0530 github action fixes commit 9159696a960015863bb79b194c0b1a7a6c8e40c4 Author: Subhasis Ray Date: Sun Nov 10 13:59:08 2024 +0530 github actions: Avoid pip upgared commit 9537a5c5804ae8ca1ec971e5d52760c5f6377e50 Author: Subhasis Ray Date: Sun Nov 10 13:57:52 2024 +0530 Further fix to github action: activateing mamba env commit 7e675737abc46040e2a8be7803c0129c8f369865 Author: Subhasis Ray Date: Sun Nov 10 13:54:11 2024 +0530 Fix github action commit ab7d52ab3163f2df0a6023dfb390f95f905de9e2 Author: Subhasis Ray Date: Sun Nov 10 13:53:05 2024 +0530 Fixing automatic build commit 6c4b99a712fbde7f475a29b2c9b434ab5bbe529b Author: Subhasis Ray Date: Sun Nov 10 01:49:39 2024 +0530 github actions: further fix for ubuntu commit 1c143e63015f802054caf858337efc90053bf3da Author: Subhasis Ray Date: Sun Nov 10 01:41:58 2024 +0530 github actions: fix ninja installation on ubuntu latest commit cbba8a5a099056732e8767a379d5a88f70795d32 Author: Subhasis Ray Date: Sun Nov 10 01:39:30 2024 +0530 github actions: fix for meson installation on ubuntu-lates commit 863d7f7aa81b2cf9897261b3d6c2ada9c69c76bc Author: Subhasis Ray Date: Sun Nov 10 01:23:57 2024 +0530 Fixing github actions to build commit f1d99818957a1e33a48af0be571f8c3366ed1f83 Merge: 65b8ea6d9 fa3b76482 Author: Subhasis Ray Date: Sun Nov 10 01:12:55 2024 +0530 Merge branch 'windows_build' of https://github.com/subhacom/moose-core into windows_build commit 65b8ea6d97ac64a9fef396865cb38e34088d926b Author: Subhasis Ray Date: Sun Nov 10 01:12:07 2024 +0530 Another attempt at fixing github workflow commit fa3b764822c4afc9f9f97660cb4c2450e893e0c3 Author: subhacom Date: Sun Nov 10 01:04:46 2024 +0530 Update pymoose.yml: tab and space mixup in github editor commit 3cd5d0ef8943c5bb14ca59fa0b2dc2243ee2ab00 Author: subhacom Date: Sun Nov 10 01:03:41 2024 +0530 Update pymoose.yml commit ecfa505adbc22b3d8137c86b52b8bee243ae3730 Author: Subhasis Ray Date: Sun Nov 10 00:58:37 2024 +0530 Fixed tab issues in workflow commit 15c8b442a2a1d328072341e95fc81aa888c58263 Author: Subhasis Ray Date: Sun Nov 10 00:56:49 2024 +0530 attempt to fix workflow commit bf294b877422d11a75e8dd37d3bf2c29efca0ce1 Author: Subhasis Ray Date: Sun Nov 10 00:24:06 2024 +0530 Updated exprtk and fixed some deprecation warnings from meson commit 71598d1ceed969671b2990b2d45545493c82f695 Author: Anal Kumar Date: Fri Nov 8 13:30:32 2024 +0530 Execute the module to access the funtion in its namespace (#480) commit 38fc00f26a57a67ecfe8f9d03a307816bf4b80bc Author: Subhasis Ray Date: Fri Nov 8 11:29:28 2024 +0530 Added moose class/object check in moose.isinstance_ function commit 7c82f698a52bfc2c3c0367c4809d59555e15b604 Author: Subhasis Ray Date: Sun Oct 27 16:51:16 2024 +0530 Minor update of build instructions. commit 5c325c11781e2626cdcc277397df3ae966cca2bc Author: Subhasis Ray Date: Sun Oct 27 12:26:55 2024 +0530 Added instructions on build options commit 575760e8856206048f5c8fcdaa5d8eb55d75f148 Author: Subhasis Ray Date: Fri Oct 18 15:39:07 2024 +0530 neuroml2 reader: Added option to use interpolation by default commit 3cc2291a4d424d0a47d3aeded82d832b7fc5ec2a Author: Subhasis Ray Date: Thu Oct 3 12:20:43 2024 +0530 Minor fix for non-conda build commit 584394ff73573295688d0395e40ff07cda4d5122 Author: Subhasis Ray Date: Tue Sep 3 22:02:57 2024 +0530 HHChannel2D cleanup Addrsses issue #482 commit a20c95b96bb52911c10b674be6b589ad11146fb9 Author: Subhasis Ray Date: Tue Sep 3 19:09:38 2024 +0530 Windows build working, HHChannel fixed, pymoose cleaned up This commit puts together several bug fixes and cleanups. Meson-based build functional now. - Windows MSVC Build works. - Tested on WSL-Ubuntu as well - Removed cmake build files (CMakeLists.txt) HHChannel class hierarchy - Original version of HHChannel was using the diamond of death multiple inheritance. While linux/gcc was forgiving of this, on Windows MSVC this was producing strange errors issue#483. - Turns out this design was not essential and single inheritance along the line ChanBase->ChanCommon->HHChannelBase->HHChannel sufficed. pybind11 based pymoose This code was quite dirty with static member functions under __Finfo__ which had no relations with the class. Reorganized the code here. commit 4c0b13c5a36ba4d369e481f236b390b405275377 Author: Subhasis Ray Date: Sun Sep 1 02:58:37 2024 +0530 Cleanup of build process. - cleanups to avoid multiple definitions: no more forcing linker to allow multiple definition - redifinition of doubleEq removed - some type-conversions made explicit to avoid warnings - set compiler to use c/c++-17 - separate settings for MSVC and MS Windows: llvm-clang can also work commit 9f85fe9336cb8f9fa71e335232b1c3c613527353 Author: Subhasis Ray Date: Wed Aug 28 16:53:30 2024 +0530 Fixed small bug in neuroml2 reader commit 5d58ac013bf108b82c9c212ada3855e80bca298d Author: Subhasis Ray Date: Tue Aug 27 13:08:58 2024 +0530 Minor fix in neuroml2 reader commit 8b9f01cb7586e275eb672acdfb45fe55f1bc0a39 Author: Subhasis Ray Date: Mon Aug 26 17:42:10 2024 +0530 Further cleanup of neuroml2 reader The results can be sensitive to ranges and resolution used in gate tables. Made these parameters of the NML2Reader's read() method. Set defaults to create good fit for Granule 98 model. commit f7dec7b0975df7de5fe12f2831e8085e16963be8 Author: Subhasis Ray Date: Mon Aug 26 12:16:28 2024 +0530 Got 2D channel to work when reading in NeuroML2 commit 717e0a9246318835a2178c6f3abb5db5ec699ff6 Merge: 8cdacb75f da455e2ca Author: Subhasis Ray Date: Fri Aug 23 11:46:29 2024 +0530 Merge branch 'windows_build' commit 8cdacb75fe5e2381bf180d39f9174aac1f905352 Author: Subhasis Ray Date: Tue Jul 30 15:26:51 2024 +0530 Support for voltage and Ca dependent channel in NeuroML2 reader - array_eval_component() reimplements neuroml expression evaluation using numpy vectorization. This adds dependency on pint for unit handling. - Numerous other fixes and cleanups. commit da455e2ca1ae4933f6303731e0d5ccf6730ed9d3 Author: Subhasis Ray Date: Tue Jul 30 15:26:51 2024 +0530 Removed optimization in favor of simplicity - The switch between Ca dependent and voltage dependent gates put inside for loop instead of having one loop under each condition. commit 8c4db058fd0ecb98d96f034ecfe74b1706e4f5eb Author: Subhasis Ray Date: Tue Jul 30 15:18:13 2024 +0530 Fixes to NeuroML2 reader - Fixed the calculation of gate parameters for HH-type channels with non-standard formula - String formatting switched to f-strings - Refactored functions for updating gates/creating HHChannels - Added some function docstrings commit c3534b5ad89f083f753e55850613649904095295 Author: Subhasis Ray Date: Fri Jul 19 18:54:25 2024 +0530 Code cleanup of morphology reading commit ce9cb73d2c675f9152f82af405a25633c4513b43 Author: Subhasis Ray Date: Wed Jul 17 10:14:17 2024 +0530 Windows portability fix - Removed function filepath_exists to check existence of a file: now this is done portably with the `access` (unix) or `_access` (win) function call. commit 629d00d8760530e1dabf2affd8fce101034b09c8 Author: Subhasis Ray Date: Tue Jul 16 14:46:13 2024 +0530 meson build updated for Ubuntu (tested on WSL) - Updated meson.build files to build on Ubuntu with gcc - Added instructions for Ubuntu build - Updated instructions for Windows build - Fixed minor issue with loading kkit file commit 2aac80f4df6c5c7383e02f26519fe8d31022453d Author: Subhasis Ray Date: Mon Jul 15 10:39:38 2024 +0530 Some more cleanup in meson build commit 6c1016ff98c7aa57897e81698bf5c697042ed278 Author: Subhasis Ray Date: Mon Jul 15 10:38:03 2024 +0530 Fixed typo. commit 258424a98cea5577ce19f2860af110784665a54b Author: Subhasis Ray Date: Mon Jul 15 10:33:57 2024 +0530 Minor fixes to meson build and pyproject commit 52bf16167d90a3271fd575ab94877909d0f58849 Author: Subhasis Ray Date: Wed Jul 10 11:24:17 2024 +0530 Windows MSVC build working with meson. - Updated guide to windows build commit e4b76551f367a2189b15baa2b9c337a1eec3b45c Author: Subhasis Ray Date: Tue Jul 9 23:12:24 2024 +0530 Finally, working windows build with meson commit 0ca6b947688a3766dc573e6d4b0ee1a3ae6c6a5d Author: Subhasis Ray Date: Mon Jul 8 03:53:57 2024 +0530 Added meson build files commit c0e0229ba69ec3d2d25c1c54d457551c35d5eb93 Author: Subhasis Ray Date: Wed Jul 3 08:54:05 2024 +0530 Updated mac build/installation guide commit 7e8427c854d5b0c9abfd206a6595276751c0ae82 Author: Subhasis Ray Date: Wed Jul 3 07:14:53 2024 +0530 Added guide for mac build commit f02bc6f51d796cda0953fd404b213a6182c7adde Author: Subhasis Ray Date: Tue Jul 2 17:39:49 2024 +0530 Added troubleshooting advice for WSL. commit 130b67431aec3ab77dea4a43f2fa5a9627ddaf9f Author: Subhasis Ray Date: Tue Jul 2 12:35:56 2024 +0530 Correction in wsl guide commit caeeab5b0b169c3cdca8cd1bda8f44969c6da49a Author: Subhasis Ray Date: Tue Jul 2 12:30:25 2024 +0530 Added a guide for setting up moose on WSL2 commit b8eb0ba7a5de66c6df013d24872d2d80e207faea Author: Subhasis Ray Date: Thu Jun 20 12:39:51 2024 +0530 Try fixing apple build commit e3d660713e8e3aba6adf3706897f8ae6a1413029 Author: Subhasis Ray Date: Thu Jun 20 12:20:29 2024 +0530 Fixed cmake file to not include extern/getopt on non-win32 commit 7906424098b1147a0ec58960be69906d18e4c6dc Author: Subhasis Ray Date: Thu Jun 20 10:20:37 2024 +0530 Trying to fix syntax error from newer C++ standard commit 0cd59504feab284a728f97526293bea1ed6ba344 Author: Subhasis Ray Date: Thu Jun 20 09:23:20 2024 +0530 Build updates for WIN32/MSVC commit 5756e38b074baa3d044dfac4a8ff309138122d58 Author: Subhasis Ray Date: Wed Jun 12 16:56:03 2024 +0530 Fixed lib name for moose used in linking moose.bin commit e71ce2fb4aecaab32f0ba92ae43e61165217c9ad Author: Subhasis Ray Date: Wed Jun 12 16:49:13 2024 +0530 Fixes to build configs - setup.py for two passes of cmake - first to create config, second to run build tool - pybind11/CMakeLists.txt - going back to no prefix, directly put `_moose` for target. Reverted pyd suffix to dll on windows commit 965d1a1b8fe4080ee7e7fd55dedd98e0a6450174 Author: Subhasis Ray Date: Wed Jun 12 16:16:00 2024 +0530 Attempt to fix build - setup.py: use `cmake --build` for all systems - switch filename suffix pyd back to dll for windows commit 035ee0ed40dad8f43621f4adfa079e8e0c25012d Author: Subhasis Ray Date: Wed Jun 12 15:09:48 2024 +0530 Trying c++11 for mac build to fix syntax issue commit 1d8de0443ed8e94d868180739abdd6ac71f0832d Author: Subhasis Ray Date: Wed Jun 12 15:02:51 2024 +0530 Fixup for getopt on Windows commit d6bc7ff41ab7b040dc796feac3ff1b4407cb7081 Author: Subhasis Ray Date: Wed Jun 12 14:47:32 2024 +0530 Minor fixup for platform check with WIN32 macro --- .clang-format | 1 - .github/workflows/pymoose.yml | 37 +- AppleM1_Guide.md | 27 + CMakeLists.txt | 427 - CheckCXXCompiler.cmake | 64 - MANIFEST.in | 1 - UbuntuBuild.md | 67 + WSLGuide.md | 57 + WindowsBuild.md | 125 + basecode/CMakeLists.txt | 33 - basecode/Conv.h | 12 +- basecode/doubleEq.h | 4 +- basecode/main.cpp | 4 + basecode/meson.build | 28 + biophysics/CMakeLists.txt | 59 - biophysics/ChanBase.h | 4 +- biophysics/ChanCommon.cpp | 6 +- biophysics/ChanCommon.h | 37 +- biophysics/HHChannel.cpp | 16 +- biophysics/HHChannel.h | 63 +- biophysics/HHChannel2D.h | 12 +- biophysics/HHChannelBase.cpp | 15 +- biophysics/HHChannelBase.h | 18 +- biophysics/HHGate.cpp | 6 +- biophysics/HHGate.h | 4 +- biophysics/HHGate2D.cpp | 178 +- biophysics/HHGate2D.h | 41 +- biophysics/MarkovOdeSolver.cpp | 2 +- biophysics/meson.build | 48 + biophysics/testBiophysics.cpp | 1 + builtins/CMakeLists.txt | 88 - builtins/SocketStreamer.cpp | 20 +- builtins/StreamerBase.cpp | 4 +- builtins/meson.build | 30 + cmake/FindGSL.cmake | 116 - devel/CMakeLists.txt | 20 - device/CMakeLists.txt | 8 - device/meson.build | 9 + diffusion/CMakeLists.txt | 13 - diffusion/meson.build | 9 + examples/CMakeLists.txt | 7 - examples/Ex.cpp | 10 + examples/meson.build | 7 + external/CMakeLists.txt | 2 - external/exprtk/exprtk.hpp | 13273 +++++++++++++++------- external/fmt/CMakeLists.txt | 4 - external/fmt/meson.build | 11 + external/getopt/getopt.c | 52 + external/getopt/getopt.h | 37 + external/getopt/meson.build | 4 + external/getopt/unistd.h | 56 + external/libsoda/.travis.yml | 25 - external/libsoda/CMakeLists.txt | 15 - external/libsoda/LSODA.cpp | 2 +- external/libsoda/meson.build | 6 + external/tinyexpr/CMakeLists.txt | 64 - hsolve/CMakeLists.txt | 19 - hsolve/ZombieHHChannel.cpp | 4 +- hsolve/ZombieHHChannel.h | 60 +- hsolve/meson.build | 19 + intfire/CMakeLists.txt | 4 - intfire/meson.build | 12 + kinetics/CMakeLists.txt | 16 - kinetics/WriteKkit.cpp | 12 +- kinetics/meson.build | 17 + ksolve/CMakeLists.txt | 48 - ksolve/SteadyStateGsl.cpp | 2 +- ksolve/Stoich.cpp | 2 +- ksolve/meson.build | 20 + mesh/CMakeLists.txt | 18 - mesh/CylBase.cpp | 26 +- mesh/meson.build | 19 + meson.build | 279 + meson_options.txt | 2 + mpi/CMakeLists.txt | 13 - mpi/meson.build | 6 + msg/CMakeLists.txt | 12 - msg/meson.build | 14 + pybind11/CMakeLists.txt | 84 - pybind11/Finfo.cpp | 595 +- pybind11/Finfo.h | 195 +- pybind11/MooseVec.cpp | 4 +- pybind11/MooseVec.h | 5 + pybind11/PyRun.cpp | 1 - pybind11/PyRun.h | 17 +- pybind11/helper.cpp | 9 +- pybind11/helper.h | 2 +- pybind11/meson.build | 19 + pybind11/pymoose.cpp | 45 +- pymoose/CMakeLists.txt | 140 - pyproject.toml | 75 + python/moose/__init__.py | 40 + python/moose/chemMerge/mtypes.py | 8 +- python/moose/neuroml2/reader.py | 1646 ++- python/moose/neuroml2/test_granule98.py | 167 +- randnum/CMakeLists.txt | 8 - randnum/meson.build | 7 + scheduling/CMakeLists.txt | 3 - scheduling/meson.build | 6 + setup.py | 174 - shell/CMakeLists.txt | 26 - shell/Shell.cpp | 2 + shell/meson.build | 14 + signeur/CMakeLists.txt | 6 - signeur/meson.build | 7 + synapse/CMakeLists.txt | 16 - synapse/meson.build | 15 + tests/CMakeLists.txt | 114 - utility/CMakeLists.txt | 31 - utility/cnpy.cpp | 32 +- utility/fileutils.cpp | 26 - utility/meson.build | 14 + utility/print_function.hpp | 2 +- utility/strutil.cpp | 1 - utility/testing_macros.hpp | 10 +- utility/utility.cpp | 2 +- utility/utility.h | 11 +- 117 files changed, 12492 insertions(+), 7000 deletions(-) create mode 100644 AppleM1_Guide.md delete mode 100644 CMakeLists.txt delete mode 100644 CheckCXXCompiler.cmake create mode 100644 UbuntuBuild.md create mode 100644 WSLGuide.md create mode 100644 WindowsBuild.md delete mode 100644 basecode/CMakeLists.txt create mode 100644 basecode/meson.build delete mode 100644 biophysics/CMakeLists.txt create mode 100644 biophysics/meson.build delete mode 100644 builtins/CMakeLists.txt create mode 100644 builtins/meson.build delete mode 100644 cmake/FindGSL.cmake delete mode 100644 devel/CMakeLists.txt delete mode 100644 device/CMakeLists.txt create mode 100644 device/meson.build delete mode 100644 diffusion/CMakeLists.txt create mode 100644 diffusion/meson.build delete mode 100644 examples/CMakeLists.txt create mode 100644 examples/meson.build delete mode 100644 external/CMakeLists.txt delete mode 100644 external/fmt/CMakeLists.txt create mode 100644 external/fmt/meson.build create mode 100644 external/getopt/getopt.c create mode 100644 external/getopt/getopt.h create mode 100644 external/getopt/meson.build create mode 100644 external/getopt/unistd.h delete mode 100644 external/libsoda/.travis.yml delete mode 100644 external/libsoda/CMakeLists.txt create mode 100644 external/libsoda/meson.build delete mode 100644 external/tinyexpr/CMakeLists.txt delete mode 100644 hsolve/CMakeLists.txt create mode 100644 hsolve/meson.build delete mode 100644 intfire/CMakeLists.txt create mode 100644 intfire/meson.build delete mode 100644 kinetics/CMakeLists.txt create mode 100644 kinetics/meson.build delete mode 100644 ksolve/CMakeLists.txt create mode 100644 ksolve/meson.build delete mode 100644 mesh/CMakeLists.txt create mode 100644 mesh/meson.build create mode 100644 meson.build create mode 100644 meson_options.txt delete mode 100644 mpi/CMakeLists.txt create mode 100644 mpi/meson.build delete mode 100644 msg/CMakeLists.txt create mode 100644 msg/meson.build delete mode 100644 pybind11/CMakeLists.txt create mode 100644 pybind11/meson.build delete mode 100644 pymoose/CMakeLists.txt create mode 100644 pyproject.toml delete mode 100644 randnum/CMakeLists.txt create mode 100644 randnum/meson.build delete mode 100644 scheduling/CMakeLists.txt create mode 100644 scheduling/meson.build delete mode 100644 setup.py delete mode 100644 shell/CMakeLists.txt create mode 100644 shell/meson.build delete mode 100644 signeur/CMakeLists.txt create mode 100644 signeur/meson.build delete mode 100644 synapse/CMakeLists.txt create mode 100644 synapse/meson.build delete mode 100644 tests/CMakeLists.txt delete mode 100644 utility/CMakeLists.txt delete mode 100644 utility/fileutils.cpp create mode 100644 utility/meson.build diff --git a/.clang-format b/.clang-format index 5e9fd52108..f614d0b0a5 100644 --- a/.clang-format +++ b/.clang-format @@ -31,7 +31,6 @@ PenaltyReturnTypeOnItsOwnLine: 200 PointerBindsToType: true SpacesBeforeTrailingComments: 2 Cpp11BracedListStyle: true -Standard: Auto IndentWidth: 4 TabWidth: 4 UseTab: Never diff --git a/.github/workflows/pymoose.yml b/.github/workflows/pymoose.yml index cc0119026a..1c63caee5f 100644 --- a/.github/workflows/pymoose.yml +++ b/.github/workflows/pymoose.yml @@ -7,7 +7,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, macos-14] + os: [ubuntu-latest, macos-14, windows-latest] build_type: [Release] c_compiler: [clang] python-version: ["3.12"] @@ -16,6 +16,8 @@ jobs: apt: 10 - os: macos-14 brew: 20 + - os: windows-latest + winget: 30 steps: - name: mamba-setup uses: mamba-org/setup-micromamba@v1 @@ -25,7 +27,10 @@ jobs: cache-downloads: true create-args: >- python=${{ matrix.python-version }} + pkg-config + clang hdf5 + pybind11[global] graphviz pytables numpy @@ -35,25 +40,41 @@ jobs: doxygen setuptools wheel + meson + ninja + meson-python + gsl + post-cleanup: all + generate-run-shell: false - name: Display Python version run: | python -c "import sys; print(sys.version)" - if: ${{ matrix.apt }} - run: sudo apt-get install libhdf5-dev libgsl0-dev graphviz-dev python3-lxml cmake doxygen + run: | + sudo apt-get -y install libhdf5-dev libgsl0-dev graphviz-dev python3-lxml doxygen libgsl-dev - if: ${{ matrix.brew }} run: | brew install gsl brew install hdf5 brew install graphviz - brew install cmake brew install doxygen - - name: install python module dependencies via pip - run: | - pip install pybind11[global] - pip install python-libsbml - name: checkout uses: actions/checkout@v4 - - name: build and install + - name: build and install (non-windows) + if: runner.os != 'Windows' + run: | + eval "$(micromamba shell hook --shell bash)" + micromamba activate moose + python -c "import sys; print('#' * 60, sys.version)" + pip install python-libsbml + pip install . + python -c "import moose; moose.le()" + - name: build and install (windows) + if: runner.os == 'Windows' run: | + micromamba shell hook -s powershell | Out-String | Invoke-Expression + micromamba activate moose + python -c "import sys; print('#' * 60, sys.version)" + pip install python-libsbml pip install . python -c "import moose; moose.le()" diff --git a/AppleM1_Guide.md b/AppleM1_Guide.md new file mode 100644 index 0000000000..8f6c18e9bb --- /dev/null +++ b/AppleM1_Guide.md @@ -0,0 +1,27 @@ +- Install homebrew: https://brew.sh/ +- Set up required development environment + - Install command line tools for XCode + - Install build dependencies by running these commands in a terminal + ``` + brew install gsl + brew install hdf5 + brew install graphviz + brew install cmake + brew install doxygen + ``` + +- Install anaconda/miniconda/micromamba/miniforge. For example, for micromamba, run +``` +"${SHELL}" <(curl -L micro.mamba.pm/install.sh) +``` + + in command line +- Update micromamba: `micromamba self-update` +- Restart terminal and create an environment with necessary packages: + +``` +micromamba create -n moose hdf5 graphviz pytables numpy matplotlib vpython lxml doxygen setuptools wheel pybind11[global] +``` +- Activate the moose environment: `micromamba activate moose` +- Install libsbml: `pip install python-libsbml` +- Install moose from github: `pip install git+https://github.com/BhallaLab/moose-core.git` diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index cb51595c2c..0000000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,427 +0,0 @@ -cmake_minimum_required(VERSION 3.20 FATAL_ERROR) - -# Project to build MOOSE's python module. -project(PyMOOSE) - -# cmake related macros. -set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") -include(CheckCXXCompiler.cmake) -include(CheckIncludeFileCXX) - -# We find python executable here. Though mainly used inside pymoose. -find_package(Python3 COMPONENTS Interpreter Numpy) -set(PYTHON_EXECUTABLE ${Python3_EXECUTABLE}) -find_package(PythonInterp 3.8) - -set(CMAKE_MACOSX_RPATH OFF) - -# NOTE: version should be changed in setup.py file. -# If moose version is not given, use setup.py file to get the default version. -if(NOT VERSION_MOOSE) - execute_process(COMMAND ${PYTHON_EXECUTABLE} setup.py --version - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - OUTPUT_VARIABLE VERSION_MOOSE - OUTPUT_STRIP_TRAILING_WHITESPACE) -endif() - -add_definitions(-DMOOSE_VERSION="${VERSION_MOOSE}") -message(STATUS "MOOSE Version ${VERSION_MOOSE}") - -# This snippet is from LLVM project. -# Sanity check our source directory to make sure that we are not trying to -# generate an in-tree build (unless on MSVC_IDE, where it is ok), and to make -# sure that we don't have any stray generated files lying around in the tree -# (which would end up getting picked up by header search, instead of the correct -# versions). -if( CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR AND NOT MSVC_IDE ) - message(FATAL_ERROR - "======================================================================\n" - "In-source builds are not allowed. Remove CMakeCache.txt and CMakeFiles\n" - "directory and do something like this inside this directory \n" - " $ mkdir _build_dir \n" - " $ cd _build_dir \n" - " $ cmake .. \n" - "===================================================================== \n" - ) -endif() - -################################ CMAKE OPTIONS ################################## -option(DEBUG "Build with debug support" OFF) -option(GPROF "Build for profiling using gprof" OFF) -option(ENABLE_UNIT_TESTS "Enable unit tests (DEBUG should also be ON)" OFF) -option(WITH_MPI "Enable Openmpi support" OFF) - -option(WITH_BOOST "Enable boost. Prefer boost over stl" OFF) -option(WITH_BOOST_ODE "Use boost library ode2 library instead of GSL" OFF) -option(WITH_GSL "Use gsl-library. Alternative is WITH_BOOST" ON) - -option(WITH_ASAN "Use AddressSanitizer in DEBUG mode." OFF) - -option(WITH_NSDF "Enable NSDF support. Requires hdf5" OFF ) - -option(WITH_LEGACY_BINDING "Use legacy python-bindings" OFF) - -############################ BUILD CONFIGURATION ################################# - -# Default definitions. -add_definitions(-DUSE_GENESIS_PARSER) -if(DEBUG OR "${CMAKE_BUILD_TYPE}" STREQUAL "Debug") - message(STATUS "Building for Debug/Unit testing") - add_definitions(-DDO_UNIT_TESTS -O) - set(CMAKE_BUILD_TYPE Debug) -elseif(ENABLE_UNIT_TESTS) - MESSAGE(STATUS "Enabled Unit tests") - add_definitions(-DDO_UNIT_TESTS) - set(CMAKE_BUILD_TYPE Debug) -else() - message(STATUS "Building for Release/No unit tests.") - set(CMAKE_BUILD_TYPE Release) - add_definitions(-UDO_UNIT_TESTS -O3 -DDISABLE_DEBUG) -endif() - -if(GPROF AND "${CMAKE_BUILD_TYPE}" STREQUAL "Debug") - message(STATUS "Compiling with profiling with gprof") - add_definitions(-pg) - set(CMAKE_EXE_LINKER_FLAGS_DEBUG "-pg") -endif() - -if(WITH_ASAN AND "${CMAKE_BUILD_TYPE}" STREQUAL "Debug") - message(STATUS "Compiling with ASAN") - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} \ - -fno-omit-frame-pointer -fsanitize=leak -fsanitize=address") - set(CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} \ - -fno-omit-frame-pointer -fsanitize=leak -fsanitize=address") - set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -fsanitize=address") -endif() - -# Override default GSL solvers when BOOST is enabled. -if(WITH_BOOST OR WITH_BOOST_ODE) - set(WITH_BOOST_ODE ON) - set(WITH_GSL OFF) -endif() - -find_package(HDF5 COMPONENTS CXX HL) - -if (NOT HDF5_FOUND) - message("==================================================================\n" - " HDF5 not found. Disabling NSDF support.\n\n" - " If you need NSDF support, please install hdf5-dev or hdf5-devel\n" - " package or equivalent.\n\n" - " $ sudo apt-get install libhdf5-dev \n" - " $ sudo yum install libhdf5-devel \n" - " $ brew install hdf5 \n\n" - " Otherwise, continue with 'make' and 'make install' \n" - " If you install hdf5 to non-standard path, export environment \n" - " variable HDF5_ROOT to the location. Rerun cmake \n" - "================================================================ \n" - ) -elseif(HDF5_FOUND) - set(WITH_NSDF ON) -endif() - -################################### TARGETS #################################### - -link_directories(${CMAKE_BINARY_DIR}) -add_library(libmoose SHARED basecode/main.cpp) -set_target_properties(libmoose PROPERTIES PREFIX "") -add_executable(moose.bin basecode/main.cpp) - - -################################### SETUP BUILD ################################ - -# Variable to collect all static libraries. -set(STATIC_LIBRARIES "" ) -# Collect all shared libraries here. -set(SYSTEM_SHARED_LIBS "") - -# BOOST ode library performs better than GSL and ideally should be made default. -# Unfortunately Boost does not have a very good matrix library; it has ublas -# which is not well maintained and emit a lot -# of warning during compilation. Nonetheless, WITH_BOOST_ODE works fine and -# produce results quicker than GSL. -if(WITH_GSL) - find_package(GSL 1.16 REQUIRED) - if(NOT GSL_FOUND) - message(FATAL_ERROR - "=====================================================================\n" - " FATAL gsl(>=1.16) not found.\n\n" - " MOOSE requires Gnu Scientific Library (GSL) 1.16 or higher. \n" - " Please install the `dev` or `devel` package e.g. \n" - " $ sudo apt-get install libgsl0-dev \n" - " $ sudo yum install libgsl-devel \n" - " $ brew install gsl \n\n" - " Or build and install gsl from source code \n" - " https://www.gnu.org/software/gsl/ \n" - " After installing gsl, rerun cmake.\n\n" - " If you install gsl in non-standard place, set the GSL_ROOT_DIR environment \n" - " variable. CMAKE use this to search for required files. \n" - "====================================================================\n" - ) - endif(NOT GSL_FOUND) -elseif(WITH_BOOST_ODE) - find_package(Boost 1.53 REQUIRED) - find_package(LAPACK REQUIRED) -endif() - - -# Openmpi -if(WITH_MPI) - find_package(MPI REQUIRED) - if(MPI_CXX_FOUND) - message(STATUS "Using MPI from ${MPI_CXX_INCLUDE_PATH}") - include_directories(${MPI_CXX_INCLUDE_PATH}) - set(CMAKE_CXX_COMPILE_FLAGS ${CMAKE_CXX_COMPILE_FLAGS} ${MPI_COMPILE_FLAGS}) - add_definitions(-DUSE_MPI) - SET(CMAKE_CXX_COMPILER ${MPI_CXX_COMPILER}) - SET(CMAKE_C_COMPILER ${MPI_C_COMPILER}) - else() - message(STATUS "Cound not find MPI") - add_definitions(-UUSE_MPI) - endif() -endif(WITH_MPI) - -if(WITH_BOOST_ODE) - list(APPEND SYSTEM_SHARED_LIBS ${LAPACK_LIBRARIES}) - list(APPEND SYSTEM_SHARED_LIBS ${Boost_LIBRARIES}) -endif(WITH_BOOST_ODE) - -find_package( Threads ) -list(APPEND SYSTEM_SHARED_LIBS ${CMAKE_THREAD_LIBS_INIT}) - -# These libraries could be static of dynamic. We need to discrimate between -# these two types because of --whole-archive option. See -# BhallaLab/moose-core#66, -if(WITH_GSL) - if(GSL_STATIC_LIBRARIES) - message( STATUS "Using static libraries ${GSL_STATIC_LIBRARIES}" ) - list(APPEND STATIC_LIBRARIES ${GSL_STATIC_LIBRARIES}) - else( ) - # message(DEBUG "Using gsl libraries: ${GSL_LIBRARIES}") - foreach(GSL_LIB ${GSL_LIBRARIES} ) - if(GSL_LIB) - get_filename_component( GSL_LIB_EXT ${GSL_LIB} EXT ) - if(GSL_LIB_EXT) - if(GSL_LIB_EXT STREQUAL ".a" ) - list(APPEND STATIC_LIBRARIES ${GSL_LIB}) - else() - list(APPEND SYSTEM_SHARED_LIBS ${GSL_LIB}) - endif( ) - endif( ) - endif( ) - endforeach( ) - endif( ) -endif() - -if(WITH_MPI) - if(MPI_CXX_FOUND) - list(APPEND SYSTEM_SHARED_LIBS ${MPI_CXX_LIBRARIES}) - endif() -endif(WITH_MPI) - -# Add subdirectroeis -add_subdirectory(basecode) -add_subdirectory(msg) -add_subdirectory(shell) -add_subdirectory(randnum) -add_subdirectory(scheduling) -add_subdirectory(biophysics) -add_subdirectory(builtins) -add_subdirectory(utility) -add_subdirectory(mesh) -add_subdirectory(mpi) -add_subdirectory(signeur) -add_subdirectory(ksolve) -add_subdirectory(hsolve) -add_subdirectory(diffusion) -add_subdirectory(device) -add_subdirectory(kinetics) -add_subdirectory(synapse) -add_subdirectory(intfire) -add_subdirectory(external) - -# development related. -add_subdirectory(devel) - -###################################### LINKING ################################# -list(APPEND MOOSE_LIBRARIES - moose_builtins - msg - shell - randnum - scheduling - moose_mpi - biophysics - utility - kinetics - synapse - intfire - hsolve - mesh - signeur - diffusion - ksolve - lsoda - device - basecode - ) - -# Make sure to remove duplicates. -list(REMOVE_DUPLICATES STATIC_LIBRARIES) -if(SYSTEM_SHARED_LIBS) - list(REMOVE_DUPLICATES SYSTEM_SHARED_LIBS) -endif( ) - -# cmake --help-policy CMP0042. Also in pymoose/CMakeLists.txt -# More details: -# https://gitlab.kitware.com/cmake/community/wikis/doc/cmake/RPATH-handling -# especially section 'Mac OS X and the RPATH' -# Switching is OFF since all libraries are statically linked in module. -if(APPLE) - set_target_properties(libmoose PROPERTIES MACOSX_RPATH OFF) -endif(APPLE) - -# MAC linker does not understand many of gnu-ld options. -# message( DEBUG "Shared libs: ${SYSTEM_SHARED_LIBS}") -if(APPLE) - target_link_libraries(libmoose - "-Wl,-all_load" - ${MOOSE_LIBRARIES} - ${STATIC_LIBRARIES} - ) - - target_link_libraries(libmoose - ${SYSTEM_SHARED_LIBS} - ${CMAKE_DL_LIBS} - ) -else(APPLE) - target_link_libraries(libmoose - "-Wl,--whole-archive" - ${MOOSE_LIBRARIES} - ${STATIC_LIBRARIES} - "-Wl,--no-whole-archive" - ${SYSTEM_SHARED_LIBS} - ) -endif(APPLE) - -add_dependencies(moose.bin libmoose) -target_link_libraries(moose.bin moose ${CMAKE_DL_LIBS}) - -if( WITH_BOOST ) - target_link_libraries( moose.bin ${Boost_LIBRARIES} ) -endif( WITH_BOOST ) - -######################### BUILD PYMOOSE ######################################## - -# pybind11 should be installed as a dependency. -# It can be easily done with `pip install pybind11` -# See: https://pybind11.readthedocs.io/en/stable/installing.html -# - Subha, Mon Apr 22 14:26:58 IST 2024 -execute_process(COMMAND ${CMAKE_COMMAND} -E pybind11-config --cmakedir OUTPUT_VARIABLE pybind11_DIR OUTPUT_STRIP_TRAILING_WHITESPACE) -find_package(pybind11 REQUIRED HINTS "${Python3_SITELIB}") -add_subdirectory(pybind11) - - -# always override debian default installation directory. It will be installed in -# site-packages instead of dist-packages. -# See https://bugs.launchpad.net/ubuntu/+source/python2.6/+bug/362570 -# HACK: Get platform information from python and use it to fix the layout. -execute_process(COMMAND ${PYTHON_EXECUTABLE} -mplatform OUTPUT_VARIABLE _platform_desc) -message(STATUS "Platform: ${_platform_desc}") - -# DISTUTILS_EXTRA_ARGS may come of top-level cmake script. On DEBIAN/UBUNTU, it -# is most likely to be --install-layout=deb . -set(EXTRA_ARGS "--prefix ${CMAKE_INSTALL_PREFIX} ${DISTUTILS_EXTRA_ARGS}") - -# On Debian/Ubuntu install using debian layout. -# NOTE: Also create setup.cfg file which setup prefix and install-layout -# suitable for DEBIAN systems. -if(${_platform_desc} MATCHES ".*(Ubuntu|debian).*") - list(APPEND EXTRA_ARGS "--install-layout=deb") - file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/setup.cfg - "[install]\nprefix=/usr\ninstall-layout=deb" - ) -endif() - - -######################### INSTALL ############################################## - -install(TARGETS moose.bin DESTINATION bin CONFIGURATIONS Debug) -install(TARGETS libmoose DESTINATION lib CONFIGURATIONS Debug) - -# Print message to start build process -if(${CMAKE_BUILD_TOOL} MATCHES "make") - message( - "=======================================\n" - "If cmake did not report any error, run \n" - " 'make' to build MOOSE \n" - "=======================================\n" - ) -endif() - - -############################ CTEST ###################################### -include(CTest) -add_subdirectory(tests) - -########################### RELEASE ######################################### -set(PYMOOSE_SDIST_FILE ${CMAKE_BINARY_DIR}/pymoose-${VERSION_MOOSE}.tar.gz) -add_custom_target(sdist - COMMAND ${PYTHON_EXECUTABLE} setup.py sdist --formats=gztar - -d ${CMAKE_BINARY_DIR} - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - COMMENT "Creating sdist ${PYMOOSE_SDIST_FILE}" - VERBATIM) - -add_custom_target(upload_test DEPENDS sdist - COMMAND ${PYTHON_EXECUTABLE} -m twine upload - --user $ENV{PYMOOSE_PYPI_USER} --password $ENV{PYMOOSE_PYPI_PASSWORD} - --repository-url https://test.pypi.org/legacy/ - ${PYMOOSE_SDIST_FILE} - COMMENT "Uploading source distribution to test.pypi.org" - VERBATIM) - -add_custom_target(upload DEPENDS sdist - COMMAND ${PYTHON_EXECUTABLE} -m twine upload - --user $ENV{PYMOOSE_PYPI_USER} --password $ENV{PYMOOSE_PYPI_PASSWORD} - ${PYMOOSE_SDIST_FILE} - COMMENT "Uploading source distribution to PyPI" - VERBATIM) - -####################### DEVELOPMENT ######################################## - -# PYLINT target. -set(PYSCRIPTS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/python) -file(GLOB_RECURSE PY_SCRIPTS "python/*.py") -add_custom_target(pylint) -foreach(_py_script ${PY_SCRIPTS}) - get_filename_component( _py_name ${_py_script} NAME_WE) - file( READ ${_py_script} pytext) - string(MD5 _md5 "${pytext}") - set(TGT_NAME "${_py_name}-${_md5}" ) - set(PYLINT_OPTIONS --disable=no-member --disable=no-name-in-module - --disable=invalid-unary-operand-type - --disable=import-error - --disable=no-method-argument - ) - add_custom_target( ${TGT_NAME} - COMMAND ${PYTHON_EXECUTABLE} -m pylint -E ${PYLINT_OPTIONS} ${_py_script} - COMMENT "Running pylint on ${_py_script}" - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - ) - add_dependencies(pylint ${TGT_NAME} ) -endforeach( ) - -######################## DOCS ############################################### -find_package(Doxygen) -if(DOXYGEN_FOUND) - set(DOXYGEN_IN ${CMAKE_CURRENT_SOURCE_DIR}/devel/Doxyfile.in) - set(DOXYGEN_OUT ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) - configure_file(${DOXYGEN_IN} ${DOXYGEN_OUT} @ONLY) - add_custom_target(doc - COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_OUT} - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - COMMENT "Generating API documentation using Doxygen." - VERBATIM) -else() - message(STATUS "Doxygen needs to be installed to generate API docs") -endif() diff --git a/CheckCXXCompiler.cmake b/CheckCXXCompiler.cmake deleted file mode 100644 index 1fbf9cd2e6..0000000000 --- a/CheckCXXCompiler.cmake +++ /dev/null @@ -1,64 +0,0 @@ -# Compiler check. -# Must support c++14 -# If python2 is supported then we can not use c++17. -if(COMPILER_IS_TESTED) - return() -endif() - -########################### COMPILER MACROS ##################################### -include(CheckCXXCompilerFlag) -if(WIN32) - CHECK_CXX_COMPILER_FLAG("/std:c++14" COMPILER_SUPPORTS_CXX14 ) -else(WIN32) - CHECK_CXX_COMPILER_FLAG("-std=c++14" COMPILER_SUPPORTS_CXX14 ) - CHECK_CXX_COMPILER_FLAG("-Wno-strict-aliasing" COMPILER_WARNS_STRICT_ALIASING ) -endif(WIN32) - -# Turn warning to error: Not all of the options may be supported on all -# versions of compilers. be careful here. -add_definitions(-Wall - #-Wno-return-type-c-linkage - -Wno-unused-variable - -Wno-unused-function - #-Wno-unused-private-field - ) - -if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") - if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "5.1") - message(FATAL_ERROR "Insufficient gcc version. Minimum requried 5.1") - endif() - add_definitions( -Wno-unused-local-typedefs ) - add_definitions( -fmax-errors=5 ) -elseif(("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang") OR ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")) - add_definitions( -Wno-unused-local-typedef ) -endif() - -add_definitions(-fPIC) -if(COMPILER_WARNS_STRICT_ALIASING) - add_definitions( -Wno-strict-aliasing ) -endif(COMPILER_WARNS_STRICT_ALIASING) - -# Disable some harmless warnings. -CHECK_CXX_COMPILER_FLAG( "-Wno-unused-but-set-variable" - COMPILER_SUPPORT_UNUSED_BUT_SET_VARIABLE_NO_WARN - ) -if(COMPILER_SUPPORT_UNUSED_BUT_SET_VARIABLE_NO_WARN) - add_definitions( "-Wno-unused-but-set-variable" ) -endif(COMPILER_SUPPORT_UNUSED_BUT_SET_VARIABLE_NO_WARN) - -if(COMPILER_SUPPORTS_CXX14) - if(WIN32) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /std:c++14") - else(WIN32) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14") - endif(WIN32) - if(APPLE) - add_definitions( -mllvm -inline-threshold=1000 ) - endif(APPLE) -else(COMPILER_SUPPORTS_CXX14) - message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} is too old. \n" - "Please use a compiler which has full c++14 support." - ) -endif(COMPILER_SUPPORTS_CXX14) - -set(COMPILER_IS_TESTED ON) diff --git a/MANIFEST.in b/MANIFEST.in index d71333ee95..ba89aab576 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,7 +1,6 @@ include AUTHORS include CMakeLists.txt include CONTRIBUTING.md -include CheckCXXCompiler.cmake include INSTALL.md include LICENSE include MANIFEST.in diff --git a/UbuntuBuild.md b/UbuntuBuild.md new file mode 100644 index 0000000000..362e24a0d5 --- /dev/null +++ b/UbuntuBuild.md @@ -0,0 +1,67 @@ +# Building MOOSE on Ubuntu (possibly in WSL) +0. Install GNU build tools + +``` +sudo apt install build-essential +``` + +1. Install conda/mamba/micromamba (in all the commands below `conda` can be replaced by `mamba` or `micromamba` respectively) + +2. Create an environment with required packages + +``` +conda create -n moose meson gsl hdf5 cmake numpy matplotlib vpython doxygen pybind11[global] pkg-config -c conda-forge +``` + +3. Activate the environment + +``` +conda activate moose +``` + +4. Clone `moose-core` source code using git +5. Build moose +``` +cd moose-core + +meson setup --wipe _build --prefix=`pwd`/_build_install -Duse_mpi=false -Dbuildtype=release +ninja -v -C _build +meson install -C _build +``` + +This will create `moose` module inside `moose-core/_build_install` directory. To make moose importable from any terminal, add this directory to your `PYTHONPATH` environment variable. For standard installation you can simply run `pip install .` in the `moose-core` directory. + +Meson provides many builtin options: https://mesonbuild.com/Builtin-options.html. Meson options are supplied in the command line to `meson setup` in the format `-Doption=value`. + + - **Buildtype** + If you want a developement build with debug enabled, pass `-Dbuildtype=debug` in the `meson setup`. + + + ``` + meson setup --wipe _build --prefix=`pwd`/_build_install -Duse_mpi=false -Dbuildtype=debug -Ddebug=true + ``` + + You can either use `buildtype` option alone or use the two options `debug` and `optimization` for finer grained control over the build. According to `meson` documentation `-Dbuildtype=debug` will create a debug build with optimization level 0 (i.e., no optimization, passing `-O0 -g` to GCC), `-Dbuildtype=debugoptimized` will create a debug build with optimization level 2 (equivalent to `-Ddebug=true -Doptimization=2`), `-Dbuildtype=release` will create a release build with optimization level 3 (equivalent to `-Ddebug=false -Doptimization=3`), and `-Dbuildtype=minsize` will create a release build with space optimization (passing `-Os` to GCC). + + - **Optimization level** + + To set optimization level, pass `-Doptimization=level`, where level can be `plain`, `0`, `g`, `1`, `2`, `3`, `s`. + +6. For a Python development build so that your edits to the Python source code are included, run: + +``` +python -m pip install --no-build-isolation --editable . +``` + +7. To build a wheel (for distribution), you need `build` and `meson-python` modules: + +``` +conda install meson-python +conda install build +``` + +In a terminal, `cd` to `moose-core` and run the following: + +``` +python -m build +``` diff --git a/WSLGuide.md b/WSLGuide.md new file mode 100644 index 0000000000..8e527e81de --- /dev/null +++ b/WSLGuide.md @@ -0,0 +1,57 @@ +# On WSL or git bash + +- If not already setup, open PowerShell and install it: +``` +wsl --install +``` + +- The above will install Ubuntu. Now open the terminal on WSL/Ubuntu and install `g++` and `make` +``` +sudo apt-get install g++ +sudo apt-get install make +sudo apt-get install qtbase5-dev +sudo apt install firefox +``` + +- Install micromamba: + +https://mamba.readthedocs.io/en/latest/installation/micromamba-installation.html + +``` +"${SHELL}" <(curl -L micro.mamba.pm/install.sh) +``` + +- Update micromamba + +``` +micromamba self-update +``` + +- Create environment with various required packages + +``` +micromamba create -n moose pip h5py numpy vpython scipy matplotlib gsl hdf5 jupyter pyqt cmake pybind11[global] jupyterlab-vpython +``` + +- Activate the environment + +``` +micromamba activate moose +``` + +- Build and install pymoose + +``` +pip install git+https://github.com/BhallaLab/moose-core.git +``` + +You need to do the above only once. After that, each time to use moose, open WSL Ubuntu terminal and do the following + +``` +micromamba activate moose +``` + +and you are ready to start running moose scripts. + + +NOTE: When running moose examples that use vpython for 3D visualization, you may run into a message like `"gio: http://localhost:39143: Operation not supported` and nothing much happens. To see the visualization, start `firefox` (or any other browser you installed on WSL) from another WSL terminal and enter the web address (http://localhost:39143 in this case) in its address bar. diff --git a/WindowsBuild.md b/WindowsBuild.md new file mode 100644 index 0000000000..3afe501aa5 --- /dev/null +++ b/WindowsBuild.md @@ -0,0 +1,125 @@ +# Building MOOSE on Windows with MSVC + +## Virtual environment +You may want to use one of the virtual environment systems like Anaconda, Miniforge with Mamba, or Micromamba (https://mamba.readthedocs.io/en/latest/), which will allow you to create isolated Python environments. There are binary packages for most of the requirements in the conda channels (conda-forge). In contrast, pip will actually download the package source code and try to build it locally, which opens up a chain of dependencies on various other libraries. + +If you want to keep things slim, `micromamba` may be ideal because it is a single statically linked C++ executable and does not install any base environment. + +In this guide, `conda` command can be replaced by `mamba` or `micromamba` if you are using one of those systems. + +To create an environment, open Anaconda command prompt (below we assume Windows CMD shell, you may need to change some commands for PowerShell) and enter + +``` +conda create -n moose meson gsl hdf5 cmake numpy matplotlib vpython doxygen pkg-config pybind11[global] -c conda-forge +``` + +This will create an environment name `moose`. In some terminals (windows cmd?) you may get an error for `pybind11[global]`. Put it inside quotes to work around it. + +Then activate this environment for your build : + +``` +conda activate moose +``` + +## Requirements + +You need to use Windows cmd shell (not powershell) for the following: + +* Install either MS Visual Studio 2015 or newer or MS Visual Studio Build Tools. + Add path to this folder in your PATH variable +* Install git for Windows +* [Skip] For MPI install MS-MPI (https://github.com/microsoft/Microsoft-MPI/releases/), the only free MPI for Windows + - TODO: MPI-build on Windows is not supported yet +* [Skip] Install doxygen +* Install `pkg-config` + +``` +conda install pkg-config +``` + +* Get the environment variable for MS Visual Studio command line tools set up by running + +``` +"C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Auxiliary\Build\vcvars64.bat" +``` + +Gotcha: if you are on a 64 bit machine, the machine type is `x64`. MSVC comes with cross compilation support for various machine-os combos (x86, x86_64). You can initialize the architecture according to your specific case (see this [stackoverflow comment](https://stackoverflow.com/questions/78446613/whats-the-difference-in-visual-studio-between-amd64-x86-vs-x86-amd64) + +"C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" {combo} + +* Clone `moose-core` source code using git +* Build moose +``` +cd moose-core + +meson setup --wipe _build --prefix=%CD%\\_build_install -Duse_mpi=false --buildtype=release +ninja -v -C _build +meson install -C _build +``` + +This will create `moose` module inside `moose-core/_build_install` directory. To make moose importable from any terminal, add this directory to your `PYTHONPATH` environment variable. + + +Meson provides many builtin options: https://mesonbuild.com/Builtin-options.html. Meson options are supplied in the command line to `meson setup` in the format `-Doption=value`. + + - **Buildtype** + If you want a developement build with debug enabled, pass `-Dbuildtype=debug` in the `meson setup`. + + + ``` + meson setup --wipe _build --prefix=%CD%\\_build_install -Duse_mpi=false -Dbuildtype=debug + ``` + + You can either use `buildtype` option alone or use the two options `debug` and `optimization` for finer grained control over the build. According to `meson` documentation `-Dbuildtype=debug` will create a debug build with optimization level 0 (i.e., no optimization, passing `-O0 -g` to GCC), `-Dbuildtype=debugoptimized` will create a debug build with optimization level 2 (equivalent to `-Ddebug=true -Doptimization=2`), `-Dbuildtype=release` will create a release build with optimization level 3 (equivalent to `-Ddebug=false -Doptimization=3`), and `-Dbuildtype=minsize` will create a release build with space optimization (passing `-Os` to GCC). + + - **Optimization level** + + To set optimization level, pass `-Doptimization=level`, where level can be `plain`, `0`, `g`, `1`, `2`, `3`, `s`. + + + +For standard installation you can simply run `pip install .` in the `moose-core` directory. + +To build a wheel, you need `build` and `meson-python` modules: + +``` +conda install meson-python +conda install build +``` + +In a terminal, `cd` to `moose-core` and run the following: + +``` +python -m build +``` + +# Debug build +Debug build tries to link with debug build of Python, and this is not +readily available on Windows, unless you build the Python interpreter +(CPython) itself from sources in debug mode. Therefore, debug build of +moose will fail at the linking stage complaining that the linker could +not find `python3x_d.lib`. + +The workaround, as pointed out by Ali Ramezani +[here](https://stackoverflow.com/questions/66162568/lnk1104cannot-open-file-python39-d-lib), +is to make a copy of `python3x.lib` named `python3x_d.lib` in the same +directory (`libs`). After that, you can run meson setup as follows: + +``` +meson setup --wipe _build --prefix=%CD%\\_build_install -Duse_mpi=false --buildtype=debug +``` + +and then go through the rest of the steps. + +A free graphical debugger available for MS Windows is WinDbg (https://learn.microsoft.com/en-us/windows-hardware/drivers/debugger/). You can +use it to attach to a running Python process and set breakpoints at +target function/line etc. + +In WinDbg command line you find the moose module name with +`lm m _moose*` + +The will show something like `_moose_cp311_win_amd64` when your build produced `_moose.cp311-win_amd64.lib`. + +Now you can set a breakpoint to a class function with the module name as prefix as follows: + +`bp _moose_cp311_win_amd64!ChanBase::setGbar` diff --git a/basecode/CMakeLists.txt b/basecode/CMakeLists.txt deleted file mode 100644 index 7b0b9484fe..0000000000 --- a/basecode/CMakeLists.txt +++ /dev/null @@ -1,33 +0,0 @@ -cmake_minimum_required(VERSION 3.20) -include( ${CMAKE_CURRENT_SOURCE_DIR}/../CheckCXXCompiler.cmake ) -add_library(basecode - Element.cpp - DataElement.cpp - GlobalDataElement.cpp - LocalDataElement.cpp - Eref.cpp - Finfo.cpp - DestFinfo.cpp - Cinfo.cpp - SrcFinfo.cpp - ValueFinfo.cpp - SharedFinfo.cpp - FieldElementFinfo.cpp - FieldElement.cpp - Id.cpp - ObjId.cpp - global.cpp - SetGet.cpp - OpFuncBase.cpp - EpFunc.cpp - HopFunc.cpp - SparseMatrix.cpp - doubleEq.cpp - testAsync.cpp - ) - -add_executable(test_globals testGlobals.cpp global.cpp) - -enable_testing() -add_test(NAME cpp_test_globals COMMAND $) - diff --git a/basecode/Conv.h b/basecode/Conv.h index 0baf86a498..487536018b 100644 --- a/basecode/Conv.h +++ b/basecode/Conv.h @@ -478,7 +478,7 @@ template<> class Conv< bool > } static void val2str( string& s, bool val ) { - if ( val > 0.5 ) + if ( val ) s = "1"; else s = "0"; @@ -566,11 +566,11 @@ template< class T > class Conv< vector< vector< T > > > { static vector< vector< T > > ret; ret.clear(); - unsigned int numEntries = **buf; // first entry is vec size + unsigned int numEntries = (unsigned int)**buf; // first entry is vec size ret.resize( numEntries ); (*buf)++; for ( unsigned int i = 0; i < numEntries; ++i ) { - unsigned int rowSize = **buf; + unsigned int rowSize = (unsigned int)**buf; (*buf)++; for ( unsigned int j = 0; j < rowSize; ++j ) ret[i].push_back( Conv< T >::buf2val( buf ) ); @@ -581,9 +581,9 @@ template< class T > class Conv< vector< vector< T > > > static void val2buf( const vector< vector< T > >& val, double**buf ) { double* temp = *buf; - *temp++ = val.size(); + *temp++ = (double)val.size(); for( unsigned int i = 0; i < val.size(); ++i ) { - *temp++ = val[i].size(); + *temp++ = (double)val[i].size(); for ( unsigned int j = 0; j < val[i].size(); ++j ) { Conv< T >::val2buf( val[i][j], &temp ); } @@ -641,7 +641,7 @@ template< class T > class Conv< vector< T > > static void val2buf( const vector< T >& val, double**buf ) { double* temp = *buf; - *temp++ = val.size(); + *temp++ = (double)val.size(); for( unsigned int i = 0; i < val.size(); ++i ) { Conv< T >::val2buf( val[i], &temp ); } diff --git a/basecode/doubleEq.h b/basecode/doubleEq.h index 458d704bf2..5fb935a09a 100644 --- a/basecode/doubleEq.h +++ b/basecode/doubleEq.h @@ -7,5 +7,5 @@ ** See the file COPYING.LIB for the full notice. **********************************************************************/ -bool doubleEq( double x, double y ); -bool doubleApprox( double x, double y ); +extern bool doubleEq( double x, double y ); +extern bool doubleApprox( double x, double y ); diff --git a/basecode/main.cpp b/basecode/main.cpp index 162f57ea16..ccc024089e 100644 --- a/basecode/main.cpp +++ b/basecode/main.cpp @@ -13,7 +13,11 @@ #include #include #include +#if defined(_WIN32) +#include "getopt.h" +#else #include // for getopt +#endif #include "../scheduling/Clock.h" #include "../msg/DiagonalMsg.h" #include "../msg/SparseMsg.h" diff --git a/basecode/meson.build b/basecode/meson.build new file mode 100644 index 0000000000..092c3f4254 --- /dev/null +++ b/basecode/meson.build @@ -0,0 +1,28 @@ +# Author: Subhasis Ray +# Date: Sun Jul 7 + +basecode_src = ['Element.cpp', + 'DataElement.cpp', + 'GlobalDataElement.cpp', + 'LocalDataElement.cpp', + 'Eref.cpp', + 'Finfo.cpp', + 'DestFinfo.cpp', + 'Cinfo.cpp', + 'SrcFinfo.cpp', + 'ValueFinfo.cpp', + 'SharedFinfo.cpp', + 'FieldElementFinfo.cpp', + 'FieldElement.cpp', + 'Id.cpp', + 'ObjId.cpp', + 'global.cpp', + 'SetGet.cpp', + 'OpFuncBase.cpp', + 'EpFunc.cpp', + 'HopFunc.cpp', + 'SparseMatrix.cpp', + 'doubleEq.cpp', + 'testAsync.cpp'] + + basecode_lib = static_library('basecode', basecode_src) diff --git a/biophysics/CMakeLists.txt b/biophysics/CMakeLists.txt deleted file mode 100644 index 2bd733fbbd..0000000000 --- a/biophysics/CMakeLists.txt +++ /dev/null @@ -1,59 +0,0 @@ -cmake_minimum_required(VERSION 3.20) -include(${CMAKE_CURRENT_SOURCE_DIR}/../CheckCXXCompiler.cmake) - -if(WITH_GSL) - find_package(GSL 1.16) - include_directories(${GSL_INCLUDE_DIRS}) -elseif(WITH_BOOST_ODE) - find_package(Boost) - include_directories(${Boost_INCLUDE_DIRS}) -endif(WITH_GSL) - -set(BIOPHYSICS_SRCS - IntFire.cpp - SpikeGen.cpp - RandSpike.cpp - CompartmentDataHolder.cpp - CompartmentBase.cpp - Compartment.cpp - SymCompartment.cpp - GapJunction.cpp - ChanBase.cpp - ChanCommon.cpp - HHChannel.cpp - HHChannelBase.cpp - HHChannel2D.cpp - HHGate.cpp - HHGate2D.cpp - HHChannel2D.cpp - CaConcBase.cpp - CaConc.cpp - MgBlock.cpp - Nernst.cpp - Neuron.cpp - ReadCell.cpp - SwcSegment.cpp - ReadSwc.cpp - SynChan.cpp - NMDAChan.cpp - IzhikevichNrn.cpp - DifShellBase.cpp - DifShell.cpp - DifBufferBase.cpp - DifBuffer.cpp - MMPump.cpp - Leakage.cpp - VectorTable.cpp - MarkovRateTable.cpp - MarkovChannel.cpp - MatrixOps.cpp - MarkovSolverBase.cpp - MarkovSolver.cpp - VClamp.cpp - Spine.cpp - MarkovOdeSolver.cpp - testBiophysics.cpp - ) - -add_library(biophysics ${BIOPHYSICS_SRCS}) - diff --git a/biophysics/ChanBase.h b/biophysics/ChanBase.h index 13c81d943f..65a576b4f9 100644 --- a/biophysics/ChanBase.h +++ b/biophysics/ChanBase.h @@ -11,6 +11,8 @@ #ifndef _ChanBase_h #define _ChanBase_h +#include "../basecode/header.h" + /** * The ChanBase is the base class for all ion channel classes in MOOSE. * It knows how to communicate with the parent compartment, not much else. @@ -20,7 +22,7 @@ class ChanBase { public: ChanBase(); - ~ChanBase(); + virtual ~ChanBase() = 0; ///////////////////////////////////////////////////////////// // Value field access function definitions diff --git a/biophysics/ChanCommon.cpp b/biophysics/ChanCommon.cpp index a65282e76e..738c6c54a9 100644 --- a/biophysics/ChanCommon.cpp +++ b/biophysics/ChanCommon.cpp @@ -6,11 +6,11 @@ ** GNU Lesser General Public License version 2.1 ** See the file COPYING.LIB for the full notice. **********************************************************************/ - -#include "../basecode/header.h" -#include "ChanBase.h" +// #include "../basecode/header.h" +// #include "ChanBase.h" #include "ChanCommon.h" + /////////////////////////////////////////////////// // Constructor /////////////////////////////////////////////////// diff --git a/biophysics/ChanCommon.h b/biophysics/ChanCommon.h index 50725bb667..2204d2f118 100644 --- a/biophysics/ChanCommon.h +++ b/biophysics/ChanCommon.h @@ -12,35 +12,38 @@ #ifndef _ChanCommon_h #define _ChanCommon_h +#include "ChanBase.h" + +// #include "../basecode/header.h" + /** * The ChanCommon.g handles the data fields for all ion channel classes * in MOOSE, when they are using regular ee calculations rather than * being zombified by the solver. */ -class ChanCommon: public virtual ChanBase +class ChanCommon: public ChanBase { public: ChanCommon(); - ~ChanCommon(); + virtual ~ChanCommon() = 0; ///////////////////////////////////////////////////////////// // Value field access function definitions ///////////////////////////////////////////////////////////// - void vSetGbar( const Eref& e, double Gbar ); - double vGetGbar( const Eref& e ) const; - void vSetModulation( const Eref& e, double modulation ); - double vGetModulation( const Eref& e ) const; - double getModulation() const; - void vSetEk( const Eref& e, double Ek ); - double vGetEk( const Eref& e ) const; - void vSetGk( const Eref& e, double Gk ); - double vGetGk( const Eref& e ) const; + void vSetGbar ( const Eref& e, double Gbar ) override; + double vGetGbar( const Eref& e ) const override; + void vSetModulation( const Eref& e, double modulation ) override; + double vGetModulation( const Eref& e ) const override; + void vSetEk( const Eref& e, double Ek ) override; + double vGetEk( const Eref& e ) const override; + void vSetGk( const Eref& e, double Gk ) override; + double vGetGk( const Eref& e ) const override; /// Ik is read-only for MOOSE, but we provide the set /// func for derived classes to update it. - void vSetIk( const Eref& e, double Ic ); - double vGetIk( const Eref& e ) const; + void vSetIk( const Eref& e, double Ic ) override; + double vGetIk( const Eref& e ) const override; ///////////////////////////////////////////////////////////// // Dest function definitions @@ -49,7 +52,7 @@ class ChanCommon: public virtual ChanBase /** * Assign the local Vm_ to the incoming Vm from the compartment */ - void vHandleVm( double Vm ); + void vHandleVm( double Vm ) override; ///////////////////////////////////////////////////////////// /** @@ -75,6 +78,12 @@ class ChanCommon: public virtual ChanBase /// Specify the Class Info static variable for initialization. static const Cinfo* initCinfo(); protected: + // Note: this is for sublcasses to get the value directly; + // different from getModulation(const Eref&) for getting the value + // field + // + double getModulation() const; + /// Vm_ is input variable from compartment, used for most rates double Vm_; diff --git a/biophysics/HHChannel.cpp b/biophysics/HHChannel.cpp index 3d84fe6975..942d974ac5 100644 --- a/biophysics/HHChannel.cpp +++ b/biophysics/HHChannel.cpp @@ -14,7 +14,7 @@ #include "ChanCommon.h" #include "HHChannelBase.h" #include "HHChannel.h" -#include "../shell/Shell.h" + const double HHChannel::EPSILON = 1.0e-10; const int HHChannel::INSTANT_X = 1; @@ -65,6 +65,7 @@ HHChannel::HHChannel() HHChannel::~HHChannel() { + ; // if ( xGate_ && reinterpret_cast< char* >( this ) == // ObjId( xGate_->originalChannelId(), 0 ).data() ) // delete xGate_; @@ -311,7 +312,7 @@ void HHChannel::vProcess(const Eref& e, ProcPtr info) g_ *= takeZpower_(Z_, Zpower_); } - ChanCommon::vSetGk(e, g_ * HHChannelBase::modulation_); + ChanCommon::vSetGk(e, g_ * ChanCommon::vGetModulation(e)); ChanCommon::updateIk(); // Gk_ = g_; // Ik_ = ( Ek_ - Vm_ ) * g_; @@ -372,7 +373,7 @@ void HHChannel::vReinit(const Eref& er, ProcPtr info) g_ *= takeZpower_(Z_, Zpower_); } - ChanCommon::vSetGk(er, g_ * HHChannelBase::modulation_); + ChanCommon::vSetGk(er, g_ * ChanCommon::vGetModulation(er)); ChanCommon::updateIk(); // Gk_ = g_; // Ik_ = ( Ek_ - Vm_ ) * g_; @@ -389,15 +390,6 @@ void HHChannel::vHandleConc(const Eref& e, double conc) conc_ = conc; } -void HHChannel::vSetModulation(const Eref& e, double modulation) -{ - if (modulation > 0.0) HHChannelBase::modulation_ = modulation; -} - -double HHChannel::vGetModulation(const Eref& e) const -{ - return HHChannelBase::modulation_; -} /////////////////////////////////////////////////// // HHGate functions diff --git a/biophysics/HHChannel.h b/biophysics/HHChannel.h index 2417749a69..3ceb14985f 100644 --- a/biophysics/HHChannel.h +++ b/biophysics/HHChannel.h @@ -1,5 +1,3 @@ -#ifndef _HHChannel_h -#define _HHChannel_h /********************************************************************** ** This program is part of 'MOOSE', the ** Messaging Object Oriented Simulation Environment, @@ -11,6 +9,15 @@ ********************************************************************* */ +#ifndef _HHChannel_h +#define _HHChannel_h + +#include "ChanBase.h" +#include "ChanCommon.h" +#include "HHChannelBase.h" + +class HHGate; + /** * The HHChannel class sets up a Hodkin-Huxley type ion channel. * The form used here is quite general and can handle up to 3 @@ -45,33 +52,53 @@ * on each node. */ -class HHChannel : public HHChannelBase, public ChanCommon { +class HHChannel : public HHChannelBase { + #ifdef DO_UNIT_TESTS friend void testHHChannel(); friend void testHHGateCreation(); #endif // DO_UNIT_TESTS + public: HHChannel(); ~HHChannel(); + ////////////////////////////////////////////////////////////////////////////////////////////// + // Avoid warning C4250 from MSVC: + // "'HHChannel': inherits 'ChanCommon::ChanCommon::vSetGbar' via dominance" + // Although vSetX where X is the field to be set is pure virtual in ChanBase, and is + // implemented in ChanCommon, MSVC seems to still resolve it by dominance. + // Probably the ambiguity between ChanBase::vSetEk and ChanCommon::vSetEk etc. cause Ek to be + // garbage when built with MSVC. + // Looks like this bug persists since 2005: + // https://stackoverflow.com/questions/469508/visual-studio-compiler-warning-c4250-class1-inherits-class2member-via-d + ////////////////////////////////////////////////////////////////////////////////////////////// + // void vSetGbar(const Eref&e, double Gbar ); + // double vGetGbar(const Eref&e) const; + // void vSetEk(const Eref&e, double Ek ); + // double vGetEk(const Eref&e) const; + // void vSetGk(const Eref&e, double Gk ); + // double vGetGk(const Eref&e) const; + // void vSetIk(const Eref&e, double Ic ); + // double vGetIk(const Eref&e) const; + // void vHandleVm(double Vm ); ///////////////////////////////////////////////////////////// // Value field access function definitions ///////////////////////////////////////////////////////////// - - void vSetXpower(const Eref& e, double Xpower); - void vSetYpower(const Eref& e, double Ypower); - void vSetZpower(const Eref& e, double Zpower); - void vSetInstant(const Eref& e, int Instant); - int vGetInstant(const Eref& e) const; - void vSetX(const Eref& e, double X); - double vGetX(const Eref& e) const; - void vSetY(const Eref& e, double Y); - double vGetY(const Eref& e) const; - void vSetZ(const Eref& e, double Z); - double vGetZ(const Eref& e) const; - void vSetUseConcentration(const Eref& e, int value); - void vSetModulation(const Eref& e, double modulation); - double vGetModulation(const Eref& e) const; + void vSetXpower(const Eref& e, double Xpower) override; + void vSetYpower(const Eref& e, double Ypower) override; + void vSetZpower(const Eref& e, double Zpower) override; + void vSetInstant(const Eref& e, int Instant) override; + int vGetInstant(const Eref& e) const override; + void vSetX(const Eref& e, double X) override; + double vGetX(const Eref& e) const override; + void vSetY(const Eref& e, double Y) override; + double vGetY(const Eref& e) const override; + void vSetZ(const Eref& e, double Z) override; + double vGetZ(const Eref& e) const override; + void vSetUseConcentration(const Eref& e, int value) override; + // void vSetModulation(const Eref& e, double modulation) override; // defined in ChanCommon + // double vGetModulation(const Eref& e) const override; // defined in ChanCommon void innerSetXpower(double Xpower); void innerSetYpower(double Ypower); diff --git a/biophysics/HHChannel2D.h b/biophysics/HHChannel2D.h index d674ca7c3a..b29398274c 100644 --- a/biophysics/HHChannel2D.h +++ b/biophysics/HHChannel2D.h @@ -1,5 +1,3 @@ -#ifndef _HHChannel2D_h -#define _HHChannel2D_h /********************************************************************** ** This program is part of 'MOOSE', the ** Messaging Object Oriented Simulation Environment, @@ -11,6 +9,13 @@ ********************************************************************* */ +#ifndef _HHChannel2D_h +#define _HHChannel2D_h + +#include "ChanBase.h" +#include "ChanCommon.h" +#include "HHChannelBase.h" + /** * * In HHChannel2D, there are three possible arguments to each gate: @@ -21,6 +26,9 @@ // Ported to asyn13 on 2014-05-30 by Subhasis Ray typedef double ( *PFDD )( double, double ); + +class HHGate2D; + class HHChannel2D: public ChanCommon { #ifdef DO_UNIT_TESTS diff --git a/biophysics/HHChannelBase.cpp b/biophysics/HHChannelBase.cpp index 46dc496555..e2926c5be7 100644 --- a/biophysics/HHChannelBase.cpp +++ b/biophysics/HHChannelBase.cpp @@ -146,15 +146,14 @@ HHChannelBase::HHChannelBase() : Xpower_(0.0), Ypower_(0.0), Zpower_(0.0), - useConcentration_(0), - modulation_(1.0) + useConcentration_(0) { - ; + ; } HHChannelBase::~HHChannelBase() { - ; + ; } bool checkPower(double power) @@ -264,10 +263,10 @@ int HHChannelBase::getUseConcentration(const Eref& e) const return useConcentration_; } -double HHChannelBase::vGetModulation(const Eref& e) const -{ - return modulation_; -} +// double HHChannelBase::vGetModulation(const Eref& e) const +// { +// return modulation_; +// } /////////////////////////////////////////////////// // Dest function definitions diff --git a/biophysics/HHChannelBase.h b/biophysics/HHChannelBase.h index 8d6a753182..d66896edd5 100644 --- a/biophysics/HHChannelBase.h +++ b/biophysics/HHChannelBase.h @@ -1,5 +1,3 @@ -#ifndef _HHChannelBase_h -#define _HHChannelBase_h /********************************************************************** ** This program is part of 'MOOSE', the ** Messaging Object Oriented Simulation Environment, @@ -11,8 +9,16 @@ ********************************************************************* */ +#ifndef _HHChannelBase_h +#define _HHChannelBase_h + +#include "ChanCommon.h" + + typedef double ( *PFDD )( double, double ); +class HHGate; + /** * The HHChannelBase is the base class for defining Hodgkin-Huxley type * channels, specifically dealing with derivatives used in the HSolver. @@ -21,11 +27,11 @@ typedef double ( *PFDD )( double, double ); * fields. */ -class HHChannelBase: public virtual ChanBase +class HHChannelBase: public ChanCommon { public: HHChannelBase(); - ~HHChannelBase(); + virtual ~HHChannelBase() = 0; // this class is not to be instantiated ///////////////////////////////////////////////////////////// // Value field access function definitions @@ -47,7 +53,7 @@ class HHChannelBase: public virtual ChanBase double getZ( const Eref& e ) const; void setUseConcentration( const Eref& e, int value ); int getUseConcentration( const Eref& e ) const; - double vGetModulation( const Eref& e ) const; + // double vGetModulation( const Eref& e ) const; // provided by ChanCommon ///////////////////////////////////////////////////////////// // Dest function definitions ///////////////////////////////////////////////////////////// @@ -185,7 +191,7 @@ class HHChannelBase: public virtual ChanBase bool useConcentration_; /// Value used to scale channel conductance up or down - double modulation_; + // double modulation_; // this clashes with same field in ChanCommon }; diff --git a/biophysics/HHGate.cpp b/biophysics/HHGate.cpp index f4e3787355..930a66e592 100644 --- a/biophysics/HHGate.cpp +++ b/biophysics/HHGate.cpp @@ -26,7 +26,7 @@ const Cinfo* HHGate::initCinfo() "Alternatively uses linear interpolation." "The range of the double is predefined based on knowledge of" "voltage or conc ranges, and the granularity is specified by" - "the xmin, xmax, and dV fields.", + "the xmin, xmax, and xdivs fields.", &HHGate::lookupA); static ReadOnlyLookupValueFinfo B( "B", @@ -499,7 +499,7 @@ vector HHGate::getAlphaParms(const Eref& e) const { vector ret = alpha_; ret.insert(ret.end(), beta_.begin(), beta_.end()); - ret.push_back(A_.size()); + ret.push_back((double)A_.size()); ret.push_back(xmin_); ret.push_back(xmax_); @@ -816,7 +816,7 @@ void HHGate::updateTables() return; vector parms = alpha_; parms.insert(parms.end(), beta_.begin(), beta_.end()); - parms.push_back(A_.size()); + parms.push_back((double)A_.size()); parms.push_back(xmin_); parms.push_back(xmax_); diff --git a/biophysics/HHGate.h b/biophysics/HHGate.h index a3bb4a3ce9..f9f4ce7ea2 100644 --- a/biophysics/HHGate.h +++ b/biophysics/HHGate.h @@ -1,5 +1,3 @@ -#ifndef _HHGate_h -#define _HHGate_h /********************************************************************** ** This program is part of 'MOOSE', the ** Messaging Object Oriented Simulation Environment. @@ -8,6 +6,8 @@ ** GNU Lesser General Public License version 2.1 ** See the file COPYING.LIB for the full notice. **********************************************************************/ +#ifndef _HHGate_h +#define _HHGate_h /** * This class handles a single gate on an HHChannel. It is equivalent to the diff --git a/biophysics/HHGate2D.cpp b/biophysics/HHGate2D.cpp index c3c88138ea..29fff06462 100644 --- a/biophysics/HHGate2D.cpp +++ b/biophysics/HHGate2D.cpp @@ -46,70 +46,37 @@ const Cinfo* HHGate2D::initCinfo() &HHGate2D::setTableB, &HHGate2D::getTableB); - static ElementValueFinfo< HHGate2D, double > xminA( "xminA", + static ElementValueFinfo< HHGate2D, double > xmin( "xmin", "Minimum range for lookup", - &HHGate2D::setXminA, - &HHGate2D::getXminA + &HHGate2D::setXmin, + &HHGate2D::getXmin ); - static ElementValueFinfo< HHGate2D, double > xmaxA( "xmaxA", + static ElementValueFinfo< HHGate2D, double > xmax( "xmax", "Minimum range for lookup", - &HHGate2D::setXmaxA, - &HHGate2D::getXmaxA + &HHGate2D::setXmax, + &HHGate2D::getXmax ); - static ElementValueFinfo< HHGate2D, unsigned int > xdivsA( "xdivsA", + static ElementValueFinfo< HHGate2D, unsigned int > xdivs( "xdivs", "Divisions for lookup. Zero means to use linear interpolation", - &HHGate2D::setXdivsA, - &HHGate2D::getXdivsA); + &HHGate2D::setXdivs, + &HHGate2D::getXdivs); - static ElementValueFinfo< HHGate2D, double > yminA( "yminA", + static ElementValueFinfo< HHGate2D, double > ymin( "ymin", "Minimum range for lookup", - &HHGate2D::setYminA, - &HHGate2D::getYminA); + &HHGate2D::setYmin, + &HHGate2D::getYmin); - static ElementValueFinfo< HHGate2D, double > ymaxA( "ymaxA", + static ElementValueFinfo< HHGate2D, double > ymax( "ymax", "Minimum range for lookup", - &HHGate2D::setYmaxA, - &HHGate2D::getYmaxA); + &HHGate2D::setYmax, + &HHGate2D::getYmax); - static ElementValueFinfo< HHGate2D, unsigned int > ydivsA( "ydivsA", + static ElementValueFinfo< HHGate2D, unsigned int > ydivs( "ydivs", "Divisions for lookup. Zero means to use linear interpolation", - &HHGate2D::setYdivsA, - &HHGate2D::getYdivsA); - - static ElementValueFinfo< HHGate2D, double > xminB( "xminB", - "Minimum range for lookup", - &HHGate2D::setXminB, - &HHGate2D::getXminB - ); - - static ElementValueFinfo< HHGate2D, double > xmaxB( "xmaxB", - "Minimum range for lookup", - &HHGate2D::setXmaxB, - &HHGate2D::getXmaxB - ); - - static ElementValueFinfo< HHGate2D, unsigned int > xdivsB( "xdivsB", - "Divisions for lookup. Zero means to use linear interpolation", - &HHGate2D::setXdivsB, - &HHGate2D::getXdivsB - ); - - static ElementValueFinfo< HHGate2D, double > yminB( "yminB", - "Minimum range for lookup", - &HHGate2D::setYminB, - &HHGate2D::getYminB); - - static ElementValueFinfo< HHGate2D, double > ymaxB( "ymaxB", - "Minimum range for lookup", - &HHGate2D::setYmaxB, - &HHGate2D::getYmaxB); - - static ElementValueFinfo< HHGate2D, unsigned int > ydivsB( "ydivsB", - "Divisions for lookup. Zero means to use linear interpolation", - &HHGate2D::setYdivsB, - &HHGate2D::getYdivsB); + &HHGate2D::setYdivs, + &HHGate2D::getYdivs); /////////////////////////////////////////////////////// // DestFinfos @@ -120,24 +87,18 @@ const Cinfo* HHGate2D::initCinfo() &B, // ReadOnlyLookupValue &tableA, // ElementValue &tableB, // ElementValue - &xminA, - &xmaxA, - &xdivsA, - &yminA, - &ymaxA, - &ydivsA, - &xminB, - &xmaxB, - &xdivsB, - &yminB, - &ymaxB, - &ydivsB + &xmin, + &xmax, + &xdivs, + &ymin, + &ymax, + &ydivs, }; static string doc[] = { "Name", "HHGate2D", - "Author", "Niraj Dudani, 2009, NCBS. Updated by Subhasis Ray, 2014, NCBS.", + "Author", "Niraj Dudani, 2009, NCBS. Updated by Subhasis Ray, 2014, 2024 NCBS.", "Description", "HHGate2D: Gate for Hodkgin-Huxley type channels, equivalent to the " "m and h terms on the Na squid channel and the n term on K. " "This takes the voltage and state variable from the channel, " @@ -254,126 +215,73 @@ Id HHGate2D::originalChannelId() const return originalChanId_; } -double HHGate2D::getXminA(const Eref& e) const +double HHGate2D::getXmin(const Eref& e) const { return A_.getXmin(); } -void HHGate2D::setXminA(const Eref& e, double value) +void HHGate2D::setXmin(const Eref& e, double value) { A_.setXmin(value); + B_.setXmin(value); } -double HHGate2D::getXmaxA(const Eref& e) const +double HHGate2D::getXmax(const Eref& e) const { return A_.getXmax(); } -void HHGate2D::setXmaxA(const Eref& e, double value) +void HHGate2D::setXmax(const Eref& e, double value) { A_.setXmax(value); + B_.setXmax(value); } -unsigned int HHGate2D::getXdivsA(const Eref& e) const +unsigned int HHGate2D::getXdivs(const Eref& e) const { return A_.getXdivs(); } -void HHGate2D::setXdivsA(const Eref& e, unsigned int value) +void HHGate2D::setXdivs(const Eref& e, unsigned int value) { A_.setXdivs(value); + B_.setXdivs(value); } -double HHGate2D::getYminA(const Eref& e) const +double HHGate2D::getYmin(const Eref& e) const { return A_.getYmin(); } -void HHGate2D::setYminA(const Eref& e, double value) +void HHGate2D::setYmin(const Eref& e, double value) { A_.setYmin(value); + B_.setYmin(value); } -double HHGate2D::getYmaxA(const Eref& e) const +double HHGate2D::getYmax(const Eref& e) const { return A_.getYmax(); } -void HHGate2D::setYmaxA(const Eref& e, double value) +void HHGate2D::setYmax(const Eref& e, double value) { A_.setYmax(value); + B_.setYmax(value); } -unsigned int HHGate2D::getYdivsA(const Eref& e) const +unsigned int HHGate2D::getYdivs(const Eref& e) const { return A_.getYdivs(); } -void HHGate2D::setYdivsA(const Eref& e, unsigned int value) +void HHGate2D::setYdivs(const Eref& e, unsigned int value) { A_.setYdivs(value); -} - -double HHGate2D::getXminB(const Eref& e) const -{ - return B_.getXmin(); -} - -void HHGate2D::setXminB(const Eref& e, double value) -{ - B_.setXmin(value); -} - -double HHGate2D::getXmaxB(const Eref& e) const -{ - return B_.getXmax(); -} - -void HHGate2D::setXmaxB(const Eref& e, double value) -{ - B_.setXmax(value); -} - -unsigned int HHGate2D::getXdivsB(const Eref& e) const -{ - return B_.getXdivs(); -} - -void HHGate2D::setXdivsB(const Eref& e, unsigned int value) -{ - B_.setXdivs(value); -} - -double HHGate2D::getYminB(const Eref& e) const -{ - return B_.getYmin(); -} - -void HHGate2D::setYminB(const Eref& e, double value) -{ - B_.setYmin(value); -} - -double HHGate2D::getYmaxB(const Eref& e) const -{ - return B_.getYmax(); -} - -void HHGate2D::setYmaxB(const Eref& e, double value) -{ - B_.setYmax(value); -} - -unsigned int HHGate2D::getYdivsB(const Eref& e) const -{ - return B_.getYdivs(); -} - -void HHGate2D::setYdivsB(const Eref& e, unsigned int value) -{ B_.setYdivs(value); } + /////////////////////////////////////////////////// // Dest function definitions /////////////////////////////////////////////////// diff --git a/biophysics/HHGate2D.h b/biophysics/HHGate2D.h index b1e115655e..fe920c9c04 100644 --- a/biophysics/HHGate2D.h +++ b/biophysics/HHGate2D.h @@ -1,5 +1,3 @@ -#ifndef _HHGate2D_h -#define _HHGate2D_h /********************************************************************** ** This program is part of 'MOOSE', the ** Messaging Object Oriented Simulation Environment, @@ -9,6 +7,9 @@ ** GNU Lesser General Public License version 2.1 ** See the file COPYING.LIB for the full notice. **********************************************************************/ +#ifndef _HHGate2D_h +#define _HHGate2D_h + class HHGate2D { public: @@ -66,30 +67,18 @@ class HHGate2D /// // Setting table parameters /// - double getXminA(const Eref& e) const; - void setXminA(const Eref& e, double value); - double getXmaxA(const Eref& e) const; - void setXmaxA(const Eref& e, double value); - unsigned int getXdivsA(const Eref& e) const; - void setXdivsA(const Eref& e, unsigned int value); - double getYminA(const Eref& e) const; - void setYminA(const Eref& e, double value); - double getYmaxA(const Eref& e) const; - void setYmaxA(const Eref& e, double value); - unsigned int getYdivsA(const Eref& e) const; - void setYdivsA(const Eref& e, unsigned int value); - double getXminB(const Eref& e) const; - void setXminB(const Eref& e, double value); - double getXmaxB(const Eref& e) const; - void setXmaxB(const Eref& e, double value); - unsigned int getXdivsB(const Eref& e) const; - void setXdivsB(const Eref& e, unsigned int value); - double getYminB(const Eref& e) const; - void setYminB(const Eref& e, double value); - double getYmaxB(const Eref& e) const; - void setYmaxB(const Eref& e, double value); - unsigned int getYdivsB(const Eref& e) const; - void setYdivsB(const Eref& e, unsigned int value); + double getXmin(const Eref& e) const; + void setXmin(const Eref& e, double value); + double getXmax(const Eref& e) const; + void setXmax(const Eref& e, double value); + unsigned int getXdivs(const Eref& e) const; + void setXdivs(const Eref& e, unsigned int value); + double getYmin(const Eref& e) const; + void setYmin(const Eref& e, double value); + double getYmax(const Eref& e) const; + void setYmax(const Eref& e, double value); + unsigned int getYdivs(const Eref& e) const; + void setYdivs(const Eref& e, unsigned int value); static const Cinfo* initCinfo(); private: diff --git a/biophysics/MarkovOdeSolver.cpp b/biophysics/MarkovOdeSolver.cpp index 9e951e7475..f678ff577e 100644 --- a/biophysics/MarkovOdeSolver.cpp +++ b/biophysics/MarkovOdeSolver.cpp @@ -8,7 +8,7 @@ **********************************************************************/ #include "../basecode/header.h" -#if USE_BOOSE_ODE +#if USE_BOOST_ODE #include "../utility/boost_ode.h" #endif #include "MarkovOdeSolver.h" diff --git a/biophysics/meson.build b/biophysics/meson.build new file mode 100644 index 0000000000..268cf2097e --- /dev/null +++ b/biophysics/meson.build @@ -0,0 +1,48 @@ +# Author: Subhasis Ray +# Date: Sun Jul 7 + +biophysics_src = ['IntFire.cpp', + 'SpikeGen.cpp', + 'RandSpike.cpp', + 'CompartmentDataHolder.cpp', + 'CompartmentBase.cpp', + 'Compartment.cpp', + 'SymCompartment.cpp', + 'GapJunction.cpp', + 'ChanBase.cpp', + 'ChanCommon.cpp', + 'HHChannel.cpp', + 'HHChannelBase.cpp', + 'HHChannel2D.cpp', + 'HHGate.cpp', + 'HHGate2D.cpp', + 'HHChannel2D.cpp', + 'CaConcBase.cpp', + 'CaConc.cpp', + 'MgBlock.cpp', + 'Nernst.cpp', + 'Neuron.cpp', + 'ReadCell.cpp', + 'SwcSegment.cpp', + 'ReadSwc.cpp', + 'SynChan.cpp', + 'NMDAChan.cpp', + 'IzhikevichNrn.cpp', + 'DifShellBase.cpp', + 'DifShell.cpp', + 'DifBufferBase.cpp', + 'DifBuffer.cpp', + 'MMPump.cpp', + 'Leakage.cpp', + 'VectorTable.cpp', + 'MarkovRateTable.cpp', + 'MarkovChannel.cpp', + 'MatrixOps.cpp', + 'MarkovSolverBase.cpp', + 'MarkovSolver.cpp', + 'VClamp.cpp', + 'Spine.cpp', + 'MarkovOdeSolver.cpp', + 'testBiophysics.cpp'] + +biophysics_lib = static_library('biophysics', biophysics_src, dependencies: gsl_dep, include_directories: gsl_dep.get_variable(pkgconfig:'includedir')) diff --git a/biophysics/testBiophysics.cpp b/biophysics/testBiophysics.cpp index e00575e7c5..6db9ff8270 100644 --- a/biophysics/testBiophysics.cpp +++ b/biophysics/testBiophysics.cpp @@ -15,6 +15,7 @@ #include "CompartmentBase.h" #include "Compartment.h" +extern bool doubleEq(double, double); // defined in doubleEq.cpp extern void testCompartment(); // Defined in Compartment.cpp extern void testCompartmentProcess(); // Defined in Compartment.cpp extern void testMarkovRateTable(); // Defined in MarkovRateTable.cpp diff --git a/builtins/CMakeLists.txt b/builtins/CMakeLists.txt deleted file mode 100644 index 4794df7d4d..0000000000 --- a/builtins/CMakeLists.txt +++ /dev/null @@ -1,88 +0,0 @@ -cmake_minimum_required(VERSION 3.20) -include( ${CMAKE_CURRENT_SOURCE_DIR}/../CheckCXXCompiler.cmake ) - -# NSDF5 support. Disabled by default. -if(WITH_NSDF) - find_package(HDF5 COMPONENTS CXX HL) - if(NOT HDF5_FOUND) - message( - "==================================================================\n" - " HDF5 not found. Disabling NSDF support.\n\n" - " If you need NSDF support, please install hdf5-dev or hdf5-devel\n" - " package or equivalent.\n\n" - " $ sudo apt-get install libhdf5-dev \n" - " $ sudo yum install libhdf5-devel \n" - " $ brew install hdf5 \n\n" - " Otherwise, continue with 'make' and 'make install' \n" - " If you install hdf5 to non-standard path, export environment \n" - " variable HDF5_ROOT to the location. Rerun cmake \n" - "================================================================ \n" - ) - endif(NOT HDF5_FOUND) - - if(HDF5_FOUND) - include_directories(${HDF5_CXX_INCLUDE_DIRS} ) - add_definitions(-DUSE_HDF5 -DENABLE_NSDF ) - add_definitions(${HDF5_CXX_DEFINITIONS}) - if(HDF5_USE_STATIC_LIBRARIES) - message(STATUS "Finding static HDF5 libraries in $ENV{HDF5_ROOT}") - find_library(HDF5_CXX_LIBRARIES NAMES libhdf5.a - PATHS $ENV{HDF5_ROOT}/lib $ENV{HDF5_ROOT}/lib64 - ) - find_library(HDF5_HL_LIBRARIES NAMES libhdf5_hl.a - PATHS $ENV{HDF5_ROOT}/lib $ENV{HDF5_ROOT}/lib64 - ) - set(HDF5_LIBRARIES ${HDF5_CXX_LIBRARIES} ${HDF5_HL_LIBRARIES}) - endif() - - # Make sure, HDF5_HL_LIBRARIES are set. The COMPONENTS in find_package may - # or may not work. See BhallaLab/moose-core#163. - if(NOT HDF5_HL_LIBRARIES) - set(HDF5_HL_LIBRARIES ${HDF5_HL_LIBRARIES}) - endif(NOT HDF5_HL_LIBRARIES) - list(APPEND HDF5_LIBRARIES ${HDF5_HL_LIBRARIES}) - - else(HDF5_FOUND) - message(STATUS "HDF5 is not found. Disabling NSDF support." ) - add_definitions(-UUSE_HDF5 -UENABLE_NSDF) - endif( HDF5_FOUND ) -endif(WITH_NSDF) - -set(SRCS - Arith.cpp - Group.cpp - Mstring.cpp - Function.cpp - Variable.cpp - InputVariable.cpp - TableBase.cpp - Table.cpp - Interpol.cpp - StimulusTable.cpp - TimeTable.cpp - StreamerBase.cpp - Streamer.cpp - Stats.cpp - Interpol2D.cpp - SpikeStats.cpp - MooseParser.cpp - SocketStreamer.cpp - testBuiltins.cpp - ) - -if(WITH_NSDF AND HDF5_FOUND) - list(APPEND SRCS - HDF5WriterBase.cpp - NSDFWriter.cpp - NSDFWriter2.cpp - HDF5DataWriter.cpp - SpikeStats.cpp - testBuiltins.cpp - testNSDF.cpp - ) -endif() - -add_library(moose_builtins ${SRCS} ) -if(WITH_NSDF AND HDF5_FOUND) - target_link_libraries(moose_builtins ${HDF5_CXX_LIBRARIES} ${HDF5_HL_LIBRARIES}) -endif() diff --git a/builtins/SocketStreamer.cpp b/builtins/SocketStreamer.cpp index 502f3ca182..c42bfa1c6e 100644 --- a/builtins/SocketStreamer.cpp +++ b/builtins/SocketStreamer.cpp @@ -1,19 +1,27 @@ /*** - * Filename: SocketStreamer.cpp + * Filename: SocketStreamer.cpp * - * Description: TCP and Unix Domain Socket to stream data. + * Description: TCP and Unix Domain Socket to stream data. * - * Author: Dilawar Singh - * Organization: NCBS Bangalore + * Author: Dilawar Singh + * Updated: 2024-07-17 by subha + * Organization: NCBS Bangalore * - * License: See MOOSE licence. + * License: See MOOSE licence. */ #include #include #include #include + +#ifdef _WIN32 +#include +#define F_OK 0 +#define access _access +#else #include +#endif #include "../basecode/global.h" #include "../basecode/header.h" @@ -260,7 +268,7 @@ void SocketStreamer::initUDSServer( void ) ); } - if(! moose::filepath_exists(sockInfo_.filepath)) + if(access(sockInfo_.filepath.c_str(), F_OK) != 0) { LOG( moose::warning, "No file " << sockInfo_.filepath << " exists." ); isValid_ = false; diff --git a/builtins/StreamerBase.cpp b/builtins/StreamerBase.cpp index e944ce8322..57489365ff 100644 --- a/builtins/StreamerBase.cpp +++ b/builtins/StreamerBase.cpp @@ -26,6 +26,8 @@ #include #include +extern void cnpy2::appendNumpy(const string& outfile, const vector& vec, const vector& colnames); +extern void cnpy2::writeNumpy(const string& outfile, const vector& vec, const vector& colnames); // Class function definitions StreamerBase::StreamerBase() { @@ -70,7 +72,7 @@ void StreamerBase::writeToOutFile( const string& filepath OpenMode m = (openmode == WRITE)?WRITE_BIN:APPEND_BIN; writeToNPYFile( filepath, m, data, columns ); } - else if( "csv" == outputFormat or "dat" == outputFormat ) + else if( "csv" == outputFormat || "dat" == outputFormat ) { OpenMode m = (openmode == WRITE)?WRITE_STR:APPEND_STR; writeToCSVFile( filepath, m, data, columns ); diff --git a/builtins/meson.build b/builtins/meson.build new file mode 100644 index 0000000000..f60c701233 --- /dev/null +++ b/builtins/meson.build @@ -0,0 +1,30 @@ +# Author: Subhasis Ray +# Date: Sun Jul 7 + +builtins_src = ['Arith.cpp', + 'Group.cpp', + 'Mstring.cpp', + 'Function.cpp', + 'Variable.cpp', + 'InputVariable.cpp', + 'TableBase.cpp', + 'Table.cpp', + 'Interpol.cpp', + 'StimulusTable.cpp', + 'TimeTable.cpp', + 'StreamerBase.cpp', + 'Streamer.cpp', + 'Stats.cpp', + 'Interpol2D.cpp', + 'SpikeStats.cpp', + 'MooseParser.cpp', + # '../utility/cnpy.cpp', + # '../external/fmt/src/format.cc', + # '../external/fmt/src/os.cc', + 'testBuiltins.cpp'] + +if host_machine.system() != 'windows' + builtins_src += files(['SocketStreamer.cpp']) +endif + +builtins_lib = static_library('builtins', builtins_src, include_directories: ['../external/fmt/include']) diff --git a/cmake/FindGSL.cmake b/cmake/FindGSL.cmake deleted file mode 100644 index e07c063b19..0000000000 --- a/cmake/FindGSL.cmake +++ /dev/null @@ -1,116 +0,0 @@ -# Try to find gnu scientific library GSL -# (see http://www.gnu.org/software/gsl/) -# Once run this will define: -# -# GSL_FOUND = system has GSL lib -# -# GSL_VERSION = gsl version -# -# GSL_LIBRARIES = name of the libraries. -# -# GSL_INCLUDE_DIRS = where to find headers -# -# GSL_USE_STATIC_LIBRARIES = Set it ON if you want to search for static -# libraries. -# -# Felix Woelk 07/2004 -# minor corrections Jan Woetzel -# -# www.mip.informatik.uni-kiel.de -# -------------------------------- -# -# Friday 18 November 2016 09:05:56 AM IST -# MODIFICATIONS: ## dilawars@ncbs.res.in, For the MOOSE project. -# This version does not use gsl-config file. -# - -# Set this envrionment variable to search in this path first. -SET(GSL_ROOT_DIR $ENV{GSL_ROOT_DIR}) -if(GSL_ROOT_DIR) - message( STATUS "Debug: GSL_ROOT_DIR = ${GSL_ROOT_DIR}") -endif(GSL_ROOT_DIR) - -IF(WIN32) - - SET(GSL_MINGW_PREFIX "c:/msys/local" ) - SET(GSL_MSVC_PREFIX "$ENV{LIB_DIR}") - FIND_LIBRARY(GSL_LIB gsl PATHS - ${GSL_MINGW_PREFIX}/lib - ${GSL_MSVC_PREFIX}/lib - ) - #MSVC version of the lib is just called 'cblas' - FIND_LIBRARY(GSLCBLAS_LIB gslcblas cblas PATHS - ${GSL_MINGW_PREFIX}/lib - ${GSL_MSVC_PREFIX}/lib - ) - - FIND_PATH(GSL_INCLUDE_DIRS gsl/gsl_blas.h - ${GSL_MINGW_PREFIX}/include - ${GSL_MSVC_PREFIX}/include - ) - - IF (GSL_LIB AND GSLCBLAS_LIB) - SET (GSL_LIBRARIES ${GSL_LIB} ${GSLCBLAS_LIB}) - ENDIF (GSL_LIB AND GSLCBLAS_LIB) - -ELSE(WIN32) - # UNIX - if((GSL_USE_STATIC_LIBRARIES) OR ($ENV{GSL_USE_STATIC_LIBRARIES})) - SET(GSL_LIB_NAMES libgsl.a) - SET(GSL_CBLAS_LIB_NAMES libgslcblas.a) - else() - SET(GSL_LIB_NAMES gsl) - SET(GSL_CBLAS_LIB_NAMES gslcblas) - endif( ) - - if(GSL_ROOT_DIR) - FIND_LIBRARY(GSL_LIB - NAMES ${GSL_LIB_NAMES} - PATHS ${GSL_ROOT_DIR}/lib NO_DEFAULT_PATH - ) - - FIND_LIBRARY(GSLCBLAS_LIB - NAMES ${GSL_CBLAS_LIB_NAMES} - PATHS ${GSL_ROOT_DIR}/lib NO_DEFAULT_PATH - ) - IF (GSL_LIB AND GSLCBLAS_LIB) - SET (GSL_LIBRARIES ${GSL_LIB} ${GSLCBLAS_LIB}) - ENDIF (GSL_LIB AND GSLCBLAS_LIB) - - FIND_PATH(GSL_INCLUDE_DIRS NAMES gsl/gsl_blas.h - PATHS ${GSL_ROOT_DIR}/include NO_DEFAULT_PATH - ) - else(GSL_ROOT_DIR) - FIND_LIBRARY(GSL_LIB NAMES ${GSL_LIB_NAMES} ) - FIND_LIBRARY(GSLCBLAS_LIB NAMES ${GSL_CBLAS_LIB_NAMES}) - - IF (GSL_LIB AND GSLCBLAS_LIB) - SET (GSL_LIBRARIES ${GSL_LIB} ${GSLCBLAS_LIB}) - ENDIF (GSL_LIB AND GSLCBLAS_LIB) - - FIND_PATH(GSL_INCLUDE_DIRS NAMES gsl/gsl_blas.h - PATHS ${GSL_ROOT_DIR}/include /opt/include - ) - endif( ) - -ENDIF(WIN32) - -# FIND version -# message(STATUS "Searching in ${GSL_INCLUDE_DIRS}") -if(GSL_INCLUDE_DIRS) - file(READ "${GSL_INCLUDE_DIRS}/gsl/gsl_version.h" GSL_VERSION_TEXT) - string(REGEX REPLACE ".*define[ ]+GSL_MAJOR_VERSION[ ]*([0-9]+).*" "\\1" - GSL_MAJOR_VERSION "${GSL_VERSION_TEXT}") - string(REGEX REPLACE ".*define[ ]+GSL_MINOR_VERSION[ ]*([0-9]+).*" "\\1" - GSL_MINOR_VERSION "${GSL_VERSION_TEXT}") - set(GSL_VERSION "${GSL_MAJOR_VERSION}.${GSL_MINOR_VERSION}") - message(STATUS "GSL version : ${GSL_VERSION}") -endif(GSL_INCLUDE_DIRS) - -IF(GSL_LIBRARIES AND GSL_VERSION) - IF(GSL_INCLUDE_DIRS) - MESSAGE(STATUS "Found GSL ${GSL_LIBRARIES}") - SET(GSL_FOUND 1) - ENDIF(GSL_INCLUDE_DIRS) -ENDIF() - diff --git a/devel/CMakeLists.txt b/devel/CMakeLists.txt deleted file mode 100644 index 73b8f0cd82..0000000000 --- a/devel/CMakeLists.txt +++ /dev/null @@ -1,20 +0,0 @@ -# Replicate Travis-CI building using docker -add_custom_target(travis - COMMAND docker build -t bhallalab/travis:latest - -f ${CMAKE_CURRENT_SOURCE_DIR}/docker/travis/Dockerfile . - COMMENT "Replicating Travis-CI building using Docker." - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - VERBATIM) - -add_custom_target(centos - COMMAND docker build -t bhallalab/centos:latest - -f ${CMAKE_CURRENT_SOURCE_DIR}/docker/centos/Dockerfile . - COMMENT "Building moose on centos" - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - VERBATIM) - -add_custom_target(gitlab - COMMAND gitlab-runner exec docker build - COMMENT "Replicating gitlab build using Docker." - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - VERBATIM) diff --git a/device/CMakeLists.txt b/device/CMakeLists.txt deleted file mode 100644 index 2797c6752e..0000000000 --- a/device/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -cmake_minimum_required(VERSION 3.20) -include( ${CMAKE_CURRENT_SOURCE_DIR}/../CheckCXXCompiler.cmake) -add_library(device - PulseGen.cpp - DiffAmp.cpp - PIDController.cpp - RC.cpp - ) diff --git a/device/meson.build b/device/meson.build new file mode 100644 index 0000000000..7c5e3b6d83 --- /dev/null +++ b/device/meson.build @@ -0,0 +1,9 @@ +# Author: Subhasis Ray +# Date: Sun Jul 7 + +device_src = ['PulseGen.cpp', + 'DiffAmp.cpp', + 'PIDController.cpp', + 'RC.cpp'] + +device_lib = static_library('device', device_src) diff --git a/diffusion/CMakeLists.txt b/diffusion/CMakeLists.txt deleted file mode 100644 index e65eb97a18..0000000000 --- a/diffusion/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -cmake_minimum_required(VERSION 3.20) -include( ${CMAKE_CURRENT_SOURCE_DIR}/../CheckCXXCompiler.cmake) - -if(WITH_GSL) - include_directories(${GSL_INCLUDE_DIRS}) -endif(WITH_GSL) - -add_library(diffusion - FastMatrixElim.cpp - DiffPoolVec.cpp - Dsolve.cpp - testDiffusion.cpp - ) diff --git a/diffusion/meson.build b/diffusion/meson.build new file mode 100644 index 0000000000..c14376d383 --- /dev/null +++ b/diffusion/meson.build @@ -0,0 +1,9 @@ +# Author: Subhasis Ray +# Date: Sun Jul 7 + +diffusion_src = ['FastMatrixElim.cpp', + 'DiffPoolVec.cpp', + 'Dsolve.cpp', + 'testDiffusion.cpp'] + +diffusion_lib = static_library('diffusion', diffusion_src, include_directories: gsl_dep.get_pkgconfig_variable('includedir')) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt deleted file mode 100644 index 00ede5e17c..0000000000 --- a/examples/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -cmake_minimum_required(VERSION 3.20) -include( ${CMAKE_CURRENT_SOURCE_DIR}/../CheckCXXCompiler.cmake) -ADD_LIBRARY(examples - Example.cpp - Ex.cpp - ) - diff --git a/examples/Ex.cpp b/examples/Ex.cpp index 2554e468b0..a5589852f7 100644 --- a/examples/Ex.cpp +++ b/examples/Ex.cpp @@ -182,3 +182,13 @@ void Ex::setVal(unsigned int index, double val) values_[index] = val; } + +void Ex::handleX(double x) +{ + x_ = x; +} + +void Ex::handleN(int n) +{ + n_ = n; +} diff --git a/examples/meson.build b/examples/meson.build new file mode 100644 index 0000000000..720223f70d --- /dev/null +++ b/examples/meson.build @@ -0,0 +1,7 @@ +# Author: Subhasis Ray +# Date: Sun Jul 7 + +examples_src = ['Example.cpp', + 'Ex.cpp'] + +examples_lib = static_library('examples', examples_src) diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt deleted file mode 100644 index 9854288e33..0000000000 --- a/external/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -add_subdirectory(libsoda) -add_subdirectory(fmt) diff --git a/external/exprtk/exprtk.hpp b/external/exprtk/exprtk.hpp index 4ab9b9169f..9e0cf6fcf6 100644 --- a/external/exprtk/exprtk.hpp +++ b/external/exprtk/exprtk.hpp @@ -2,7 +2,7 @@ ****************************************************************** * C++ Mathematical Expression Toolkit Library * * * - * Author: Arash Partow (1999-2023) * + * Author: Arash Partow (1999-2024) * * URL: https://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * @@ -10,6 +10,7 @@ * permitted under the guidelines and in accordance with the most * * current version of the MIT License. * * 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)] * * * @@ -42,7 +43,6 @@ #include #include #include -#include #include #include #include @@ -67,20 +67,6 @@ 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") \ - - #else - #define exprtk_disable_fallthrough_begin (void)0; - #define exprtk_disable_fallthrough_end (void)0; - #endif - #if __cplusplus >= 201103L #define exprtk_override override #define exprtk_final final @@ -91,6 +77,18 @@ namespace exprtk #define exprtk_delete #endif + #if __cplusplus >= 201603L + #define exprtk_fallthrough [[fallthrough]]; + #elif __cplusplus >= 201103L + #define exprtk_fallthrough [[gnu::fallthrough]]; + #else + #ifndef _MSC_VER + #define exprtk_fallthrough __attribute__ ((fallthrough)); + #else + #define exprtk_fallthrough + #endif + #endif + namespace details { typedef char char_t; @@ -218,15 +216,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(std::tolower(s1[i])); const char_t c2 = static_cast(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(); @@ -364,9 +362,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; } @@ -381,6 +379,7 @@ namespace exprtk (*itr2++) = (*itr1++); ++removal_count; } + continue; } else @@ -432,85 +431,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); @@ -646,7 +645,7 @@ namespace exprtk } } else if (data_end == d_itr) - return true; + break; if ((data_end == d_itr) || (null_itr == nd_itr)) return false; @@ -661,23 +660,27 @@ namespace exprtk inline bool wc_match(const std::string& wild_card, const std::string& str) { - return match_impl( + return match_impl + ( 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( + return match_impl + ( wild_card.data(), wild_card.data() + wild_card.size(), str.data(), str.data() + str.size(), - '*', '?'); + '*', '?' + ); } inline bool sequence_match(const std::string& pattern, @@ -750,13 +753,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 + 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 \ + { \ + 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 + inline void set_zero_value(T* data, const std::size_t size) + { + set_zero_value_impl::process(data,size); + } + + template + inline void set_zero_value(std::vector& 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); @@ -789,17 +834,17 @@ namespace exprtk number_type() {} }; - #define exprtk_register_real_type_tag(T) \ - template <> struct number_type \ - { typedef real_type_tag type; number_type() {} }; \ + #define exprtk_register_real_type_tag(T) \ + template <> struct number_type \ + { typedef real_type_tag type; number_type() {} }; \ - #define exprtk_register_int_type_tag(T) \ - template <> struct number_type \ - { typedef int_type_tag type; number_type() {} }; \ + #define exprtk_register_int_type_tag(T) \ + template <> struct number_type \ + { 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_int_type_tag(short ) exprtk_register_int_type_tag(int ) @@ -848,6 +893,12 @@ namespace exprtk return static_cast<_int64_t>(v); } + template + inline _uint64_t to_uint64_impl(const T v, real_type_tag) + { + return static_cast<_uint64_t>(v); + } + template inline bool is_true_impl(const T v) { @@ -982,8 +1033,8 @@ namespace exprtk else return (T(-0.5) * v + T(1)) * v; } - else - return std::numeric_limits::quiet_NaN(); + + return std::numeric_limits::quiet_NaN(); } template @@ -993,8 +1044,8 @@ namespace exprtk { return std::log(T(1) + v); } - else - return std::numeric_limits::quiet_NaN(); + + return std::numeric_limits::quiet_NaN(); } template @@ -1193,9 +1244,9 @@ namespace exprtk #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 @@ -1204,13 +1255,14 @@ namespace exprtk { #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())); @@ -1262,10 +1314,7 @@ namespace exprtk template inline T ncdf_impl(const T v, real_type_tag) { - const 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 @@ -1289,12 +1338,47 @@ namespace exprtk return sinc_impl(static_cast(v),real_type_tag()); } + #if __cplusplus >= 201103L + template + inline T acosh_impl(const T v, real_type_tag) + { + return std::acosh(v); + } + + template + inline T asinh_impl(const T v, real_type_tag) + { + return std::asinh(v); + } + + template + inline T atanh_impl(const T v, real_type_tag) + { + return std::atanh(v); + } + #else + template + inline T acosh_impl(const T v, real_type_tag) + { + return std::log(v + std::sqrt((v * v) - T(1))); + } + + template + inline T asinh_impl(const T v, real_type_tag) + { + return std::log(v + std::sqrt((v * v) + T(1))); + } + + template + 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 inline T acos_impl(const T v, real_type_tag) { return std::acos (v); } - template inline T acosh_impl(const T v, real_type_tag) { return std::log(v + std::sqrt((v * v) - T(1))); } template inline T asin_impl(const T v, real_type_tag) { return std::asin (v); } - template inline T asinh_impl(const T v, real_type_tag) { return std::log(v + std::sqrt((v * v) + T(1))); } template inline T atan_impl(const T v, real_type_tag) { return std::atan (v); } - template inline T atanh_impl(const T v, real_type_tag) { return (std::log(T(1) + v) - std::log(T(1) - v)) / T(2); } template inline T ceil_impl(const T v, real_type_tag) { return std::ceil (v); } template inline T cos_impl(const T v, real_type_tag) { return std::cos (v); } template inline T cosh_impl(const T v, real_type_tag) { return std::cosh (v); } @@ -1390,6 +1474,13 @@ namespace exprtk return to_int64_impl(v, num_type); } + template + inline _uint64_t to_uint64(const T v) + { + const typename details::number_type::type num_type; + return to_uint64_impl(v, num_type); + } + template inline bool is_nan(const T v) { @@ -1629,38 +1720,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(sizeof(fract10) / sizeof(double)); @@ -1710,7 +1801,6 @@ namespace exprtk if (length <= 4) { - exprtk_disable_fallthrough_begin switch (length) { #ifdef exprtk_use_lut @@ -1723,17 +1813,19 @@ 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 @@ -1748,7 +1840,6 @@ namespace exprtk #undef exprtk_process_digit } - exprtk_disable_fallthrough_end } else return_result = false; @@ -2067,14 +2158,74 @@ namespace exprtk 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() {} + virtual ~loop_runtime_check() + {} }; 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() + {} + + 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() + {} + + 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() + {} + }; + + typedef compilation_check* compilation_check_ptr; + namespace lexer { struct token @@ -2282,7 +2433,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_)) @@ -2345,7 +2496,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_; } @@ -2353,7 +2506,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_; } @@ -2497,7 +2652,7 @@ namespace exprtk } } - ++s_itr_; + ++s_itr_; } if (2 == mode) @@ -2509,9 +2664,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; @@ -2521,34 +2684,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_); @@ -2658,7 +2826,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); } @@ -2858,12 +3026,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); @@ -2903,8 +3071,8 @@ namespace exprtk } t.set_string( - parsed_string, - static_cast(std::distance(base_itr_,initial_itr))); + parsed_string, + static_cast(std::distance(base_itr_,initial_itr))); } token_list_.push_back(t); @@ -2945,7 +3113,8 @@ namespace exprtk { public: - virtual ~token_scanner() {} + virtual ~token_scanner() + {} explicit token_scanner(const std::size_t& stride) : stride_(stride) @@ -3211,7 +3380,7 @@ namespace exprtk generator::token_list_t token_list; token_list.reserve(10000); - for (int i = 0; i < static_cast(g.token_list_.size() - 1); ++i) + for (int i = 0; i < static_cast(g.token_list_.size() - 1); ++i) { token t; @@ -3227,7 +3396,7 @@ namespace exprtk ++changes; - i+=2; + i += 2; if (static_cast(i) >= (g.token_list_.size() - 1)) break; @@ -3253,7 +3422,7 @@ namespace exprtk generator::token_list_t token_list; token_list.reserve(10000); - for (int i = 0; i < static_cast(g.token_list_.size() - 2); ++i) + for (int i = 0; i < static_cast(g.token_list_.size() - 2); ++i) { token t; @@ -3269,7 +3438,7 @@ namespace exprtk ++changes; - i+=3; + i += 3; if (static_cast(i) >= (g.token_list_.size() - 2)) break; @@ -3367,7 +3536,7 @@ namespace exprtk std::set ignore_set_; }; - class operator_joiner : public token_joiner + class operator_joiner exprtk_final : public token_joiner { public: @@ -3543,7 +3712,7 @@ namespace exprtk } }; - class bracket_checker : public lexer::token_scanner + class bracket_checker exprtk_final : public lexer::token_scanner { public: @@ -3554,7 +3723,7 @@ namespace exprtk , state_(true) {} - bool result() + bool result() exprtk_override { if (!stack_.empty()) { @@ -3575,7 +3744,7 @@ namespace exprtk return error_token_; } - void reset() + void reset() exprtk_override { // Why? because msvc doesn't support swap properly. stack_ = std::stack >(); @@ -3583,7 +3752,7 @@ namespace exprtk error_token_.clear(); } - bool operator() (const lexer::token& t) + bool operator() (const lexer::token& t) exprtk_override { if ( !t.value.empty() && @@ -3640,18 +3809,18 @@ namespace exprtk , current_index_(0) {} - bool result() + bool result() exprtk_override { return error_list_.empty(); } - void reset() + void reset() exprtk_override { error_list_.clear(); current_index_ = 0; } - bool operator() (const lexer::token& t) + bool operator() (const lexer::token& t) exprtk_override { if (token::e_number == t.type) { @@ -3692,7 +3861,7 @@ namespace exprtk std::vector error_list_; }; - class symbol_replacer : public lexer::token_modifier + class symbol_replacer exprtk_final : public lexer::token_modifier { private: @@ -3735,7 +3904,7 @@ namespace exprtk private: - bool modify(lexer::token& t) + bool modify(lexer::token& t) exprtk_override { if (lexer::token::e_symbol == t.type) { @@ -3798,12 +3967,12 @@ namespace exprtk add_invalid_set1(lexer::token::e_ternary); } - bool result() + bool result() exprtk_override { return error_list_.empty(); } - bool operator() (const lexer::token& t0, const lexer::token& t1) + 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); @@ -3965,12 +4134,12 @@ namespace exprtk add_invalid(lexer::token::e_pow , lexer::token::e_mod , lexer::token::e_pow ); } - bool result() + bool result() exprtk_override { return error_list_.empty(); } - bool operator() (const lexer::token& t0, const lexer::token& t1, const lexer::token& t2) + 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)); @@ -4227,6 +4396,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, @@ -4270,6 +4444,92 @@ 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_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); @@ -4296,16 +4556,22 @@ namespace exprtk typedef T* data_ptr_t; vector_view(data_ptr_t data, const std::size_t& size) - : size_(size) + : base_size_(size) + , size_(size) , data_(data) , data_ref_(0) - {} + { + assert(size_ > 0); + } vector_view(const vector_view& vv) - : size_(vv.size_) + : base_size_(vv.base_size_) + , size_(vv.size_) , data_(vv.data_) , data_ref_(0) - {} + { + assert(size_ > 0); + } inline void rebase(data_ptr_t data) { @@ -4325,6 +4591,11 @@ namespace exprtk return data_; } + inline std::size_t base_size() const + { + return base_size_; + } + inline std::size_t size() const { return size_; @@ -4332,22 +4603,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(data_ref), + static_cast(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(data_ref), + static_cast(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(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_ref_; }; @@ -4523,6 +4827,16 @@ namespace exprtk return v_; } + inline operator value_t() const + { + return v_; + } + + inline operator value_t() + { + return v_; + } + template inline bool to_int(IntType& i) const { @@ -4571,6 +4885,9 @@ namespace exprtk public: typedef type_store 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) @@ -4594,6 +4911,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 + 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& 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() @@ -4740,10 +5112,11 @@ 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 @@ -4770,11 +5143,28 @@ namespace exprtk ptr, static_cast(size))); else - exprtk_debug(("%s - addr: %p\n",s.c_str(),ptr)); + exprtk_debug(("%s - addr: %p\n", s.c_str(), ptr)); + } + + template + 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(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 + inline void dump_vector(const std::string&, const T*, const std::size_t) {} #endif template @@ -4897,7 +5287,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; @@ -4947,7 +5337,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 @@ -5060,8 +5450,8 @@ namespace exprtk case e_xnor : return xnor_opr(arg0,arg1); case e_root : return root (arg0,arg1); case e_roundn : return roundn (arg0,arg1); - case e_equal : return equal (arg0,arg1); - case e_nequal : return nequal (arg0,arg1); + case e_equal : return equal (arg0,arg1); + case e_nequal : return nequal (arg0,arg1); case e_hypot : return hypot (arg0,arg1); case e_shr : return shr (arg0,arg1); case e_shl : return shl (arg0,arg1); @@ -5130,17 +5520,19 @@ namespace exprtk typedef Node** node_pp_t; typedef std::vector noderef_list_t; - virtual ~node_collector_interface() {} + virtual ~node_collector_interface() + {} - virtual void collect_nodes(noderef_list_t&) {} + virtual void collect_nodes(noderef_list_t&) + {} }; template struct node_depth_base; template - class expression_node : public node_collector_interface >, - public node_depth_base > + class expression_node : public node_collector_interface > + , public node_depth_base > { public: @@ -5177,12 +5569,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_vecondition , 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; @@ -5191,7 +5585,8 @@ namespace exprtk typedef typename nci_t::noderef_list_t noderef_list_t; typedef node_depth_base > ndb_t; - virtual ~expression_node() {} + virtual ~expression_node() + {} inline virtual T value() const { @@ -5207,6 +5602,11 @@ namespace exprtk { return e_none; } + + inline virtual bool valid() const + { + return true; + } }; // class expression_node template @@ -5251,6 +5651,12 @@ namespace exprtk return std::equal_to()(T(0),node.first->value()); } + template + inline bool is_literal_node(const expression_node* node) + { + return node && (details::expression_node::e_constant == node->type()); + } + template inline bool is_unary_node(const expression_node* node) { @@ -5280,10 +5686,15 @@ namespace exprtk { return node && ( - details::expression_node::e_variable == node->type() || - details::expression_node::e_vecelem == node->type() || - details::expression_node::e_rbvecelem == node->type() || - details::expression_node::e_rbveccelem == node->type() + details::expression_node::e_variable == node->type() || + details::expression_node::e_vecelem == node->type() || + details::expression_node::e_veccelem == node->type() || + details::expression_node::e_vecelemrtc == node->type() || + details::expression_node::e_veccelemrtc == node->type() || + details::expression_node::e_rbvecelem == node->type() || + details::expression_node::e_rbveccelem == node->type() || + details::expression_node::e_rbvecelemrtc == node->type() || + details::expression_node::e_rbveccelemrtc == node->type() ); } @@ -5293,12 +5704,42 @@ namespace exprtk return node && (details::expression_node::e_vecelem == node->type()); } + template + inline bool is_vector_celem_node(const expression_node* node) + { + return node && (details::expression_node::e_veccelem == node->type()); + } + + template + inline bool is_vector_elem_rtc_node(const expression_node* node) + { + return node && (details::expression_node::e_vecelemrtc == node->type()); + } + + template + inline bool is_vector_celem_rtc_node(const expression_node* node) + { + return node && (details::expression_node::e_veccelemrtc == node->type()); + } + template inline bool is_rebasevector_elem_node(const expression_node* node) { return node && (details::expression_node::e_rbvecelem == node->type()); } + template + inline bool is_rebasevector_elem_rtc_node(const expression_node* node) + { + return node && (details::expression_node::e_rbvecelemrtc == node->type()); + } + + template + inline bool is_rebasevector_celem_rtc_node(const expression_node* node) + { + return node && (details::expression_node::e_rbveccelemrtc == node->type()); + } + template inline bool is_rebasevector_celem_node(const expression_node* node) { @@ -5376,6 +5817,12 @@ namespace exprtk return node && (details::expression_node::e_function == node->type()); } + template + inline bool is_vararg_node(const expression_node* node) + { + return node && (details::expression_node::e_vararg == node->type()); + } + template inline bool is_return_node(const expression_node* node) { @@ -5395,6 +5842,12 @@ namespace exprtk return false; } + template + inline bool is_assert_node(const expression_node* node) + { + return node && (details::expression_node::e_assert == node->type()); + } + template inline bool branch_deletable(const expression_node* node) { @@ -5478,7 +5931,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(node))); + exprtk_debug(("ncd::delete_nodes() - deleting: %p\n", reinterpret_cast(node))); delete node; node = reinterpret_cast(0); } @@ -5583,7 +6036,8 @@ namespace exprtk , depth(0) {} - virtual ~node_depth_base() {} + virtual ~node_depth_base() + {} virtual std::size_t node_depth() const { return 1; } @@ -5615,6 +6069,7 @@ namespace exprtk if (!depth_set) { depth = 0; + for (std::size_t i = 0; i < N; ++i) { if (branch[i].first) @@ -5622,6 +6077,7 @@ namespace exprtk depth = std::max(depth,branch[i].first->node_depth()); } } + depth += 1; depth_set = true; } @@ -5629,12 +6085,34 @@ namespace exprtk return depth; } + template + 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 + 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 + 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 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; } @@ -5647,9 +6125,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; } @@ -5662,9 +6138,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; } @@ -5684,6 +6158,7 @@ namespace exprtk depth = std::max(depth, compute_node_depth(branch_list[i])); } } + depth_set = true; } @@ -5703,6 +6178,7 @@ namespace exprtk depth = std::max(depth, compute_node_depth(branch_list[i].first)); } } + depth_set = true; } @@ -5795,12 +6271,14 @@ namespace exprtk typedef Type value_type; typedef value_type* value_ptr; typedef const value_ptr const_value_ptr; + typedef vector_holder vector_holder_t; class vector_holder_base { public: - virtual ~vector_holder_base() {} + virtual ~vector_holder_base() + {} inline value_ptr operator[](const std::size_t& index) const { @@ -5812,6 +6290,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); @@ -5822,15 +6305,25 @@ 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* rebaseable_instance() + { + return reinterpret_cast*>(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: @@ -5843,17 +6336,20 @@ namespace exprtk value_ptr value_at(const std::size_t& index) const exprtk_override { - if (index < size_) - return const_cast(vec_ + index); - else - return const_value_ptr(0); + assert(index < size_); + return const_cast(vec_ + index); } - std::size_t vector_size() const + 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(const array_vector_impl&) exprtk_delete; @@ -5865,7 +6361,7 @@ namespace exprtk template class Sequence> - class sequence_vector_impl : public vector_holder_base + class sequence_vector_impl exprtk_final : public vector_holder_base { public: @@ -5879,7 +6375,8 @@ namespace exprtk 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 exprtk_override @@ -5887,6 +6384,11 @@ namespace exprtk return sequence_.size(); } + std::size_t vector_base_size() const exprtk_override + { + return vector_size(); + } + private: sequence_vector_impl(const sequence_vector_impl&) exprtk_delete; @@ -5895,7 +6397,7 @@ namespace exprtk sequence_t& sequence_; }; - class vector_view_impl : public vector_holder_base + class vector_view_impl exprtk_final : public vector_holder_base { public: @@ -5903,30 +6405,48 @@ 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) + void set_ref(value_ptr* ref) exprtk_override { vec_view_.set_ref(ref); } - virtual inline bool rebaseable() const + void remove_ref(value_ptr* ref) exprtk_override + { + vec_view_.remove_ref(ref); + } + + bool rebaseable() const exprtk_override { return true; } + vector_view* rebaseable_instance() exprtk_override + { + return &vec_view_; + } + protected: - value_ptr value_at(const std::size_t& index) const + 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 + 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(); + } + private: vector_view_impl(const vector_view_impl&) exprtk_delete; @@ -5935,6 +6455,62 @@ namespace exprtk 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()); + } + + virtual ~resizable_vector_impl() + {} + + protected: + + value_ptr value_at(const std::size_t& index) const exprtk_override + { + assert(index < vector_size()); + return const_cast(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; + } + + virtual vector_view* 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& vec_view_holder_; + }; + public: typedef typename details::vec_data_store vds_t; @@ -5956,6 +6532,10 @@ namespace exprtk : 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]; @@ -5966,6 +6546,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(); @@ -5973,7 +6558,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 @@ -5981,8 +6577,16 @@ namespace exprtk return vector_holder_base_->rebaseable(); } + vector_view* rebaseable_instance() + { + return vector_holder_base_->rebaseable_instance(); + } + private: + vector_holder(const vector_holder&) exprtk_delete; + vector_holder& operator=(const vector_holder&) exprtk_delete; + mutable vector_holder_base* vector_holder_base_; uchar_t buffer[64]; }; @@ -6060,12 +6664,11 @@ namespace exprtk : equality_(equality) { construct_branch_pair(branch_, branch); + assert(valid()); } inline T value() const exprtk_override { - assert(branch_.first); - const T v = branch_.first->value(); const bool result = details::numeric::is_nan(v); @@ -6085,6 +6688,11 @@ namespace exprtk return branch_.first; } + inline bool valid() const exprtk_override + { + return branch_.first; + } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::collect(branch_, node_delete_list); @@ -6146,7 +6754,8 @@ namespace exprtk typedef range_pack range_t; - virtual ~range_interface() {} + virtual ~range_interface() + {} virtual range_t& range_ref() = 0; @@ -6161,7 +6770,8 @@ namespace exprtk typedef range_data_type range_data_type_t; - virtual ~string_base_node() {} + virtual ~string_base_node() + {} virtual std::string str () const = 0; @@ -6172,9 +6782,9 @@ namespace exprtk template class string_literal_node exprtk_final - : public expression_node , - public string_base_node, - public range_interface + : public expression_node + , public string_base_node + , public range_interface { public: @@ -6183,8 +6793,8 @@ namespace exprtk explicit string_literal_node(const std::string& v) : value_(v) { - rp_.n0_c = std::make_pair(true,0); - rp_.n1_c = std::make_pair(true,v.size() - 1); + rp_.n0_c = std::make_pair(true, 0); + rp_.n1_c = std::make_pair(true, v.size()); rp_.cache.first = rp_.n0_c.second; rp_.cache.second = rp_.n1_c.second; } @@ -6251,13 +6861,13 @@ namespace exprtk : operation_(opr) { construct_branch_pair(branch_,branch); + assert(valid()); } inline T value() const exprtk_override { - assert(branch_.first); - const T arg = branch_.first->value(); - return numeric::process(operation_,arg); + return numeric::process + (operation_,branch_.first->value()); } inline typename expression_node::node_type type() const exprtk_override @@ -6275,6 +6885,11 @@ namespace exprtk return branch_.first; } + inline bool valid() const exprtk_override + { + return branch_.first && branch_.first->valid(); + } + inline void release() { branch_.second = false; @@ -6310,17 +6925,17 @@ namespace exprtk : operation_(opr) { init_branches<2>(branch_, branch0, branch1); + assert(valid()); } 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(operation_, arg0, arg1); + return numeric::process + ( + operation_, + branch_[0].first->value(), + branch_[1].first->value() + ); } inline typename expression_node::node_type type() const exprtk_override @@ -6335,17 +6950,20 @@ namespace exprtk inline expression_node* 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(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::noderef_list_t& node_delete_list) exprtk_override { - expression_node::ndb_t::template collect(branch_, node_delete_list); + expression_node::ndb_t::collect(branch_, node_delete_list); } std::size_t node_depth() const exprtk_final @@ -6370,16 +6988,13 @@ namespace exprtk binary_ext_node(expression_ptr branch0, expression_ptr branch1) { init_branches<2>(branch_, branch0, branch1); + assert(valid()); } 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); } @@ -6395,17 +7010,20 @@ namespace exprtk inline expression_node* 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(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::noderef_list_t& node_delete_list) exprtk_override { - expression_node::ndb_t::template collect(branch_, node_delete_list); + expression_node::ndb_t::collect(branch_, node_delete_list); } std::size_t node_depth() const exprtk_override @@ -6433,14 +7051,11 @@ namespace exprtk : operation_(opr) { init_branches<3>(branch_, branch0, branch1, branch2); + assert(valid()); } 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(); @@ -6466,9 +7081,17 @@ namespace exprtk return expression_node::e_trinary; } + 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() ; + } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { - expression_node::ndb_t::template collect(branch_, node_delete_list); + expression_node::ndb_t::collect(branch_, node_delete_list); } std::size_t node_depth() const exprtk_override exprtk_final @@ -6512,7 +7135,7 @@ namespace exprtk void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { - expression_node::ndb_t::template collect(branch_, node_delete_list); + expression_node::ndb_t::collect(branch_, node_delete_list); } std::size_t node_depth() const exprtk_override exprtk_final @@ -6520,6 +7143,15 @@ namespace exprtk return expression_node::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_; @@ -6541,14 +7173,11 @@ namespace exprtk construct_branch_pair(condition_ , condition ); construct_branch_pair(consequent_ , consequent ); construct_branch_pair(alternative_, alternative); + assert(valid()); } inline T value() const exprtk_override { - assert(condition_ .first); - assert(consequent_ .first); - assert(alternative_.first); - if (is_true(condition_)) return consequent_.first->value(); else @@ -6560,6 +7189,14 @@ namespace exprtk return expression_node::e_conditional; } + inline bool valid() const exprtk_override + { + return + condition_ .first && condition_ .first->valid() && + consequent_ .first && consequent_ .first->valid() && + alternative_.first && alternative_.first->valid() ; + } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::collect(condition_ , node_delete_list); @@ -6594,13 +7231,11 @@ namespace exprtk { construct_branch_pair(condition_ , condition ); construct_branch_pair(consequent_, consequent); + assert(valid()); } inline T value() const exprtk_override { - assert(condition_ .first); - assert(consequent_.first); - if (is_true(condition_)) return consequent_.first->value(); else @@ -6612,6 +7247,13 @@ namespace exprtk return expression_node::e_conditional; } + inline bool valid() const exprtk_override + { + return + condition_ .first && condition_ .first->valid() && + consequent_.first && consequent_.first->valid() ; + } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::collect(condition_ , node_delete_list); @@ -6653,7 +7295,7 @@ namespace exprtk typedef expression_node* expression_ptr; typedef std::pair branch_t; - break_node(expression_ptr ret = expression_ptr(0)) + explicit break_node(expression_ptr ret = expression_ptr(0)) { construct_branch_pair(return_, ret); } @@ -6666,7 +7308,7 @@ namespace exprtk throw break_exception(result); - #ifndef _MSC_VER + #if !defined(_MSC_VER) && !defined(__NVCOMPILER) return std::numeric_limits::quiet_NaN(); #endif } @@ -6699,7 +7341,7 @@ namespace exprtk inline T value() const exprtk_override { throw continue_exception(); - #ifndef _MSC_VER + #if !defined(_MSC_VER) && !defined(__NVCOMPILER) return std::numeric_limits::quiet_NaN(); #endif } @@ -6730,9 +7372,11 @@ namespace exprtk inline bool check() const { + assert(loop_runtime_check_); + if ( - (0 == loop_runtime_check_) || - ((++iteration_count_ <= max_loop_iterations_) && loop_runtime_check_->check()) + (++iteration_count_ <= max_loop_iterations_) && + loop_runtime_check_->check() ) { return true; @@ -6747,6 +7391,11 @@ namespace exprtk return false; } + bool valid() const + { + 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_; @@ -6766,13 +7415,11 @@ namespace exprtk { construct_branch_pair(condition_, condition); construct_branch_pair(loop_body_, loop_body); + assert(valid()); } inline T value() const exprtk_override { - assert(condition_.first); - assert(loop_body_.first); - T result = T(0); while (is_true(condition_)) @@ -6788,6 +7435,13 @@ namespace exprtk return expression_node::e_while; } + 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::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::collect(condition_ , node_delete_list); @@ -6820,12 +7474,12 @@ namespace exprtk 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 { - assert(parent_t::condition_.first); - assert(parent_t::loop_body_.first); T result = T(0); @@ -6838,6 +7492,14 @@ namespace exprtk return result; } + + using parent_t::valid; + + bool valid() const exprtk_override exprtk_final + { + return parent_t::valid() && + loop_runtime_checker::valid(); + } }; template @@ -6853,13 +7515,11 @@ namespace exprtk { construct_branch_pair(condition_, condition); construct_branch_pair(loop_body_, loop_body); + assert(valid()); } inline T value() const exprtk_override { - assert(condition_.first); - assert(loop_body_.first); - T result = T(0); do @@ -6876,6 +7536,13 @@ namespace exprtk return expression_node::e_repeat; } + 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::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::collect(condition_ , node_delete_list); @@ -6908,13 +7575,12 @@ namespace exprtk 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 { - assert(parent_t::condition_.first); - assert(parent_t::loop_body_.first); - T result = T(0); loop_runtime_checker::reset(1); @@ -6927,6 +7593,14 @@ namespace exprtk return result; } + + using parent_t::valid; + + inline bool valid() const exprtk_override exprtk_final + { + return parent_t::valid() && + loop_runtime_checker::valid(); + } }; template @@ -6946,13 +7620,11 @@ namespace exprtk construct_branch_pair(condition_ , condition ); construct_branch_pair(incrementor_, incrementor); construct_branch_pair(loop_body_ , loop_body ); + assert(valid()); } inline T value() const exprtk_override { - assert(condition_.first); - assert(loop_body_.first); - T result = T(0); if (initialiser_.first) @@ -6982,6 +7654,11 @@ namespace exprtk return expression_node::e_for; } + inline bool valid() const exprtk_override + { + return condition_.first && loop_body_.first; + } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::collect(initialiser_ , node_delete_list); @@ -7021,13 +7698,12 @@ namespace exprtk 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) - {} + { + assert(valid()); + } inline T value() const exprtk_override { - assert(parent_t::condition_.first); - assert(parent_t::loop_body_.first); - T result = T(0); loop_runtime_checker::reset(); @@ -7053,6 +7729,14 @@ namespace exprtk return result; } + + using parent_t::valid; + + inline bool valid() const exprtk_override exprtk_final + { + return parent_t::valid() && + loop_runtime_checker::valid(); + } }; #ifndef exprtk_disable_break_continue @@ -7067,13 +7751,12 @@ namespace exprtk 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 { - assert(parent_t::condition_.first); - assert(parent_t::loop_body_.first); - T result = T(0); while (is_true(parent_t::condition_)) @@ -7109,13 +7792,12 @@ namespace exprtk 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 { - assert(parent_t::condition_.first); - assert(parent_t::loop_body_.first); - T result = T(0); loop_runtime_checker::reset(); @@ -7136,6 +7818,14 @@ namespace exprtk return result; } + + using parent_t::valid; + + inline bool valid() const exprtk_override exprtk_final + { + return parent_t::valid() && + loop_runtime_checker::valid(); + } }; template @@ -7149,13 +7839,12 @@ namespace exprtk repeat_until_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 { - assert(parent_t::condition_.first); - assert(parent_t::loop_body_.first); - T result = T(0); do @@ -7179,8 +7868,8 @@ namespace exprtk template class repeat_until_loop_bc_rtc_node exprtk_final - : public repeat_until_loop_bc_node, - public loop_runtime_checker + : public repeat_until_loop_bc_node + , public loop_runtime_checker { public: @@ -7192,13 +7881,12 @@ namespace exprtk 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 { - assert(parent_t::condition_.first); - assert(parent_t::loop_body_.first); - T result = T(0); loop_runtime_checker::reset(); @@ -7220,6 +7908,14 @@ namespace exprtk return result; } + + using parent_t::valid; + + inline bool valid() const exprtk_override exprtk_final + { + return parent_t::valid() && + loop_runtime_checker::valid(); + } }; template @@ -7235,13 +7931,12 @@ namespace exprtk expression_ptr incrementor, expression_ptr loop_body) : parent_t(initialiser, condition, incrementor, loop_body) - {} + { + assert(parent_t::valid()); + } inline T value() const exprtk_override { - assert(parent_t::condition_.first); - assert(parent_t::loop_body_.first); - T result = T(0); if (parent_t::initialiser_.first) @@ -7303,13 +7998,12 @@ namespace exprtk 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) - {} + { + assert(valid()); + } inline T value() const exprtk_override { - assert(parent_t::condition_.first); - assert(parent_t::loop_body_.first); - T result = T(0); loop_runtime_checker::reset(); @@ -7354,6 +8048,14 @@ namespace exprtk return result; } + + using parent_t::valid; + + inline bool valid() const exprtk_override exprtk_final + { + return parent_t::valid() && + loop_runtime_checker::valid(); + } }; #endif @@ -7376,7 +8078,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]); } @@ -7386,29 +8088,26 @@ namespace exprtk return; } } + + assert(valid()); } 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::quiet_NaN(); + + return arg_list_[upper_bound].first->value(); } inline typename expression_node::node_type type() const exprtk_override exprtk_final @@ -7416,6 +8115,11 @@ namespace exprtk return expression_node::e_switch; } + inline bool valid() const exprtk_override + { + return !arg_list_.empty(); + } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::collect(arg_list_, node_delete_list); @@ -7469,7 +8173,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]); } @@ -7479,19 +8183,16 @@ namespace exprtk return; } } + + assert(valid()); } inline T value() const exprtk_override { - T result = T(0); - - if (arg_list_.empty()) - { - return std::numeric_limits::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; @@ -7511,6 +8212,11 @@ namespace exprtk return expression_node::e_mswitch; } + inline bool valid() const exprtk_override + { + return !arg_list_.empty() && (0 == (arg_list_.size() % 2)); + } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::collect(arg_list_, node_delete_list); @@ -7531,7 +8237,8 @@ namespace exprtk { public: - virtual ~ivariable() {} + virtual ~ivariable() + {} virtual T& ref() = 0; virtual const T& ref() const = 0; @@ -7539,8 +8246,8 @@ namespace exprtk template class variable_node exprtk_final - : public expression_node, - public ivariable + : public expression_node + , public ivariable { public: @@ -7677,7 +8384,7 @@ namespace exprtk (std::numeric_limits::max() == r1 ) ) { - r1 = size - 1; + r1 = size; } cache.first = r0; @@ -7692,12 +8399,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 n0_e; @@ -7711,16 +8418,20 @@ namespace exprtk const std::size_t r1, const std::size_t size) const { - if (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 >= 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); @@ -7762,19 +8473,22 @@ namespace exprtk typedef vector_node* vector_node_ptr; typedef vec_data_store vds_t; - virtual ~vector_interface() {} + virtual ~vector_interface() + {} + + virtual std::size_t size () const = 0; - virtual std::size_t size () const = 0; + virtual std::size_t base_size() const = 0; - virtual vector_node_ptr vec() const = 0; + virtual vector_node_ptr vec () const = 0; - virtual vector_node_ptr vec() = 0; + virtual vector_node_ptr vec () = 0; - virtual vds_t& vds () = 0; + virtual vds_t& vds () = 0; - virtual const vds_t& vds () const = 0; + virtual const vds_t& vds () const = 0; - virtual bool side_effect () const { return false; } + virtual bool side_effect () const { return false; } }; template @@ -7801,6 +8515,12 @@ namespace exprtk , vds_(vds) {} + ~vector_node() + { + assert(valid()); + vector_holder_->remove_ref(&vds_.ref()); + } + inline T value() const exprtk_override { return vds().data()[0]; @@ -7821,9 +8541,19 @@ namespace exprtk return expression_node::e_vector; } + inline bool valid() const exprtk_override + { + return vector_holder_; + } + std::size_t size() const exprtk_override { - return vds().size(); + return vec_holder().size(); + } + + std::size_t base_size() const exprtk_override + { + return vec_holder().base_size(); } vds_t& vds() exprtk_override @@ -7841,16 +8571,65 @@ namespace exprtk return (*vector_holder_); } + inline vector_holder_t& vec_holder() const + { + return (*vector_holder_); + } + private: vector_holder_t* vector_holder_; vds_t vds_; }; + template + class vector_size_node exprtk_final + : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef vector_holder vector_holder_t; + + explicit vector_size_node(vector_holder_t* vh) + : vector_holder_(vh) + {} + + ~vector_size_node() + { + assert(valid()); + } + + inline T value() const exprtk_override + { + assert(vector_holder_); + return static_cast(vector_holder_->size()); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_vecsize; + } + + inline bool valid() const exprtk_override + { + return vector_holder_ && vector_holder_->size(); + } + + inline vector_holder_t* vec_holder() + { + return vector_holder_; + } + + private: + + vector_holder_t* vector_holder_; + }; + template class vector_elem_node exprtk_final - : public expression_node, - public ivariable + : public expression_node + , public ivariable { public: @@ -7859,26 +8638,30 @@ namespace exprtk typedef vector_holder_t* vector_holder_ptr; typedef std::pair branch_t; - vector_elem_node(expression_ptr index, vector_holder_ptr vec_holder) - : vec_holder_(vec_holder) + vector_elem_node(expression_ptr vec_node, + expression_ptr index, + vector_holder_ptr vec_holder) + : vector_holder_(vec_holder) , vector_base_((*vec_holder)[0]) { - construct_branch_pair(index_, index); + construct_branch_pair(vector_node_, vec_node); + construct_branch_pair(index_ , index ); + assert(valid()); } inline T value() const exprtk_override { - return *(vector_base_ + static_cast(details::numeric::to_int64(index_.first->value()))); + return *access_vector(); } inline T& ref() exprtk_override { - return *(vector_base_ + static_cast(details::numeric::to_int64(index_.first->value()))); + return *access_vector(); } inline const T& ref() const exprtk_override { - return *(vector_base_ + static_cast(details::numeric::to_int64(index_.first->value()))); + return *access_vector(); } inline typename expression_node::node_type type() const exprtk_override @@ -7886,67 +8669,96 @@ namespace exprtk return expression_node::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() { - return (*vec_holder_); + return (*vector_holder_); } void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { - expression_node::ndb_t::collect(index_, node_delete_list); + expression_node::ndb_t::collect(vector_node_, node_delete_list); + expression_node::ndb_t::collect(index_ , node_delete_list); } std::size_t node_depth() const exprtk_override { - return expression_node::ndb_t::compute_node_depth(index_); + return expression_node::ndb_t::compute_node_depth + (vector_node_, index_); } private: - vector_holder_ptr vec_holder_; + inline T* access_vector() const + { + vector_node_.first->value(); + return (vector_base_ + details::numeric::to_uint64(index_.first->value())); + } + + vector_holder_ptr vector_holder_; T* vector_base_; + branch_t vector_node_; branch_t index_; }; template - class rebasevector_elem_node exprtk_final - : public expression_node, - public ivariable + class vector_celem_node exprtk_final + : public expression_node + , public ivariable { public: typedef expression_node* expression_ptr; typedef vector_holder vector_holder_t; typedef vector_holder_t* vector_holder_ptr; - typedef vec_data_store vds_t; typedef std::pair 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_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(index_, index); + construct_branch_pair(vector_node_, vec_node); + assert(valid()); } inline T value() const exprtk_override { - return *(vds_.data() + static_cast(details::numeric::to_int64(index_.first->value()))); + return *access_vector(); } inline T& ref() exprtk_override { - return *(vds_.data() + static_cast(details::numeric::to_int64(index_.first->value()))); + return *access_vector(); } inline const T& ref() const exprtk_override { - return *(vds_.data() + static_cast(details::numeric::to_int64(index_.first->value()))); + return *access_vector(); } inline typename expression_node::node_type type() const exprtk_override { - return expression_node::e_rbvecelem; + return expression_node::e_veccelem; + } + + inline bool valid() const exprtk_override + { + return + vector_holder_ && + vector_node_.first && + vector_node_.first->valid(); } inline vector_holder_t& vec_holder() @@ -7956,59 +8768,82 @@ namespace exprtk void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { - expression_node::ndb_t::template collect(index_, node_delete_list); + expression_node::ndb_t::collect(vector_node_, node_delete_list); } std::size_t node_depth() const exprtk_override { - return expression_node::ndb_t::compute_node_depth(index_); + return expression_node::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_; - branch_t index_; + T* vector_base_; + branch_t vector_node_; }; template - class rebasevector_celem_node exprtk_final - : public expression_node, - public ivariable + class vector_elem_rtc_node exprtk_final + : public expression_node + , public ivariable { public: - typedef expression_node* expression_ptr; - typedef vector_holder vector_holder_t; - typedef vector_holder_t* vector_holder_ptr; - typedef vec_data_store vds_t; + typedef expression_node* expression_ptr; + typedef vector_holder vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; + typedef std::pair 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_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) { - vector_holder_->set_ref(&vds_.ref()); + construct_branch_pair(vector_node_, vec_node); + construct_branch_pair(index_ , index ); + assert(valid()); } inline T value() const exprtk_override { - return *(vds_.data() + index_); + return *access_vector(); } inline T& ref() exprtk_override { - return *(vds_.data() + index_); + return *access_vector(); } inline const T& ref() const exprtk_override { - return *(vds_.data() + index_); + return *access_vector(); } inline typename expression_node::node_type type() const exprtk_override { - return expression_node::e_rbveccelem; + return expression_node::e_vecelemrtc; + } + + 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() @@ -8016,451 +8851,1432 @@ namespace exprtk return (*vector_holder_); } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::collect(vector_node_, node_delete_list); + expression_node::ndb_t::collect(index_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::ndb_t::compute_node_depth + (vector_node_, index_); + } + private: - const std::size_t index_; + inline T* access_vector() const + { + const _uint64_t index = details::numeric::to_uint64(index_.first->value()); + vector_node_.first->value(); + + 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(vector_base_); + context.end_ptr = reinterpret_cast(vector_base_ + vector_holder_->size()); + context.access_ptr = reinterpret_cast(vector_base_ + index); + context.type_size = sizeof(T); + + return vec_rt_chk_->handle_runtime_violation(context) ? + reinterpret_cast(context.access_ptr) : + vector_base_ ; + } + vector_holder_ptr vector_holder_; - vds_t vds_; + 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 - class vector_assignment_node exprtk_final : public expression_node + class vector_celem_rtc_node exprtk_final + : public expression_node + , public ivariable { public: - typedef expression_node* expression_ptr; + typedef expression_node* expression_ptr; + typedef vector_holder vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; + typedef std::pair branch_t; - vector_assignment_node(T* vector_base, - const std::size_t& size, - const std::vector& initialiser_list, - const bool single_value_initialse) - : vector_base_(vector_base) - , initialiser_list_(initialiser_list) - , size_(size) - , single_value_initialse_(single_value_initialse) - {} + 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) + { + construct_branch_pair(vector_node_, vec_node); + assert(valid()); + } 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 - { - const std::size_t initialiser_list_size = initialiser_list_.size(); - - for (std::size_t i = 0; i < initialiser_list_size; ++i) - { - *(vector_base_ + i) = initialiser_list_[i]->value(); - } + return *access_vector(); + } - if (initialiser_list_size < size_) - { - for (std::size_t i = initialiser_list_size; i < size_; ++i) - { - *(vector_base_ + i) = T(0); - } - } - } + inline T& ref() exprtk_override + { + return *access_vector(); + } - return *(vector_base_); + inline const T& ref() const exprtk_override + { + return *access_vector(); } inline typename expression_node::node_type type() const exprtk_override { - return expression_node::e_vecdefass; + return expression_node::e_veccelemrtc; + } + + inline bool valid() const exprtk_override + { + return + vector_holder_ && + vector_node_.first && + vector_node_.first->valid(); + } + + inline vector_holder_t& vec_holder() + { + return (*vector_holder_); } void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { - expression_node::ndb_t::collect(initialiser_list_, node_delete_list); + expression_node::ndb_t::collect(vector_node_, node_delete_list); } std::size_t node_depth() const exprtk_override { - return expression_node::ndb_t::compute_node_depth(initialiser_list_); + return expression_node::ndb_t::compute_node_depth(vector_node_); } private: - vector_assignment_node(const vector_assignment_node&) exprtk_delete; - vector_assignment_node& operator=(const vector_assignment_node&) exprtk_delete; + inline T* access_vector() const + { + vector_node_.first->value(); - mutable T* vector_base_; - std::vector 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(vector_base_); + context.end_ptr = reinterpret_cast(vector_base_ + vector_holder_->size()); + context.access_ptr = reinterpret_cast(vector_base_ + index_); + context.type_size = sizeof(T); + + return vec_rt_chk_->handle_runtime_violation(context) ? + reinterpret_cast(context.access_ptr) : + vector_base_ ; + } + + 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_; }; template - class swap_node exprtk_final : public expression_node + class rebasevector_elem_node exprtk_final + : public expression_node + , public ivariable { public: - typedef expression_node* expression_ptr; - typedef variable_node* variable_node_ptr; + typedef expression_node* expression_ptr; + typedef vector_holder vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; + typedef vec_data_store vds_t; + typedef std::pair branch_t; - swap_node(variable_node_ptr var0, variable_node_ptr var1) - : var0_(var0) - , var1_(var1) - {} + 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()); + } inline T value() const exprtk_override { - std::swap(var0_->ref(),var1_->ref()); - return var1_->ref(); + return *access_vector(); } - inline typename expression_node::node_type type() const exprtk_override + inline T& ref() exprtk_override { - return expression_node::e_swap; + return *access_vector(); } - private: - - variable_node_ptr var0_; - variable_node_ptr var1_; - }; + inline const T& ref() const exprtk_override + { + return *access_vector(); + } - template - class swap_generic_node exprtk_final : public binary_node - { - public: + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_rbvecelem; + } - typedef expression_node* expression_ptr; - typedef ivariable* ivariable_ptr; + inline bool valid() const exprtk_override + { + return + vector_holder_ && + index_.first && + vector_node_.first && + index_.first->valid() && + vector_node_.first->valid(); + } - swap_generic_node(expression_ptr var0, expression_ptr var1) - : binary_node(details::e_swap, var0, var1) - , var0_(dynamic_cast(var0)) - , var1_(dynamic_cast(var1)) - {} + inline vector_holder_t& vec_holder() + { + return (*vector_holder_); + } - inline T value() const exprtk_override + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { - std::swap(var0_->ref(),var1_->ref()); - return var1_->ref(); + expression_node::ndb_t::collect(vector_node_, node_delete_list); + expression_node::ndb_t::collect(index_, node_delete_list); } - inline typename expression_node::node_type type() const exprtk_override + std::size_t node_depth() const exprtk_override { - return expression_node::e_swap; + return expression_node::ndb_t::compute_node_depth + (vector_node_, index_); } private: - ivariable_ptr var0_; - ivariable_ptr var1_; + 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_; }; template - class swap_vecvec_node exprtk_final - : public binary_node - , public vector_interface + class rebasevector_celem_node exprtk_final + : public expression_node + , public ivariable { public: typedef expression_node* expression_ptr; - typedef vector_node * vector_node_ptr; - typedef vec_data_store vds_t; - - using binary_node::branch; + typedef vector_holder vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; + typedef std::pair branch_t; - swap_vecvec_node(expression_ptr branch0, - expression_ptr branch1) - : binary_node(details::e_swap, branch0, branch1) - , vec0_node_ptr_(0) - , vec1_node_ptr_(0) - , vec_size_ (0) - , initialised_ (false) + rebasevector_celem_node(expression_ptr vec_node, + const std::size_t index, + vector_holder_ptr vec_holder) + : index_(index) + , vector_holder_(vec_holder) { - if (is_ivector_node(branch(0))) - { - vector_interface* vi = reinterpret_cast*>(0); - - if (0 != (vi = dynamic_cast*>(branch(0)))) - { - vec0_node_ptr_ = vi->vec(); - vds() = vi->vds(); - } - } - - if (is_ivector_node(branch(1))) - { - vector_interface* vi = reinterpret_cast*>(0); - - if (0 != (vi = dynamic_cast*>(branch(1)))) - { - vec1_node_ptr_ = vi->vec(); - } - } - - if (vec0_node_ptr_ && vec1_node_ptr_) - { - vec_size_ = std::min(vec0_node_ptr_->vds().size(), - vec1_node_ptr_->vds().size()); - - initialised_ = true; - } - - assert(initialised_); + construct_branch_pair(vector_node_, vec_node); + assert(valid()); } inline T value() const exprtk_override { - if (initialised_) - { - assert(branch(0)); - assert(branch(1)); - - binary_node::branch(0)->value(); - binary_node::branch(1)->value(); - - T* vec0 = vec0_node_ptr_->vds().data(); - T* vec1 = vec1_node_ptr_->vds().data(); - - for (std::size_t i = 0; i < vec_size_; ++i) - { - std::swap(vec0[i],vec1[i]); - } - - return vec1_node_ptr_->value(); - } - else - return std::numeric_limits::quiet_NaN(); + vector_node_.first->value(); + return ref();; } - vector_node_ptr vec() const exprtk_override + inline T& ref() exprtk_override { - return vec0_node_ptr_; + return *(vector_holder_->data() + index_); } - vector_node_ptr vec() exprtk_override + inline const T& ref() const exprtk_override { - return vec0_node_ptr_; + return *(vector_holder_->data() + index_); } inline typename expression_node::node_type type() const exprtk_override { - return expression_node::e_vecvecswap; + return expression_node::e_rbveccelem; } - std::size_t size() const exprtk_override + inline bool valid() const exprtk_override { - return vec_size_; + return + vector_holder_ && + vector_node_.first && + vector_node_.first->valid(); } - vds_t& vds() exprtk_override + inline vector_holder_t& vec_holder() { - return vds_; + return (*vector_holder_); } - const vds_t& vds() const exprtk_override + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { - return vds_; + expression_node::ndb_t::collect(vector_node_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::ndb_t::compute_node_depth(vector_node_); } private: - vector_node* vec0_node_ptr_; - vector_node* vec1_node_ptr_; - std::size_t vec_size_; - bool initialised_; - vds_t vds_; + const std::size_t index_; + vector_holder_ptr vector_holder_; + branch_t vector_node_; }; - #ifndef exprtk_disable_string_capabilities template - class stringvar_node exprtk_final - : public expression_node , - public string_base_node, - public range_interface + class rebasevector_elem_rtc_node exprtk_final + : public expression_node + , public ivariable { public: - typedef typename range_interface::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(true,0); - rp_.n1_c = std::make_pair(true,v.size() - 1); - rp_.cache.first = rp_.n0_c.second; - rp_.cache.second = rp_.n1_c.second; - } + typedef expression_node* expression_ptr; + typedef vector_holder vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; + typedef std::pair branch_t; - inline bool operator <(const stringvar_node& v) const + 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) { - return this < (&v); + construct_branch_pair(vector_node_, vec_node); + construct_branch_pair(index_ , index ); + assert(valid()); } inline T value() const exprtk_override { - rp_.n1_c.second = (*value_).size() - 1; - rp_.cache.second = rp_.n1_c.second; - - return std::numeric_limits::quiet_NaN(); + return *access_vector(); } - std::string str() const exprtk_override + inline T& ref() exprtk_override { - return ref(); + return *access_vector(); } - char_cptr base() const exprtk_override + inline const T& ref() const exprtk_override { - return &(*value_)[0]; + return *access_vector(); } - std::size_t size() const exprtk_override + inline typename expression_node::node_type type() const exprtk_override { - return ref().size(); + return expression_node::e_rbvecelemrtc; } - std::string& ref() + inline bool valid() const exprtk_override { - return (*value_); + return + vector_holder_ && + index_.first && + vector_node_.first && + index_.first->valid() && + vector_node_.first->valid(); } - const std::string& ref() const + inline vector_holder_t& vec_holder() { - return (*value_); + return (*vector_holder_); } - range_t& range_ref() exprtk_override + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { - return rp_; + expression_node::ndb_t::collect(vector_node_, node_delete_list); + expression_node::ndb_t::collect(index_ , node_delete_list); } - const range_t& range_ref() const exprtk_override + std::size_t node_depth() const exprtk_override { - return rp_; + return expression_node::ndb_t::compute_node_depth + (vector_node_, index_); } - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_stringvar; - } + private: - void rebase(std::string& s) + inline T* access_vector() const { - value_ = &s; - rp_.n0_c = std::make_pair(true,0); - rp_.n1_c = std::make_pair(true,value_->size() - 1); - rp_.cache.first = rp_.n0_c.second; - rp_.cache.second = rp_.n1_c.second; - } + vector_node_.first->value(); + const _uint64_t index = details::numeric::to_uint64(index_.first->value()); - private: + if (index <= (vector_holder_->size() - 1)) + { + return (vector_holder_->data() + index); + } - std::string* value_; - mutable range_t rp_; - }; + assert(vec_rt_chk_); - template - std::string stringvar_node::null_value = std::string(""); + vector_access_runtime_check::violation_context context; + context.base_ptr = reinterpret_cast(vector_holder_->data()); + context.end_ptr = reinterpret_cast(vector_holder_->data() + vector_holder_->size()); + context.access_ptr = reinterpret_cast(vector_holder_->data() + index); + context.type_size = sizeof(T); + + return vec_rt_chk_->handle_runtime_violation(context) ? + reinterpret_cast(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 - class string_range_node exprtk_final - : public expression_node , - public string_base_node, - public range_interface + class rebasevector_celem_rtc_node exprtk_final + : public expression_node + , public ivariable { public: - typedef typename range_interface::range_t range_t; - - static std::string null_value; - - explicit string_range_node(std::string& v, const range_t& rp) - : value_(&v) - , rp_(rp) - {} - - virtual ~string_range_node() - { - rp_.free(); - } + typedef expression_node* expression_ptr; + typedef vector_holder vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; + typedef std::pair branch_t; - inline bool operator <(const string_range_node& v) const + 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) { - return this < (&v); + construct_branch_pair(vector_node_, vec_node); + assert(valid()); } inline T value() const exprtk_override { - return std::numeric_limits::quiet_NaN(); + return *access_vector(); } - inline std::string str() const exprtk_override + inline T& ref() exprtk_override { - return (*value_); + return *access_vector(); } - char_cptr base() const exprtk_override + inline const T& ref() const exprtk_override { - return &(*value_)[0]; + return *access_vector(); } - std::size_t size() const exprtk_override + inline typename expression_node::node_type type() const exprtk_override { - return ref().size(); + return expression_node::e_rbveccelemrtc; } - inline range_t range() const + inline bool valid() const exprtk_override { - return rp_; + return + vector_holder_ && + vector_node_.first && + vector_node_.first->valid(); } - inline virtual std::string& ref() + inline vector_holder_t& vec_holder() { - return (*value_); + return (*vector_holder_); } - inline virtual const std::string& ref() const + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { - return (*value_); + expression_node::ndb_t::collect(vector_node_, node_delete_list); } - inline range_t& range_ref() exprtk_override + std::size_t node_depth() const exprtk_override { - return rp_; + return expression_node::ndb_t::compute_node_depth(vector_node_); } - inline const range_t& range_ref() const exprtk_override - { - return rp_; - } + private: - inline typename expression_node::node_type type() const exprtk_override + inline T* access_vector() const { - return expression_node::e_stringvarrng; - } + vector_node_.first->value(); - private: + if (index_ <= vector_holder_->size() - 1) + { + return (vector_holder_->data() + index_); + } - std::string* value_; - range_t rp_; - }; + assert(vec_rt_chk_); + + vector_access_runtime_check::violation_context context; + context.base_ptr = reinterpret_cast(vector_base_); + context.end_ptr = reinterpret_cast(vector_base_ + vector_holder_->size()); + context.access_ptr = reinterpret_cast(vector_base_ + index_); + context.type_size = sizeof(T); + + return vec_rt_chk_->handle_runtime_violation(context) ? + reinterpret_cast(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 + class vector_initialisation_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + + vector_initialisation_node(T* vector_base, + const std::size_t& size, + const std::vector& 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)) + { + 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); + + 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_); + } + } + } + } + + inline T value() const exprtk_override + { + if (single_value_initialse_) + { + 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(); + + for (std::size_t i = 0; i < initialiser_list_size; ++i) + { + *(vector_base_ + i) = initialiser_list_[i]->value(); + } + + if (initialiser_list_size < size_) + { + details::set_zero_value( + vector_base_ + initialiser_list_size, + (size_ - initialiser_list_size)); + } + } + + return *(vector_base_); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_vecinit; + } + + inline bool valid() const exprtk_override + { + return vector_base_; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::collect(initialiser_list_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::ndb_t::compute_node_depth(initialiser_list_); + } + + private: + + vector_initialisation_node(const vector_initialisation_node&) exprtk_delete; + vector_initialisation_node& operator=(const vector_initialisation_node&) exprtk_delete; + + mutable T* vector_base_; + std::vector 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_; + }; + + template + class vector_init_zero_value_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + + vector_init_zero_value_node(T* vector_base, + const std::size_t& size, + const std::vector& initialiser_list) + : vector_base_(vector_base) + , size_(size) + , initialiser_list_(initialiser_list) + {} + + inline T value() const exprtk_override + { + details::set_zero_value(vector_base_, size_); + return *(vector_base_); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_vecinit; + } + + inline bool valid() const exprtk_override + { + return vector_base_; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::collect(initialiser_list_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::ndb_t::compute_node_depth(initialiser_list_); + } + + private: + + vector_init_zero_value_node(const vector_init_zero_value_node&) exprtk_delete; + vector_init_zero_value_node& operator=(const vector_init_zero_value_node&) exprtk_delete; + + mutable T* vector_base_; + const std::size_t size_; + std::vector initialiser_list_; + }; + + template + class vector_init_single_constvalue_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + + vector_init_single_constvalue_node(T* vector_base, + const std::size_t& size, + const std::vector& initialiser_list) + : vector_base_(vector_base) + , size_(size) + , initialiser_list_(initialiser_list) + { + single_initialiser_value_ = initialiser_list_[0]->value(); + assert(valid()); + } + + inline T value() const exprtk_override + { + for (std::size_t i = 0; i < size_; ++i) + { + *(vector_base_ + i) = single_initialiser_value_; + } + + return *(vector_base_); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_vecinit; + } + + inline bool valid() const exprtk_override + { + return vector_base_ && + (initialiser_list_.size() == 1) && + (details::is_constant_node(initialiser_list_[0])) && + (single_initialiser_value_ != T(0)); + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::collect(initialiser_list_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::ndb_t::compute_node_depth(initialiser_list_); + } + + private: + + vector_init_single_constvalue_node(const vector_init_single_constvalue_node&) exprtk_delete; + vector_init_single_constvalue_node& operator=(const vector_init_single_constvalue_node&) exprtk_delete; + + mutable T* vector_base_; + const std::size_t size_; + std::vector initialiser_list_; + T single_initialiser_value_; + }; + + template + class vector_init_single_value_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + + vector_init_single_value_node(T* vector_base, + const std::size_t& size, + const std::vector& initialiser_list) + : vector_base_(vector_base) + , size_(size) + , initialiser_list_(initialiser_list) + { + assert(valid()); + } + + inline T value() const exprtk_override + { + expression_node& node = *initialiser_list_[0]; + + for (std::size_t i = 0; i < size_; ++i) + { + *(vector_base_ + i) = node.value(); + } + + return *(vector_base_); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::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::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::collect(initialiser_list_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::ndb_t::compute_node_depth(initialiser_list_); + } + + private: + + vector_init_single_value_node(const vector_init_single_value_node&) exprtk_delete; + vector_init_single_value_node& operator=(const vector_init_single_value_node&) exprtk_delete; + + mutable T* vector_base_; + const std::size_t size_; + std::vector initialiser_list_; + }; + + template + class vector_init_iota_constconst_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + + vector_init_iota_constconst_node(T* vector_base, + const std::size_t& size, + const std::vector& 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::node_type type() const exprtk_override + { + return expression_node::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::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::collect(initialiser_list_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::ndb_t::compute_node_depth(initialiser_list_); + } + + private: + + vector_init_iota_constconst_node(const vector_init_iota_constconst_node&) exprtk_delete; + vector_init_iota_constconst_node& operator=(const vector_init_iota_constconst_node&) exprtk_delete; + + mutable T* vector_base_; + const std::size_t size_; + std::vector initialiser_list_; + T base_value_; + T increment_value_; + }; + + template + class vector_init_iota_constnconst_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + + vector_init_iota_constnconst_node(T* vector_base, + const std::size_t& size, + const std::vector& 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& 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::node_type type() const exprtk_override + { + return expression_node::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::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::collect(initialiser_list_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::ndb_t::compute_node_depth(initialiser_list_); + } + + private: + + vector_init_iota_constnconst_node(const vector_init_iota_constnconst_node&) exprtk_delete; + vector_init_iota_constnconst_node& operator=(const vector_init_iota_constnconst_node&) exprtk_delete; + + mutable T* vector_base_; + const std::size_t size_; + std::vector initialiser_list_; + T base_value_; + }; + + template + class vector_init_iota_nconstconst_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + + vector_init_iota_nconstconst_node(T* vector_base, + const std::size_t& size, + const std::vector& 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::node_type type() const exprtk_override + { + return expression_node::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::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::collect(initialiser_list_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::ndb_t::compute_node_depth(initialiser_list_); + } + + private: + + vector_init_iota_nconstconst_node(const vector_init_iota_nconstconst_node&) exprtk_delete; + vector_init_iota_nconstconst_node& operator=(const vector_init_iota_nconstconst_node&) exprtk_delete; + + mutable T* vector_base_; + const std::size_t size_; + std::vector initialiser_list_; + }; + + template + class vector_init_iota_nconstnconst_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + + vector_init_iota_nconstnconst_node(T* vector_base, + const std::size_t& size, + const std::vector& 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& 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::node_type type() const exprtk_override + { + return expression_node::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::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::collect(initialiser_list_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::ndb_t::compute_node_depth(initialiser_list_); + } + + private: + + vector_init_iota_nconstnconst_node(const vector_init_iota_nconstnconst_node&) exprtk_delete; + vector_init_iota_nconstnconst_node& operator=(const vector_init_iota_nconstnconst_node&) exprtk_delete; + + mutable T* vector_base_; + const std::size_t size_; + std::vector initialiser_list_; + }; + + template + class swap_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef variable_node* 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::node_type type() const exprtk_override + { + return expression_node::e_swap; + } + + private: + + variable_node_ptr var0_; + variable_node_ptr var1_; + }; + + template + class swap_generic_node exprtk_final : public binary_node + { + public: + + typedef expression_node* expression_ptr; + typedef ivariable* ivariable_ptr; + + swap_generic_node(expression_ptr var0, expression_ptr var1) + : binary_node(details::e_swap, var0, var1) + , var0_(dynamic_cast(var0)) + , var1_(dynamic_cast(var1)) + {} + + inline T value() const exprtk_override + { + std::swap(var0_->ref(),var1_->ref()); + return var1_->ref(); + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_swap; + } + + private: + + ivariable_ptr var0_; + ivariable_ptr var1_; + }; + + template + class swap_vecvec_node exprtk_final + : public binary_node + , public vector_interface + { + public: + + typedef expression_node* expression_ptr; + typedef vector_node * vector_node_ptr; + typedef vec_data_store vds_t; + + using binary_node::branch; + + swap_vecvec_node(expression_ptr branch0, + expression_ptr branch1) + : binary_node(details::e_swap, branch0, branch1) + , vec0_node_ptr_(0) + , vec1_node_ptr_(0) + , initialised_ (false) + { + if (is_ivector_node(branch(0))) + { + vector_interface* vi = reinterpret_cast*>(0); + + if (0 != (vi = dynamic_cast*>(branch(0)))) + { + vec0_node_ptr_ = vi->vec(); + vds() = vi->vds(); + } + } + + if (is_ivector_node(branch(1))) + { + vector_interface* vi = reinterpret_cast*>(0); + + if (0 != (vi = dynamic_cast*>(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::branch(0)->value(); + binary_node::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::node_type type() const exprtk_override + { + return expression_node::e_vecvecswap; + } + + inline bool valid() const exprtk_override + { + return initialised_ && binary_node::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* vec0_node_ptr_; + vector_node* vec1_node_ptr_; + bool initialised_; + vds_t vds_; + }; + + #ifndef exprtk_disable_string_capabilities + template + class stringvar_node exprtk_final + : public expression_node + , public string_base_node + , public range_interface + { + public: + + typedef typename range_interface::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(true,0); + rp_.n1_c = std::make_pair(true,v.size()); + rp_.cache.first = rp_.n0_c.second; + rp_.cache.second = rp_.n1_c.second; + } + + inline bool operator <(const stringvar_node& 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::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::node_type type() const exprtk_override + { + return expression_node::e_stringvar; + } + + void rebase(std::string& s) + { + value_ = &s; + rp_.n0_c = std::make_pair(true,0); + rp_.n1_c = std::make_pair(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 + std::string stringvar_node::null_value = std::string(""); + + template + class string_range_node exprtk_final + : public expression_node + , public string_base_node + , public range_interface + { + public: + + typedef typename range_interface::range_t range_t; + + static std::string null_value; + + explicit string_range_node(std::string& v, const range_t& rp) + : value_(&v) + , rp_(rp) + {} + + virtual ~string_range_node() + { + rp_.free(); + } + + inline bool operator <(const string_range_node& v) const + { + return this < (&v); + } + + inline T value() const exprtk_override + { + return std::numeric_limits::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::node_type type() const exprtk_override + { + return expression_node::e_stringvarrng; + } + + private: + + std::string* value_; + range_t rp_; + }; template std::string string_range_node::null_value = std::string(""); template class const_string_range_node exprtk_final - : public expression_node , - public string_base_node, - public range_interface + : public expression_node + , public string_base_node + , public range_interface { public: @@ -8527,9 +10343,9 @@ namespace exprtk template class generic_string_range_node exprtk_final - : public expression_node , - public string_base_node, - public range_interface + : public expression_node + , public string_base_node + , public range_interface { public: @@ -8569,8 +10385,7 @@ namespace exprtk } initialised_ = (str_base_ptr_ && str_range_ptr_); - - assert(initialised_); + assert(valid()); } ~generic_string_range_node() @@ -8580,34 +10395,184 @@ namespace exprtk inline T value() const exprtk_override { - if (initialised_) + 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) + ) { - assert(branch_.first); + const std::size_t size = r1 - r0; - branch_.first->value(); + range_.n1_c.second = size; + range_.cache.second = range_.n1_c.second; - std::size_t str_r0 = 0; - std::size_t str_r1 = 0; + value_.assign(str_base_ptr_->base() + str_r0 + r0, size); + } - std::size_t r0 = 0; - std::size_t r1 = 0; + return std::numeric_limits::quiet_NaN(); + } - const range_t& range = str_range_ptr_->range_ref(); + std::string str() const exprtk_override + { + return value_; + } - const std::size_t base_str_size = str_base_ptr_->size(); + char_cptr base() const exprtk_override + { + return &value_[0]; + } - 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) + 1; + std::size_t size() const exprtk_override + { + return value_.size(); + } - range_.n1_c.second = size - 1; - range_.cache.second = range_.n1_c.second; + range_t& range_ref() exprtk_override + { + return range_; + } - value_.assign(str_base_ptr_->base() + str_r0 + r0, size); - } + const range_t& range_ref() const exprtk_override + { + return range_; + } + + inline typename expression_node::node_type type() const exprtk_override + { + return expression_node::e_strgenrange; + } + + inline bool valid() const exprtk_override + { + return initialised_ && branch_.first; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::collect(branch_, node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::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 + class string_concat_node exprtk_final + : public binary_node + , public string_base_node + , public range_interface + { + public: + + typedef typename range_interface::range_t range_t; + typedef range_interface irange_t; + typedef irange_t* irange_ptr; + typedef range_t* range_ptr; + typedef expression_node * expression_ptr; + typedef string_base_node* str_base_ptr; + + using binary_node::branch; + + string_concat_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(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(true,0); + range_.n1_c = std::make_pair(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(branch(0)); + + if (0 == str0_base_ptr_) + return; + + str0_range_ptr_ = dynamic_cast(branch(0)); + + if (0 == str0_range_ptr_) + return; + } + + if (is_generally_string_node(branch(1))) + { + str1_base_ptr_ = dynamic_cast(branch(1)); + + if (0 == str1_base_ptr_) + return; + + str1_range_ptr_ = dynamic_cast(branch(1)); + + if (0 == str1_range_ptr_) + return; + } + + initialised_ = str0_base_ptr_ && + str1_base_ptr_ && + str0_range_ptr_ && + str1_range_ptr_ ; + + assert(valid()); + } + + inline T value() const exprtk_override + { + branch(0)->value(); + branch(1)->value(); + + std::size_t str0_r0 = 0; + std::size_t str0_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(); + + 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); + + range_.n1_c.second = value_.size(); + range_.cache.second = range_.n1_c.second; } return std::numeric_limits::quiet_NaN(); @@ -8640,163 +10605,12 @@ namespace exprtk inline typename expression_node::node_type type() const exprtk_override { - return expression_node::e_strgenrange; - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(branch_, node_delete_list); - } - - std::size_t node_depth() const exprtk_override - { - return expression_node::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 - class string_concat_node exprtk_final - : public binary_node , - public string_base_node, - public range_interface - { - public: - - typedef typename range_interface::range_t range_t; - typedef range_interface irange_t; - typedef irange_t* irange_ptr; - typedef range_t* range_ptr; - typedef expression_node * expression_ptr; - typedef string_base_node* str_base_ptr; - - using binary_node::branch; - - string_concat_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(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(true,0); - range_.n1_c = std::make_pair(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(branch(0)); - - if (0 == str0_base_ptr_) - return; - - str0_range_ptr_ = dynamic_cast(branch(0)); - - if (0 == str0_range_ptr_) - return; - } - - if (is_generally_string_node(branch(1))) - { - str1_base_ptr_ = dynamic_cast(branch(1)); - - if (0 == str1_base_ptr_) - return; - - str1_range_ptr_ = dynamic_cast(branch(1)); - - if (0 == str1_range_ptr_) - return; - } - - initialised_ = str0_base_ptr_ && - str1_base_ptr_ && - str0_range_ptr_ && - str1_range_ptr_ ; - - assert(initialised_); - } - - inline T value() const exprtk_override - { - if (initialised_) - { - assert(branch(0)); - assert(branch(1)); - - branch(0)->value(); - branch(1)->value(); - - std::size_t str0_r0 = 0; - std::size_t str0_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(); - - 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; - - 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; - } - } - - return std::numeric_limits::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_; + return expression_node::e_strconcat; } - inline typename expression_node::node_type type() const exprtk_override + inline bool valid() const exprtk_override { - return expression_node::e_strconcat; + return initialised_ && binary_node::valid(); } private: @@ -8812,9 +10626,9 @@ namespace exprtk template class swap_string_node exprtk_final - : public binary_node , - public string_base_node, - public range_interface + : public binary_node + , public string_base_node + , public range_interface { public: @@ -8829,10 +10643,10 @@ namespace exprtk using binary_node::branch; swap_string_node(expression_ptr branch0, expression_ptr branch1) - : binary_node(details::e_swap, branch0, branch1), - initialised_(false), - str0_node_ptr_(0), - str1_node_ptr_(0) + : binary_node(details::e_swap, branch0, branch1) + , initialised_(false) + , str0_node_ptr_(0) + , str1_node_ptr_(0) { if (is_string_node(branch(0))) { @@ -8845,22 +10659,15 @@ namespace exprtk } initialised_ = (str0_node_ptr_ && str1_node_ptr_); - - assert(initialised_); + assert(valid()); } inline T value() const exprtk_override { - if (initialised_) - { - assert(branch(0)); - assert(branch(1)); - - branch(0)->value(); - branch(1)->value(); + branch(0)->value(); + branch(1)->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::quiet_NaN(); } @@ -8895,6 +10702,11 @@ namespace exprtk return expression_node::e_strswap; } + inline bool valid() const exprtk_override + { + return initialised_ && binary_node::valid(); + } + private: bool initialised_; @@ -8960,87 +10772,81 @@ namespace exprtk str0_range_ptr_ && str1_range_ptr_ ; - assert(initialised_); + assert(valid()); } inline T value() const exprtk_override { - if (initialised_) - { - assert(branch(0)); - assert(branch(1)); + branch(0)->value(); + branch(1)->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()) + ) + { + 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(str0_base_ptr_->base() + str0_r0); + char_ptr s1 = const_cast(str1_base_ptr_->base() + str1_r0); - char_ptr s0 = const_cast(str0_base_ptr_->base() + str0_r0); - char_ptr s1 = const_cast(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::quiet_NaN(); @@ -9051,6 +10857,11 @@ namespace exprtk return expression_node::e_strswap; } + inline bool valid() const exprtk_override + { + return initialised_ && binary_node::valid(); + } + private: swap_genstrings_node(const swap_genstrings_node&) exprtk_delete; @@ -9068,7 +10879,7 @@ namespace exprtk { public: - static std::string null_value; + static const std::string null_value; explicit stringvar_size_node() : value_(&null_value) @@ -9090,11 +10901,11 @@ namespace exprtk private: - std::string* value_; + const std::string* value_; }; template - std::string stringvar_size_node::null_value = std::string(""); + const std::string stringvar_size_node::null_value = std::string(""); template class string_size_node exprtk_final : public expression_node @@ -9113,23 +10924,15 @@ namespace exprtk if (is_generally_string_node(branch_.first)) { str_base_ptr_ = dynamic_cast(branch_.first); - - if (0 == str_base_ptr_) - return; } + + assert(valid()); } inline T value() const exprtk_override { - T result = std::numeric_limits::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::node_type type() const exprtk_override @@ -9137,6 +10940,11 @@ namespace exprtk return expression_node::e_stringsize; } + inline bool valid() const exprtk_override + { + return str_base_ptr_; + } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::collect(branch_, node_delete_list); @@ -9149,7 +10957,7 @@ namespace exprtk private: - branch_t branch_; + branch_t branch_; str_base_ptr str_base_ptr_; }; @@ -9167,9 +10975,9 @@ namespace exprtk template class assignment_string_node exprtk_final - : public binary_node , - public string_base_node, - public range_interface + : public binary_node + , public string_base_node + , public range_interface { public: @@ -9219,31 +11027,25 @@ namespace exprtk str0_node_ptr_ && str1_range_ptr_ ; - assert(initialised_); + assert(valid()); } inline T value() const exprtk_override { - if (initialised_) - { - assert(branch(0)); - assert(branch(1)); + branch(1)->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)); - branch(0)->value(); - } + branch(0)->value(); } return std::numeric_limits::quiet_NaN(); @@ -9279,6 +11081,11 @@ namespace exprtk return expression_node::e_strass; } + inline bool valid() const exprtk_override + { + return initialised_ && binary_node::valid(); + } + private: bool initialised_; @@ -9290,9 +11097,9 @@ namespace exprtk template class assignment_string_range_node exprtk_final - : public binary_node , - public string_base_node, - public range_interface + : public binary_node + , public string_base_node + , public range_interface { public: @@ -9351,39 +11158,34 @@ namespace exprtk str0_range_ptr_ && str1_range_ptr_ ; - assert(initialised_); + assert(valid()); } inline T value() const exprtk_override { - if (initialised_) - { - assert(branch(0)); - assert(branch(1)); - - branch(0)->value(); - branch(1)->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(base() + s0_r0)); - } + std::copy( + str1_base_ptr_->base() + s1_r0, + str1_base_ptr_->base() + s1_r0 + size, + const_cast(base() + s0_r0)); } return std::numeric_limits::quiet_NaN(); @@ -9419,6 +11221,11 @@ namespace exprtk return expression_node::e_strass; } + inline bool valid() const exprtk_override + { + return initialised_ && binary_node::valid(); + } + private: bool initialised_; @@ -9431,9 +11238,9 @@ namespace exprtk template class conditional_string_node exprtk_final - : public trinary_node , - public string_base_node, - public range_interface + : public trinary_node + , public string_base_node + , public range_interface { public: @@ -9494,55 +11301,48 @@ namespace exprtk str0_range_ptr_ && str1_range_ptr_ ; - assert(initialised_); + assert(valid()); } 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); } } @@ -9579,6 +11379,15 @@ namespace exprtk return expression_node::e_strcondition; } + inline bool valid() const exprtk_override + { + return + initialised_ && + condition_ && condition_ ->valid() && + consequent_ && consequent_ ->valid() && + alternative_&& alternative_->valid() ; + } + private: bool initialised_; @@ -9596,9 +11405,9 @@ namespace exprtk template class cons_conditional_str_node exprtk_final - : public binary_node , - public string_base_node, - public range_interface + : public binary_node + , public string_base_node + , public range_interface { public: @@ -9640,37 +11449,30 @@ namespace exprtk } initialised_ = str0_base_ptr_ && str0_range_ptr_ ; - - assert(initialised_); + assert(valid()); } inline T value() const exprtk_override { - if (initialised_) + if (is_true(condition_)) { - assert(condition_ ); - assert(consequent_); - - if (is_true(condition_)) - { - consequent_->value(); + 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); } } @@ -9707,6 +11509,14 @@ namespace exprtk return expression_node::e_strccondition; } + inline bool valid() const exprtk_override + { + return + initialised_ && + condition_ && condition_ ->valid() && + consequent_ && consequent_ ->valid() ; + } + private: bool initialised_; @@ -9721,9 +11531,9 @@ namespace exprtk template class str_vararg_node exprtk_final - : public expression_node , - public string_base_node, - public range_interface + : public expression_node + , public string_base_node + , public range_interface { public: @@ -9759,8 +11569,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; @@ -9769,7 +11577,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]); } @@ -9779,7 +11587,12 @@ namespace exprtk return; } } + + initialised_ = true; } + + initialised_ &= str_base_ptr_ && str_range_ptr_; + assert(valid()); } inline T value() const exprtk_override @@ -9824,6 +11637,13 @@ namespace exprtk return expression_node::e_stringvararg; } + inline bool valid() const exprtk_override + { + return + initialised_ && + final_node_.first && final_node_.first->valid(); + } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::collect(final_node_ , node_delete_list); @@ -9847,6 +11667,104 @@ namespace exprtk }; #endif + template + class assert_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + typedef string_base_node* 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(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::node_type type() const exprtk_override + { + return expression_node::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::noderef_list_t& node_delete_list) exprtk_override + { + expression_node::ndb_t::collect(assert_condition_node_, node_delete_list); + expression_node::ndb_t::collect(assert_message_node_ , node_delete_list); + } + + std::size_t node_depth() const exprtk_override + { + return expression_node::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 inline T axn(const T a, const T x) { @@ -10087,10 +12005,6 @@ namespace exprtk inline T value() const exprtk_override { - assert(trinary_node::branch_[0].first); - assert(trinary_node::branch_[1].first); - assert(trinary_node::branch_[2].first); - const T x = trinary_node::branch_[0].first->value(); const T y = trinary_node::branch_[1].first->value(); const T z = trinary_node::branch_[2].first->value(); @@ -10116,11 +12030,6 @@ namespace exprtk inline T value() const exprtk_override { - assert(quaternary_node::branch_[0].first); - assert(quaternary_node::branch_[1].first); - assert(quaternary_node::branch_[2].first); - assert(quaternary_node::branch_[3].first); - const T x = quaternary_node::branch_[0].first->value(); const T y = quaternary_node::branch_[1].first->value(); const T z = quaternary_node::branch_[2].first->value(); @@ -10209,12 +12118,13 @@ namespace exprtk template class Sequence> explicit vararg_node(const Sequence& 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]); } @@ -10224,6 +12134,9 @@ namespace exprtk return; } } + + initialised_ = (arg_list_.size() == arg_list.size()); + assert(valid()); } inline T value() const exprtk_override @@ -10236,6 +12149,11 @@ namespace exprtk return expression_node::e_vararg; } + inline bool valid() const exprtk_override + { + return initialised_; + } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::collect(arg_list_, node_delete_list); @@ -10246,9 +12164,20 @@ namespace exprtk return expression_node::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 arg_list_; + bool initialised_; }; template @@ -10261,12 +12190,13 @@ namespace exprtk template class Sequence> explicit vararg_varnode(const Sequence& 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* var_node_ptr = static_cast*>(arg_list[i]); arg_list_[i] = (&var_node_ptr->ref()); @@ -10277,14 +12207,14 @@ namespace exprtk return; } } + + initialised_ = (arg_list.size() == arg_list_.size()); + assert(valid()); } inline T value() const exprtk_override { - if (!arg_list_.empty()) - return VarArgFunction::process(arg_list_); - else - return std::numeric_limits::quiet_NaN(); + return VarArgFunction::process(arg_list_); } inline typename expression_node::node_type type() const exprtk_override @@ -10292,9 +12222,15 @@ namespace exprtk return expression_node::e_vararg; } + inline bool valid() const exprtk_override + { + return initialised_; + } + private: std::vector arg_list_; + bool initialised_; }; template @@ -10314,22 +12250,12 @@ namespace exprtk { ivec_ptr_ = dynamic_cast*>(v_.first); } - else - ivec_ptr_ = 0; } 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::quiet_NaN(); + v_.first->value(); + return VecFunction::process(ivec_ptr_); } inline typename expression_node::node_type type() const exprtk_override @@ -10337,6 +12263,11 @@ namespace exprtk return expression_node::e_vecfunc; } + inline bool valid() const exprtk_override + { + return ivec_ptr_ && v_.first && v_.first->valid(); + } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::collect(v_, node_delete_list); @@ -10375,17 +12306,15 @@ namespace exprtk inline T value() const exprtk_override { - if (var_node_ptr_) - { - assert(branch(1)); - - T& result = var_node_ptr_->ref(); + T& result = var_node_ptr_->ref(); result = branch(1)->value(); - return result; - } - else - return std::numeric_limits::quiet_NaN(); + return result; + } + + inline bool valid() const exprtk_override + { + return var_node_ptr_ && binary_node::valid(); } private: @@ -10411,26 +12340,66 @@ namespace exprtk { vec_node_ptr_ = static_cast*>(branch(0)); } + + assert(valid()); } inline T value() const exprtk_override { - if (vec_node_ptr_) + T& result = vec_node_ptr_->ref(); + result = branch(1)->value(); + + return result; + } + + inline bool valid() const exprtk_override + { + return vec_node_ptr_ && binary_node::valid(); + } + + private: + + vector_elem_node* vec_node_ptr_; + }; + + template + class assignment_vec_elem_rtc_node exprtk_final : public binary_node + { + public: + + typedef expression_node* expression_ptr; + using binary_node::branch; + + assignment_vec_elem_rtc_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1) + , vec_node_ptr_(0) + { + if (is_vector_elem_rtc_node(branch(0))) { - assert(branch(1)); + vec_node_ptr_ = static_cast*>(branch(0)); + } - T& result = vec_node_ptr_->ref(); + assert(valid()); + } + + inline T value() const exprtk_override + { + T& result = vec_node_ptr_->ref(); result = branch(1)->value(); - return result; - } - else - return std::numeric_limits::quiet_NaN(); + return result; + } + + inline bool valid() const exprtk_override + { + return vec_node_ptr_ && binary_node::valid(); } private: - vector_elem_node* vec_node_ptr_; + vector_elem_rtc_node* vec_node_ptr_; }; template @@ -10451,27 +12420,66 @@ namespace exprtk { rbvec_node_ptr_ = static_cast*>(branch(0)); } + + assert(valid()); } inline T value() const exprtk_override { - if (rbvec_node_ptr_) + T& result = rbvec_node_ptr_->ref(); + result = branch(1)->value(); + + return result; + } + + inline bool valid() const exprtk_override + { + return rbvec_node_ptr_ && binary_node::valid(); + } + + private: + + rebasevector_elem_node* rbvec_node_ptr_; + }; + + template + class assignment_rebasevec_elem_rtc_node exprtk_final : public binary_node + { + public: + + typedef expression_node* expression_ptr; + using expression_node::branch; + + assignment_rebasevec_elem_rtc_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1) + , rbvec_node_ptr_(0) + { + if (is_rebasevector_elem_rtc_node(branch(0))) { - assert(branch(1)); + rbvec_node_ptr_ = static_cast*>(branch(0)); + } - T& result = rbvec_node_ptr_->ref(); + assert(valid()); + } + inline T value() const exprtk_override + { + T& result = rbvec_node_ptr_->ref(); result = branch(1)->value(); - return result; - } - else - return std::numeric_limits::quiet_NaN(); + return result; + } + + inline bool valid() const exprtk_override + { + return rbvec_node_ptr_ && binary_node::valid(); } private: - rebasevector_elem_node* rbvec_node_ptr_; + rebasevector_elem_rtc_node* rbvec_node_ptr_; }; template @@ -10492,21 +12500,21 @@ namespace exprtk { rbvec_node_ptr_ = static_cast*>(branch(0)); } + + assert(valid()); } inline T value() const exprtk_override { - if (rbvec_node_ptr_) - { - assert(branch(1)); - - T& result = rbvec_node_ptr_->ref(); + T& result = rbvec_node_ptr_->ref(); result = branch(1)->value(); - return result; - } - else - return std::numeric_limits::quiet_NaN(); + return result; + } + + inline bool valid() const exprtk_override + { + return rbvec_node_ptr_ && binary_node::valid(); } private: @@ -10538,66 +12546,60 @@ namespace exprtk vec_node_ptr_ = static_cast*>(branch(0)); vds() = vec_node_ptr_->vds(); } + + assert(valid()); } inline T value() const exprtk_override { - if (vec_node_ptr_) - { - assert(branch(1)); + const T v = branch(1)->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::quiet_NaN(); + return vec_node_ptr_->value(); } vector_node_ptr vec() const exprtk_override @@ -10615,9 +12617,22 @@ namespace exprtk return expression_node::e_vecvalass; } + inline bool valid() const exprtk_override + { + return + vec_node_ptr_ && + (vds().size() <= vec_node_ptr_->vec_holder().base_size()) && + binary_node::valid(); + } + std::size_t size() const exprtk_override { - return vds().size(); + return vec_node_ptr_->vec_holder().size(); + } + + std::size_t base_size() const exprtk_override + { + return vec_node_ptr_->vec_holder().base_size(); } vds_t& vds() exprtk_override @@ -10687,74 +12702,71 @@ 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::valid(); - assert(initialised_); + assert(valid()); } inline T value() const exprtk_override { - if (initialised_) - { - assert(branch(1)); - - branch(1)->value(); + branch(1)->value(); - if (src_is_ivec_) - return vec0_node_ptr_->value(); + if (src_is_ivec_) + return vec0_node_ptr_->value(); - T* vec0 = vec0_node_ptr_->vds().data(); - T* vec1 = vec1_node_ptr_->vds().data(); + 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; + loop_unroll::details lud(size()); + const T* upper_bound = vec0 + lud.upper_bound; - while (vec0 < upper_bound) - { - #define exprtk_loop(N) \ - vec0[N] = vec1[N]; \ + while (vec0 < upper_bound) + { + #define exprtk_loop(N) \ + 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; + } - exprtk_disable_fallthrough_begin - switch (lud.remainder) - { - #define case_stmt(N) \ - case N : *vec0++ = *vec1++; \ + switch (lud.remainder) + { + #define case_stmt(N,fall_through) \ + case N : *vec0++ = *vec1++; \ + 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::quiet_NaN(); + return vec0_node_ptr_->value(); } vector_node_ptr vec() exprtk_override @@ -10772,9 +12784,23 @@ namespace exprtk return expression_node::e_vecvecass; } + 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()); + } + + 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 @@ -10814,146 +12840,306 @@ namespace exprtk { var_node_ptr_ = static_cast*>(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::valid(); + } + + private: + + variable_node* var_node_ptr_; + }; + + template + class assignment_vec_elem_op_node exprtk_final : public binary_node + { + public: + + typedef expression_node* expression_ptr; + using binary_node::branch; + + assignment_vec_elem_op_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1) + , vec_node_ptr_(0) + { + if (is_vector_elem_node(branch(0))) + { + vec_node_ptr_ = static_cast*>(branch(0)); + } + + assert(valid()); } inline T value() const exprtk_override { - if (var_node_ptr_) + 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::valid(); + } + + private: + + vector_elem_node* vec_node_ptr_; + }; + + template + class assignment_vec_elem_op_rtc_node exprtk_final : public binary_node + { + public: + + typedef expression_node* expression_ptr; + using binary_node::branch; + + assignment_vec_elem_op_rtc_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1) + , vec_node_ptr_(0) + { + if (is_vector_elem_rtc_node(branch(0))) { - assert(branch(1)); + vec_node_ptr_ = static_cast*>(branch(0)); + } - T& v = var_node_ptr_->ref(); + assert(valid()); + } + + inline T value() const exprtk_override + { + T& v = vec_node_ptr_->ref(); v = Operation::process(v,branch(1)->value()); - return v; + return v; + } + + inline bool valid() const exprtk_override + { + return vec_node_ptr_ && binary_node::valid(); + } + + private: + + vector_elem_rtc_node* vec_node_ptr_; + }; + + template + class assignment_vec_celem_op_rtc_node exprtk_final : public binary_node + { + public: + + typedef expression_node* expression_ptr; + using binary_node::branch; + + assignment_vec_celem_op_rtc_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1) + , vec_node_ptr_(0) + { + if (is_vector_celem_rtc_node(branch(0))) + { + vec_node_ptr_ = static_cast*>(branch(0)); } - else - return std::numeric_limits::quiet_NaN(); + + 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::valid(); } private: - variable_node* var_node_ptr_; + vector_celem_rtc_node* vec_node_ptr_; + }; + + template + class assignment_rebasevec_elem_op_node exprtk_final : public binary_node + { + public: + + typedef expression_node* expression_ptr; + using binary_node::branch; + + assignment_rebasevec_elem_op_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1) + , rbvec_node_ptr_(0) + { + if (is_rebasevector_elem_node(branch(0))) + { + rbvec_node_ptr_ = static_cast*>(branch(0)); + } + + assert(valid()); + } + + inline T value() const exprtk_override + { + T& v = rbvec_node_ptr_->ref(); + v = Operation::process(v,branch(1)->value()); + + return v; + } + + inline bool valid() const exprtk_override + { + return rbvec_node_ptr_ && binary_node::valid(); + } + + private: + + rebasevector_elem_node* rbvec_node_ptr_; }; template - class assignment_vec_elem_op_node exprtk_final : public binary_node + class assignment_rebasevec_celem_op_node exprtk_final : public binary_node { public: typedef expression_node* expression_ptr; using binary_node::branch; - assignment_vec_elem_op_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) + assignment_rebasevec_celem_op_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) : binary_node(opr, branch0, branch1) - , vec_node_ptr_(0) + , rbvec_node_ptr_(0) { - if (is_vector_elem_node(branch(0))) + if (is_rebasevector_celem_node(branch(0))) { - vec_node_ptr_ = static_cast*>(branch(0)); + rbvec_node_ptr_ = static_cast*>(branch(0)); } + + assert(valid()); } inline T value() const exprtk_override { - if (vec_node_ptr_) - { - assert(branch(1)); + T& v = rbvec_node_ptr_->ref(); + v = Operation::process(v,branch(1)->value()); - T& v = vec_node_ptr_->ref(); - v = Operation::process(v,branch(1)->value()); + return v; + } - return v; - } - else - return std::numeric_limits::quiet_NaN(); + inline bool valid() const exprtk_override + { + return rbvec_node_ptr_ && binary_node::valid(); } private: - vector_elem_node* vec_node_ptr_; + rebasevector_celem_node* rbvec_node_ptr_; }; template - class assignment_rebasevec_elem_op_node exprtk_final : public binary_node + class assignment_rebasevec_elem_op_rtc_node exprtk_final : public binary_node { public: typedef expression_node* expression_ptr; using binary_node::branch; - assignment_rebasevec_elem_op_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) + assignment_rebasevec_elem_op_rtc_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) : binary_node(opr, branch0, branch1) , rbvec_node_ptr_(0) { - if (is_rebasevector_elem_node(branch(0))) + if (is_rebasevector_elem_rtc_node(branch(0))) { - rbvec_node_ptr_ = static_cast*>(branch(0)); + rbvec_node_ptr_ = static_cast*>(branch(0)); } + + assert(valid()); } inline T value() const exprtk_override { - if (rbvec_node_ptr_) - { - assert(branch(1)); + T& v = rbvec_node_ptr_->ref(); + v = Operation::process(v,branch(1)->value()); - T& v = rbvec_node_ptr_->ref(); - v = Operation::process(v,branch(1)->value()); + return v; + } - return v; - } - else - return std::numeric_limits::quiet_NaN(); + inline bool valid() const exprtk_override + { + return rbvec_node_ptr_ && binary_node::valid(); } private: - rebasevector_elem_node* rbvec_node_ptr_; + rebasevector_elem_rtc_node* rbvec_node_ptr_; }; template - class assignment_rebasevec_celem_op_node exprtk_final : public binary_node + class assignment_rebasevec_celem_op_rtc_node exprtk_final : public binary_node { public: typedef expression_node* expression_ptr; using binary_node::branch; - assignment_rebasevec_celem_op_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) + assignment_rebasevec_celem_op_rtc_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) : binary_node(opr, branch0, branch1) , rbvec_node_ptr_(0) { - if (is_rebasevector_celem_node(branch(0))) + if (is_rebasevector_celem_rtc_node(branch(0))) { - rbvec_node_ptr_ = static_cast*>(branch(0)); + rbvec_node_ptr_ = static_cast*>(branch(0)); } + + assert(valid()); } inline T value() const exprtk_override { - if (rbvec_node_ptr_) - { - assert(branch(1)); + T& v = rbvec_node_ptr_->ref(); + v = Operation::process(v,branch(1)->value()); - T& v = rbvec_node_ptr_->ref(); - v = Operation::process(v,branch(1)->value()); + return v; + } - return v; - } - else - return std::numeric_limits::quiet_NaN(); + inline bool valid() const exprtk_override + { + return rbvec_node_ptr_ && binary_node::valid(); } private: - rebasevector_celem_node* rbvec_node_ptr_; + rebasevector_celem_rtc_node* rbvec_node_ptr_; }; template @@ -10980,66 +13166,60 @@ namespace exprtk vec_node_ptr_ = static_cast*>(branch(0)); vds() = vec_node_ptr_->vds(); } + + assert(valid()); } inline T value() const exprtk_override { - if (vec_node_ptr_) - { - assert(branch(1)); - - const T v = branch(1)->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) \ - Operation::assign(vec[N],v); \ + while (vec < upper_bound) + { + #define exprtk_loop(N) \ + Operation::assign(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 : Operation::assign(*vec++,v); \ + 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) 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 vec_node_ptr_->value(); - } - else - return std::numeric_limits::quiet_NaN(); + return vec_node_ptr_->value(); } vector_node_ptr vec() const exprtk_override @@ -11057,9 +13237,22 @@ namespace exprtk return expression_node::e_vecopvalass; } + inline bool valid() const exprtk_override + { + return + vec_node_ptr_ && + (size() <= base_size()) && + binary_node::valid() ; + } + std::size_t size() const exprtk_override { - return vds().size(); + return vec_node_ptr_->vec_holder().size(); + } + + std::size_t base_size() const exprtk_override + { + return vec_node_ptr_->vec_holder().base_size(); } vds_t& vds() exprtk_override @@ -11122,81 +13315,76 @@ namespace exprtk if (0 != (vi = dynamic_cast*>(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::valid(); - assert(initialised_); + assert(valid()); } inline T value() const exprtk_override { - if (initialised_) - { - assert(branch(0)); - assert(branch(1)); - - branch(0)->value(); - branch(1)->value(); + branch(0)->value(); + branch(1)->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::quiet_NaN(); + return vec0_node_ptr_->value(); } vector_node_ptr vec() const exprtk_override @@ -11214,9 +13402,23 @@ namespace exprtk return expression_node::e_vecopvecass; } + 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()); + } + + 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 @@ -11242,6 +13444,64 @@ namespace exprtk vds_t vds_; }; + template + struct memory_context_t + { + typedef vector_node* vector_node_ptr; + typedef vector_holder 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 + inline memory_context_t make_memory_context(vector_holder& vec_holder, + vec_data_store& vds) + { + memory_context_t result_ctxt; + result_ctxt.temp_ = (vec_holder.rebaseable()) ? + new vector_holder(vec_holder,vds) : + new vector_holder(vds) ; + result_ctxt.temp_vec_node_ = new vector_node (vds,result_ctxt.temp_); + return result_ctxt; + } + + template + inline memory_context_t make_memory_context(vector_holder& vec_holder0, + vector_holder& vec_holder1, + vec_data_store& vds) + { + memory_context_t result_ctxt; + + if (!vec_holder0.rebaseable() && !vec_holder1.rebaseable()) + result_ctxt.temp_ = new vector_holder(vds); + else if (vec_holder0.rebaseable() && !vec_holder1.rebaseable()) + result_ctxt.temp_ = new vector_holder(vec_holder0,vds); + else if (!vec_holder0.rebaseable() && vec_holder1.rebaseable()) + result_ctxt.temp_ = new vector_holder(vec_holder1,vds); + else + { + result_ctxt.temp_ = (vec_holder0.base_size() >= vec_holder1.base_size()) ? + new vector_holder(vec_holder0, vds) : + new vector_holder(vec_holder1, vds) ; + } + + result_ctxt.temp_vec_node_ = new vector_node (vds,result_ctxt.temp_); + return result_ctxt; + } + template class vec_binop_vecvec_node exprtk_final : public binary_node @@ -11251,8 +13511,10 @@ namespace exprtk typedef expression_node* expression_ptr; typedef vector_node* vector_node_ptr; - typedef vector_holder* vector_holder_ptr; + typedef vector_holder vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; typedef vec_data_store vds_t; + typedef memory_context_t memory_context; using binary_node::branch; @@ -11262,8 +13524,6 @@ namespace exprtk : binary_node(opr, branch0, branch1) , vec0_node_ptr_(0) , vec1_node_ptr_(0) - , temp_ (0) - , temp_vec_node_(0) , initialised_(false) { bool v0_is_ivec = false; @@ -11304,104 +13564,102 @@ namespace exprtk vector_holder& vec0 = vec0_node_ptr_->vec_holder(); vector_holder& 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(vds().data(),vds().size()); - temp_vec_node_ = new vector_node (vds(),temp_); + memory_context_ = make_memory_context(vec0, vec1, vds()); - initialised_ = true; + initialised_ = + (size() <= base_size()) && + binary_node::valid(); } - assert(initialised_); + assert(valid()); } ~vec_binop_vecvec_node() { - delete temp_; - delete temp_vec_node_; + memory_context_.clear(); } inline T value() const exprtk_override { - if (initialised_) - { - assert(branch(0)); - assert(branch(1)); - - branch(0)->value(); - branch(1)->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::quiet_NaN(); + return (vds().data())[0]; } vector_node_ptr vec() const exprtk_override { - return temp_vec_node_; + return memory_context_.temp_vec_node_; } vector_node_ptr vec() exprtk_override { - return temp_vec_node_; + return memory_context_.temp_vec_node_; } inline typename expression_node::node_type type() const exprtk_override @@ -11409,9 +13667,23 @@ namespace exprtk return expression_node::e_vecvecarith; } + 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()); + } + + 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 @@ -11426,12 +13698,11 @@ namespace exprtk 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 @@ -11443,8 +13714,10 @@ namespace exprtk typedef expression_node* expression_ptr; typedef vector_node* vector_node_ptr; - typedef vector_holder* vector_holder_ptr; + typedef vector_holder vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; typedef vec_data_store vds_t; + typedef memory_context_t memory_context; using binary_node::branch; @@ -11453,8 +13726,6 @@ namespace exprtk expression_ptr branch1) : binary_node(opr, branch0, branch1) , vec0_node_ptr_(0) - , temp_ (0) - , temp_vec_node_(0) { bool v0_is_ivec = false; @@ -11478,93 +13749,84 @@ 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(vds()); - temp_vec_node_ = new vector_node (vds(),temp_); + memory_context_ = make_memory_context(vec0_node_ptr_->vec_holder(), vds()); } + + assert(valid()); } ~vec_binop_vecval_node() { - delete temp_; - delete temp_vec_node_; + memory_context_.clear(); } inline T value() const exprtk_override { - if (vec0_node_ptr_) - { - assert(branch(0)); - assert(branch(1)); - - branch(0)->value(); - const T v = branch(1)->value(); + branch(0)->value(); + const T v = branch(1)->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::quiet_NaN(); + return (vds().data())[0]; } vector_node_ptr vec() const exprtk_override { - return temp_vec_node_; + return memory_context_.temp_vec_node_; } vector_node_ptr vec() exprtk_override { - return temp_vec_node_; + return memory_context_.temp_vec_node_; } inline typename expression_node::node_type type() const exprtk_override @@ -11572,9 +13834,22 @@ namespace exprtk return expression_node::e_vecvalarith; } + inline bool valid() const exprtk_override + { + return + vec0_node_ptr_ && + (size() <= base_size()) && + binary_node::valid(); + } + std::size_t size() const exprtk_override { - return vds().size(); + return vec0_node_ptr_->size(); + } + + std::size_t base_size() const exprtk_override + { + return vec0_node_ptr_->vec_holder().base_size(); } vds_t& vds() exprtk_override @@ -11590,9 +13865,8 @@ 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 @@ -11604,8 +13878,10 @@ namespace exprtk typedef expression_node* expression_ptr; typedef vector_node* vector_node_ptr; - typedef vector_holder* vector_holder_ptr; + typedef vector_holder vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; typedef vec_data_store vds_t; + typedef memory_context_t memory_context; using binary_node::branch; @@ -11614,8 +13890,6 @@ namespace exprtk expression_ptr branch1) : binary_node(opr, branch0, branch1) , vec1_node_ptr_(0) - , temp_ (0) - , temp_vec_node_(0) { bool v1_is_ivec = false; @@ -11639,93 +13913,84 @@ 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(vds()); - temp_vec_node_ = new vector_node (vds(),temp_); + memory_context_ = make_memory_context(vec1_node_ptr_->vec_holder(), vds()); } + + assert(valid()); } ~vec_binop_valvec_node() { - delete temp_; - delete temp_vec_node_; + memory_context_.clear(); } inline T value() const exprtk_override { - if (vec1_node_ptr_) - { - assert(branch(0)); - assert(branch(1)); - - const T v = branch(0)->value(); - branch(1)->value(); + const T v = branch(0)->value(); + branch(1)->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::quiet_NaN(); + return (vds().data())[0]; } vector_node_ptr vec() const exprtk_override { - return temp_vec_node_; + return memory_context_.temp_vec_node_; } vector_node_ptr vec() exprtk_override { - return temp_vec_node_; + return memory_context_.temp_vec_node_; } inline typename expression_node::node_type type() const exprtk_override @@ -11733,9 +13998,23 @@ namespace exprtk return expression_node::e_vecvalarith; } + inline bool valid() const exprtk_override + { + return + vec1_node_ptr_ && + (size() <= base_size()) && + (vds_.size() <= base_size()) && + binary_node::valid(); + } + std::size_t size() const exprtk_override { - return vds().size(); + return vec1_node_ptr_->vec_holder().size(); + } + + std::size_t base_size() const exprtk_override + { + return vec1_node_ptr_->vec_holder().base_size(); } vds_t& vds() exprtk_override @@ -11751,9 +14030,8 @@ 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 @@ -11765,28 +14043,28 @@ namespace exprtk typedef expression_node* expression_ptr; typedef vector_node* vector_node_ptr; - typedef vector_holder* vector_holder_ptr; + typedef vector_holder vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; typedef vec_data_store vds_t; + typedef memory_context_t memory_context; using expression_node::branch; unary_vector_node(const operator_type& opr, expression_ptr branch0) : unary_node(opr, branch0) , vec0_node_ptr_(0) - , temp_ (0) - , temp_vec_node_(0) { bool vec0_is_ivec = false; - if (is_vector_node(branch())) + if (is_vector_node(branch(0))) { - vec0_node_ptr_ = static_cast(branch()); + vec0_node_ptr_ = static_cast(branch(0)); } - else if (is_ivector_node(branch())) + else if (is_ivector_node(branch(0))) { vector_interface* vi = reinterpret_cast*>(0); - if (0 != (vi = dynamic_cast*>(branch()))) + if (0 != (vi = dynamic_cast*>(branch(0)))) { vec0_node_ptr_ = vi->vec(); vec0_is_ivec = true; @@ -11798,91 +14076,84 @@ 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(vds()); - temp_vec_node_ = new vector_node (vds(),temp_); + memory_context_ = make_memory_context(vec0_node_ptr_->vec_holder(), vds()); } + + assert(valid()); } ~unary_vector_node() { - delete temp_; - delete temp_vec_node_; + memory_context_.clear(); } inline T value() const exprtk_override { - assert(branch()); - branch()->value(); - if (vec0_node_ptr_) - { - 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]); \ + while (vec0 < upper_bound) + { + #define exprtk_loop(N) \ + vec1[N] = Operation::process(vec0[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 : { vec1[i] = Operation::process(vec0[i]); ++i; } \ + switch (lud.remainder) + { + #define case_stmt(N) \ + case N : { vec1[i] = Operation::process(vec0[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::quiet_NaN(); + return (vds().data())[0]; } vector_node_ptr vec() const exprtk_override { - return temp_vec_node_; + return memory_context_.temp_vec_node_; } vector_node_ptr vec() exprtk_override { - return temp_vec_node_; + return memory_context_.temp_vec_node_; } inline typename expression_node::node_type type() const exprtk_override @@ -11890,9 +14161,19 @@ namespace exprtk return expression_node::e_vecunaryop; } + inline bool valid() const exprtk_override + { + return vec0_node_ptr_ && unary_node::valid(); + } + std::size_t size() const exprtk_override { - return vds().size(); + 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 @@ -11907,10 +14188,9 @@ namespace exprtk private: - vector_node_ptr vec0_node_ptr_; - vector_holder_ptr temp_; - vector_node_ptr temp_vec_node_; - vds_t vds_; + vector_node_ptr vec0_node_ptr_; + vds_t vds_; + memory_context memory_context_; }; template @@ -11923,8 +14203,10 @@ namespace exprtk typedef expression_node * expression_ptr; typedef vector_interface* vec_interface_ptr; typedef vector_node * vector_node_ptr; - typedef vector_holder * vector_holder_ptr; + typedef vector_holder vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; typedef vec_data_store vds_t; + typedef memory_context_t memory_context; typedef std::pair branch_t; conditional_vector_node(expression_ptr condition, @@ -11934,7 +14216,7 @@ namespace exprtk , alternative_node_ptr_(0) , temp_vec_node_ (0) , temp_ (0) - , vec_size_ (0) + , result_vec_size_ (0) , initialised_ (false) { construct_branch_pair(condition_ , condition ); @@ -11963,67 +14245,62 @@ namespace exprtk if (consequent_node_ptr_ && alternative_node_ptr_) { - vec_size_ = std::min(consequent_node_ptr_ ->vds().size(), - alternative_node_ptr_->vds().size()); + 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_); - temp_ = new vector_holder(vds_); - temp_vec_node_ = new vector_node (vds(),temp_); + vds_ = vds_t(vec_size); + memory_context_ = make_memory_context( + consequent_node_ptr_ ->vec_holder(), + alternative_node_ptr_->vec_holder(), + vds()); - initialised_ = true; + initialised_ = (vec_size > 0); } - assert(initialised_ && (vec_size_ > 0)); + assert(initialised_); } ~conditional_vector_node() { - delete temp_; - delete temp_vec_node_; + memory_context_.clear(); } inline T value() const exprtk_override { - if (initialised_) - { - assert(condition_ .first); - assert(consequent_ .first); - assert(alternative_.first); - - T result = T(0); - T* source_vector = 0; - T* result_vector = vds().data(); - - if (is_true(condition_)) - { - result = consequent_.first->value(); - source_vector = consequent_node_ptr_->vds().data(); - } - else - { - result = alternative_.first->value(); - source_vector = alternative_node_ptr_->vds().data(); - } + T result = T(0); + T* source_vector = 0; + T* result_vector = vds().data(); - for (std::size_t i = 0; i < vec_size_; ++i) - { - result_vector[i] = source_vector[i]; - } + if (is_true(condition_)) + { + result = consequent_.first->value(); + source_vector = consequent_node_ptr_->vds().data(); + result_vec_size_ = consequent_node_ptr_->size(); + } + else + { + result = alternative_.first->value(); + source_vector = alternative_node_ptr_->vds().data(); + result_vec_size_ = alternative_node_ptr_->size(); + } - return result; + for (std::size_t i = 0; i < result_vec_size_; ++i) + { + result_vector[i] = source_vector[i]; } - return std::numeric_limits::quiet_NaN(); + return result; } vector_node_ptr vec() const exprtk_override { - return temp_vec_node_; + return memory_context_.temp_vec_node_; } vector_node_ptr vec() exprtk_override { - return temp_vec_node_; + return memory_context_.temp_vec_node_; } inline typename expression_node::node_type type() const exprtk_override @@ -12031,9 +14308,26 @@ namespace exprtk return expression_node::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 vec_size_; + return result_vec_size_; + } + + std::size_t base_size() const exprtk_override + { + return std::min( + consequent_node_ptr_ ->vec_holder().base_size(), + alternative_node_ptr_->vec_holder().base_size()); } vds_t& vds() exprtk_override @@ -12061,16 +14355,17 @@ namespace exprtk private: - 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_; - std::size_t vec_size_; - bool initialised_; + 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 @@ -12085,13 +14380,12 @@ namespace exprtk expression_ptr branch0, expression_ptr branch1) : binary_node(opr, branch0, branch1) - {} + { + assert(binary_node::valid()); + } inline T value() const exprtk_override { - assert(branch(0)); - assert(branch(1)); - return ( std::not_equal_to() (T(0),branch(0)->value()) && @@ -12113,13 +14407,12 @@ namespace exprtk expression_ptr branch0, expression_ptr branch1) : binary_node(opr, branch0, branch1) - {} + { + assert(binary_node::valid()); + } inline T value() const exprtk_override { - assert(branch(0)); - assert(branch(1)); - return ( std::not_equal_to() (T(0),branch(0)->value()) || @@ -12134,7 +14427,7 @@ namespace exprtk { public: - // Function of N paramters. + // Function of N parameters. typedef expression_node* expression_ptr; typedef std::pair branch_t; typedef IFunction ifunction; @@ -12142,6 +14435,7 @@ namespace exprtk explicit function_N_node(ifunction* func) : function_((N == func->param_count) ? func : reinterpret_cast(0)) , parameter_count_(func->param_count) + , initialised_(false) {} template @@ -12152,19 +14446,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 @@ -12182,14 +14481,11 @@ namespace exprtk #pragma warning(push) #pragma warning(disable: 4127) #endif - if ((0 == function_) || (0 == N)) - return std::numeric_limits::quiet_NaN(); - else - { - T v[N]; - evaluate_branches::execute(v,branch_); - return invoke::execute(*function_,v); - } + + T v[N]; + evaluate_branches::execute(v,branch_); + return invoke::execute(*function_,v); + #ifdef _MSC_VER #pragma warning(pop) #endif @@ -12200,9 +14496,14 @@ namespace exprtk return expression_node::e_function; } + inline bool valid() const exprtk_override + { + return initialised_; + } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { - expression_node::ndb_t::template collect(branch_, node_delete_list); + expression_node::ndb_t::collect(branch_, node_delete_list); } std::size_t node_depth() const exprtk_override @@ -12222,6 +14523,20 @@ namespace exprtk } }; + template + struct evaluate_branches + { + 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 struct evaluate_branches { @@ -12425,6 +14740,7 @@ namespace exprtk ifunction* function_; std::size_t parameter_count_; branch_t branch_[N]; + bool initialised_; }; template @@ -12437,7 +14753,9 @@ namespace exprtk explicit function_N_node(ifunction* func) : function_((0 == func->param_count) ? func : reinterpret_cast(0)) - {} + { + assert(valid()); + } inline bool operator <(const function_N_node& fn) const { @@ -12446,10 +14764,7 @@ namespace exprtk inline T value() const exprtk_override { - if (function_) - return (*function_)(); - else - return std::numeric_limits::quiet_NaN(); + return (*function_)(); } inline typename expression_node::node_type type() const exprtk_override @@ -12457,6 +14772,11 @@ namespace exprtk return expression_node::e_function; } + inline bool valid() const exprtk_override + { + return function_; + } + private: ifunction* function_; @@ -12475,6 +14795,7 @@ namespace exprtk , arg_list_(arg_list) { value_list_.resize(arg_list.size(),std::numeric_limits::quiet_NaN()); + assert(valid()); } inline bool operator <(const vararg_function_node& fn) const @@ -12484,13 +14805,8 @@ namespace exprtk inline T value() const exprtk_override { - if (function_) - { - populate_value_list(); - return (*function_)(value_list_); - } - else - return std::numeric_limits::quiet_NaN(); + populate_value_list(); + return (*function_)(value_list_); } inline typename expression_node::node_type type() const exprtk_override @@ -12498,6 +14814,11 @@ namespace exprtk return expression_node::e_vafunction; } + inline bool valid() const exprtk_override + { + return function_; + } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { for (std::size_t i = 0; i < arg_list_.size(); ++i) @@ -12545,7 +14866,8 @@ namespace exprtk typedef typename range_interface::range_t range_t; typedef std::pair branch_t; - typedef std::pair void_t; + typedef vector_holder* vh_t; + typedef vector_view* vecview_t; typedef std::vector tmp_vs_t; typedef std::vector typestore_list_t; @@ -12557,7 +14879,18 @@ namespace exprtk , arg_list_(arg_list) {} - virtual ~generic_function_node() {} + virtual ~generic_function_node() + { + 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::noderef_list_t& node_delete_list) exprtk_override { @@ -12571,10 +14904,11 @@ namespace exprtk 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(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(0),false)); + vv_list_ .resize(arg_list_.size(), vecview_t(0)); for (std::size_t i = 0; i < arg_list_.size(); ++i) { @@ -12592,7 +14926,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])) @@ -12628,7 +14970,10 @@ namespace exprtk range_list_[i].range = reinterpret_cast(0); } else + { range_list_[i].range = &(ri->range_ref()); + range_param_list_.push_back(i); + } } #endif else if (is_variable_node(arg_list_[i])) @@ -12662,14 +15007,11 @@ namespace exprtk 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::quiet_NaN(); @@ -12680,6 +15022,11 @@ namespace exprtk return expression_node::e_genfunction; } + inline bool valid() const exprtk_override + { + return function_; + } + protected: inline virtual bool populate_value_list() const @@ -12689,30 +15036,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(rdt.str_node->base()) + rp.cache.first; - else - #endif - ts.data = static_cast(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(rdt.str_node->base()) + rp.cache.first; else - return false; + #endif + ts.data = static_cast(rdt.data) + (rp.cache.first * rdt.type_size); } } @@ -12725,16 +15082,18 @@ namespace exprtk private: std::vector arg_list_; - std::vector branch_; - mutable tmp_vs_t expr_as_vec1_store_; - mutable range_list_t range_list_; + std::vector branch_; + std::vector vv_list_; + mutable tmp_vs_t expr_as_vec1_store_; + mutable range_list_t range_list_; + std::vector range_param_list_; }; #ifndef exprtk_disable_string_capabilities template - class string_function_node : public generic_function_node, - public string_base_node, - public range_interface + class string_function_node : public generic_function_node + , public string_base_node + , public range_interface { public: @@ -12749,6 +15108,7 @@ namespace exprtk range_.n1_c = std::make_pair(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& fn) const @@ -12758,23 +15118,21 @@ namespace exprtk 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::quiet_NaN(); @@ -12785,6 +15143,11 @@ namespace exprtk return expression_node::e_strfunction; } + inline bool valid() const exprtk_override + { + return gen_function_t::function_; + } + std::string str() const exprtk_override { return ret_string_; @@ -12834,18 +15197,18 @@ namespace exprtk 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::quiet_NaN(); @@ -12879,24 +15242,22 @@ namespace exprtk 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::quiet_NaN(); @@ -12913,15 +15274,15 @@ namespace exprtk }; #endif - class return_exception - {}; + class return_exception {}; template class null_igenfunc { public: - virtual ~null_igenfunc() {} + virtual ~null_igenfunc() + {} typedef type_store generic_type; typedef typename generic_type::parameter_list parameter_list_t; @@ -12947,14 +15308,13 @@ namespace exprtk results_context_t& rc) : gen_function_t (arg_list) , results_context_(&rc) - {} + { + assert(valid()); + } 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::parameter_list parameter_list_t; @@ -12972,6 +15332,11 @@ namespace exprtk return expression_node::e_return; } + inline bool valid() const exprtk_override + { + return results_context_; + } + private: results_context_t* results_context_; @@ -12991,12 +15356,11 @@ namespace exprtk , return_invoked_ (false) { construct_branch_pair(body_, body); + assert(valid()); } inline T value() const exprtk_override { - assert(body_.first); - try { return_invoked_ = false; @@ -13007,6 +15371,7 @@ namespace exprtk catch(const return_exception&) { return_invoked_ = true; + return std::numeric_limits::quiet_NaN(); } } @@ -13016,6 +15381,11 @@ namespace exprtk return expression_node::e_retenv; } + inline bool valid() const exprtk_override + { + return results_context_ && body_.first; + } + inline bool* retinvk_ptr() { return &return_invoked_; @@ -13400,7 +15770,7 @@ namespace exprtk } template - struct vararg_add_op : public opr_base + struct vararg_add_op exprtk_final : public opr_base { typedef typename opr_base::Type Type; @@ -13423,7 +15793,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; @@ -13467,7 +15837,7 @@ namespace exprtk }; template - struct vararg_mul_op : public opr_base + struct vararg_mul_op exprtk_final : public opr_base { typedef typename opr_base::Type Type; @@ -13534,7 +15904,7 @@ namespace exprtk }; template - struct vararg_avg_op : public opr_base + struct vararg_avg_op exprtk_final : public opr_base { typedef typename opr_base::Type Type; @@ -13590,7 +15960,7 @@ namespace exprtk }; template - struct vararg_min_op : public opr_base + struct vararg_min_op exprtk_final : public opr_base { typedef typename opr_base::Type Type; @@ -13661,7 +16031,7 @@ namespace exprtk }; template - struct vararg_max_op : public opr_base + struct vararg_max_op exprtk_final : public opr_base { typedef typename opr_base::Type Type; @@ -13732,7 +16102,7 @@ namespace exprtk }; template - struct vararg_mand_op : public opr_base + struct vararg_mand_op exprtk_final : public opr_base { typedef typename opr_base::Type Type; @@ -13812,7 +16182,7 @@ namespace exprtk }; template - struct vararg_mor_op : public opr_base + struct vararg_mor_op exprtk_final : public opr_base { typedef typename opr_base::Type Type; @@ -13892,7 +16262,7 @@ namespace exprtk }; template - struct vararg_multi_op : public opr_base + struct vararg_multi_op exprtk_final : public opr_base { typedef typename opr_base::Type Type; @@ -13913,14 +16283,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()); + } } } @@ -14009,7 +16378,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); @@ -14018,24 +16387,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 @@ -14070,24 +16439,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 @@ -14110,7 +16478,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); @@ -14119,24 +16487,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 @@ -14171,33 +16538,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 ; } @@ -14210,7 +16576,7 @@ namespace exprtk static inline T process(const ivector_ptr v) { - const T vec_size = T(v->vec()->vds().size()); + const T vec_size = T(v->vec()->size()); return vec_add_op::process(v) / vec_size; } }; @@ -14223,7 +16589,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]; @@ -14247,7 +16613,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]; @@ -14268,7 +16634,8 @@ namespace exprtk { public: - virtual ~vov_base_node() {} + virtual ~vov_base_node() + {} inline virtual operator_type operation() const { @@ -14285,7 +16652,8 @@ namespace exprtk { public: - virtual ~cov_base_node() {} + virtual ~cov_base_node() + {} inline virtual operator_type operation() const { @@ -14302,7 +16670,8 @@ namespace exprtk { public: - virtual ~voc_base_node() {} + virtual ~voc_base_node() + {} inline virtual operator_type operation() const { @@ -14319,7 +16688,8 @@ namespace exprtk { public: - virtual ~vob_base_node() {} + virtual ~vob_base_node() + {} virtual const T& v() const = 0; }; @@ -14329,7 +16699,8 @@ namespace exprtk { public: - virtual ~bov_base_node() {} + virtual ~bov_base_node() + {} virtual const T& v() const = 0; }; @@ -14339,7 +16710,8 @@ namespace exprtk { public: - virtual ~cob_base_node() {} + virtual ~cob_base_node() + {} inline virtual operator_type operation() const { @@ -14358,7 +16730,8 @@ namespace exprtk { public: - virtual ~boc_base_node() {} + virtual ~boc_base_node() + {} inline virtual operator_type operation() const { @@ -14377,7 +16750,8 @@ namespace exprtk { public: - virtual ~uv_base_node() {} + virtual ~uv_base_node() + {} inline virtual operator_type operation() const { @@ -14392,7 +16766,8 @@ namespace exprtk { public: - virtual ~sos_base_node() {} + virtual ~sos_base_node() + {} inline virtual operator_type operation() const { @@ -14405,7 +16780,8 @@ namespace exprtk { public: - virtual ~sosos_base_node() {} + virtual ~sosos_base_node() + {} inline virtual operator_type operation() const { @@ -14418,7 +16794,8 @@ namespace exprtk { public: - virtual ~T0oT1oT2_base_node() {} + virtual ~T0oT1oT2_base_node() + {} virtual std::string type_id() const = 0; }; @@ -14428,7 +16805,8 @@ namespace exprtk { public: - virtual ~T0oT1oT2oT3_base_node() {} + virtual ~T0oT1oT2oT3_base_node() + {} virtual std::string type_id() const = 0; }; @@ -14564,6 +16942,11 @@ namespace exprtk return Operation::type(); } + inline bool valid() const exprtk_override + { + return branch_.first && branch_.first->valid(); + } + inline operator_type operation() { return Operation::operation(); @@ -15186,7 +17569,8 @@ namespace exprtk { public: - virtual ~sf3ext_type_node() {} + virtual ~sf3ext_type_node() + {} virtual T0 t0() const = 0; @@ -15644,16 +18028,16 @@ namespace exprtk typedef std::pair 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 exprtk_override { - assert(branch_.first); return Operation::process(v_,branch_.first->value()); } @@ -15662,6 +18046,11 @@ namespace exprtk return v_; } + inline bool valid() const exprtk_override + { + return branch_.first && branch_.first->valid(); + } + inline expression_node* branch(const std::size_t&) const exprtk_override { return branch_.first; @@ -15669,7 +18058,7 @@ namespace exprtk void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { - expression_node::ndb_t::template collect(branch_, node_delete_list); + expression_node::ndb_t::collect(branch_, node_delete_list); } std::size_t node_depth() const exprtk_override @@ -15695,16 +18084,16 @@ namespace exprtk typedef std::pair 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 exprtk_override { - assert(branch_.first); return Operation::process(branch_.first->value(),v_); } @@ -15713,6 +18102,11 @@ namespace exprtk return v_; } + inline bool valid() const exprtk_override + { + return branch_.first && branch_.first->valid(); + } + inline expression_node* branch(const std::size_t&) const exprtk_override { return branch_.first; @@ -15720,7 +18114,7 @@ namespace exprtk void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { - expression_node::ndb_t::template collect(branch_, node_delete_list); + expression_node::ndb_t::collect(branch_, node_delete_list); } std::size_t node_depth() const exprtk_override @@ -15746,16 +18140,16 @@ namespace exprtk typedef std::pair 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 exprtk_override { - assert(branch_.first); return Operation::process(c_,branch_.first->value()); } @@ -15774,6 +18168,11 @@ namespace exprtk (*const_cast(&c_)) = new_c; } + inline bool valid() const exprtk_override + { + return branch_.first && branch_.first->valid(); + } + inline expression_node* branch(const std::size_t&) const exprtk_override { return branch_.first; @@ -15787,7 +18186,7 @@ namespace exprtk void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { - expression_node::ndb_t::template collect(branch_, node_delete_list); + expression_node::ndb_t::collect(branch_, node_delete_list); } std::size_t node_depth() const exprtk_override @@ -15813,16 +18212,16 @@ namespace exprtk typedef std::pair 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 exprtk_override { - assert(branch_.first); return Operation::process(branch_.first->value(),c_); } @@ -15841,6 +18240,11 @@ namespace exprtk (*const_cast(&c_)) = new_c; } + inline bool valid() const exprtk_override + { + return branch_.first && branch_.first->valid(); + } + inline expression_node* branch(const std::size_t&) const exprtk_override { return branch_.first; @@ -15854,7 +18258,7 @@ namespace exprtk void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { - expression_node::ndb_t::template collect(branch_, node_delete_list); + expression_node::ndb_t::collect(branch_, node_delete_list); } std::size_t node_depth() const exprtk_override @@ -16013,7 +18417,13 @@ namespace exprtk 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); } @@ -16085,10 +18495,11 @@ 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); @@ -16149,6 +18560,7 @@ namespace exprtk , str1_base_ptr_ (0) , str0_range_ptr_(0) , str1_range_ptr_(0) + , initialised_ (false) { if (is_generally_string_node(branch(0))) { @@ -16179,39 +18591,40 @@ namespace exprtk 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 exprtk_override { - if ( - str0_base_ptr_ && - str1_base_ptr_ && - str0_range_ptr_ && - str1_range_ptr_ - ) - { - branch(0)->value(); - branch(1)->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::quiet_NaN(); @@ -16222,6 +18635,11 @@ namespace exprtk return Operation::type(); } + inline bool valid() const exprtk_override + { + return initialised_; + } + private: str_sogens_node(const str_sogens_node&) exprtk_delete; @@ -16231,6 +18649,7 @@ namespace exprtk str_base_ptr str1_base_ptr_; range_ptr str0_range_ptr_; range_ptr str1_range_ptr_; + bool initialised_; }; template @@ -16242,7 +18661,7 @@ namespace exprtk typedef Operation operation_t; typedef sosos_node 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) @@ -16334,11 +18753,11 @@ namespace exprtk explicit bipow_node(expression_ptr branch) { construct_branch_pair(branch_, branch); + assert(valid()); } inline T value() const exprtk_override { - assert(branch_.first); return PowOp::result(branch_.first->value()); } @@ -16347,6 +18766,11 @@ namespace exprtk return expression_node::e_ipow; } + inline bool valid() const exprtk_override + { + return branch_.first && branch_.first->valid(); + } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::collect(branch_, node_delete_list); @@ -16396,7 +18820,7 @@ namespace exprtk }; template - class bipowninv_node exprtk_final : public expression_node + class bipowinv_node exprtk_final : public expression_node { public: @@ -16404,14 +18828,14 @@ namespace exprtk typedef std::pair 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 exprtk_override { - assert(branch_.first); return (T(1) / PowOp::result(branch_.first->value())); } @@ -16420,9 +18844,14 @@ namespace exprtk return expression_node::e_ipowinv; } + inline bool valid() const exprtk_override + { + return branch_.first && branch_.first->valid(); + } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { - expression_node::ndb_t::template collect(branch_, node_delete_list); + expression_node::ndb_t::collect(branch_, node_delete_list); } std::size_t node_depth() const exprtk_override @@ -16432,8 +18861,8 @@ namespace exprtk private: - bipowninv_node(const bipowninv_node&) exprtk_delete; - bipowninv_node& operator=(const bipowninv_node&) exprtk_delete; + bipowinv_node(const bipowinv_node&) exprtk_delete; + bipowinv_node& operator=(const bipowinv_node&) exprtk_delete; branch_t branch_; }; @@ -17117,7 +19546,8 @@ namespace exprtk : param_count(pc) {} - virtual ~ifunction() {} + virtual ~ifunction() + {} #define empty_method_body(N) \ { \ @@ -17208,7 +19638,8 @@ namespace exprtk { public: - virtual ~ivararg_function() {} + virtual ~ivararg_function() + {} inline virtual T operator() (const std::vector&) { @@ -17233,12 +19664,13 @@ namespace exprtk typedef type_store 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) + 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() {} + virtual ~igeneric_function() + {} #define igeneric_function_empty_body(N) \ { \ @@ -17262,6 +19694,8 @@ 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; }; @@ -17765,7 +20199,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(&(p->ref())), ptr)); return (&(p->ref()) == ptr); } }; @@ -18029,7 +20463,7 @@ namespace exprtk public: - symbol_table(const symtab_mutability_type mutability = e_mutable) + explicit symbol_table(const symtab_mutability_type mutability = e_mutable) : control_block_(control_block::create()) { control_block_->set_mutability(mutability); @@ -18508,6 +20942,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* 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 inline bool add_vector(const std::string& vector_name, T (&v)[N]) { @@ -18682,12 +21144,48 @@ namespace exprtk template class Sequence> - inline std::size_t get_vector_list(Sequence& vlist) const + inline std::size_t get_vector_list(Sequence& 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 class Sequence> + inline std::size_t get_function_list(Sequence& function_list) const + { + if (!valid()) + return 0; + + std::vector 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 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 get_function_list() const + { + std::vector result; + get_function_list(result); + return result; } inline bool symbol_exists(const std::string& symbol_name, const bool check_reserved_symb = true) const @@ -18878,6 +21376,38 @@ namespace exprtk } } + inline void load_variables_from(const symbol_table& st) + { + std::vector 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& st) + { + std::vector 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 @@ -18973,6 +21503,21 @@ 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() @@ -19178,17 +21723,18 @@ namespace exprtk return details::is_true(value()); } - inline void register_symbol_table(symbol_table& st) + inline bool register_symbol_table(symbol_table& st) { for (std::size_t i = 0; i < symbol_table_list_.size(); ++i) { - if (&st == &symbol_table_list_[i]) + if (st == symbol_table_list_[i]) { - return; + return false; } } symbol_table_list_.push_back(st); + return true; } inline const symbol_table& get_symbol_table(const std::size_t& index = 0) const @@ -19201,6 +21747,11 @@ namespace exprtk return symbol_table_list_[index]; } + std::size_t num_symbol_tables() const + { + return symbol_table_list_.size(); + } + typedef results_context results_context_t; inline const results_context_t& results() const @@ -19330,6 +21881,8 @@ namespace exprtk friend class parser; friend class expression_helper; friend class function_compositor; + template + friend bool is_valid(const expression& expr); }; // class expression template @@ -19337,55 +21890,165 @@ namespace exprtk { public: - static inline bool is_constant(const expression& expr) + enum node_types { - return details::is_constant_node(expr.control_block_->expr); + 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& expr) + { + return expr.control_block_ && details::is_literal_node(expr.control_block_->expr); } static inline bool is_variable(const expression& 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& expr) + { + return expr.control_block_ && details::is_generally_string_node(expr.control_block_->expr); } static inline bool is_unary(const expression& 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& 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& 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& expr) + { + return expr.control_block_ && details::is_vararg_node(expr.control_block_->expr); } static inline bool is_null(const expression& 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& expr) + { + return expr.control_block_ && details::is_assert_node(expr.control_block_->expr); + } + + static inline bool is_sf3ext(const expression& expr) + { + return expr.control_block_ && details::is_sf3ext_node(expr.control_block_->expr); + } + + static inline bool is_sf4ext(const expression& expr) + { + return expr.control_block_ && details::is_sf4ext_node(expr.control_block_->expr); + } + + static inline bool is_type(const expression& 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& expr, const std::vector& type_seq) + { + if ((0 == expr.control_block_) || !is_vararg(expr)) + { + return false; + } + + typedef details::vararg_node > mo_vararg_t; + + mo_vararg_t* vnode = dynamic_cast(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 inline bool is_valid(const expression& expr) { - return !expression_helper::is_null(expr); + return expr.control_block_ && !expression_helper::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 @@ -19414,7 +22077,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; } @@ -19428,7 +22091,7 @@ namespace exprtk 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; } @@ -19520,70 +22183,79 @@ namespace exprtk e_level10, e_level11, e_level12, e_level13, e_level14 }; - typedef const T& cref_t; - typedef const T const_t; - typedef ifunction F; - typedef ivararg_function VAF; - typedef igeneric_function GF; - typedef ifunction ifunction_t; - typedef ivararg_function ivararg_function_t; - typedef igeneric_function igeneric_function_t; - typedef details::expression_node expression_node_t; - typedef details::literal_node literal_node_t; - typedef details::unary_node unary_node_t; - typedef details::binary_node binary_node_t; - typedef details::trinary_node trinary_node_t; - typedef details::quaternary_node quaternary_node_t; - typedef details::conditional_node conditional_node_t; - typedef details::cons_conditional_node cons_conditional_node_t; - typedef details::while_loop_node while_loop_node_t; - typedef details::repeat_until_loop_node repeat_until_loop_node_t; - typedef details::for_loop_node for_loop_node_t; - typedef details::while_loop_rtc_node while_loop_rtc_node_t; - typedef details::repeat_until_loop_rtc_node repeat_until_loop_rtc_node_t; - typedef details::for_loop_rtc_node for_loop_rtc_node_t; + typedef const T& cref_t; + typedef const T const_t; + typedef ifunction F; + typedef ivararg_function VAF; + typedef igeneric_function GF; + typedef ifunction ifunction_t; + typedef ivararg_function ivararg_function_t; + typedef igeneric_function igeneric_function_t; + typedef details::expression_node expression_node_t; + typedef details::literal_node literal_node_t; + typedef details::unary_node unary_node_t; + typedef details::binary_node binary_node_t; + typedef details::trinary_node trinary_node_t; + typedef details::quaternary_node quaternary_node_t; + typedef details::conditional_node conditional_node_t; + typedef details::cons_conditional_node cons_conditional_node_t; + typedef details::while_loop_node while_loop_node_t; + typedef details::repeat_until_loop_node repeat_until_loop_node_t; + typedef details::for_loop_node for_loop_node_t; + typedef details::while_loop_rtc_node while_loop_rtc_node_t; + typedef details::repeat_until_loop_rtc_node repeat_until_loop_rtc_node_t; + typedef details::for_loop_rtc_node for_loop_rtc_node_t; #ifndef exprtk_disable_break_continue - typedef details::while_loop_bc_node while_loop_bc_node_t; - typedef details::repeat_until_loop_bc_node repeat_until_loop_bc_node_t; - typedef details::for_loop_bc_node for_loop_bc_node_t; - typedef details::while_loop_bc_rtc_node while_loop_bc_rtc_node_t; - typedef details::repeat_until_loop_bc_rtc_node repeat_until_loop_bc_rtc_node_t; - typedef details::for_loop_bc_rtc_node for_loop_bc_rtc_node_t; + typedef details::while_loop_bc_node while_loop_bc_node_t; + typedef details::repeat_until_loop_bc_node repeat_until_loop_bc_node_t; + typedef details::for_loop_bc_node for_loop_bc_node_t; + typedef details::while_loop_bc_rtc_node while_loop_bc_rtc_node_t; + typedef details::repeat_until_loop_bc_rtc_node repeat_until_loop_bc_rtc_node_t; + typedef details::for_loop_bc_rtc_node for_loop_bc_rtc_node_t; #endif - typedef details::switch_node switch_node_t; - typedef details::variable_node variable_node_t; - typedef details::vector_elem_node vector_elem_node_t; - typedef details::rebasevector_elem_node rebasevector_elem_node_t; - typedef details::rebasevector_celem_node rebasevector_celem_node_t; - typedef details::vector_node vector_node_t; - typedef details::range_pack range_t; + typedef details::switch_node switch_node_t; + typedef details::variable_node variable_node_t; + typedef details::vector_elem_node vector_elem_node_t; + typedef details::vector_celem_node vector_celem_node_t; + typedef details::vector_elem_rtc_node vector_elem_rtc_node_t; + typedef details::vector_celem_rtc_node vector_celem_rtc_node_t; + typedef details::rebasevector_elem_node rebasevector_elem_node_t; + typedef details::rebasevector_celem_node rebasevector_celem_node_t; + typedef details::rebasevector_elem_rtc_node rebasevector_elem_rtc_node_t; + typedef details::rebasevector_celem_rtc_node rebasevector_celem_rtc_node_t; + typedef details::vector_node vector_node_t; + typedef details::vector_size_node vector_size_node_t; + typedef details::range_pack range_t; #ifndef exprtk_disable_string_capabilities - typedef details::stringvar_node stringvar_node_t; - typedef details::string_literal_node string_literal_node_t; - typedef details::string_range_node string_range_node_t; - typedef details::const_string_range_node const_string_range_node_t; - typedef details::generic_string_range_node generic_string_range_node_t; - typedef details::string_concat_node string_concat_node_t; - typedef details::assignment_string_node assignment_string_node_t; - typedef details::assignment_string_range_node assignment_string_range_node_t; - typedef details::conditional_string_node conditional_string_node_t; - typedef details::cons_conditional_str_node cons_conditional_str_node_t; + typedef details::stringvar_node stringvar_node_t; + typedef details::string_literal_node string_literal_node_t; + typedef details::string_range_node string_range_node_t; + typedef details::const_string_range_node const_string_range_node_t; + typedef details::generic_string_range_node generic_string_range_node_t; + typedef details::string_concat_node string_concat_node_t; + typedef details::assignment_string_node assignment_string_node_t; + typedef details::assignment_string_range_node assignment_string_range_node_t; + typedef details::conditional_string_node conditional_string_node_t; + typedef details::cons_conditional_str_node cons_conditional_str_node_t; #endif - typedef details::assignment_node assignment_node_t; - typedef details::assignment_vec_elem_node assignment_vec_elem_node_t; - typedef details::assignment_rebasevec_elem_node assignment_rebasevec_elem_node_t; - typedef details::assignment_rebasevec_celem_node assignment_rebasevec_celem_node_t; - typedef details::assignment_vec_node assignment_vec_node_t; - typedef details::assignment_vecvec_node assignment_vecvec_node_t; - typedef details::conditional_vector_node conditional_vector_node_t; - typedef details::scand_node scand_node_t; - typedef details::scor_node scor_node_t; - typedef lexer::token token_t; - typedef expression_node_t* expression_node_ptr; - typedef expression expression_t; - typedef symbol_table symbol_table_t; - typedef typename expression::symtab_list_t symbol_table_list_t; - typedef details::vector_holder* vector_holder_ptr; + typedef details::assignment_node assignment_node_t; + typedef details::assignment_vec_elem_node assignment_vec_elem_node_t; + typedef details::assignment_vec_elem_rtc_node assignment_vec_elem_rtc_node_t; + typedef details::assignment_rebasevec_elem_node assignment_rebasevec_elem_node_t; + typedef details::assignment_rebasevec_elem_rtc_node assignment_rebasevec_elem_rtc_node_t; + typedef details::assignment_rebasevec_celem_node assignment_rebasevec_celem_node_t; + typedef details::assignment_vec_node assignment_vec_node_t; + typedef details::assignment_vecvec_node assignment_vecvec_node_t; + typedef details::conditional_vector_node conditional_vector_node_t; + typedef details::scand_node scand_node_t; + typedef details::scor_node scor_node_t; + typedef lexer::token token_t; + typedef expression_node_t* expression_node_ptr; + typedef expression expression_t; + typedef symbol_table symbol_table_t; + typedef typename expression::symtab_list_t symbol_table_list_t; + typedef details::vector_holder vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; typedef typename details::functor_t functor_t; typedef typename functor_t::qfunc_t quaternary_functor_t; @@ -19636,6 +22308,7 @@ namespace exprtk enum element_type { e_none , + e_literal , e_variable, e_vector , e_vecelem , @@ -19643,6 +22316,7 @@ namespace exprtk }; typedef details::vector_holder vector_holder_t; + 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; @@ -19657,8 +22331,8 @@ namespace exprtk , depth(std::numeric_limits::max()) , ref_count(0) , ip_index (0) - , type (e_none) - , active(false) + , type (e_none) + , active (false) , data (0) , var_node (0) , vec_node (0) @@ -19842,6 +22516,10 @@ namespace exprtk switch (se.type) { + case scope_element::e_literal : delete reinterpret_cast(se.data); + delete se.var_node; + break; + case scope_element::e_variable : delete reinterpret_cast(se.data); delete se.var_node; break; @@ -19906,6 +22584,25 @@ 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(const scope_element_manager&) exprtk_delete; @@ -20092,16 +22789,17 @@ namespace exprtk 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--; } @@ -20211,22 +22909,23 @@ namespace exprtk inline variable_context get_variable_context(const std::string& variable_name) const { variable_context result; - if (!valid_symbol(variable_name)) - return result; - for (std::size_t i = 0; i < symtab_list_.size(); ++i) + if (valid_symbol(variable_name)) { - if (!symtab_list_[i].valid()) + for (std::size_t i = 0; i < symtab_list_.size(); ++i) { - continue; - } + 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; + result.variable = local_data(i) + .variable_store.get(variable_name); + if (result.variable) + { + result.symbol_table = &symtab_list_[i]; + break; + } } } @@ -20461,12 +23160,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; @@ -20480,9 +23183,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; @@ -20513,9 +23221,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; @@ -20675,6 +23388,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; @@ -20692,12 +23406,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; @@ -20730,7 +23445,8 @@ namespace exprtk : mode(m) {} - virtual ~unknown_symbol_resolver() {} + virtual ~unknown_symbol_resolver() + {} virtual bool process(const std::string& /*unknown_symbol*/, usr_symbol_type& st, @@ -20806,11 +23522,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(); } @@ -20831,9 +23550,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(); } @@ -21020,7 +23742,7 @@ namespace exprtk e_ineq_gte , e_ineq_gt }; - static const std::size_t compile_all_opts = + static const std::size_t default_compile_all_opts = e_replacer + e_joiner + e_numeric_check + @@ -21029,9 +23751,10 @@ namespace exprtk e_commutative_check + e_strength_reduction; - settings_store(const std::size_t compile_options = compile_all_opts) + 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); } @@ -21078,12 +23801,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_func_set_, disabled_func_set_.begin())); + (disabled_func_set_, disabled_func_set_.begin())); return (*this); } @@ -21092,7 +23827,7 @@ namespace exprtk std::copy(details::cntrl_struct_list, details::cntrl_struct_list + details::cntrl_struct_list_size, std::insert_iterator - (disabled_ctrl_set_, disabled_ctrl_set_.begin())); + (disabled_ctrl_set_, disabled_ctrl_set_.begin())); return (*this); } @@ -21110,7 +23845,7 @@ namespace exprtk std::copy(details::arithmetic_ops_list, details::arithmetic_ops_list + details::arithmetic_ops_list_size, std::insert_iterator - (disabled_arithmetic_set_, disabled_arithmetic_set_.begin())); + (disabled_arithmetic_set_, disabled_arithmetic_set_.begin())); return (*this); } @@ -21119,7 +23854,7 @@ namespace exprtk std::copy(details::assignment_ops_list, details::assignment_ops_list + details::assignment_ops_list_size, std::insert_iterator - (disabled_assignment_set_, disabled_assignment_set_.begin())); + (disabled_assignment_set_, disabled_assignment_set_.begin())); return (*this); } @@ -21128,7 +23863,7 @@ namespace exprtk std::copy(details::inequality_ops_list, details::inequality_ops_list + details::inequality_ops_list_size, std::insert_iterator - (disabled_inequality_set_, disabled_inequality_set_.begin())); + (disabled_inequality_set_, disabled_inequality_set_.begin())); return (*this); } @@ -21138,6 +23873,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_; } @@ -21263,7 +24010,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) && @@ -21276,7 +24023,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) && @@ -21289,7 +24036,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) && @@ -21302,7 +24049,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) && @@ -21315,7 +24062,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) && @@ -21328,7 +24075,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) && @@ -21341,7 +24088,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) && @@ -21359,7 +24106,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) && @@ -21377,7 +24124,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) && @@ -21395,7 +24142,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) && @@ -21413,7 +24160,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) && @@ -21431,7 +24178,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) && @@ -21459,6 +24206,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) @@ -21501,6 +24268,7 @@ namespace exprtk case details::e_mul : return "*"; case details::e_div : return "/"; case details::e_mod : return "%"; + case details::e_pow : return "^"; default : return "" ; } } @@ -21559,13 +24327,14 @@ namespace exprtk std::size_t max_stack_depth_; std::size_t max_node_depth_; + std::size_t max_local_vector_size_; friend class parser; }; typedef settings_store settings_t; - parser(const settings_t& settings = settings_t()) + explicit parser(const settings_t& settings = settings_t()) : settings_(settings) , resolve_unknown_symbol_(false) , results_context_(0) @@ -21581,6 +24350,9 @@ namespace exprtk , 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(); @@ -21593,15 +24365,16 @@ 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() {} + ~parser() + {} inline void init_precompilation() { @@ -21669,11 +24442,15 @@ namespace exprtk inline bool compile(const std::string& expression_string, expression& 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(); @@ -21681,10 +24458,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; } @@ -21697,19 +24474,31 @@ 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; + } + if (!run_assemblies()) { 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(); @@ -21743,11 +24532,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)) @@ -21799,11 +24588,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)); } } } @@ -21842,11 +24631,11 @@ namespace exprtk if (0 != (bracket_checker_ptr = dynamic_cast(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*>(helper_assembly_.error_token_scanner))) { @@ -21854,11 +24643,11 @@ namespace exprtk { 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()) @@ -21872,13 +24661,13 @@ namespace exprtk { std::pair 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()) @@ -21892,13 +24681,13 @@ namespace exprtk { std::pair 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()) @@ -21923,9 +24712,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 @@ -21994,11 +24785,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 @@ -22102,11 +24923,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(); @@ -22132,9 +24953,7 @@ 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; @@ -22158,13 +24977,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; @@ -22176,11 +24999,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() @@ -22193,10 +25018,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(), + "ERR010 - 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) @@ -22221,110 +25094,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) @@ -22344,49 +25218,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, + "ERR011 - 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, + "ERR012 - 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, + "ERR013 - 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, + "ERR014 - Invalid or disabled assignment operation '" + details::to_str(current_state.operation) + "'", + exprtk_error_location)); return error_node(); } @@ -22401,34 +25275,38 @@ namespace exprtk 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, + "ERR015 - 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_ : + "ERR016 - General parsing error at token: '" + prev_token.value + "'", + exprtk_error_location)); } free_node(node_allocator_, expression ); @@ -22454,14 +25332,14 @@ 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(expression->node_depth())) + - " exceeds maximum allowed expression depth of " + details::to_str(static_cast(settings_.max_node_depth_)), - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR017 - Expression depth of " + details::to_str(static_cast(expression->node_depth())) + + " exceeds maximum allowed expression depth of " + details::to_str(static_cast(settings_.max_node_depth_)), + exprtk_error_location)); - free_node(node_allocator_,expression); + free_node(node_allocator_, expression); return error_node(); } @@ -22479,7 +25357,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; @@ -22501,20 +25379,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(), + "ERR018 - Failed to find variable node in symbol table", + exprtk_error_location)); - free_node(node_allocator_,node); + free_node(node_allocator_, node); return false; } @@ -22610,6 +25488,7 @@ namespace exprtk { for (std::size_t i = 0; i < deq_.size(); ++i) { + exprtk_debug(("~scoped_deq_delete() - deleting node: %p\n", reinterpret_cast(deq_[i]))); free_node(parser_.node_allocator_,deq_[i]); } @@ -22644,6 +25523,7 @@ namespace exprtk { for (std::size_t i = 0; i < vec_.size(); ++i) { + exprtk_debug(("~scoped_vec_delete() - deleting node: %p\n", reinterpret_cast(vec_[i]))); free_node(parser_.node_allocator_,vec_[i]); } @@ -22651,6 +25531,11 @@ namespace exprtk } } + ptr_t operator[](const std::size_t index) + { + return vec_[index]; + } + bool delete_ptr; parser& parser_; std::vector& vec_; @@ -22732,11 +25617,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(), + "ERR019 - Invalid number of parameters for function: '" + function_name + "'", + exprtk_error_location)); return error_node(); } @@ -22746,11 +25631,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(), + "ERR020 - Failed to generate call to function: '" + function_name + "'", + exprtk_error_location)); return error_node(); } @@ -22765,11 +25650,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(), + "ERR021 - Expecting ifunction '" + function_name + "' to have non-zero parameter count", + exprtk_error_location)); return error_node(); } @@ -22788,11 +25673,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(), + "ERR022 - Expecting argument list for function: '" + function_name + "'", + exprtk_error_location)); return error_node(); } @@ -22803,11 +25688,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(), + "ERR023 - Failed to parse argument " + details::to_str(i) + " for function: '" + function_name + "'", + exprtk_error_location)); return error_node(); } @@ -22815,11 +25700,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(), + "ERR024 - Invalid number of arguments for function: '" + function_name + "'", + exprtk_error_location)); return error_node(); } @@ -22828,11 +25713,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(), + "ERR025 - Invalid number of arguments for function: '" + function_name + "'", + exprtk_error_location)); return error_node(); } @@ -22857,13 +25742,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(), + "ERR026 - Expecting '()' to proceed call to function: '" + function_name + "'", + exprtk_error_location)); - free_node(node_allocator_,result); + free_node(node_allocator_, result); return error_node(); } @@ -22882,23 +25767,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(), + "ERR027 - 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(), + "ERR028 - Expected at least one input parameter for function call '" + function_name + "'", + exprtk_error_location)); return 0; } @@ -22920,11 +25805,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(), + "ERR029 - Expected a ',' between function input parameters, instead got: '" + current_token().value + "'", + exprtk_error_location)); return 0; } @@ -22932,11 +25817,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(), + "ERR030 - Invalid number of input parameters passed to function '" + function_name + "'", + exprtk_error_location)); return 0; } @@ -22955,11 +25840,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, + "ERR031 - No entry found for base operation: " + operation_name, + exprtk_error_location)); return error_node(); } @@ -23002,11 +25887,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, + "ERR032 - Invalid number of input parameters for call to function: '" + operation_name + "'", + exprtk_error_location)); return error_node(); } @@ -23022,47 +25907,52 @@ 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(), + "ERR033 - 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(), + "ERR034 - 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(), + "ERR035 - 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(), + "ERR036 - 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(), + "ERR037 - Expected ')' at the end of if-statement", + exprtk_error_location)); + result = false; } @@ -23076,15 +25966,30 @@ namespace exprtk { 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(), + "ERR038 - 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 if-statement differ: string/non-string", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR039 - Return types of if-statement differ: string/non-string", + exprtk_error_location)); result = false; } @@ -23104,11 +26009,11 @@ namespace exprtk .conditional_vector(condition, consequent, alternative); } - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR038 - Return types of if-statement differ: vector/non-vector", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR040 - Return types of if-statement differ: vector/non-vector", + exprtk_error_location)); result = false; } @@ -23138,11 +26043,31 @@ namespace exprtk { if (0 == (consequent = parse_multi_sequence("if-statement-01"))) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR039 - Failed to parse body of consequent for if-statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR041 - 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) + ) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR042 - Expected ';' at the end of the consequent for if-statement (1)", + exprtk_error_location)); result = false; } @@ -23161,22 +26086,22 @@ namespace exprtk { if (!token_is(token_t::e_eof)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR040 - Expected ';' at the end of the consequent for if-statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR043 - 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(), - "ERR041 - Failed to parse body of consequent for if-statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR044 - Failed to parse body of consequent for if-statement", + exprtk_error_location)); result = false; } @@ -23192,11 +26117,11 @@ namespace exprtk { if (0 == (alternative = parse_multi_sequence("else-statement-01"))) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR042 - Failed to parse body of the 'else' for if-statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR045 - Failed to parse body of the 'else' for if-statement", + exprtk_error_location)); result = false; } @@ -23205,35 +26130,38 @@ namespace exprtk { if (0 == (alternative = parse_conditional_statement())) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR043 - Failed to parse body of if-else statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR046 - 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_eof) + ) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR044 - 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(), + "ERR047 - 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(), - "ERR045 - Failed to parse body of the 'else' for if-statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR048 - Failed to parse body of the 'else' for if-statement", + exprtk_error_location)); result = false; } @@ -23254,11 +26182,11 @@ namespace exprtk .conditional_string(condition, consequent, alternative); } - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR046 - Return types of if-statement differ: string/non-string", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR049 - Return types of if-statement differ: string/non-string", + exprtk_error_location)); result = false; } @@ -23278,11 +26206,11 @@ namespace exprtk .conditional_vector(condition, consequent, alternative); } - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR047 - Return types of if-statement differ: vector/non-vector", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR050 - Return types of if-statement differ: vector/non-vector", + exprtk_error_location)); result = false; } @@ -23309,21 +26237,21 @@ namespace exprtk if (!token_is(token_t::e_lbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR048 - Expected '(' at start of if-statement, instead got: '" + current_token().value + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR051 - 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(), - "ERR049 - Failed to parse condition for if-statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR052 - Failed to parse condition for if-statement", + exprtk_error_location)); return error_node(); } @@ -23353,13 +26281,13 @@ namespace exprtk return parse_conditional_statement_02(condition); } - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR050 - Invalid if-statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR053 - Invalid if-statement", + exprtk_error_location)); - free_node(node_allocator_,condition); + free_node(node_allocator_, condition); return error_node(); } @@ -23374,51 +26302,51 @@ namespace exprtk if (0 == condition) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR051 - Encountered invalid condition branch for ternary if-statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR054 - 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(), - "ERR052 - Expected '?' after condition of ternary if-statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR055 - 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(), - "ERR053 - Failed to parse consequent for ternary if-statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR056 - 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(), - "ERR054 - Expected ':' between ternary if-statement consequent and alternative", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR057 - 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(), - "ERR055 - Failed to parse alternative for ternary if-statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR058 - Failed to parse alternative for ternary if-statement", + exprtk_error_location)); result = false; } @@ -23437,11 +26365,11 @@ namespace exprtk .conditional_string(condition, consequent, alternative); } - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR056 - Return types of ternary differ: string/non-string", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR059 - Return types of ternary differ: string/non-string", + exprtk_error_location)); result = false; } @@ -23461,11 +26389,11 @@ namespace exprtk .conditional_vector(condition, consequent, alternative); } - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR057 - Return types of ternary differ: vector/non-vector", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR060 - Return types of ternary differ: vector/non-vector", + exprtk_error_location)); result = false; } @@ -23488,11 +26416,11 @@ namespace exprtk { if (settings_.logic_disabled("not")) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR058 - Invalid or disabled logic operation 'not'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR061 - Invalid or disabled logic operation 'not'", + exprtk_error_location)); return error_node(); } @@ -23519,31 +26447,31 @@ namespace exprtk if (!token_is(token_t::e_lbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR059 - Expected '(' at start of while-loop condition statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR062 - 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(), - "ERR060 - Failed to parse condition for while-loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR063 - 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(), - "ERR061 - Expected ')' at end of while-loop condition statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR064 - Expected ')' at end of while-loop condition statement", + exprtk_error_location)); result = false; } @@ -23556,21 +26484,21 @@ namespace exprtk if (0 == (branch = parse_multi_sequence("while-loop", true))) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR062 - Failed to parse body of while-loop")); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR065 - 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(), - "ERR063 - Failed to synthesize while-loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR066 - Failed to synthesize while-loop", + exprtk_error_location)); result = false; } @@ -23587,7 +26515,20 @@ namespace exprtk return error_node(); } - return result_node; + if (result_node && result_node->valid()) + { + return result_node; + } + + set_error(make_error( + parser_error::e_synthesis, + current_token(), + "ERR067 - 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() @@ -23611,7 +26552,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); @@ -23642,13 +26583,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(), - "ERR064 - 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(), + "ERR068 - Expected '" + token_t::to_str(separator) + "' in body of repeat until loop", + exprtk_error_location)); return error_node(); } @@ -23666,11 +26607,11 @@ namespace exprtk if (sdd.delete_ptr) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR065 - Failed to parse body of repeat until loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR069 - Failed to parse body of repeat until loop", + exprtk_error_location)); return error_node(); } @@ -23678,33 +26619,33 @@ namespace exprtk if (!token_is(token_t::e_lbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR066 - Expected '(' before condition statement of repeat until loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR070 - Expected '(' before condition statement of repeat until loop", + exprtk_error_location)); - free_node(node_allocator_,branch); + free_node(node_allocator_, branch); return error_node(); } else if (0 == (condition = parse_expression())) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR067 - Failed to parse condition for repeat until loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR071 - Failed to parse condition for repeat until loop", + exprtk_error_location)); - free_node(node_allocator_,branch); + 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(), - "ERR068 - Expected ')' after condition of repeat until loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR072 - Expected ')' after condition of repeat until loop", + exprtk_error_location)); free_node(node_allocator_, branch ); free_node(node_allocator_, condition); @@ -23712,27 +26653,42 @@ namespace exprtk 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(), - "ERR069 - Failed to synthesize repeat until loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR073 - Failed to synthesize repeat until loop", + exprtk_error_location)); - free_node(node_allocator_,condition); + free_node(node_allocator_, condition); return error_node(); } handle_brkcnt_scope_exit(); - return result; + if (result_node && result_node->valid()) + { + return result_node; + } + + set_error(make_error( + parser_error::e_synthesis, + current_token(), + "ERR074 - 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() @@ -23751,11 +26707,11 @@ namespace exprtk if (!token_is(token_t::e_lbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR070 - Expected '(' at start of for-loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR075 - Expected '(' at start of for-loop", + exprtk_error_location)); return error_node(); } @@ -23771,21 +26727,21 @@ namespace exprtk if (!token_is(token_t::e_symbol,prsrhlpr_t::e_hold)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR071 - 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(), + "ERR076 - 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(), - "ERR072 - Expected variable assignment of initialiser section of for-loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR077 - Expected variable assignment of initialiser section of for-loop", + exprtk_error_location)); return error_node(); } @@ -23796,11 +26752,11 @@ namespace exprtk if ((se->name == loop_counter_symbol) && se->active) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR073 - 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(), + "ERR078 - For-loop variable '" + loop_counter_symbol+ "' is being shadowed by a previous declaration", + exprtk_error_location)); return error_node(); } @@ -23828,11 +26784,11 @@ namespace exprtk if (!sem_.add_element(nse)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR074 - Failed to add new local variable '" + loop_counter_symbol + "' to SEM", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR079 - Failed to add new local variable '" + loop_counter_symbol + "' to SEM", + exprtk_error_location)); sem_.free_element(nse); @@ -23840,7 +26796,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()"); } @@ -23850,21 +26806,21 @@ namespace exprtk if (0 == (initialiser = parse_expression())) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR075 - Failed to parse initialiser of for-loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR080 - 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(), - "ERR076 - Expected ';' after initialiser of for-loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR081 - Expected ';' after initialiser of for-loop", + exprtk_error_location)); result = false; } @@ -23874,21 +26830,21 @@ namespace exprtk { if (0 == (condition = parse_expression())) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR077 - Failed to parse condition of for-loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR082 - 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(), - "ERR078 - Expected ';' after condition section of for-loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR083 - Expected ';' after condition section of for-loop", + exprtk_error_location)); result = false; } @@ -23898,21 +26854,21 @@ namespace exprtk { if (0 == (incrementor = parse_expression())) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR079 - Failed to parse incrementor of for-loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR084 - 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(), - "ERR080 - Expected ')' after incrementor section of for-loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR085 - Expected ')' after incrementor section of for-loop", + exprtk_error_location)); result = false; } @@ -23926,11 +26882,11 @@ namespace exprtk if (0 == (loop_body = parse_multi_sequence("for-loop", true))) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR081 - Failed to parse body of for-loop", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR086 - Failed to parse body of for-loop", + exprtk_error_location)); result = false; } @@ -23958,7 +26914,20 @@ namespace exprtk brkcnt_list_.front()); handle_brkcnt_scope_exit(); - return result_node; + if (result_node && result_node->valid()) + { + return result_node; + } + + set_error(make_error( + parser_error::e_synthesis, + current_token(), + "ERR087 - 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() @@ -23968,11 +26937,11 @@ namespace exprtk if (!details::imatch(current_token().value,"switch")) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR082 - Expected keyword 'switch'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR088 - Expected keyword 'switch'", + exprtk_error_location)); return error_node(); } @@ -23983,11 +26952,11 @@ namespace exprtk if (!token_is(token_t::e_lcrlbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR083 - Expected '{' for call to switch statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR089 - Expected '{' for call to switch statement", + exprtk_error_location)); return error_node(); } @@ -24008,18 +26977,21 @@ namespace exprtk return error_node(); else if (!token_is(token_t::e_colon)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR084 - Expected ':' for case of switch statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR090 - 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) { @@ -24029,11 +27001,11 @@ namespace exprtk } else if (!token_is(token_t::e_eof)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR085 - Expected ';' at end of case for switch statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR091 - Expected ';' at end of case for switch statement", + exprtk_error_location)); free_node(node_allocator_, condition ); free_node(node_allocator_, consequent); @@ -24058,11 +27030,11 @@ namespace exprtk { if (0 != default_statement) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR086 - Multiple default cases for switch statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR092 - Multiple default cases for switch statement", + exprtk_error_location)); return error_node(); } @@ -24071,29 +27043,29 @@ namespace exprtk if (!token_is(token_t::e_colon)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR087 - Expected ':' for default of switch statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR093 - 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(), - "ERR088 - Expected ';' at end of default for switch statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR094 - Expected ';' at end of default for switch statement", + exprtk_error_location)); return error_node(); } @@ -24102,11 +27074,11 @@ namespace exprtk break; else { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR089 - Expected '}' at end of switch statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR095 - Expected '}' at end of switch statement", + exprtk_error_location)); return error_node(); } @@ -24118,6 +27090,10 @@ namespace exprtk { arg_list.push_back(default_statement); } + else + { + arg_list.push_back(node_allocator_.allocate_c(std::numeric_limits::quiet_NaN())); + } result = expression_generator_.switch_statement(arg_list, (0 != default_statement)); @@ -24133,11 +27109,11 @@ namespace exprtk if (!details::imatch(current_token().value,"[*]")) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR090 - Expected token '[*]'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR096 - Expected token '[*]'", + exprtk_error_location)); return error_node(); } @@ -24148,11 +27124,11 @@ namespace exprtk if (!token_is(token_t::e_lcrlbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR091 - Expected '{' for call to [*] statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR097 - Expected '{' for call to [*] statement", + exprtk_error_location)); return error_node(); } @@ -24161,11 +27137,11 @@ namespace exprtk { if (!details::imatch("case",current_token().value)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR092 - Expected a 'case' statement for multi-switch", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR098 - Expected a 'case' statement for multi-switch", + exprtk_error_location)); return error_node(); } @@ -24179,27 +27155,30 @@ namespace exprtk if (!token_is(token_t::e_colon)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR093 - Expected ':' for case of [*] statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR099 - 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(), - "ERR094 - Expected ';' at end of case for [*] statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR100 - Expected ';' at end of case for [*] statement", + exprtk_error_location)); return error_node(); } @@ -24224,11 +27203,11 @@ namespace exprtk if (!token_is(token_t::e_rcrlbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR095 - Expected '}' at end of [*] statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR101 - Expected '}' at end of [*] statement", + exprtk_error_location)); return error_node(); } @@ -24265,11 +27244,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(), - "ERR096 - Unsupported built-in vararg function: " + symbol, - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR102 - Unsupported built-in vararg function: " + symbol, + exprtk_error_location)); return error_node(); } @@ -24282,23 +27261,23 @@ namespace exprtk if (!token_is(token_t::e_lbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR097 - Expected '(' for call to vararg function: " + symbol, - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR103 - 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(), - "ERR098 - vararg function: " + symbol + - " requires at least one input parameter", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR104 - vararg function: " + symbol + + " requires at least one input parameter", + exprtk_error_location)); return error_node(); } @@ -24316,11 +27295,11 @@ namespace exprtk break; else if (!token_is(token_t::e_comma)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR099 - 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(); } @@ -24337,13 +27316,13 @@ namespace exprtk { if (!token_is(token_t::e_lsqrbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR100 - Expected '[' as start of string range definition", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR106 - Expected '[' as start of string range definition", + exprtk_error_location)); - free_node(node_allocator_,expression); + free_node(node_allocator_, expression); return error_node(); } @@ -24356,7 +27335,7 @@ namespace exprtk if (!parse_range(rp,true)) { - free_node(node_allocator_,expression); + free_node(node_allocator_, expression); return error_node(); } @@ -24365,19 +27344,32 @@ namespace exprtk if (0 == result) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR101 - Failed to generate string range node", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR107 - 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(), + "ERR108 - 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&) @@ -24386,7 +27378,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; @@ -24404,6 +27396,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* vi = dynamic_cast*>(expression); + + if (vi) + { + details::vector_holder& 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 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(), - "ERR104 - Expected '[' for start of range", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR111 - Expected '[' for start of range", + exprtk_error_location)); return false; } @@ -24607,11 +27654,11 @@ namespace exprtk if (0 == r0) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR105 - Failed parse begin section of range", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR112 - Failed parse begin section of range", + exprtk_error_location)); return false; } @@ -24626,15 +27673,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(), - "ERR106 - Range lower bound less than zero! Constraint: r0 >= 0", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR113 - Range lower bound less than zero! Constraint: r0 >= 0", + exprtk_error_location)); return false; } @@ -24647,11 +27694,11 @@ namespace exprtk if (!token_is(token_t::e_colon)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR107 - Expected ':' for break in range", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR114 - Expected ':' for break in range", + exprtk_error_location)); rp.free(); @@ -24670,11 +27717,11 @@ namespace exprtk if (0 == r1) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR108 - Failed parse end section of range", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR115 - Failed parse end section of range", + exprtk_error_location)); rp.free(); @@ -24691,15 +27738,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(), - "ERR109 - Range upper bound less than zero! Constraint: r1 >= 0", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR116 - Range upper bound less than zero! Constraint: r1 >= 0", + exprtk_error_location)); rp.free(); @@ -24714,11 +27761,11 @@ namespace exprtk if (!token_is(token_t::e_rsqrbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR110 - Expected ']' for start of range", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR117 - Expected ']' for start of range", + exprtk_error_location)); rp.free(); @@ -24742,11 +27789,11 @@ namespace exprtk if (!rp_result || (r0 > r1)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR111 - Invalid range, Constraint: r0 <= r1", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR118 - Invalid range, Constraint: r0 <= r1", + exprtk_error_location)); return false; } @@ -24786,11 +27833,11 @@ namespace exprtk if ((0 == str_ctx.str_var) || !symtab_store_.is_conststr_stringvar(symbol)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR112 - Unknown string symbol", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR119 - Unknown string symbol", + exprtk_error_location)); return error_node(); } @@ -24826,7 +27873,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())); } @@ -24839,13 +27886,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 @@ -24882,7 +27929,7 @@ namespace exprtk next_token(); next_token(); - free_node(node_allocator_,result); + free_node(node_allocator_, result); return expression_generator_(T(const_str.size())); } @@ -24891,13 +27938,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::max())) { @@ -24910,13 +27957,13 @@ namespace exprtk (rp.n1_c.first && (rp.n1_c.second >= const_str.size())) ) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR113 - Overflow in range for string: '" + const_str + "'[" + - (rp.n0_c.first ? details::to_str(static_cast(rp.n0_c.second)) : "?") + ":" + - (rp.n1_c.first ? details::to_str(static_cast(rp.n1_c.second)) : "?") + "]", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR120 - Overflow in range for string: '" + const_str + "'[" + + (rp.n0_c.first ? details::to_str(static_cast(rp.n0_c.second)) : "?") + ":" + + (rp.n1_c.first ? details::to_str(static_cast(rp.n1_c.second)) : "?") + "]", + exprtk_error_location)); rp.free(); @@ -24940,30 +27987,60 @@ 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(), + "ERR121 - 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(), + "ERR122 - 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) ) { typedef typename symtab_store::vector_context vec_ctxt_t; - vec_ctxt_t vec_ctx = symtab_store_.get_vector_context(symbol); + 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(), - "ERR114 - Symbol '" + symbol+ " not a vector", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR123 - Symbol '" + vector_name + " not a vector", + exprtk_error_location)); return error_node(); } @@ -24981,12 +28058,12 @@ namespace exprtk } } else + { vec = se.vec_node; + } assert(0 != vec); - expression_node_ptr index_expr = error_node(); - next_token(); if (!token_is(token_t::e_lsqrbracket)) @@ -24995,31 +28072,28 @@ namespace exprtk } else if (token_is(token_t::e_rsqrbracket)) { - return expression_generator_(T(vec->size())); + return (vec->rebaseable()) ? + node_allocator_.allocate(vec) : + expression_generator_(T(vec->size())); } - else if (0 == (index_expr = parse_expression())) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR115 - 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(), - "ERR116 - 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(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)) { @@ -25028,20 +28102,21 @@ namespace exprtk if (index >= vec_size) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR117 - 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(), + "ERR124 - 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* vararg_function, const std::string& vararg_function_name) @@ -25060,12 +28135,12 @@ namespace exprtk { if (!vararg_function->allow_zero_parameters()) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR118 - Zero parameter call to vararg function: " - + vararg_function_name + " not allowed", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR125 - Zero parameter call to vararg function: " + + vararg_function_name + " not allowed", + exprtk_error_location)); return error_node(); } @@ -25085,12 +28160,12 @@ namespace exprtk break; else if (!token_is(token_t::e_comma)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR119 - Expected ',' for call to vararg function: " - + vararg_function_name, - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR126 - Expected ',' for call to vararg function: " + + vararg_function_name, + exprtk_error_location)); return error_node(); } @@ -25099,37 +28174,37 @@ namespace exprtk } else if (!vararg_function->allow_zero_parameters()) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR120 - 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(); } if (arg_list.size() < vararg_function->min_num_args()) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR121 - Invalid number of parameters to call to vararg function: " - + vararg_function_name + ", require at least " - + details::to_str(static_cast(vararg_function->min_num_args())) + " parameters", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR128 - Invalid number of parameters to call to vararg function: " + + vararg_function_name + ", require at least " + + details::to_str(static_cast(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(), - "ERR122 - Invalid number of parameters to call to vararg function: " - + vararg_function_name + ", require no more than " - + details::to_str(static_cast(vararg_function->max_num_args())) + " parameters", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR129 - Invalid number of parameters to call to vararg function: " + + vararg_function_name + ", require no more than " + + details::to_str(static_cast(vararg_function->max_num_args())) + " parameters", + exprtk_error_location)); return error_node(); } @@ -25200,14 +28275,13 @@ namespace exprtk if (1 == error_list.size()) { - parser_. - set_error( - make_error(parser_error::e_syntax, - parser_.current_token(), - "ERR123 - 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(), + "ERR130 - Failed parameter type check for function '" + function_name_ + "', " + "Expected '" + function_definition_list_[0].param_seq + + "' call set: '" + param_seq + "'", + exprtk_error_location)); } else { @@ -25222,14 +28296,13 @@ namespace exprtk } } - parser_. - set_error( - make_error(parser_error::e_syntax, - parser_.current_token(), - "ERR124 - 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(), + "ERR131 - 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; @@ -25364,13 +28437,12 @@ namespace exprtk { invalid_state_ = false; - parser_. - set_error( - make_error(parser_error::e_syntax, - parser_.current_token(), - "ERR125 - 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(), + "ERR132 - Invalid parameter sequence of '" + param_seq_list[i] + + "' for function: " + function_name_, + exprtk_error_location)); return; } @@ -25380,15 +28452,14 @@ namespace exprtk { invalid_state_ = false; - parser_. - set_error( - make_error(parser_error::e_syntax, - parser_.current_token(), - "ERR126 - 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(), + "ERR133 - 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; } @@ -25424,11 +28495,11 @@ namespace exprtk if (tc.invalid()) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR127 - Type checker instantiation failure for generic function: " + function_name, - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR134 - Type checker instantiation failure for generic function: " + function_name, + exprtk_error_location)); return error_node(); } @@ -25442,12 +28513,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(), + "ERR135 - Zero parameter call to generic function: " + + function_name + " not allowed", + exprtk_error_location)); return error_node(); } @@ -25474,11 +28545,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 generic function: " + function_name, - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR136 - Expected ',' for call to generic function: " + function_name, + exprtk_error_location)); return error_node(); } @@ -25491,12 +28562,12 @@ namespace exprtk !tc .allow_zero_parameters () ) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR130 - 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(); } @@ -25508,22 +28579,21 @@ namespace exprtk !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 generic function: " + function_name, - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR138 - 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); @@ -25546,12 +28616,12 @@ namespace exprtk !tc .allow_zero_parameters() ) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR132 - 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 false; } @@ -25578,11 +28648,11 @@ namespace exprtk break; else if (!token_is(token_t::e_comma)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR133 - Expected ',' for call to string function: " + function_name, - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR140 - Expected ',' for call to string function: " + function_name, + exprtk_error_location)); return false; } @@ -25625,22 +28695,21 @@ namespace exprtk if (!tc.verify(param_type_list, param_seq_index)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR134 - Invalid input parameter sequence for call to string function: " + function_name, - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR141 - 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); @@ -25677,11 +28746,11 @@ namespace exprtk if (!tc.verify(param_type_list, param_seq_index)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR135 - Invalid input parameter sequence for call to overloaded function: " + function_name, - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR142 - Invalid input parameter sequence for call to overloaded function: " + function_name, + exprtk_error_location)); return error_node(); } @@ -25708,11 +28777,11 @@ namespace exprtk } else { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR136 - Invalid return type for call to overloaded function: " + function_name, - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR143 - Invalid return type for call to overloaded function: " + function_name, + exprtk_error_location)); } sdd.delete_ptr = (0 == result); @@ -25736,11 +28805,11 @@ namespace exprtk if (!p.token_is(token_t::e_lbracket)) { - p.set_error( - make_error(parser_error::e_syntax, - p.current_token(), - "ERR137 - Expected '(' for special function '" + sf_name + "'", - exprtk_error_location)); + p.set_error(make_error( + parser_error::e_syntax, + p.current_token(), + "ERR144 - Expected '(' for special function '" + sf_name + "'", + exprtk_error_location)); return error_node(); } @@ -25757,11 +28826,11 @@ namespace exprtk { if (!p.token_is(token_t::e_comma)) { - p.set_error( - make_error(parser_error::e_syntax, - p.current_token(), - "ERR138 - Expected ',' before next parameter of special function '" + sf_name + "'", - exprtk_error_location)); + p.set_error(make_error( + parser_error::e_syntax, + p.current_token(), + "ERR145 - Expected ',' before next parameter of special function '" + sf_name + "'", + exprtk_error_location)); return p.error_node(); } @@ -25770,11 +28839,11 @@ namespace exprtk if (!p.token_is(token_t::e_rbracket)) { - p.set_error( - make_error(parser_error::e_syntax, - p.current_token(), - "ERR139 - Invalid number of parameters for special function '" + sf_name + "'", - exprtk_error_location)); + p.set_error(make_error( + parser_error::e_syntax, + p.current_token(), + "ERR146 - Invalid number of parameters for special function '" + sf_name + "'", + exprtk_error_location)); return p.error_node(); } @@ -25797,11 +28866,11 @@ namespace exprtk !details::is_digit(sf_name[3]) ) { - set_error( - make_error(parser_error::e_token, - current_token(), - "ERR140 - Invalid special function[1]: " + sf_name, - exprtk_error_location)); + set_error(make_error( + parser_error::e_token, + current_token(), + "ERR147 - Invalid special function[1]: " + sf_name, + exprtk_error_location)); return error_node(); } @@ -25811,11 +28880,11 @@ namespace exprtk if (id >= details::e_sffinal) { - set_error( - make_error(parser_error::e_token, - current_token(), - "ERR141 - Invalid special function[2]: " + sf_name, - exprtk_error_location)); + set_error(make_error( + parser_error::e_token, + current_token(), + "ERR148 - Invalid special function[2]: " + sf_name, + exprtk_error_location)); return error_node(); } @@ -25843,21 +28912,21 @@ namespace exprtk { if (state_.parsing_break_stmt) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR142 - Invoking 'break' within a break call is not allowed", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR149 - 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(), - "ERR143 - 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(), + "ERR150 - Invalid use of 'break', allowed only in the scope of a loop", + exprtk_error_location)); return error_node(); } @@ -25876,23 +28945,23 @@ namespace exprtk { if (0 == (return_expr = parse_expression())) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR144 - Failed to parse return expression for 'break' statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR151 - 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(), - "ERR145 - Expected ']' at the completion of break's return expression", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR152 - 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(); } @@ -25904,11 +28973,11 @@ namespace exprtk } else { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR146 - 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(), + "ERR153 - Invalid use of 'break', allowed only in the scope of a loop", + exprtk_error_location)); } return error_node(); @@ -25918,11 +28987,11 @@ namespace exprtk { if (0 == state_.parsing_loop_stmt_count) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR147 - 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(), + "ERR154 - Invalid use of 'continue', allowed only in the scope of a loop", + exprtk_error_location)); return error_node(); } @@ -25940,79 +29009,156 @@ 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(), - "ERR148 - Expected '[' as part of vector size definition", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR155 - 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(), - "ERR149 - Failed to determine size of vector '" + vec_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR156 - 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::e_vecsize) && + static_cast*>(size_expression_node)->vec_holder()->rebaseable(); - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR150 - 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(), + "ERR157 - " + 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(0),vector_size - details::numeric::trunc(vector_size)) || - (vector_size > max_vector_size) + (static_cast(vector_size) > max_vector_size) ) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR151 - 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(), + "ERR158 - Invalid vector size. Must be an integer in the " + "range [0," + details::to_str(static_cast(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(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(), + "ERR159 - 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(nse.data),nse.size); + + details::set_zero_value(reinterpret_cast(nse.data),vec_size); + + if (!sem_.add_element(nse)) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR160 - 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(nse.size))); + } + + state_.activate_side_effect("parse_define_vector_statement()"); + + lodge_symbol(vec_name, e_st_local_vector); + std::vector vec_initilizer_list; scoped_vec_delete 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(), - "ERR152 - Expected ']' as part of vector size definition", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR161 - Expected ']' as part of vector size definition", + exprtk_error_location)); return error_node(); } @@ -26020,43 +29166,65 @@ namespace exprtk { if (!token_is(token_t::e_assign)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR153 - Expected ':=' as part of vector definition", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR162 - 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(), - "ERR154 - Failed to parse single vector initialiser", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR163 - 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(), + "ERR164 - 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(), - "ERR155 - Expected ']' to close single value vector initialiser", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR165 - 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)) { @@ -26066,9 +29234,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); @@ -26094,11 +29262,11 @@ namespace exprtk { if (0 == initialiser) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR156 - Expected '{' as part of vector initialiser list", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR166 - Expected '{' as part of vector initialiser list", + exprtk_error_location)); return error_node(); } @@ -26114,11 +29282,11 @@ namespace exprtk if (0 == initialiser) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR157 - Expected '{' as part of vector initialiser list", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR167 - Expected '{' as part of vector initialiser list", + exprtk_error_location)); return error_node(); } @@ -26132,11 +29300,11 @@ namespace exprtk if (!token_is(token_t::e_comma) && is_next_close) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR158 - Expected ',' between vector initialisers", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR168 - Expected ',' between vector initialisers", + exprtk_error_location)); return error_node(); } @@ -26154,97 +29322,116 @@ namespace exprtk { if (!token_is(token_t::e_eof)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR159 - Expected ';' at end of vector definition", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR169 - Expected ';' at end of vector definition", + exprtk_error_location)); return error_node(); } } - if (T(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(), - "ERR160 - 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(), + "ERR170 - 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(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(), - "ERR161 - 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 >( + (*vec_holder)[0], + vec_size, + vec_initilizer_list); + } + else + { + // vector_init_single_constvalue_node var v[10] := [123] + result = node_allocator_ + .allocate >( + (*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 >( + (*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(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(), - "ERR162 - 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 >( + (*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 >( + (*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 >( + (*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 >( + (*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(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) { @@ -26256,16 +29443,31 @@ namespace exprtk vec_initilizer_list[0]); } else + { result = node_allocator_ - .allocate >( + .allocate >( (*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(), + "ERR171 - Failed to generate initialisation node for vector: " + vec_name, + exprtk_error_location)); + + return error_node(); } #ifndef exprtk_disable_string_capabilities @@ -26279,13 +29481,13 @@ namespace exprtk { if (se.active) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR163 - Illegal redefinition of local variable: '" + str_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR172 - 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(); } @@ -26311,13 +29513,13 @@ namespace exprtk if (!sem_.add_element(nse)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR164 - Failed to add new local string variable '" + str_name + "' to SEM", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR173 - 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); @@ -26326,7 +29528,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); @@ -26357,11 +29559,11 @@ namespace exprtk { if (settings_.vardef_disabled()) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR165 - Illegal variable definition", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR174 - Illegal variable definition", + exprtk_error_location)); return error_node(); } @@ -26378,41 +29580,41 @@ namespace exprtk if (!token_is(token_t::e_symbol)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR166 - Expected a symbol for variable definition", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR175 - 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(), - "ERR167 - Illegal redefinition of reserved keyword: '" + var_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR176 - 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(), - "ERR168 - Illegal redefinition of variable '" + var_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR177 - 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(), - "ERR169 - Illegal redefinition of local variable: '" + var_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR178 - Illegal redefinition of local variable: '" + var_name + "'", + exprtk_error_location)); return error_node(); } @@ -26428,11 +29630,11 @@ namespace exprtk { if (0 == (initialisation_expression = parse_expression())) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR170 - Failed to parse initialisation expression", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR179 - Failed to parse initialisation expression", + exprtk_error_location)); return error_node(); } @@ -26446,13 +29648,13 @@ namespace exprtk { if (!token_is(token_t::e_eof,prsrhlpr_t::e_hold)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR171 - Expected ';' after variable definition", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR180 - Expected ';' after variable definition", + exprtk_error_location)); - free_node(node_allocator_,initialisation_expression); + free_node(node_allocator_, initialisation_expression); return error_node(); } @@ -26474,11 +29676,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(), + "ERR181 - Illegal redefinition of local variable: '" + var_name + "'", + exprtk_error_location)); free_node(node_allocator_, initialisation_expression); @@ -26506,11 +29708,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(), + "ERR182 - Failed to add new local variable '" + var_name + "' to SEM", + exprtk_error_location)); free_node(node_allocator_, initialisation_expression); @@ -26521,7 +29723,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()"); @@ -26536,6 +29738,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(), + "ERR183 - 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(), + "ERR184 - 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(), + "ERR185 - 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(), + "ERR186 - 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(), + "ERR187 - 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(), + "ERR188 - 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(), + "ERR189 - 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(), + "ERR190 - 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(), + "ERR191 - 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(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(), + "ERR192 - 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(init_value); + + if (!sem_.add_element(nse)) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR193 - 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 ( @@ -26543,21 +29913,21 @@ namespace exprtk !token_is(token_t::e_rcrlbracket) ) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR174 - Expected a '{}' for uninitialised var definition", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR194 - 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(), - "ERR175 - Expected ';' after uninitialised variable definition", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR195 - Expected ';' after uninitialised variable definition", + exprtk_error_location)); return error_node(); } @@ -26570,11 +29940,11 @@ namespace exprtk { if (se.active) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR176 - Illegal redefinition of local variable: '" + var_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR196 - Illegal redefinition of local variable: '" + var_name + "'", + exprtk_error_location)); return error_node(); } @@ -26600,11 +29970,11 @@ namespace exprtk if (!sem_.add_element(nse)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR177 - Failed to add new local variable '" + var_name + "' to SEM", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR197 - Failed to add new local variable '" + var_name + "' to SEM", + exprtk_error_location)); sem_.free_element(nse); @@ -26633,11 +30003,11 @@ namespace exprtk if (!token_is(token_t::e_lbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR178 - Expected '(' at start of swap statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR198 - Expected '(' at start of swap statement", + exprtk_error_location)); return error_node(); } @@ -26652,11 +30022,11 @@ 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(), + "ERR199 - Expected a symbol for variable or vector element definition", + exprtk_error_location)); return error_node(); } @@ -26664,11 +30034,11 @@ namespace exprtk { if (0 == (variable0 = parse_vector())) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR180 - First parameter to swap is an invalid vector element: '" + var0_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR200 - First parameter to swap is an invalid vector element: '" + var0_name + "'", + exprtk_error_location)); return error_node(); } @@ -26697,11 +30067,11 @@ namespace exprtk if (0 == variable0) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR181 - First parameter to swap is an invalid variable: '" + var0_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR201 - First parameter to swap is an invalid variable: '" + var0_name + "'", + exprtk_error_location)); return error_node(); } @@ -26711,15 +30081,15 @@ namespace exprtk if (!token_is(token_t::e_comma)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR182 - Expected ',' between parameters to swap", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR202 - Expected ',' between parameters to swap", + exprtk_error_location)); if (variable0_generated) { - free_node(node_allocator_,variable0); + free_node(node_allocator_, variable0); } return error_node(); @@ -26729,15 +30099,15 @@ namespace exprtk if (!token_is(token_t::e_symbol,prsrhlpr_t::e_hold)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR183 - Expected a symbol for variable or vector element definition", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR203 - 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(); @@ -26746,15 +30116,15 @@ namespace exprtk { if (0 == (variable1 = parse_vector())) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR184 - Second parameter to swap is an invalid vector element: '" + var1_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR204 - 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(); @@ -26784,15 +30154,15 @@ namespace exprtk if (0 == variable1) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR185 - Second parameter to swap is an invalid variable: '" + var1_name + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR205 - 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(); @@ -26803,20 +30173,20 @@ namespace exprtk if (!token_is(token_t::e_rbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR186 - Expected ')' at end of swap statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR206 - 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(); @@ -26838,12 +30208,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 @@ -26860,11 +30230,11 @@ namespace exprtk { if (state_.parsing_return_stmt) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR187 - Return call within a return call is not allowed", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR207 - Return call within a return call is not allowed", + exprtk_error_location)); return error_node(); } @@ -26884,11 +30254,11 @@ namespace exprtk if (!token_is(token_t::e_lsqrbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR188 - Expected '[' at start of return statement", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR208 - Expected '[' at start of return statement", + exprtk_error_location)); return error_node(); } @@ -26907,11 +30277,11 @@ namespace exprtk break; else if (!token_is(token_t::e_comma)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR189 - Expected ',' between values during call to return", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR209 - Expected ',' between values during call to return", + exprtk_error_location)); return error_node(); } @@ -26919,11 +30289,11 @@ namespace exprtk } else if (settings_.zero_return_disabled()) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR190 - Zero parameter return statement not allowed", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR210 - Zero parameter return statement not allowed", + exprtk_error_location)); return error_node(); } @@ -26934,11 +30304,11 @@ namespace exprtk { if (!arg_list.empty()) { - set_error( - make_error(parser_error::e_syntax, - prev_token, - "ERR191 - Invalid ']' found during return call", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + prev_token, + "ERR211 - Invalid ']' found during return call", + exprtk_error_location)); return error_node(); } @@ -26977,6 +30347,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(), + "ERR212 - 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 assert_arg_list(3, error_node()); + scoped_vec_delete 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(), + "ERR213 - 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(), + "ERR214 - 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(), + "ERR215 - 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(), + "ERR216 - " + + (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(), + "ERR217 - 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(), + "ERR218 - " + + (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(), + "ERR219 - 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(); + } + + #ifndef exprtk_disable_string_capabilities + if (assert_message && details::is_const_string_node(assert_message)) + { + context.message = dynamic_cast*>(assert_message)->str(); + } + + if (assert_id && details::is_const_string_node(assert_id)) + { + context.id = dynamic_cast*>(assert_id)->str(); + + if (assert_ids_.end() != assert_ids_.find(context.id)) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR220 - 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(context.offet))); + + if (0 == result_node) + { + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR221 - 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 ( @@ -26987,11 +30545,11 @@ namespace exprtk { if (!settings_.commutative_check_enabled()) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR192 - Invalid sequence of variable '" + symbol + "' and bracket", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR222 - Invalid sequence of variable '" + symbol + "' and bracket", + exprtk_error_location)); return false; } @@ -27013,19 +30571,19 @@ namespace exprtk 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; @@ -27035,11 +30593,11 @@ namespace exprtk { if (!settings_.commutative_check_enabled()) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR193 - Invalid sequence of brackets", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR223 - Invalid sequence of brackets", + exprtk_error_location)); return false; } @@ -27122,7 +30680,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); @@ -27132,7 +30693,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) { @@ -27170,11 +30733,11 @@ namespace exprtk return func_node; else { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR194 - Failed to generate node for function: '" + symbol + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR224 - Failed to generate node for function: '" + symbol + "'", + exprtk_error_location)); return error_node(); } @@ -27196,11 +30759,11 @@ namespace exprtk return vararg_func_node; else { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR195 - Failed to generate node for vararg function: '" + symbol + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR225 - Failed to generate node for vararg function: '" + symbol + "'", + exprtk_error_location)); return error_node(); } @@ -27222,11 +30785,11 @@ namespace exprtk return genericfunc_node; else { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR196 - Failed to generate node for generic function: '" + symbol + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR226 - Failed to generate node for generic function: '" + symbol + "'", + exprtk_error_location)); return error_node(); } @@ -27249,11 +30812,11 @@ namespace exprtk return stringfunc_node; else { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR197 - Failed to generate node for string function: '" + symbol + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR227 - Failed to generate node for string function: '" + symbol + "'", + exprtk_error_location)); return error_node(); } @@ -27275,11 +30838,11 @@ namespace exprtk return overloadfunc_node; else { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR198 - Failed to generate node for overload function: '" + symbol + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR228 - Failed to generate node for overload function: '" + symbol + "'", + exprtk_error_location)); return error_node(); } @@ -27301,11 +30864,11 @@ namespace exprtk !details::is_base_function(symbol) ) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR199 - Invalid use of reserved symbol '" + symbol + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR229 - Invalid use of reserved symbol '" + symbol + "'", + exprtk_error_location)); return error_node(); } @@ -27332,11 +30895,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; } @@ -27364,12 +30929,12 @@ namespace exprtk } } - set_error( - make_error(parser_error::e_symtab, - current_token(), - "ERR200 - Failed to create variable: '" + symbol + "'" + - (error_message.empty() ? "" : " - " + error_message), - exprtk_error_location)); + set_error(make_error( + parser_error::e_symtab, + current_token(), + "ERR230 - 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) @@ -27384,23 +30949,23 @@ namespace exprtk } } - set_error( - make_error(parser_error::e_symtab, - current_token(), - "ERR201 - Failed to resolve symbol: '" + symbol + "'" + - (error_message.empty() ? "" : " - " + error_message), - exprtk_error_location)); + set_error(make_error( + parser_error::e_symtab, + current_token(), + "ERR231 - 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(), - "ERR202 - Undefined symbol: '" + symbol + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR232 - Undefined symbol: '" + symbol + "'", + exprtk_error_location)); return error_node(); } @@ -27416,9 +30981,11 @@ 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" ; const std::string symbol = current_token().value; @@ -27491,6 +31058,10 @@ namespace exprtk { return parse_define_var_statement(); } + else if (details::imatch(symbol, symbol_const)) + { + return parse_define_constvar_statement(); + } else if (details::imatch(symbol, symbol_swap)) { return parse_swap_statement(); @@ -27504,17 +31075,22 @@ namespace exprtk return 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(), - "ERR203 - Variable or function detected, yet symbol-table is invalid, Symbol: " + symbol, - exprtk_error_location)); + set_error(make_error( + parser_error::e_symtab, + current_token(), + "ERR233 - Unknown variable or function encountered. Symbol table(s) " + "is either invalid or does not contain symbol: '" + symbol + "'", + exprtk_error_location)); return error_node(); } @@ -27541,11 +31117,11 @@ namespace exprtk if (0 == literal_exp) { - set_error( - make_error(parser_error::e_numeric, - current_token(), - "ERR204 - Failed generate node for scalar: '" + current_token().value + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_numeric, + current_token(), + "ERR234 - Failed generate node for scalar: '" + current_token().value + "'", + exprtk_error_location)); return error_node(); } @@ -27555,11 +31131,11 @@ namespace exprtk } else { - set_error( - make_error(parser_error::e_numeric, - current_token(), - "ERR205 - Failed to convert '" + current_token().value + "' to a number", - exprtk_error_location)); + set_error(make_error( + parser_error::e_numeric, + current_token(), + "ERR235 - Failed to convert '" + current_token().value + "' to a number", + exprtk_error_location)); return error_node(); } @@ -27580,24 +31156,28 @@ namespace exprtk if (0 == (branch = parse_expression())) return error_node(); + else if (token_is(token_t::e_eof)) + {} else if (!token_is(token_t::e_rbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR206 - Expected ')' instead of: '" + current_token().value + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR236 - Expected ')' instead of: '" + current_token().value + "'", + exprtk_error_location)); - details::free_node(node_allocator_,branch); + details::free_node(node_allocator_, branch); return error_node(); } else if (!post_bracket_process(token_t::e_lbracket,branch)) { - details::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) { @@ -27607,19 +31187,19 @@ namespace exprtk return error_node(); else if (!token_is(token_t::e_rsqrbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR207 - Expected ']' instead of: '" + current_token().value + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR237 - Expected ']' instead of: '" + current_token().value + "'", + exprtk_error_location)); - details::free_node(node_allocator_,branch); + details::free_node(node_allocator_, branch); return error_node(); } else if (!post_bracket_process(token_t::e_lsqrbracket,branch)) { - details::free_node(node_allocator_,branch); + details::free_node(node_allocator_, branch); return error_node(); } @@ -27632,19 +31212,19 @@ namespace exprtk return error_node(); else if (!token_is(token_t::e_rcrlbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR208 - Expected '}' instead of: '" + current_token().value + "'", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR238 - Expected '}' instead of: '" + current_token().value + "'", + exprtk_error_location)); - details::free_node(node_allocator_,branch); + details::free_node(node_allocator_, branch); return error_node(); } else if (!post_bracket_process(token_t::e_lcrlbracket,branch)) { - details::free_node(node_allocator_,branch); + details::free_node(node_allocator_, branch); return error_node(); } @@ -27666,7 +31246,7 @@ namespace exprtk if (0 == result) { - details::free_node(node_allocator_,branch); + details::free_node(node_allocator_, branch); return error_node(); } @@ -27681,21 +31261,21 @@ namespace exprtk } else if (token_t::e_eof == current_token().type) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR209 - Premature end of expression[1]", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR239 - Premature end of expression[1]", + exprtk_error_location)); return error_node(); } else { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR210 - Premature end of expression[2]", - exprtk_error_location)); + set_error(make_error( + parser_error::e_syntax, + current_token(), + "ERR240 - Premature end of expression[2]", + exprtk_error_location)); return error_node(); } @@ -27796,6 +31376,8 @@ namespace exprtk register_synthezier(synthesize_covocov_expression4) register_synthezier(synthesize_vocovoc_expression4) register_synthezier(synthesize_covovoc_expression4) + + #undef register_synthezier #endif } @@ -27848,7 +31430,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; @@ -28260,13 +31842,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; } @@ -28421,18 +32010,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, + "ERR241 - 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, + "ERR242 - 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, + "ERR243 - 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, + "ERR244 - Invalid branch pair for break/continue operator '" + details::to_str(operation) + "'", + exprtk_error_location)); + return error_node(); } else if (details::e_assign == operation) @@ -28551,10 +32164,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, + "ERR245 - 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, + "ERR246 - Invalid branches for string operator '" + details::to_str(operation) + "'", + exprtk_error_location)); + return error_node(); } else if (is_string_operation(operation, branch)) @@ -28601,6 +32226,16 @@ namespace exprtk 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, + "ERR247 - Invalid " + invalid_branches + " for conditional statement", + exprtk_error_location)); + return error_node(); } // Can the condition be immediately evaluated? if so optimise. @@ -28626,14 +32261,34 @@ namespace exprtk return node_allocator_->allocate >(); } } - 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(condition, consequent, alternative); + result = node_allocator_->allocate(condition, consequent, alternative); + node_name = "conditional_node_t"; } else - return node_allocator_-> - allocate(condition, consequent); + { + result = node_allocator_->allocate(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(), + "ERR248 - Failed to synthesize node: " + node_name, + exprtk_error_location)); + + details::free_node(*node_allocator_, result); + return error_node(); } #ifndef exprtk_disable_string_capabilities @@ -28647,6 +32302,16 @@ namespace exprtk 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, + "ERR249 - Invalid " + invalid_branches + " for string conditional statement", + exprtk_error_location)); + return error_node(); } // Can the condition be immediately evaluated? if so optimise. @@ -28674,10 +32339,25 @@ namespace exprtk } } else if ((0 != consequent) && (0 != alternative)) - return node_allocator_-> - allocate(condition, consequent, alternative); - else - return error_node(); + { + expression_node_ptr result = + node_allocator_->allocate(condition, consequent, alternative); + + if (result && result->valid()) + { + return result; + } + + parser_->set_error(parser_error::make_error( + parser_error::e_parser, + token_t(), + "ERR250 - 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, @@ -28698,6 +32378,16 @@ namespace exprtk 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, + "ERR251 - Invalid " + invalid_branches + " for vector conditional statement", + exprtk_error_location)); + return error_node(); } // Can the condition be immediately evaluated? if so optimise. @@ -28746,16 +32436,34 @@ 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 break_continue_present = false) const { - if (!break_continue_present && 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, + "ERR252 - Infinite loop condition without 'break' or 'return' not allowed in while-loops", + exprtk_error_location)); + result = error_node(); + } else result = node_allocator_->allocate >(); @@ -28857,13 +32565,26 @@ namespace exprtk expression_node_ptr& loop_body, bool break_continue_present = false) const { - if (!break_continue_present && 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, + "ERR253 - Infinite loop condition without 'break' or 'return' not allowed in for-loop", + exprtk_error_location)); + result = error_node(); + } else result = node_allocator_->allocate >(); @@ -28890,19 +32611,19 @@ namespace exprtk if (rtc) return node_allocator_->allocate ( - initialiser, - condition, - incrementor, - loop_body, - rtc + initialiser, + condition, + incrementor, + loop_body, + rtc ); else return node_allocator_->allocate ( - initialiser, - condition, - incrementor, - loop_body + initialiser, + condition, + incrementor, + loop_body ); } #ifndef exprtk_disable_break_continue @@ -28911,19 +32632,19 @@ namespace exprtk if (rtc) return node_allocator_->allocate ( - initialiser, - condition, - incrementor, - loop_body, - rtc + initialiser, + condition, + incrementor, + loop_body, + rtc ); else return node_allocator_->allocate ( - initialiser, - condition, - incrementor, - loop_body + initialiser, + condition, + incrementor, + loop_body ); } #else @@ -28986,8 +32707,8 @@ namespace exprtk if (0 == result) { - T zero = T(0); - result = node_allocator_->allocate(zero); + const T zero = T(0); + result = node_allocator_->allocate(zero); } for (std::size_t i = 0; i < arg_list.size(); ++i) @@ -29161,6 +32882,28 @@ namespace exprtk return node_allocator_->allocate >(arg_list); } + 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 alloc_type; + + expression_node_ptr result = node_allocator_->allocate_rrrr + (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 ) \ @@ -29280,6 +33023,8 @@ namespace exprtk default : return error_node(); } + assert(temp_node); + const T v = temp_node->value(); details::free_node(*node_allocator_,temp_node); @@ -29383,6 +33128,8 @@ namespace exprtk default : return error_node(); } + assert(temp_node); + const T v = temp_node->value(); details::free_node(*node_allocator_,temp_node); @@ -29503,7 +33250,8 @@ namespace exprtk template class Sequence> - inline expression_node_ptr varnode_optimise_varargfunc(const details::operator_type& operation, Sequence& arg_list) + inline expression_node_ptr varnode_optimise_varargfunc(const details::operator_type& operation, + Sequence& arg_list) { switch (operation) { @@ -29526,7 +33274,8 @@ namespace exprtk template class Sequence> - inline expression_node_ptr vectorize_func(const details::operator_type& operation, Sequence& arg_list) + inline expression_node_ptr vectorize_func(const details::operator_type& operation, + Sequence& arg_list) { if (1 == arg_list.size()) { @@ -29551,7 +33300,8 @@ namespace exprtk template class Sequence> - inline expression_node_ptr vararg_function(const details::operator_type& operation, Sequence& arg_list) + inline expression_node_ptr vararg_function(const details::operator_type& operation, + Sequence& arg_list) { if (!all_nodes_valid(arg_list)) { @@ -29561,9 +33311,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); @@ -29571,17 +33321,32 @@ namespace exprtk #ifndef exprtk_disable_string_capabilities if (details::e_smulti == operation) { - return node_allocator_-> + expression_node_ptr result = node_allocator_-> allocate > >(arg_list); + if (result && result->valid()) + { + return result; + } + + parser_->set_error(parser_error::make_error( + parser_error::e_synthesis, + token_t(), + "ERR254 - Failed to synthesize node: str_vararg_node", + 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_-> \ + case op0 : result = node_allocator_-> \ allocate > >(arg_list); \ + break; \ case_stmt(details::e_sum , details::vararg_add_op ) case_stmt(details::e_prod , details::vararg_mul_op ) @@ -29594,7 +33359,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(), + "ERR255 - Failed to synthesize node: vararg_node", + exprtk_error_location)); + + details::free_node(*node_allocator_, result); } + + return error_node(); } template @@ -29635,7 +33415,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(), + "ERR256 - Failed to synthesize node: function_N_node_t", + exprtk_error_location)); + + details::free_node(*node_allocator_, result); + return error_node(); } } @@ -29672,7 +33464,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(), + "ERR257 - Failed to synthesize node: vararg_function_node", + exprtk_error_location)); + + details::free_node(*node_allocator_, result); + return error_node(); } inline expression_node_ptr generic_function_call(igeneric_function_t* gf, @@ -29691,14 +33495,23 @@ namespace exprtk const std::size_t no_psi = std::numeric_limits::max(); expression_node_ptr result = error_node(); + std::string node_name = "Unknown"; if (no_psi == param_seq_index) + { result = node_allocator_->allocate(arg_list,gf); + node_name = "generic_function_node"; + } else + { result = node_allocator_->allocate(gf, param_seq_index, arg_list); + node_name = "multimode_genfunction_node"; + } alloc_type1* genfunc_node_ptr = static_cast(result); + assert(genfunc_node_ptr); + if ( !arg_list.empty() && !gf->has_side_effects() && @@ -29716,9 +33529,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(), + "ERR258 - Failed to synthesize node: " + node_name, + exprtk_error_location)); + + details::free_node(*node_allocator_, result); + return error_node(); } else { @@ -29746,14 +33570,23 @@ namespace exprtk const std::size_t no_psi = std::numeric_limits::max(); expression_node_ptr result = error_node(); + std::string node_name = "Unknown"; if (no_psi == param_seq_index) + { result = node_allocator_->allocate(gf,arg_list); + node_name = "string_function_node"; + } else + { result = node_allocator_->allocate(gf, param_seq_index, arg_list); + node_name = "multimode_strfunction_node"; + } alloc_type1* strfunc_node_ptr = static_cast(result); + assert(strfunc_node_ptr); + if ( !arg_list.empty() && !gf->has_side_effects() && @@ -29770,9 +33603,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(), + "ERR259 - Failed to synthesize node: " + node_name, + exprtk_error_location)); + + details::free_node(*node_allocator_, result); + return error_node(); } else { @@ -29800,11 +33644,24 @@ namespace exprtk alloc_type* return_node_ptr = static_cast(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(), + "ERR260 - Failed to synthesize node: return_node", + exprtk_error_location)); + + details::free_node(*node_allocator_, result); + return error_node(); } else { @@ -29842,28 +33699,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(details::numeric::to_int64(index->value())); + const std::size_t vec_index = static_cast(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(), + "ERR261 - 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(i,vector_base); + vector_access_runtime_check_ptr rtc = get_vector_access_runtime_check(); + + result = (rtc) ? + node_allocator_->allocate(vec_node, vec_index, vector_base, rtc) : + node_allocator_->allocate(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(), + "ERR262 - 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(vec_node, vec_index, vector_base, rtc) : + node_allocator_->allocate(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(), + "ERR263 - 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 { @@ -29872,10 +33794,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((*(*vector_base)[i])); + nse.var_node = node_allocator_->allocate((*(*vector_base)[vec_index])); if (!parser_->sem_.add_element(nse)) { @@ -29886,19 +33808,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(index,vector_base); else - result = node_allocator_->allocate(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(vec_node, index, vector_base, rtc) : + node_allocator_->allocate(vec_node, index, vector_base ) ; + + node_name = (rtc) ? + "rebasevector_elem_rtc_node_t" : + "rebasevector_elem_node_t" ; + } + else + { + result = rtc ? + node_allocator_->allocate(vec_node, index, vector_base, rtc) : + node_allocator_->allocate(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(), + "ERR264 - Failed to synthesize node: " + node_name, + exprtk_error_location)); + + details::free_node(*node_allocator_, result); + return error_node(); } private: @@ -29995,12 +33953,27 @@ namespace exprtk case details::expression_node::e_vecelem: return reinterpret_cast(&static_cast(node)->ref()); + case details::expression_node::e_veccelem: + return reinterpret_cast(&static_cast(node)->ref()); + + case details::expression_node::e_vecelemrtc: + return reinterpret_cast(&static_cast(node)->ref()); + + case details::expression_node::e_veccelemrtc: + return reinterpret_cast(&static_cast(node)->ref()); + case details::expression_node::e_rbvecelem: return reinterpret_cast(&static_cast(node)->ref()); + case details::expression_node::e_rbvecelemrtc: + return reinterpret_cast(&static_cast(node)->ref()); + case details::expression_node::e_rbveccelem: return reinterpret_cast(&static_cast(node)->ref()); + case details::expression_node::e_rbveccelemrtc: + return reinterpret_cast(&static_cast(node)->ref()); + case details::expression_node::e_vector: return reinterpret_cast(static_cast(node)->vec_holder().data()); @@ -30032,11 +34005,11 @@ namespace exprtk if (parser_->immutable_symtok_map_.end() != itr) { token_t& token = itr->second; - parser_->set_error( - parser_error::make_error(parser_error::e_parser, - token, - "ERR211 - Symbol '" + token.value + "' cannot be assigned-to as it is immutable.", - exprtk_error_location)); + parser_->set_error(parser_error::make_error( + parser_error::e_parser, + token, + "ERR265 - 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."); @@ -30058,16 +34031,26 @@ namespace exprtk lodge_assignment(e_st_variable,branch[0]); return synthesize_expression(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(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(operation, branch); + } else if (details::is_rebasevector_elem_node(branch[0])) { lodge_assignment(e_st_vecelem,branch[0]); return synthesize_expression(operation, branch); } + else if (details::is_rebasevector_elem_rtc_node(branch[0])) + { + lodge_assignment(e_st_vecelem,branch[0]); + return synthesize_expression(operation, branch); + } else if (details::is_rebasevector_celem_node(branch[0])) { lodge_assignment(e_st_vecelem,branch[0]); @@ -30094,9 +34077,23 @@ namespace exprtk else return synthesize_expression(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, + "ERR266 - 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, + "ERR267 - Invalid branches for assignment operator '" + details::to_str(operation) + "'", + exprtk_error_location)); return error_node(); } @@ -30110,6 +34107,9 @@ namespace exprtk 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]); @@ -30117,9 +34117,11 @@ namespace exprtk switch (operation) { #define case_stmt(op0, op1) \ - case op0 : return node_allocator_-> \ + case op0 : result = node_allocator_-> \ template allocate_rrr > > \ (operation, branch[0], branch[1]); \ + node_name = "assignment_op_node"; \ + break; \ case_stmt(details::e_addass , details::add_op) case_stmt(details::e_subass , details::sub_op) @@ -30137,9 +34139,55 @@ namespace exprtk switch (operation) { #define case_stmt(op0, op1) \ - case op0 : return node_allocator_-> \ + case op0 : result = node_allocator_-> \ template allocate_rrr > > \ (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]); + + switch (operation) + { + #define case_stmt(op0, op1) \ + case op0 : result = node_allocator_-> \ + template allocate_rrr > > \ + (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 > > \ + (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) @@ -30157,9 +34205,11 @@ namespace exprtk switch (operation) { #define case_stmt(op0, op1) \ - case op0 : return node_allocator_-> \ + case op0 : result = node_allocator_-> \ template allocate_rrr > > \ (operation, branch[0], branch[1]); \ + node_name = "assignment_rebasevec_elem_op_node"; \ + break; \ case_stmt(details::e_addass , details::add_op) case_stmt(details::e_subass , details::sub_op) @@ -30177,9 +34227,55 @@ namespace exprtk switch (operation) { #define case_stmt(op0, op1) \ - case op0 : return node_allocator_-> \ + case op0 : result = node_allocator_-> \ template allocate_rrr > > \ (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]); + + switch (operation) + { + #define case_stmt(op0, op1) \ + case op0 : result = node_allocator_-> \ + template allocate_rrr > > \ + (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 > > \ + (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) @@ -30199,9 +34295,11 @@ namespace exprtk switch (operation) { #define case_stmt(op0, op1) \ - case op0 : return node_allocator_-> \ + case op0 : result = node_allocator_-> \ template allocate_rrr > > \ (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) @@ -30217,9 +34315,11 @@ namespace exprtk switch (operation) { #define case_stmt(op0, op1) \ - case op0 : return node_allocator_-> \ + case op0 : result = node_allocator_-> \ template allocate_rrr > > \ (operation, branch[0], branch[1]); \ + node_name = "assignment_vec_op_node"; \ + break; \ case_stmt(details::e_addass , details::add_op) case_stmt(details::e_subass , details::sub_op) @@ -30241,15 +34341,34 @@ namespace exprtk lodge_assignment(e_st_string,branch[0]); - return synthesize_expression(operation,branch); + result = synthesize_expression(operation,branch); + node_name = "assignment_string_node"; } #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, + "ERR268 - 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(), + "ERR269 - 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, @@ -30273,14 +34392,19 @@ namespace exprtk 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_-> \ + case op0 : result = node_allocator_-> \ template allocate_rrr > > \ (operation, branch[0], branch[1]); \ + node_name = "vec_binop_vecvec_node"; \ + break; \ batch_eqineq_logic_case #undef case_stmt @@ -30292,9 +34416,11 @@ namespace exprtk switch (operation) { #define case_stmt(op0, op1) \ - case op0 : return node_allocator_-> \ + case op0 : result = node_allocator_-> \ template allocate_rrr > > \ (operation, branch[0], branch[1]); \ + node_name = "vec_binop_vecval_node"; \ + break; \ batch_eqineq_logic_case #undef case_stmt @@ -30306,9 +34432,11 @@ namespace exprtk switch (operation) { #define case_stmt(op0, op1) \ - case op0 : return node_allocator_-> \ + case op0 : result = node_allocator_-> \ template allocate_rrr > > \ (operation, branch[0], branch[1]); \ + node_name = "vec_binop_valvec_node"; \ + break; \ batch_eqineq_logic_case #undef case_stmt @@ -30318,6 +34446,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(), + "ERR270 - Failed to synthesize node: " + node_name, + exprtk_error_location)); + + details::free_node(*node_allocator_, result); + return error_node(); + #undef batch_eqineq_logic_case } @@ -30334,14 +34476,19 @@ namespace exprtk 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_-> \ + case op0 : result = node_allocator_-> \ template allocate_rrr > > \ (operation, branch[0], branch[1]); \ + node_name = "vec_binop_vecvec_node"; \ + break; \ vector_ops case_stmt(details::e_pow,details:: pow_op) @@ -30354,9 +34501,11 @@ namespace exprtk switch (operation) { #define case_stmt(op0, op1) \ - case op0 : return node_allocator_-> \ + case op0 : result = node_allocator_-> \ template allocate_rrr > > \ (operation, branch[0], branch[1]); \ + node_name = "vec_binop_vecval_node(b0ivec,!b1ivec)"; \ + break; \ vector_ops case_stmt(details::e_pow,details:: pow_op) @@ -30369,9 +34518,11 @@ namespace exprtk switch (operation) { #define case_stmt(op0, op1) \ - case op0 : return node_allocator_-> \ + case op0 : result = node_allocator_-> \ template allocate_rrr > > \ (operation, branch[0], branch[1]); \ + node_name = "vec_binop_vecval_node(!b0ivec,b1ivec)"; \ + break; \ vector_ops #undef case_stmt @@ -30381,6 +34532,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(), + "ERR271 - Failed to synthesize node: " + node_name, + exprtk_error_location)); + + details::free_node(*node_allocator_, result); + return error_node(); + #undef vector_ops } @@ -30398,6 +34563,7 @@ namespace exprtk #endif expression_node_ptr result = error_node(); + std::string node_name = "Unknown"; if (v0_is_ivar && v1_is_ivar) { @@ -30411,36 +34577,57 @@ namespace exprtk (0 != (v1 = dynamic_cast(branch[1]))) ) { - result = node_allocator_->allocate >(v0,v1); + result = node_allocator_->allocate >(v0,v1); + node_name = "swap_node"; } else - result = node_allocator_->allocate >(branch[0],branch[1]); + { + result = node_allocator_->allocate >(branch[0],branch[1]); + node_name = "swap_generic_node"; + } } else if (v0_is_ivec && v1_is_ivec) { - result = node_allocator_->allocate >(branch[0],branch[1]); + result = node_allocator_->allocate >(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 > (branch[0], branch[1]); + node_name = "swap_string_node"; + } else + { result = node_allocator_->allocate > (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(), + "ERR272 - Failed to synthesize node: " + node_name, + exprtk_error_location)); + + details::free_node(*node_allocator_, result); + return error_node(); } #ifndef exprtk_disable_sc_andor @@ -30596,7 +34783,7 @@ namespace exprtk else if (not_recipricol) return cardinal_pow_optimisation_impl(branch[0],p); else - return cardinal_pow_optimisation_impl(branch[0],p); + return cardinal_pow_optimisation_impl(branch[0],p); } #else inline expression_node_ptr cardinal_pow_optimisation(T&, const T&) @@ -31969,9 +36156,9 @@ namespace exprtk 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"; } }; @@ -32034,9 +36221,9 @@ namespace exprtk 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)"; } }; @@ -32100,9 +36287,9 @@ namespace exprtk 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"; } }; @@ -32165,9 +36352,9 @@ namespace exprtk 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)"; } }; @@ -32230,9 +36417,9 @@ namespace exprtk 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"; } }; @@ -32295,9 +36482,9 @@ namespace exprtk 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)"; } }; @@ -32360,9 +36547,9 @@ namespace exprtk 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"; } }; @@ -32426,9 +36613,9 @@ namespace exprtk 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)"; } }; @@ -32545,9 +36732,9 @@ namespace exprtk 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"; } }; @@ -32664,9 +36851,9 @@ namespace exprtk 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)"; } }; @@ -32795,9 +36982,9 @@ namespace exprtk 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)"; } }; @@ -32922,9 +37109,9 @@ namespace exprtk 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"; } }; @@ -33057,10 +37244,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)"; } }; @@ -33146,10 +37333,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)"; } }; @@ -33235,10 +37422,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)"; } }; @@ -33324,10 +37511,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)"; } }; @@ -33413,10 +37600,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 +37794,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)"; } }; @@ -33851,10 +38038,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)"; } }; @@ -34045,10 +38232,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)"; } }; @@ -34238,10 +38425,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)"; } }; @@ -34298,10 +38485,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))"; } }; @@ -34358,10 +38545,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))"; } }; @@ -34418,10 +38605,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))"; } }; @@ -34478,10 +38665,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))"; } }; @@ -34539,10 +38726,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))"; } }; @@ -34600,10 +38787,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))"; } }; @@ -34660,10 +38847,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))"; } }; @@ -34720,10 +38907,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))"; } }; @@ -34780,10 +38967,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))"; } }; @@ -34840,10 +39027,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)"; } }; @@ -34900,10 +39087,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)"; } }; @@ -34960,10 +39147,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)"; } }; @@ -35020,10 +39207,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)"; } }; @@ -35081,10 +39268,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)"; } }; @@ -35142,10 +39329,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)"; } }; @@ -35202,10 +39389,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)"; } }; @@ -35263,10 +39450,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)"; } }; @@ -35344,10 +39531,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"; } }; @@ -35405,10 +39592,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"; } }; @@ -35465,10 +39652,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"; } }; @@ -35525,10 +39712,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"; } }; @@ -35585,10 +39772,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"; } }; @@ -35645,10 +39832,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"; } }; @@ -35706,10 +39893,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"; } }; @@ -35767,10 +39954,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"; } }; @@ -35827,10 +40014,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"; } }; @@ -35887,10 +40074,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"; } }; @@ -35948,10 +40135,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"; } }; @@ -36008,10 +40195,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"; } }; @@ -36067,10 +40254,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"; } }; @@ -36127,10 +40314,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"; } }; @@ -36187,10 +40374,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"; } }; @@ -36248,10 +40435,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"; } }; @@ -36309,10 +40496,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"; } }; @@ -36737,6 +40924,8 @@ namespace exprtk default : return error_node(); } } + + #undef string_opr_switch_statements #endif #ifndef exprtk_disable_string_capabilities @@ -37070,11 +41259,22 @@ namespace exprtk return node_allocator_->allocate(v); } - else + + if (expression_point && expression_point->valid()) + { return expression_point; + } + + parser_->set_error(parser_error::make_error( + parser_error::e_parser, + token_t(), + "ERR273 - Failed to synthesize node: NodeType", + exprtk_error_location)); + + details::free_node(*node_allocator_, expression_point); } - else - return error_node(); + + return error_node(); } template @@ -37154,8 +41354,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) ) { @@ -37428,6 +41631,7 @@ namespace exprtk sf4_map_t sf4_map_; std::string synthesis_error_; scope_element_manager sem_; + std::vector current_state_stack_; immutable_memory_map_t immutable_memory_map_; immutable_symtok_map_t immutable_symtok_map_; @@ -37443,7 +41647,11 @@ namespace exprtk 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 assert_ids_; template friend void details::disable_type_checking(ParserType& p); @@ -37460,17 +41668,19 @@ namespace exprtk 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 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&) + std::string&) exprtk_override { static T v[1]; symbol_table.add_vector(unknown_symbol,v); @@ -37682,7 +41892,9 @@ namespace exprtk const symbol_table& sym_table = e.get_symbol_table(); if (!sym_table.valid()) + { return std::numeric_limits::quiet_NaN(); + } details::variable_node* var = sym_table.get_variable(variable_name); @@ -37695,8 +41907,8 @@ namespace exprtk return result; } - else - return std::numeric_limits::quiet_NaN(); + + return std::numeric_limits::quiet_NaN(); } template @@ -37786,8 +41998,8 @@ namespace exprtk return result; } - else - return std::numeric_limits::quiet_NaN(); + + return std::numeric_limits::quiet_NaN(); } template @@ -37813,8 +42025,8 @@ namespace exprtk return result; } - else - return std::numeric_limits::quiet_NaN(); + + return std::numeric_limits::quiet_NaN(); } template @@ -37840,8 +42052,8 @@ namespace exprtk return result; } - else - return std::numeric_limits::quiet_NaN(); + + return std::numeric_limits::quiet_NaN(); } /* @@ -38120,97 +42332,98 @@ namespace exprtk disable_has_side_effects(*this); } - virtual ~polynomial() {} + virtual ~polynomial() + {} #define poly_rtrn(NN) \ return (NN != N) ? std::numeric_limits::quiet_NaN() : - inline virtual T operator() (const T& x, const T& c1, const T& c0) + inline virtual T operator() (const T& x, const T& c1, const T& c0) exprtk_override { poly_rtrn(1) (poly_impl::evaluate(x, c1, c0)); } - inline virtual T operator() (const T& x, const T& c2, const T& c1, const T& c0) + inline virtual T operator() (const T& x, const T& c2, const T& c1, const T& c0) exprtk_override { poly_rtrn(2) (poly_impl::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 virtual T operator() (const T& x, const T& c3, const T& c2, const T& c1, const T& c0) exprtk_override { poly_rtrn(3) (poly_impl::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) + const T& c0) exprtk_override { poly_rtrn(4) (poly_impl::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) + const T& c1, const T& c0) exprtk_override { poly_rtrn(5) (poly_impl::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) + const T& c2, const T& c1, const T& c0) exprtk_override { poly_rtrn(6) (poly_impl::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) + const T& c3, const T& c2, const T& c1, const T& c0) exprtk_override { poly_rtrn(7) (poly_impl::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) + const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) exprtk_override { poly_rtrn(8) (poly_impl::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) + const T& c0) exprtk_override { poly_rtrn(9) (poly_impl::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) + const T& c1, const T& c0) exprtk_override { poly_rtrn(10) (poly_impl::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) + const T& c2, const T& c1, const T& c0) exprtk_override { poly_rtrn(11) (poly_impl::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) + const T& c3, const T& c2, const T& c1, const T& c0) exprtk_override { poly_rtrn(12) (poly_impl::evaluate(x, c12, c11, c10, c9, c8, c7, c6, c5, c4, c3, c2, c1, c0)); } #undef poly_rtrn - inline virtual T operator() () + inline virtual T operator() () exprtk_override { return std::numeric_limits::quiet_NaN(); } - inline virtual T operator() (const T&) + inline virtual T operator() (const T&) exprtk_override { return std::numeric_limits::quiet_NaN(); } - inline virtual T operator() (const T&, const T&) + inline virtual T operator() (const T&, const T&) exprtk_override { return std::numeric_limits::quiet_NaN(); } @@ -38312,6 +42525,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 v_; @@ -38321,12 +42578,14 @@ namespace exprtk struct base_func : public exprtk::ifunction { - typedef const T& type; - typedef exprtk::ifunction function_t; - typedef std::vector varref_t; - typedef std::vector var_t; + typedef const T& type; + typedef exprtk::ifunction function_t; + typedef std::vector varref_t; + typedef std::vector var_t; + typedef std::vector str_t; typedef std::pair lvarref_t; typedef std::vector lvr_vec_t; + typedef std::vector lstr_vec_t; using exprtk::ifunction::operator(); @@ -38338,10 +42597,11 @@ namespace exprtk v.resize(pc); } - virtual ~base_func() {} + virtual ~base_func() + {} - #define exprtk_assign(Index) \ - (*v[Index]) = v##Index; \ + #define exprtk_assign(Index) \ + (*v[Index]) = v##Index; \ inline void update(const T& v0) { @@ -38387,17 +42647,33 @@ namespace exprtk { 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 index_list; + std::vector > 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(i), + expression_t::control_block::to_str(ldl[i].type).c_str(), + static_cast(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)); } } @@ -38405,19 +42681,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(ldl[index].pointer), - ldl[index].size)); + if (local_var.type == ctrlblk_t::e_string) + { + local_str_vars.push_back( + reinterpret_cast(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(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(ldl[index].pointer); + { + v[input_param_count++] = reinterpret_cast(local_var.pointer); + } } clear_stack(); @@ -38433,14 +42724,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); } } } @@ -38451,14 +42749,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 (!lv.empty()) + if (!local_vars.empty()) { - copy(local_stack.back(),lv); - local_stack.pop_back(); + copy(local_var_stack.back(), local_vars); + local_var_stack.pop_back(); + } + + if (!local_str_vars.empty()) + { + copy(local_str_stack.back(), local_str_vars); + local_str_stack.pop_back(); } } } @@ -38471,6 +42775,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) @@ -38503,9 +42815,12 @@ namespace exprtk typename var_t::const_iterator itr = src_v.begin(); typedef typename std::iterator_traits::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++; @@ -38517,6 +42832,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) @@ -38530,29 +42855,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 param_stack; - std::deque 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 input_params_stack; + std::deque local_var_stack; + std::deque local_str_stack; }; typedef std::map funcparam_t; - struct func_0param : public base_func - { - using exprtk::ifunction::operator(); - - func_0param() : base_func(0) {} - - inline T operator() () - { - return this->value(base_func::expression); - } - }; - typedef const T& type; template @@ -38577,13 +42892,26 @@ namespace exprtk scoped_bft& operator=(const scoped_bft&) exprtk_delete; }; + struct func_0param : public base_func + { + using exprtk::ifunction::operator(); + + func_0param() : base_func(0) {} + + inline T operator() () exprtk_override + { + scoped_bft sb(*this); + return this->value(base_func::expression); + } + }; + struct func_1param : public base_func { using exprtk::ifunction::operator(); func_1param() : base_func(1) {} - inline T operator() (type v0) + inline T operator() (type v0) exprtk_override { scoped_bft sb(*this); base_func::update(v0); @@ -38597,7 +42925,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 sb(*this); base_func::update(v0, v1); @@ -38611,7 +42939,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 sb(*this); base_func::update(v0, v1, v2); @@ -38625,7 +42953,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 sb(*this); base_func::update(v0, v1, v2, v3); @@ -38639,7 +42967,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 sb(*this); base_func::update(v0, v1, v2, v3, v4); @@ -38653,7 +42981,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 sb(*this); base_func::update(v0, v1, v2, v3, v4, v5); @@ -38680,14 +43008,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) @@ -38697,6 +43025,8 @@ namespace exprtk def_fp_retval(5) def_fp_retval(6) + #undef def_fp_retval + template class Sequence> inline bool add(const std::string& name, @@ -38739,16 +43069,20 @@ namespace exprtk public: function_compositor() - : parser_(settings_t::compile_all_opts + + : 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) + explicit function_compositor(const symbol_table_t& st) : symbol_table_(st) - , parser_(settings_t::compile_all_opts + + , parser_(settings_t::default_compile_all_opts + settings_t::e_disable_zero_return) , fp_map_(7) + , load_variables_(false) + , load_vectors_(false) {} ~function_compositor() @@ -38771,6 +43105,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(); @@ -38789,6 +43163,10 @@ 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) @@ -38796,6 +43174,31 @@ namespace exprtk return add(f.name_, f.expression_, f.v_,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: template expr_map_; std::vector fp_map_; std::vector auxiliary_symtab_list_; + std::deque error_list_; + bool load_variables_; + bool load_vectors_; }; // class function_compositor } // namespace exprtk -#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) +#if defined(_MSC_VER) || defined(_WIN32) || defined(__WIN32__) || defined(WIN32) # ifndef NOMINMAX # define NOMINMAX # endif @@ -39001,9 +43433,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_); } @@ -39081,7 +43515,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_; @@ -39114,7 +43548,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 @@ -39174,19 +43624,19 @@ namespace exprtk } // namespace exprtk::rtl::io::details template - struct print : public exprtk::igeneric_function + struct print exprtk_final : public exprtk::igeneric_function { typedef typename igeneric_function::parameter_list_t parameter_list_t; using exprtk::igeneric_function::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::process(scalar_format_,parameters); return T(0); @@ -39196,19 +43646,19 @@ namespace exprtk }; template - struct println : public exprtk::igeneric_function + struct println exprtk_final : public exprtk::igeneric_function { typedef typename igeneric_function::parameter_list_t parameter_list_t; using exprtk::igeneric_function::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::process(scalar_format_,parameters); printf("\n"); @@ -39290,8 +43740,8 @@ namespace exprtk return false; } - else - stream_ptr = stream; + + stream_ptr = stream; return true; } @@ -39306,8 +43756,8 @@ namespace exprtk return false; } - else - stream_ptr = stream; + + stream_ptr = stream; return true; } @@ -39322,13 +43772,13 @@ namespace exprtk return false; } - else - stream_ptr = stream; + + stream_ptr = stream; return true; } - else - return false; + + return false; } template @@ -39475,12 +43925,13 @@ namespace exprtk #ifdef _MSC_VER #pragma warning(pop) #endif + assert(sizeof(T) <= sizeof(void*)); } } // namespace exprtk::rtl::io::file::details template - class open : public exprtk::igeneric_function + class open exprtk_final : public exprtk::igeneric_function { public: @@ -39489,18 +43940,20 @@ namespace exprtk typedef typename igfun_t::generic_type generic_type; typedef typename generic_type::string_view string_t; - using exprtk::igeneric_function::operator(); + using igfun_t::operator(); open() : exprtk::igeneric_function("S|SS") { details::perform_check(); } - 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 std::string file_name = to_str(string_t(parameters[0])); if (file_name.empty()) + { return T(0); + } if ((1 == ps_index) && (0 == string_t(parameters[1]).size())) { @@ -39532,7 +43985,7 @@ namespace exprtk }; template - struct close : public exprtk::ifunction + struct close exprtk_final : public exprtk::ifunction { using exprtk::ifunction::operator(); @@ -39540,7 +43993,7 @@ namespace exprtk : exprtk::ifunction(1) { details::perform_check(); } - inline T operator() (const T& v) + inline T operator() (const T& v) exprtk_override { details::file_descriptor* fd = details::make_handle(v); @@ -39554,7 +44007,7 @@ namespace exprtk }; template - class write : public exprtk::igeneric_function + class write exprtk_final : public exprtk::igeneric_function { public: @@ -39565,13 +44018,13 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function::operator(); + using igfun_t::operator(); write() : igfun_t("TS|TST|TV|TVT") { details::perform_check(); } - 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])()); @@ -39611,7 +44064,7 @@ namespace exprtk }; template - class read : public exprtk::igeneric_function + class read exprtk_final : public exprtk::igeneric_function { public: @@ -39622,13 +44075,13 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function::operator(); + using igfun_t::operator(); read() : igfun_t("TS|TST|TV|TVT") { details::perform_check(); } - 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])()); @@ -39668,7 +44121,7 @@ namespace exprtk }; template - class getline : public exprtk::igeneric_function + class getline exprtk_final : public exprtk::igeneric_function { public: @@ -39678,14 +44131,13 @@ namespace exprtk typedef typename generic_type::string_view string_t; typedef typename generic_type::scalar_view scalar_t; - using exprtk::igeneric_function::operator(); + using igfun_t::operator(); getline() : igfun_t("T",igfun_t::e_rtrn_string) { details::perform_check(); } - 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); @@ -39693,7 +44145,7 @@ namespace exprtk }; template - struct eof : public exprtk::ifunction + struct eof exprtk_final : public exprtk::ifunction { using exprtk::ifunction::operator(); @@ -39701,10 +44153,9 @@ namespace exprtk : exprtk::ifunction(1) { details::perform_check(); } - 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)); } }; @@ -39814,44 +44265,61 @@ namespace exprtk } // namespace exprtk::rtl::details template - class all_true : public exprtk::igeneric_function + class all_true exprtk_final : public exprtk::igeneric_function { public: typedef typename exprtk::igeneric_function 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::operator(); + using igfun_t::operator(); all_true() - : exprtk::igeneric_function("V|VTT") + : exprtk::igeneric_function("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::process(parameters, r0, r1, 1, 2, 0) - ) - return std::numeric_limits::quiet_NaN(); + if ( + (1 == ps_index) && + !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) + ) + { + return std::numeric_limits::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); + } } } @@ -39860,44 +44328,61 @@ namespace exprtk }; template - class all_false : public exprtk::igeneric_function + class all_false exprtk_final : public exprtk::igeneric_function { public: typedef typename exprtk::igeneric_function 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::operator(); + using igfun_t::operator(); all_false() - : exprtk::igeneric_function("V|VTT") + : exprtk::igeneric_function("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::process(parameters, r0, r1, 1, 2, 0) - ) - return std::numeric_limits::quiet_NaN(); + if ( + (1 == ps_index) && + !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) + ) + { + return std::numeric_limits::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); + } } } @@ -39906,44 +44391,61 @@ namespace exprtk }; template - class any_true : public exprtk::igeneric_function + class any_true exprtk_final : public exprtk::igeneric_function { public: typedef typename exprtk::igeneric_function 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::operator(); + using igfun_t::operator(); any_true() - : exprtk::igeneric_function("V|VTT") + : exprtk::igeneric_function("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::process(parameters, r0, r1, 1, 2, 0) - ) - return std::numeric_limits::quiet_NaN(); + if ( + (1 == ps_index) && + !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) + ) + { + return std::numeric_limits::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); + } } } @@ -39952,44 +44454,61 @@ namespace exprtk }; template - class any_false : public exprtk::igeneric_function + class any_false exprtk_final : public exprtk::igeneric_function { public: typedef typename exprtk::igeneric_function 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::operator(); + using igfun_t::operator(); any_false() - : exprtk::igeneric_function("V|VTT") + : exprtk::igeneric_function("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::process(parameters, r0, r1, 1, 2, 0) - ) - return std::numeric_limits::quiet_NaN(); + if ( + (1 == ps_index) && + !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) + ) + { + return std::numeric_limits::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); + } } } @@ -39998,44 +44517,58 @@ namespace exprtk }; template - class count : public exprtk::igeneric_function + class count exprtk_final : public exprtk::igeneric_function { public: typedef typename exprtk::igeneric_function 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::operator(); + using igfun_t::operator(); count() - : exprtk::igeneric_function("V|VTT") + : exprtk::igeneric_function("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::process(parameters, r0, r1, 1, 2, 0) - ) - return std::numeric_limits::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::process(parameters, r0, r1, 1, 2, 0) + ) + { + return std::numeric_limits::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); @@ -40043,7 +44576,7 @@ namespace exprtk }; template - class copy : public exprtk::igeneric_function + class copy exprtk_final : public exprtk::igeneric_function { public: @@ -40053,7 +44586,7 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function::operator(); + using igfun_t::operator(); copy() : exprtk::igeneric_function("VV|VTTVTT") @@ -40064,7 +44597,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]); @@ -40096,7 +44629,7 @@ namespace exprtk }; template - class rol : public exprtk::igeneric_function + class rol exprtk_final : public exprtk::igeneric_function { public: @@ -40106,7 +44639,7 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function::operator(); + using igfun_t::operator(); rol() : exprtk::igeneric_function("VT|VTTT") @@ -40117,7 +44650,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]); @@ -40147,7 +44680,7 @@ namespace exprtk }; template - class ror : public exprtk::igeneric_function + class ror exprtk_final : public exprtk::igeneric_function { public: @@ -40157,7 +44690,7 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function::operator(); + using igfun_t::operator(); ror() : exprtk::igeneric_function("VT|VTTT") @@ -40168,7 +44701,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]); @@ -40185,8 +44718,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, @@ -40198,7 +44731,7 @@ namespace exprtk }; template - class shift_left : public exprtk::igeneric_function + class reverse exprtk_final : public exprtk::igeneric_function { public: @@ -40208,7 +44741,48 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function::operator(); + using igfun_t::operator(); + + reverse() + : exprtk::igeneric_function("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::process(parameters, r0, r1, 1, 2, 0) + ) + return T(0); + + std::reverse(vec.begin() + r0, vec.begin() + r1 + 1); + + return T(1); + } + }; + + template + class shift_left exprtk_final : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function 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("VT|VTTT") @@ -40219,7 +44793,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]); @@ -40256,7 +44830,7 @@ namespace exprtk }; template - class shift_right : public exprtk::igeneric_function + class shift_right exprtk_final : public exprtk::igeneric_function { public: @@ -40266,7 +44840,7 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function::operator(); + using igfun_t::operator(); shift_right() : exprtk::igeneric_function("VT|VTTT") @@ -40277,7 +44851,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]); @@ -40316,7 +44890,7 @@ namespace exprtk }; template - class sort : public exprtk::igeneric_function + class sort exprtk_final : public exprtk::igeneric_function { public: @@ -40326,7 +44900,7 @@ namespace exprtk typedef typename generic_type::string_view string_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function::operator(); + using igfun_t::operator(); sort() : exprtk::igeneric_function("V|VTT|VS|VSTT") @@ -40339,7 +44913,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]); @@ -40379,7 +44953,7 @@ namespace exprtk }; template - class nthelement : public exprtk::igeneric_function + class nthelement exprtk_final : public exprtk::igeneric_function { public: @@ -40389,7 +44963,7 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function::operator(); + using igfun_t::operator(); nthelement() : exprtk::igeneric_function("VT|VTTT") @@ -40400,7 +44974,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]); @@ -40412,7 +44986,9 @@ namespace exprtk return T(0); if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 2, 3, 0)) + { return std::numeric_limits::quiet_NaN(); + } std::nth_element( vec.begin() + r0, @@ -40424,7 +45000,7 @@ namespace exprtk }; template - class iota : public exprtk::igeneric_function + class assign exprtk_final : public exprtk::igeneric_function { public: @@ -40434,41 +45010,101 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function::operator(); + using igfun_t::operator(); + + assign() + : exprtk::igeneric_function("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(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::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 + class iota exprtk_final : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function 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("VT|VTT|VTTT|VTTTT") + : exprtk::igeneric_function("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::process(parameters, r0, r1, 2, 3, 0)) - return std::numeric_limits::quiet_NaN(); - else if ((3 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 3, 4, 0)) - return std::numeric_limits::quiet_NaN(); - else + if ( + ((ps_index == 2) || (ps_index == 3)) && + !helper::load_vector_range::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); @@ -40476,40 +45112,50 @@ namespace exprtk }; template - class sumk : public exprtk::igeneric_function + class sumk exprtk_final : public exprtk::igeneric_function { public: typedef typename exprtk::igeneric_function 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::operator(); + using igfun_t::operator(); sumk() - : exprtk::igeneric_function("V|VTT") + : exprtk::igeneric_function("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(scalar_t(parameters[3])()); + std::size_t r0 = 0; std::size_t r1 = vec.size() - 1; - if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0)) + if ( + ((1 == ps_index) || (2 == ps_index)) && + !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) + ) + { return std::numeric_limits::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]); } @@ -40519,7 +45165,7 @@ namespace exprtk }; template - class axpy : public exprtk::igeneric_function + class axpy exprtk_final : public exprtk::igeneric_function { public: @@ -40529,7 +45175,7 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function::operator(); + using igfun_t::operator(); axpy() : exprtk::igeneric_function("TVV|TVVTT") @@ -40541,7 +45187,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]); @@ -40566,7 +45212,7 @@ namespace exprtk }; template - class axpby : public exprtk::igeneric_function + class axpby exprtk_final : public exprtk::igeneric_function { public: @@ -40576,7 +45222,7 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function::operator(); + using igfun_t::operator(); axpby() : exprtk::igeneric_function("TVTV|TVTVTT") @@ -40588,7 +45234,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]); @@ -40614,7 +45260,7 @@ namespace exprtk }; template - class axpyz : public exprtk::igeneric_function + class axpyz exprtk_final : public exprtk::igeneric_function { public: @@ -40624,7 +45270,7 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function::operator(); + using igfun_t::operator(); axpyz() : exprtk::igeneric_function("TVVV|TVVVTT") @@ -40636,7 +45282,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]); @@ -40645,7 +45291,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::process(parameters, r0, r1, 3, 4, 1)) + if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 4, 5, 1)) return std::numeric_limits::quiet_NaN(); else if (helper::invalid_range(y, r0, r1)) return std::numeric_limits::quiet_NaN(); @@ -40664,7 +45310,7 @@ namespace exprtk }; template - class axpbyz : public exprtk::igeneric_function + class axpbyz exprtk_final : public exprtk::igeneric_function { public: @@ -40674,7 +45320,7 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function::operator(); + using igfun_t::operator(); axpbyz() : exprtk::igeneric_function("TVTVV|TVTVVTT") @@ -40686,7 +45332,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]); @@ -40695,7 +45341,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::process(parameters, r0, r1, 4, 5, 1)) + if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 5, 6, 1)) return std::numeric_limits::quiet_NaN(); else if (helper::invalid_range(y, r0, r1)) return std::numeric_limits::quiet_NaN(); @@ -40715,7 +45361,7 @@ namespace exprtk }; template - class axpbz : public exprtk::igeneric_function + class axpbsy exprtk_final : public exprtk::igeneric_function { public: @@ -40725,7 +45371,110 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function::operator(); + using igfun_t::operator(); + + axpbsy() + : exprtk::igeneric_function("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::process(parameters, r0, r1, 5, 6, 1)) + return std::numeric_limits::quiet_NaN(); + else if (helper::invalid_range(y, r0, r1)) + return std::numeric_limits::quiet_NaN(); + + const T a = scalar_t(parameters[0])(); + const T b = scalar_t(parameters[2])(); + + const std::size_t s = static_cast(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 + class axpbsyz exprtk_final : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function 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("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::process(parameters, r0, r1, 6, 7, 1)) + return std::numeric_limits::quiet_NaN(); + else if (helper::invalid_range(y, r0, r1)) + return std::numeric_limits::quiet_NaN(); + else if (helper::invalid_range(z, r0, r1)) + return std::numeric_limits::quiet_NaN(); + + const T a = scalar_t(parameters[0])(); + const T b = scalar_t(parameters[2])(); + + const std::size_t s = static_cast(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 + class axpbz exprtk_final : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function 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("TVTV|TVTVTT") @@ -40737,7 +45486,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]); @@ -40763,7 +45512,7 @@ namespace exprtk }; template - class dot : public exprtk::igeneric_function + class diff exprtk_final : public exprtk::igeneric_function { public: @@ -40773,7 +45522,55 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function::operator(); + using igfun_t::operator(); + + diff() + : exprtk::igeneric_function("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(scalar_t(parameters[2])())); + + for (std::size_t i = 0; i < stride; ++i) + { + y[i] = std::numeric_limits::quiet_NaN(); + } + + for (std::size_t i = (r0 + stride); i <= r1; ++i) + { + y[i] = x[i] - x[i - stride]; + } + + return T(1); + } + }; + + template + class dot exprtk_final : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function 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("VV|VVTT") @@ -40784,7 +45581,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]); @@ -40809,7 +45606,7 @@ namespace exprtk }; template - class dotk : public exprtk::igeneric_function + class dotk exprtk_final : public exprtk::igeneric_function { public: @@ -40819,7 +45616,7 @@ namespace exprtk typedef typename generic_type::scalar_view scalar_t; typedef typename generic_type::vector_view vector_t; - using exprtk::igeneric_function::operator(); + using igfun_t::operator(); dotk() : exprtk::igeneric_function("VV|VVTT") @@ -40830,7 +45627,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]); @@ -40855,30 +45652,155 @@ namespace exprtk } }; + template + class threshold_below exprtk_final : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function 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("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::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 + class threshold_above exprtk_final : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function 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("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::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 struct package { - all_true at; - all_false af; - any_true nt; - any_false nf; - count c; - copy cp; - rol rl; - ror rr; - shift_left sl; - shift_right sr; - sort st; - nthelement ne; - iota ia; - sumk sk; - axpy b1_axpy; - axpby b1_axpby; - axpyz b1_axpyz; - axpbyz b1_axpbyz; - axpbz b1_axpbz; - dot dt; - dotk dtk; + all_true at; + all_false af; + any_true nt; + any_false nf; + count c; + copy cp; + rol rl; + ror rr; + reverse rev; + shift_left sl; + shift_right sr; + sort st; + nthelement ne; + assign an; + iota ia; + sumk sk; + axpy b1_axpy; + axpby b1_axpby; + axpyz b1_axpyz; + axpbyz b1_axpbyz; + axpbsy b1_axpbsy; + axpbsyz b1_axpbsyz; + axpbz b1_axpbz; + diff df; + dot dt; + dotk dtk; + threshold_above ta; + threshold_below tb; bool register_package(exprtk::symbol_table& symtab) { @@ -40891,29 +45813,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; @@ -40932,11 +45861,11 @@ namespace exprtk using ::exprtk::details::char_cptr; static char_cptr library = "Mathematical Expression Toolkit"; - static char_cptr version = "2.71828182845904523536028747135266" - "2497757247093699959574966967627724" - "0766303535475945713821785251664274" - "2746639193200305992181741359662904"; - static char_cptr date = "20230101"; + static char_cptr version = "2.71828182845904523536028747135266249775" + "7247093699959574966967627724076630353547" + "5945713821785251664274274663919320030599" + "2181741359662904357290033429526059563073"; + static char_cptr date = "20240101"; static char_cptr min_cpp = "199711L"; static inline std::string data() @@ -40958,12 +45887,8 @@ namespace exprtk #undef exprtk_error_location #endif - #ifdef exprtk_disable_fallthrough_begin - #undef exprtk_disable_fallthrough_begin - #endif - - #ifdef exprtk_disable_fallthrough_end - #undef exprtk_disable_fallthrough_end + #ifdef exprtk_fallthrough + #undef exprtk_fallthrough #endif #ifdef exprtk_override diff --git a/external/fmt/CMakeLists.txt b/external/fmt/CMakeLists.txt deleted file mode 100644 index c4115e70ab..0000000000 --- a/external/fmt/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -cmake_minimum_required(VERSION 3.20 FATAL_ERROR) - -add_library(fmt STATIC src/format.cc src/os.cc) -target_include_directories(fmt PRIVATE include) diff --git a/external/fmt/meson.build b/external/fmt/meson.build new file mode 100644 index 0000000000..e3b46ac500 --- /dev/null +++ b/external/fmt/meson.build @@ -0,0 +1,11 @@ +# Author: Subhasis Ray +# Date: Sun Jul 7 + +fmt_src = [ + 'src/format.cc', + 'src/os.cc' +] + +incdir = include_directories('include') + +fmt_lib = static_library('fmt', fmt_src, include_directories: incdir) diff --git a/external/getopt/getopt.c b/external/getopt/getopt.c new file mode 100644 index 0000000000..7868ca180d --- /dev/null +++ b/external/getopt/getopt.c @@ -0,0 +1,52 @@ +/* ***************************************************************** +* +* Copyright 2016 Microsoft +* +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +******************************************************************/ + +#include "getopt.h" +#include + +char* optarg = NULL; +int optind = 1; + +int getopt(int argc, char *const argv[], const char *optstring) +{ + if ((optind >= argc) || (argv[optind][0] != '-') || (argv[optind][0] == 0)) + { + return -1; + } + + int opt = argv[optind][1]; + const char *p = strchr(optstring, opt); + + if (p == NULL) + { + return '?'; + } + if (p[1] == ':') + { + optind++; + if (optind >= argc) + { + return '?'; + } + optarg = argv[optind]; + optind++; + } + return opt; +} + diff --git a/external/getopt/getopt.h b/external/getopt/getopt.h new file mode 100644 index 0000000000..a48f5adf66 --- /dev/null +++ b/external/getopt/getopt.h @@ -0,0 +1,37 @@ +/* ***************************************************************** +* +* Copyright 2016 Microsoft +* +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +******************************************************************/ + +#ifndef GETOPT_H__ +#define GETOPT_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +extern char *optarg; +extern int optind; + +int getopt(int argc, char *const argv[], const char *optstring); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/external/getopt/meson.build b/external/getopt/meson.build new file mode 100644 index 0000000000..88e4731f13 --- /dev/null +++ b/external/getopt/meson.build @@ -0,0 +1,4 @@ +# Author: Subhasis Ray +# Date: Sun Jul 7 + +getopt_lib = static_library('getopt', ['getopt.c']) diff --git a/external/getopt/unistd.h b/external/getopt/unistd.h new file mode 100644 index 0000000000..8cf3b10ee5 --- /dev/null +++ b/external/getopt/unistd.h @@ -0,0 +1,56 @@ +#ifndef _UNISTD_H +#define _UNISTD_H 1 + +/* This is intended as a drop-in replacement for unistd.h on Windows. + * Please add functionality as neeeded. + * https://stackoverflow.com/a/826027/1202830 + */ + +#include +#include +#include "getopt.h" /* getopt at: https://gist.github.com/ashelly/7776712 */ +#include /* for getpid() and the exec..() family */ +#include /* for _getcwd() and _chdir() */ + +#define srandom srand +#define random rand + +/* Values for the second argument to access. + These may be OR'd together. */ +#define R_OK 4 /* Test for read permission. */ +#define W_OK 2 /* Test for write permission. */ +//#define X_OK 1 /* execute permission - unsupported in windows*/ +#define F_OK 0 /* Test for existence. */ + +#define access _access +#define dup2 _dup2 +#define execve _execve +#define ftruncate _chsize +#define unlink _unlink +#define fileno _fileno +#define getcwd _getcwd +#define chdir _chdir +#define isatty _isatty +#define lseek _lseek +/* read, write, and close are NOT being #defined here, because while there are file handle specific versions for Windows, they probably don't work for sockets. You need to look at your app and consider whether to call e.g. closesocket(). */ + +#ifdef _WIN64 +#define ssize_t __int64 +#else +#define ssize_t long +#endif + +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 +#define STDERR_FILENO 2 +/* should be in some equivalent to */ +//typedef __int8 int8_t; +//typedef __int16 int16_t; +//typedef __int32 int32_t; +//typedef __int64 int64_t; +//typedef unsigned __int8 uint8_t; +//typedef unsigned __int16 uint16_t; +//typedef unsigned __int32 uint32_t; +//typedef unsigned __int64 uint64_t; + +#endif /* unistd.h */ \ No newline at end of file diff --git a/external/libsoda/.travis.yml b/external/libsoda/.travis.yml deleted file mode 100644 index df47800d9e..0000000000 --- a/external/libsoda/.travis.yml +++ /dev/null @@ -1,25 +0,0 @@ -language: cpp -branches: - only: - - master - - devel - -compiler: - - clang - - gcc - -matrix: - # works on Precise and Trusty - - os: linux - addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-5 - env: - - MATRIX_EVAL="CC=gcc-5 && CXX=g++-5" - -script: - - cmake . && make && ctest --output-on-failure - diff --git a/external/libsoda/CMakeLists.txt b/external/libsoda/CMakeLists.txt deleted file mode 100644 index 572b8287a6..0000000000 --- a/external/libsoda/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -cmake_minimum_required(VERSION 3.20) - -find_package(Threads REQUIRED) - -add_library(lsoda ${CMAKE_CURRENT_SOURCE_DIR}/LSODA.cpp) - -add_executable(cpp_test_lsoda test_LSODA.cpp) -target_link_libraries(cpp_test_lsoda lsoda) - -add_executable(cpp_benchmark_lsoda benchmark_LSODA.cpp) -target_link_libraries(cpp_benchmark_lsoda lsoda ${CMAKE_THREAD_LIBS_INIT}) - -enable_testing() -add_test(NAME cpp_test_lsoda COMMAND $) -add_test(NAME cpp_test_benchmark COMMAND $) diff --git a/external/libsoda/LSODA.cpp b/external/libsoda/LSODA.cpp index 6e932a557d..fa026b59ff 100644 --- a/external/libsoda/LSODA.cpp +++ b/external/libsoda/LSODA.cpp @@ -57,7 +57,7 @@ bool LSODA::abs_compare(double a, double b) size_t LSODA::idamax1( const vector& dx, const size_t n, const size_t offset=0) { - size_t v = 0, vmax = 0; + double v = 0, vmax = 0; size_t idmax = 1; for( size_t i = 1; i <= n; i++) { diff --git a/external/libsoda/meson.build b/external/libsoda/meson.build new file mode 100644 index 0000000000..620d5d7141 --- /dev/null +++ b/external/libsoda/meson.build @@ -0,0 +1,6 @@ +# Author: Subhasis Ray +# Date: Sun Jul 7, 2024 + +threads_dep = dependency('Threads') + +lsoda_lib = static_library('soda', ['LSODA.cpp'], dependencies: threads_dep) diff --git a/external/tinyexpr/CMakeLists.txt b/external/tinyexpr/CMakeLists.txt deleted file mode 100644 index 5ebf73609d..0000000000 --- a/external/tinyexpr/CMakeLists.txt +++ /dev/null @@ -1,64 +0,0 @@ -cmake_minimum_required(VERSION 3.20) - -project(tinyexpr) - -option(TE_POW_FROM_RIGHT "Evaluate exponents from right to left." OFF) -option(TE_NAT_LOG "Define the log function as natural logarithm." OFF) -option(ENABLE_TESTS "Enabled tests" ON) -option(ENABLE_EXAMPALES "Enabled examples" ON) -option(ENABLE_BENCHMAKRS "Enabled benchamarks" ON) - -find_library(MATH_LIB m) - -set(SOURCE_FILES tinyexpr.c) -add_library(tinyexpr STATIC ${SOURCE_FILES}) - -if (TE_POW_FROM_RIGHT) - target_compile_definitions(tinyexpr PRIVATE TE_POW_FROM_RIGHT) -endif() -if (TE_NAT_LOG) - target_compile_definitions(tinyexpr PRIVATE TE_NAT_LOG) -endif() -target_link_libraries(tinyexpr ${MATH_LIB}) - -install(TARGETS tinyexpr ARCHIVE DESTINATION lib) -install(FILES tinyexpr.h DESTINATION include COMPONENT Devel) - -# Now tests. - -if (ENABLE_TESTS) - add_executable(tinyexpr_test test.c ) - target_link_libraries(tinyexpr_test tinyexpr) - - add_executable(tinyexpr_test_pr test.c) - target_compile_definitions(tinyexpr_test_pr PRIVATE TE_POW_FROM_RIGHT TE_NAT_LOG) - target_link_libraries(tinyexpr_test_pr tinyexpr ${MATH_LIB}) -endif() - -if (ENABLE_BENCHMAKRS) - add_executable(tinyexpr_benchmark benchmark.c) - target_link_libraries(tinyexpr_benchmark tinyexpr ${MATH_LIB}) -endif() - -if (ENABLE_EXAMPALES) - add_custom_target(examples) - file(GLOB _example_src "example*.c") - foreach( _ex_src ${_example_src}) - message(STATUS "Adding ${_ex_src} to examples" ) - get_filename_component(TGT_NAME ${_ex_src} NAME_WE) - set(TGT_EXAMPLE_NAME tinyexpr_${TGT_NAME}) - add_executable(${TGT_EXAMPLE_NAME} ${_ex_src} ) - target_link_libraries(${TGT_EXAMPLE_NAME} tinyexpr) - add_dependencies(examples ${TGT_EXAMPLE_NAME}) - endforeach() -endif() - -enable_testing() -add_test( NAME test1 - COMMAND $ - WORKING_DIRECTORY $CMAKE_CURRENT_BINARY_DIR} - ) -add_test( NAME test2 - COMMAND $ - WORKING_DIRECTORY $CMAKE_CURRENT_BINARY_DIR} - ) diff --git a/hsolve/CMakeLists.txt b/hsolve/CMakeLists.txt deleted file mode 100644 index 1a463e95c8..0000000000 --- a/hsolve/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -cmake_minimum_required(VERSION 3.20) -include( ${CMAKE_CURRENT_SOURCE_DIR}/../CheckCXXCompiler.cmake) -add_library(hsolve - HSolveStruct.cpp - HinesMatrix.cpp - Cell.cpp - HSolvePassive.cpp - RateLookup.cpp - HSolveActive.cpp - HSolveActiveSetup.cpp - HSolveInterface.cpp - HSolve.cpp - HSolveUtils.cpp - testHSolve.cpp - ZombieCompartment.cpp - ZombieCaConc.cpp - ZombieHHChannel.cpp -) - diff --git a/hsolve/ZombieHHChannel.cpp b/hsolve/ZombieHHChannel.cpp index 7876f9e991..d58fc3641e 100644 --- a/hsolve/ZombieHHChannel.cpp +++ b/hsolve/ZombieHHChannel.cpp @@ -156,8 +156,8 @@ void ZombieHHChannel::vSetUseConcentration( const Eref& e, int value ) void ZombieHHChannel::vSetModulation( const Eref& e , double modulation ) { if ( modulation > 0.0 ) { - modulation_ = modulation; - hsolve_->setHHmodulation( e.id(), modulation ); + ChanCommon::vSetModulation(e, modulation); + hsolve_->setHHmodulation( e.id(), modulation ); } } diff --git a/hsolve/ZombieHHChannel.h b/hsolve/ZombieHHChannel.h index 98bdf41c1a..fc70fe8dbb 100644 --- a/hsolve/ZombieHHChannel.h +++ b/hsolve/ZombieHHChannel.h @@ -54,47 +54,47 @@ class ZombieHHChannel: public HHChannelBase // Value field access function definitions ///////////////////////////////////////////////////////////// - void vSetGbar( const Eref& e , double Gbar ); - double vGetGbar( const Eref& e ) const; - void vSetGk( const Eref& e , double Gk ); - double vGetGk( const Eref& e ) const; - void vSetEk( const Eref& e , double Ek ); - double vGetEk( const Eref& e ) const; - void vSetIk( const Eref& e, double Ik ); - double vGetIk( const Eref& e ) const; - void vSetXpower( const Eref& e , double Xpower ); - void vSetYpower( const Eref& e , double Ypower ); - void vSetZpower( const Eref& e , double Zpower ); - void vSetInstant( const Eref& e , int instant ); - int vGetInstant( const Eref& e ) const; - void vSetX( const Eref& e , double X ); - double vGetX( const Eref& e ) const; - void vSetY( const Eref& e , double Y ); - double vGetY( const Eref& e ) const; - void vSetZ( const Eref& e , double Z ); - double vGetZ( const Eref& e ) const; + void vSetGbar( const Eref& e , double Gbar ) override; + double vGetGbar( const Eref& e ) const override; + void vSetGk( const Eref& e , double Gk ) override; + double vGetGk( const Eref& e ) const override; + void vSetEk( const Eref& e , double Ek ) override; + double vGetEk( const Eref& e ) const override; + void vSetIk( const Eref& e, double Ik ) override; + double vGetIk( const Eref& e ) const override; + void vSetXpower( const Eref& e , double Xpower ) override; + void vSetYpower( const Eref& e , double Ypower ) override; + void vSetZpower( const Eref& e , double Zpower ) override; + void vSetInstant( const Eref& e , int instant ) override; + int vGetInstant( const Eref& e ) const override; + void vSetX( const Eref& e , double X ) override; + double vGetX( const Eref& e ) const override; + void vSetY( const Eref& e , double Y ) override; + double vGetY( const Eref& e ) const override; + void vSetZ( const Eref& e , double Z ) override; + double vGetZ( const Eref& e ) const override; /** * Not trivial to change Ca-dependence once HSolve has been set up, and * unlikely that one would want to change this field after setup, so * keeping this field read-only. */ - void vSetUseConcentration( const Eref& e, int value ); + void vSetUseConcentration( const Eref& e, int value ) override; // implemented in baseclass: int getUseConcentration() const; - void vSetModulation( const Eref& e, double value ); + void vSetModulation( const Eref& e, double value ) override; ///////////////////////////////////////////////////////////// // Dest function definitions ///////////////////////////////////////////////////////////// - void vProcess( const Eref& e, ProcPtr p ); - void vReinit( const Eref& e, ProcPtr p ); - void vHandleConc( const Eref& e, double value); - void vCreateGate(const Eref& e , string name); + void vProcess( const Eref& e, ProcPtr p ) override; + void vReinit( const Eref& e, ProcPtr p ) override; + void vHandleConc( const Eref& e, double value) override; + void vCreateGate(const Eref& e , string name) override; ///////////////////////////////////////////////////////////// // Dummy function, not needed in Zombie. - void vHandleVm( double Vm ); + void vHandleVm( double Vm ) override; ///////////////////////////////////////////////////////////// // Gate handling functions @@ -102,19 +102,19 @@ class ZombieHHChannel: public HHChannelBase /** * Access function used for the X gate. The index is ignored. */ - HHGate* vGetXgate( unsigned int i ) const; + HHGate* vGetXgate( unsigned int i ) const override; /** * Access function used for the Y gate. The index is ignored. */ - HHGate* vGetYgate( unsigned int i ) const; + HHGate* vGetYgate( unsigned int i ) const override; /** * Access function used for the Z gate. The index is ignored. */ - HHGate* vGetZgate( unsigned int i ) const; + HHGate* vGetZgate( unsigned int i ) const override; ///////////////////////////////////////////////////////////// - void vSetSolver( const Eref& e , Id hsolve ); + void vSetSolver( const Eref& e , Id hsolve ) override; static const Cinfo* initCinfo(); diff --git a/hsolve/meson.build b/hsolve/meson.build new file mode 100644 index 0000000000..f2aa1c522c --- /dev/null +++ b/hsolve/meson.build @@ -0,0 +1,19 @@ +# Author: Subhasis Ray +# Date: Sun Jul 7 + +hsolve_src = ['HSolveStruct.cpp', + 'HinesMatrix.cpp', + 'Cell.cpp', + 'HSolvePassive.cpp', + 'RateLookup.cpp', + 'HSolveActive.cpp', + 'HSolveActiveSetup.cpp', + 'HSolveInterface.cpp', + 'HSolve.cpp', + 'HSolveUtils.cpp', + 'testHSolve.cpp', + 'ZombieCompartment.cpp', + 'ZombieCaConc.cpp', + 'ZombieHHChannel.cpp'] + +hsolve_lib = static_library('hsolve', hsolve_src) diff --git a/intfire/CMakeLists.txt b/intfire/CMakeLists.txt deleted file mode 100644 index a712c1e28f..0000000000 --- a/intfire/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -cmake_minimum_required(VERSION 3.20) -include( ${CMAKE_CURRENT_SOURCE_DIR}/../CheckCXXCompiler.cmake) -file(GLOB SRC *.cpp) -add_library(intfire ${SRC}) diff --git a/intfire/meson.build b/intfire/meson.build new file mode 100644 index 0000000000..d1868461c7 --- /dev/null +++ b/intfire/meson.build @@ -0,0 +1,12 @@ +# Author: Subhasis Ray +# Date: Sun Jul 7 + +intfire_src = ['AdExIF.cpp', + 'AdThreshIF.cpp', + 'ExIF.cpp', + 'IntFireBase.cpp', + 'IzhIF.cpp', + 'LIF.cpp', + 'QIF.cpp', + 'testIntFire.cpp'] +intfire_lib = static_library('intfire', intfire_src) diff --git a/kinetics/CMakeLists.txt b/kinetics/CMakeLists.txt deleted file mode 100644 index 714d2a5826..0000000000 --- a/kinetics/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -cmake_minimum_required(VERSION 3.20) -include( ${CMAKE_CURRENT_SOURCE_DIR}/../CheckCXXCompiler.cmake) -add_library(kinetics - PoolBase.cpp - Reac.cpp - EnzBase.cpp - Enz.cpp - MMenz.cpp - Species.cpp - ConcChan.cpp - ReadKkit.cpp - WriteKkit.cpp - ReadCspace.cpp - lookupVolumeFromMesh.cpp - testKinetics.cpp - ) diff --git a/kinetics/WriteKkit.cpp b/kinetics/WriteKkit.cpp index 2c061561c1..d24baf9c09 100644 --- a/kinetics/WriteKkit.cpp +++ b/kinetics/WriteKkit.cpp @@ -147,7 +147,7 @@ void writeEnz( ofstream& fout, Id id, double vol = Field< double >::get( enzMol, "volume" ) * NA * 1e-3; unsigned int isMichaelisMenten = 0; string enzClass = Field < string > :: get(id,"className"); - if (enzClass == "ZombieMMenz" or enzClass == "MMenz") + if (enzClass == "ZombieMMenz" || enzClass == "MMenz") { k1 = Field < double > :: get (id,"numKm"); k3 = Field < double > :: get (id,"kcat"); @@ -155,7 +155,7 @@ void writeEnz( ofstream& fout, Id id, k1 = (k2 + k3) / k1; isMichaelisMenten = 1; } - else if (enzClass == "ZombieEnz" or enzClass == "Enz") + else if (enzClass == "ZombieEnz" || enzClass == "Enz") { k1 = Field< double >::get( id, "k1" ); k2 = Field< double >::get( id, "k2" ); @@ -248,7 +248,7 @@ void writePool( ofstream& fout, Id id, string geometry; stringstream geometryTemp ; unsigned int slave_enable = 0; - if (pooltype == "BufPool" or pooltype == "ZombieBufPool") + if (pooltype == "BufPool" || pooltype == "ZombieBufPool") { vector< Id > children = Field< vector< Id > >::get( id, "children" ); if (children.size() == 0) @@ -257,7 +257,7 @@ void writePool( ofstream& fout, Id id, { string funcpath = Field :: get(*i,"path"); string clsname = Field :: get(*i,"className"); - if (clsname == "Function" or clsname == "ZombieFunction") + if (clsname == "Function" || clsname == "ZombieFunction") slave_enable = 0; else slave_enable = 4; @@ -379,7 +379,7 @@ void storeCplxEnzMsgs( Id enz, vector< string >& msgs, Id comptid ) void storeEnzMsgs( Id enz, vector< string >& msgs, Id comptid ) { string enzClass = Field < string > :: get(enz,"className"); - if (enzClass == "ZombieMMenz" or enzClass == "MMenz") + if (enzClass == "ZombieMMenz" || enzClass == "MMenz") storeMMenzMsgs(enz, msgs, comptid); else storeCplxEnzMsgs( enz, msgs, comptid ); @@ -585,7 +585,7 @@ void writeKkit( Id model, const string& fname ) string path = Field :: get (*itrp,"path"); Id enzPoolparent = Field :: get(*itrp,"parent"); string enzpoolClass = Field :: get(enzPoolparent,"className"); - if (enzpoolClass != "ZombieEnz" or enzpoolClass != "Enz") + if (enzpoolClass != "ZombieEnz" || enzpoolClass != "Enz") { Id annotaId( path+"/info"); if ( annotaId != Id() ) diff --git a/kinetics/meson.build b/kinetics/meson.build new file mode 100644 index 0000000000..7e083e671c --- /dev/null +++ b/kinetics/meson.build @@ -0,0 +1,17 @@ +# Author: Subhasis Ray +# Date: Sun Jul 7 + +kinetics_src = ['PoolBase.cpp', + 'Reac.cpp', + 'EnzBase.cpp', + 'Enz.cpp', + 'MMenz.cpp', + 'Species.cpp', + 'ConcChan.cpp', + 'ReadKkit.cpp', + 'WriteKkit.cpp', + 'ReadCspace.cpp', + 'lookupVolumeFromMesh.cpp', + 'testKinetics.cpp'] + +kinetics_lib = static_library('kinetics', kinetics_src, include_directories: gsl_dep.get_pkgconfig_variable('includedir')) diff --git a/ksolve/CMakeLists.txt b/ksolve/CMakeLists.txt deleted file mode 100644 index 35809ad362..0000000000 --- a/ksolve/CMakeLists.txt +++ /dev/null @@ -1,48 +0,0 @@ -cmake_minimum_required(VERSION 3.20) -include(CheckIncludeFileCXX) -include( ${CMAKE_CURRENT_SOURCE_DIR}/../CheckCXXCompiler.cmake) - -if(WITH_BOOST) - find_package(Boost 1.53 REQUIRED COMPONENTS thread) - add_definitions(-DUSE_BOOST ) - set(WITH_BOOST_ODE ON) - include_directories( ${Boost_INCLUDE_DIRS} ) - # This is still not part of official bindings. - include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../external/boost-numeric-bindings) -endif() - -# if boost ode is being used, don't use GSL. -if(WITH_BOOST_ODE) - # This is still not part of official bindings. - set(WITH_GSL OFF) - include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../external/boost-numeric-bindings) - add_definitions(-DUSE_BOOST_ODE -UUSE_GSL) - include_directories(${Boost_INCLUDE_DIRS}) - include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../external/boost-numeric-bindings) -elseif(WITH_GSL) - include_directories( ${GSL_INCLUDE_DIRS} ) - add_definitions(-DUSE_GSL -UUSE_BOOST_ODE -UUSE_BOOST) -endif(WITH_BOOST_ODE) - -set(KSOLVE_SRCS - KinSparseMatrix.cpp - VoxelPoolsBase.cpp - VoxelPools.cpp - GssaVoxelPools.cpp - RateTerm.cpp - FuncTerm.cpp - Stoich.cpp - Ksolve.cpp - Gsolve.cpp - KsolveBase.cpp - testKsolve.cpp - ) - -if(WITH_GSL) - list(APPEND KSOLVE_SRCS SteadyStateGsl.cpp ) -elseif(WITH_BOOST_ODE) - list(APPEND KSOLVE_SRCS SteadyStateBoost.cpp ) -endif(WITH_GSL) - -add_library( ksolve ${KSOLVE_SRCS} ) -target_link_libraries( ksolve ${Boost_LIBRARIES} ) diff --git a/ksolve/SteadyStateGsl.cpp b/ksolve/SteadyStateGsl.cpp index 7fc2332ffe..872865d895 100644 --- a/ksolve/SteadyStateGsl.cpp +++ b/ksolve/SteadyStateGsl.cpp @@ -525,7 +525,7 @@ void SteadyState::assignY( double* S ) void print_gsl_mat( gsl_matrix* m, const char* name ) { size_t i, j; - printf( "%s[%lu, %lu] = \n", name, m->size1, m->size2 ); + printf( "%s[%zu, %zu] = \n", name, m->size1, m->size2 ); for (i = 0; i < m->size1; i++) { for (j = 0; j < m->size2; j++) diff --git a/ksolve/Stoich.cpp b/ksolve/Stoich.cpp index 00ebd1ebd4..ae6b5bad90 100644 --- a/ksolve/Stoich.cpp +++ b/ksolve/Stoich.cpp @@ -425,7 +425,7 @@ void Stoich::setDsolve(Id dsolve) { dsolve_ = Id(); dinterface_ = 0; - if(not(dsolve.element()->cinfo()->isA("Dsolve"))) { + if(!(dsolve.element()->cinfo()->isA("Dsolve"))) { cout << "Error: Stoich::setDsolve: invalid class assigned," " should be Dsolve\n"; return; diff --git a/ksolve/meson.build b/ksolve/meson.build new file mode 100644 index 0000000000..95912208c7 --- /dev/null +++ b/ksolve/meson.build @@ -0,0 +1,20 @@ +# Author: Subhasis Ray +# Date: Sun Jul 7 + +ksolve_src = ['KinSparseMatrix.cpp', + 'VoxelPoolsBase.cpp', + 'VoxelPools.cpp', + 'GssaVoxelPools.cpp', + 'RateTerm.cpp', + 'FuncTerm.cpp', + 'Stoich.cpp', + 'Ksolve.cpp', + 'Gsolve.cpp', + 'KsolveBase.cpp', + 'SteadyStateGsl.cpp', + 'testKsolve.cpp', + # '../utility/utility.cpp' + ] + +ksolve_lib = static_library('ksolve', ksolve_src, dependencies: [gsl_dep], include_directories: gsl_dep.get_pkgconfig_variable('includedir')) + diff --git a/mesh/CMakeLists.txt b/mesh/CMakeLists.txt deleted file mode 100644 index be1359e624..0000000000 --- a/mesh/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -cmake_minimum_required(VERSION 3.20) -include( ${CMAKE_CURRENT_SOURCE_DIR}/../CheckCXXCompiler.cmake) -add_library(mesh - ChemCompt.cpp - MeshCompt.cpp - MeshEntry.cpp - CubeMesh.cpp - CylBase.cpp - CylMesh.cpp - NeuroNode.cpp - NeuroMesh.cpp - SpineEntry.cpp - SpineMesh.cpp - PsdMesh.cpp - EndoMesh.cpp - PresynMesh.cpp - testMesh.cpp - ) diff --git a/mesh/CylBase.cpp b/mesh/CylBase.cpp index 209977db25..4acddd3a4d 100644 --- a/mesh/CylBase.cpp +++ b/mesh/CylBase.cpp @@ -18,7 +18,7 @@ #include "CylBase.h" #include "../utility/Vec.h" -extern const double PI; // defined in consts.cpp +// extern const double PI; // defined in consts.cpp CylBase::CylBase( double x, double y, double z, double dia, double length, unsigned int numDivs ) @@ -132,10 +132,10 @@ bool CylBase::getIsCylinder() const double CylBase::volume( const CylBase& parent ) const { if ( isCylinder_ ) - return length_ * dia_ * dia_ * PI / 4.0; + return length_ * dia_ * dia_ * M_PI / 4.0; double r0 = parent.dia_/2.0; double r1 = dia_/2.0; - return length_ * ( r0*r0 + r0 *r1 + r1 * r1 ) * PI / 3.0; + return length_ * ( r0*r0 + r0 *r1 + r1 * r1 ) * M_PI / 3.0; } /** @@ -150,7 +150,7 @@ double CylBase::voxelVolume( const CylBase& parent, unsigned int fid ) const { assert( numDivs_ > fid ); if ( isCylinder_ ) - return length_ * dia_ * dia_ * PI / ( 4.0 * numDivs_ ); + return length_ * dia_ * dia_ * M_PI / ( 4.0 * numDivs_ ); double frac0 = ( static_cast< double >( fid ) ) / static_cast< double >( numDivs_ ); @@ -161,7 +161,7 @@ double CylBase::voxelVolume( const CylBase& parent, unsigned int fid ) const double s0 = length_ * frac0; double s1 = length_ * frac1; - return (s1 - s0) * ( r0*r0 + r0 *r1 + r1 * r1 ) * PI / 3.0; + return (s1 - s0) * ( r0*r0 + r0 *r1 + r1 * r1 ) * M_PI / 3.0; } /// Virtual function to return coords of mesh Entry. @@ -209,11 +209,11 @@ double CylBase::getDiffusionArea( { assert( fid < numDivs_ + 1 ); if ( isCylinder_ ) - return PI * dia_ * dia_ / 4.0; + return M_PI * dia_ * dia_ / 4.0; double frac0 = ( static_cast< double >( fid ) ) / static_cast< double >( numDivs_ ); double r0 = 0.5 * ( parent.dia_ * ( 1.0 - frac0 ) + dia_ * frac0 ); - return PI * r0 * r0; + return M_PI * r0 * r0; } /// Return the cross section area of the middle of the specified voxel. @@ -222,11 +222,11 @@ double CylBase::getMiddleArea( { assert( fid < numDivs_ ); if ( isCylinder_ ) - return PI * dia_ * dia_ / 4.0; + return M_PI * dia_ * dia_ / 4.0; double frac0 = ( 0.5 + static_cast< double >( fid ) ) / static_cast< double >( numDivs_ ); double r0 = 0.5 * ( parent.dia_ * ( 1.0 - frac0 ) + dia_ * frac0 ); - return PI * r0 * r0; + return M_PI * r0 * r0; } double CylBase::getVoxelLength() const @@ -267,9 +267,9 @@ static void fillPointsOnCircle( // This will cause small errors in area estimate but they will // be anisotropic. The alternative will have large errors toward // 360 degrees, but not elsewhere. - unsigned int numAngle = floor( 2.0 * PI * r / h + 0.5 ); + unsigned int numAngle = floor( 2.0 * M_PI * r / h + 0.5 ); assert( numAngle > 0 ); - double dtheta = 2.0 * PI / numAngle; + double dtheta = 2.0 * M_PI / numAngle; double dArea = h * dtheta * r; // March along points on surface of circle centred at q. for ( unsigned int j = 0; j < numAngle; ++j ) { @@ -295,10 +295,10 @@ static void fillPointsOnDisc( double dRadial = r / numRadial; for ( unsigned int i = 0; i < numRadial; ++i ) { double a = ( i + 0.5 ) * dRadial; - unsigned int numAngle = floor( 2.0 * PI * a / h + 0.5 ); + unsigned int numAngle = floor( 2.0 * M_PI * a / h + 0.5 ); if ( i == 0 ) numAngle = 1; - double dtheta = 2.0 * PI / numAngle; + double dtheta = 2.0 * M_PI / numAngle; double dArea = dRadial * dtheta * a; for ( unsigned int j = 0; j < numAngle; ++j ) { double theta = j * dtheta; diff --git a/mesh/meson.build b/mesh/meson.build new file mode 100644 index 0000000000..c7888eeebe --- /dev/null +++ b/mesh/meson.build @@ -0,0 +1,19 @@ +# Author: Subhasis Ray +# Date: Sun Jul 7 + +mesh_src = ['ChemCompt.cpp', + 'MeshCompt.cpp', + 'MeshEntry.cpp', + 'CubeMesh.cpp', + 'CylBase.cpp', + 'CylMesh.cpp', + 'NeuroNode.cpp', + 'NeuroMesh.cpp', + 'SpineEntry.cpp', + 'SpineMesh.cpp', + 'PsdMesh.cpp', + 'EndoMesh.cpp', + 'PresynMesh.cpp', + 'testMesh.cpp'] + +mesh_lib = static_library('mesh', mesh_src) diff --git a/meson.build b/meson.build new file mode 100644 index 0000000000..3ba7df0acf --- /dev/null +++ b/meson.build @@ -0,0 +1,279 @@ +# Project to build MOOSE's python module. +# Author: Subhasis Ray +# Date: Mon Jul 8 03:11:13 IST 2024 + +# To build pymoose with meson, run the following +# `meson setup --wipe _build` +# `cd _build` +# `meson compile` + +# To build installable wheels +# python -m build + +project('pymoose', 'c', 'cpp', + # The version is created dynamically based on git commit hash. For release, make this explicit string + version: run_command('git', 'rev-parse', '--short', 'HEAD', check:false).stdout().strip(), + default_options: ['c_std=c17', 'cpp_std=c++17']) + +pybind_dep = dependency('pybind11') +gsl_dep = dependency('gsl', version: '>=1.16') +# sundial_dep = dependency('sundial', version: '>=7.1.1') + +use_mpi = get_option('use_mpi') +if use_mpi + mpi_dep = dependency('mpi', required: true) + add_global_arguments('-DUSE_MPI', language: ['c', 'cpp']) +else + mpi_dep = [] +endif + +add_global_arguments('-DMOOSE_VERSION="4.0.1"', language: ['c', 'cpp']) +add_global_arguments('-DUSE_GSL', language: ['c', 'cpp']) + +############################################################## +# Credit: Borrowed from SciPy +############################################################## +python = import('python') +py = python.find_installation() +python_dep = py.dependency() + +min_numpy_version = '1.23.5' # keep in sync with pyproject.toml + +# Emit a warning for 32-bit Python installs on Windows; users are getting +# unexpected from-source builds there because we no longer provide wheels. +is_windows = host_machine.system() == 'windows' +if is_windows and py.has_variable('EXT_SUFFIX') + ext_suffix = py.get_variable('EXT_SUFFIX') + if ext_suffix.contains('win32') + warning('You are building from source on a 32-bit Python install. pymoose does not provide 32-bit wheels; install 64-bit Python if you are having issues!') + endif +endif + +cc = meson.get_compiler('c') +cpp = meson.get_compiler('cpp') +# cy = meson.get_compiler('cython') +message('C compiler', cc.get_id()) +message('CPP compiler', cpp.get_id()) +is_msvc = cc.get_id() == 'msvc' +link_args = [] +# link_args = ['-Wl,--allow-multiple-definition'] +# Check compiler is recent enough (see "Toolchain Roadmap" for details) +if cc.get_id() == 'gcc' + if not cc.version().version_compare('>=9.1') + error('pymoose requires GCC >= 9.1') + endif + # See: https://pybind11.readthedocs.io/en/stable/faq.html#someclass-declared-with-greater-visibility-than-the-type-of-its-field-someclass-member-wattributes + add_project_arguments('-fvisibility=hidden', language: ['c', 'cpp']) +elif cc.get_id() == 'clang' or cc.get_id() == 'clang-cl' + if not cc.version().version_compare('>=12.0') + error('pymoose requires clang >= 12.0') + endif +elif is_msvc + if not cc.version().version_compare('>=19.20') + error('pymoose requires at least vc142 (default with Visual Studio 2019) ' + \ + 'when building with MSVC') + endif + # Several sub libs link against the same other sublib and MSVC + # linker barfs at multiple defs of the same symbol + # add_project_link_arguments('/FORCE:MULTIPLE', '/WHOLEARCHIVE', language: ['c', 'cpp']) + link_args = [] +endif + + +_global_c_args = cc.get_supported_arguments( + '-Wno-unused-but-set-variable', + '-Wno-unused-function', + '-Wno-conversion', + '-Wno-misleading-indentation', +) +add_project_arguments(_global_c_args, language : 'c') + +# We need -lm for all C code (assuming it uses math functions, which is safe to +# assume for SciPy). For C++ it isn't needed, because libstdc++/libc++ is +# guaranteed to depend on it. For Fortran code, Meson already adds `-lm`. +m_dep = cc.find_library('m', required : false) +if m_dep.found() + add_project_link_arguments('-lm', language : 'c') +endif + +if host_machine.system() == 'darwin' + if cc.has_link_argument('-Wl,-ld_classic') + # New linker introduced in macOS 14 not working yet, see gh-19357 and gh-19387 + add_project_link_arguments('-Wl,-ld_classic', language : ['c', 'cpp']) + endif + if cc.has_link_argument('-Wl,-dead_strip') + # Allow linker to strip unused symbols + add_project_link_arguments('-Wl,-dead_strip', language : ['c', 'cpp']) + endif +endif + +# Link against conda env GSL +conda_res = run_command('python', '-c', 'import os; print(os.environ["CONDA_PREFIX"])', check: false) +if conda_res.returncode() == 0 + conda_lib_path = conda_res.stdout().strip() / 'Library/lib' +else + message('Environment variable CONDA_PREFIX not found. Libraries must be available in PATH, LD_LIBRARY_PARH, etc.') +endif + +if is_windows + # Deal with M_PI & friends; add `use_math_defines` to c_args or cpp_args + add_global_arguments('-D_USE_MATH_DEFINES', language: ['c', 'cpp']) + if cc.get_id() == 'gcc' # Workaround for mingw64/ucrt64 issue with `fmt` lib and `limit` + add_global_arguments('-std=gnu++11', language: ['c', 'cpp']) + endif +endif + +if is_msvc + # On Windows some of the object files are too big + add_global_arguments('/bigobj', language: ['c', 'cpp']) + if conda_res.returncode() == 0 + add_project_link_arguments('/LIBPATH:' + conda_lib_path, language: ['c', 'cpp']) + endif +endif + + + +compilers = { + 'C': cc, + 'CPP': cpp, +} + +machines = { + 'HOST': host_machine, + 'BUILD': build_machine, +} + +conf_data = configuration_data() + +# Set compiler information +foreach name, compiler : compilers + conf_data.set(name + '_COMP', compiler.get_id()) + conf_data.set(name + '_COMP_LINKER_ID', compiler.get_linker_id()) + conf_data.set(name + '_COMP_VERSION', compiler.version()) + conf_data.set(name + '_COMP_CMD_ARRAY', ', '.join(compiler.cmd_array())) + conf_data.set(name + '_COMP_ARGS', ', '.join( + get_option(name.to_lower() + '_args') + ) + ) + conf_data.set(name + '_COMP_LINK_ARGS', ', '.join( + get_option(name.to_lower() + '_link_args') + ) + ) +endforeach + +# Machines CPU and system information +foreach name, machine : machines + conf_data.set(name + '_CPU', machine.cpu()) + conf_data.set(name + '_CPU_FAMILY', machine.cpu_family()) + conf_data.set(name + '_CPU_ENDIAN', machine.endian()) + conf_data.set(name + '_CPU_SYSTEM', machine.system()) +endforeach + +add_global_arguments('-DCOMPILER_STRING="' + + compiler.get_id() + ' ' + + compiler.version() + '"', + language: ['c', 'cpp']) + +conf_data.set('CROSS_COMPILED', meson.is_cross_build()) + +# Python information +conf_data.set('PYTHON_PATH', py.full_path()) +conf_data.set('PYTHON_VERSION', py.language_version()) + + +# End Credit: SciPy +# ============================================================ +# libsoda = static_library('lsoda', 'external/libsoda/LSODA.cpp', +# include_directories: 'external/libsoda', +# install: false) +# libsoda_dep = declare_dependency(include_directories: 'external/libsoda', +# link_with: libsoda) + + +subdir(join_paths('external', 'libsoda')) +subdir(join_paths('external', 'fmt')) +if is_msvc + subdir(join_paths('external', 'getopt')) +endif +subdir('basecode') +subdir('biophysics') +subdir('builtins') +subdir('device') +subdir('diffusion') +subdir('examples') +subdir('hsolve') +subdir('intfire') +subdir('kinetics') +subdir('ksolve') +subdir('mesh') +subdir('mpi') +subdir('msg') +subdir('pybind11') +subdir('randnum') +subdir('scheduling') +subdir('shell') +subdir('signeur') +subdir('synapse') +subdir('utility') + + +sublibs = [ + lsoda_lib, + fmt_lib, + basecode_lib, + biophysics_lib, + builtins_lib, + device_lib, + diffusion_lib, + examples_lib, + hsolve_lib, + intfire_lib, + kinetics_lib, + ksolve_lib, + mesh_lib, + mpi_lib, + msg_lib, + pybind11_lib, + randnum_lib, + scheduling_lib, + shell_lib, + signeur_lib, + synapse_lib, + utility_lib, +] + + +if is_msvc + sublibs += getopt_lib +endif +moose_dir = py.get_install_dir() + +include_dirs = [join_paths('external', 'libsoda')] +# Windows does not have getopt library and its dependencies. A port is +# provided in "external/getopt" folder +if is_windows + include_dirs += [join_paths('external', 'getopt')] +endif + +pymoose = py.extension_module('_moose', join_paths('pybind11', 'pymoose.cpp'), + link_whole: sublibs, + link_args: link_args, + dependencies: [gsl_dep, mpi_dep, pybind_dep], #, libsoda_dep], + include_directories: include_dirs, + install: true, install_dir: join_paths(moose_dir, 'moose')) + +if is_windows + rename_cmd = 'move' +else + rename_cmd = 'mv' +endif + +install_subdir( + join_paths('python', 'moose'), + install_dir: moose_dir) + +install_subdir( + join_paths('python', 'rdesigneur'), + install_dir: moose_dir) + +message('Finished installing moose in', pymoose.full_path()) diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 0000000000..ac7b46a8db --- /dev/null +++ b/meson_options.txt @@ -0,0 +1,2 @@ +option('use_mpi', type: 'boolean', value: false, + description: 'If specified, build with MPI support') diff --git a/mpi/CMakeLists.txt b/mpi/CMakeLists.txt deleted file mode 100644 index d7fd2a9103..0000000000 --- a/mpi/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -cmake_minimum_required(VERSION 3.20) -include( ${CMAKE_CURRENT_SOURCE_DIR}/../CheckCXXCompiler.cmake) -IF(USE_MPI) - find_package(MPI REQUIRED) - include_directories(MPI_INCLUDE_PATH) - ADD_DEFINITIONS(-DUSE_MPI) -ENDIF(USE_MPI) - -add_library(moose_mpi - PostMaster.cpp - testMpi.cpp - ) - diff --git a/mpi/meson.build b/mpi/meson.build new file mode 100644 index 0000000000..79b82d2b43 --- /dev/null +++ b/mpi/meson.build @@ -0,0 +1,6 @@ +# Author: Subhasis Ray +# Date: Sun Jul 7 + +mpi_src = ['PostMaster.cpp', 'testMpi.cpp'] +mpi_lib = static_library('mpi', mpi_src) +# TODO: add include dirs and link options if USE_MPI is defined and MPI library is available diff --git a/msg/CMakeLists.txt b/msg/CMakeLists.txt deleted file mode 100644 index edf1592938..0000000000 --- a/msg/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -cmake_minimum_required(VERSION 3.20) -include( ${CMAKE_CURRENT_SOURCE_DIR}/../CheckCXXCompiler.cmake) -add_library(msg - Msg.cpp - DiagonalMsg.cpp - OneToAllMsg.cpp - OneToOneMsg.cpp - SingleMsg.cpp - SparseMsg.cpp - OneToOneDataIndexMsg.cpp - testMsg.cpp - ) diff --git a/msg/meson.build b/msg/meson.build new file mode 100644 index 0000000000..4015906f98 --- /dev/null +++ b/msg/meson.build @@ -0,0 +1,14 @@ +# Author: Subhasis Ray +# Date: Sun Jul 7 + +msg_src = ['Msg.cpp', + 'DiagonalMsg.cpp', + 'OneToAllMsg.cpp', + 'OneToOneMsg.cpp', + 'SingleMsg.cpp', + 'SparseMsg.cpp', + 'OneToOneDataIndexMsg.cpp', + 'testMsg.cpp'] + +msg_lib = static_library('msg', msg_src) + diff --git a/pybind11/CMakeLists.txt b/pybind11/CMakeLists.txt deleted file mode 100644 index c8fa0405b6..0000000000 --- a/pybind11/CMakeLists.txt +++ /dev/null @@ -1,84 +0,0 @@ -# Add pybind11 module. - -execute_process(COMMAND ${CMAKE_CXX_COMPILER} --version - OUTPUT_VARIABLE COMPILER_STRING - OUTPUT_STRIP_TRAILING_WHITESPACE) - -pybind11_add_module(_moose - pymoose.cpp - helper.cpp - Finfo.cpp - MooseVec.cpp - PyRun.cpp) - -add_dependencies(_moose libmoose) - -# Use in version_info dict. -target_compile_definitions(_moose PRIVATE - COMPILER_STRING="${CMAKE_CXX_COMPILER_ID},${CMAKE_CXX_COMPILER},${CMAKE_CXX_COMPILER_VERSION}") - -set_target_properties(_moose PROPERTIES - LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/python/moose - PREFIX "" - SUFFIX ".so") - -if(APPLE) - set(CMAKE_MODULE_LINKER_FLAGS "-undefined dynamic_lookup") - message(STATUS "ADDING some linker flags ${CMAKE_EXE_LINKER_FLAGS}") - # cmake --help-policy CMP0042 - set_target_properties(_moose PROPERTIES MACOSX_RPATH OFF) -endif(APPLE) - -if(APPLE) - # OSX - target_link_libraries(_moose PRIVATE - "-Wl,-all_load" - ${MOOSE_LIBRARIES} - ${STATIC_LIBRARIES}) - target_link_libraries(_moose PRIVATE ${SYSTEM_SHARED_LIBS}) -else(APPLE) - # Linux - target_link_libraries(_moose PRIVATE - "-Wl,--whole-archive" - ${MOOSE_LIBRARIES} - ${STATIC_LIBRARIES} - "-Wl,--no-whole-archive" - ${SYSTEM_SHARED_LIBS}) -endif() - - -# Copy python tree to BUILD directory. User can set PYTHONPATH to -# ${CMAKE_BINARY_DIR}/python. -set(PYMOOSE_BUILD_DIR ${CMAKE_BINARY_DIR}/python) -add_custom_target(copy_python_tree ALL - # Copy whole Python's source tree to build directory. - COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/python/ - ${PYMOOSE_BUILD_DIR} - COMMENT "pybind11: Copying Python src ${CMAKE_SOURCE_DIR}/python → ${PYMOOSE_BUILD_DIR}" - DEPENDS _moose - VERBATIM) - - -# Create a binary distribution inside a directory. Installation will copy that -# directory. -set(_platform "CMAKE") -set(PYMOOSE_BDIST_FILE ${CMAKE_BINARY_DIR}/pymoose-${VERSION_MOOSE}.${_platform}.tar.gz) -set(PYMOOSE_INSTALL_DIR ${CMAKE_BINARY_DIR}/_pymoose_temp_install) -file(MAKE_DIRECTORY ${PYMOOSE_INSTALL_DIR}) - -add_custom_command(OUTPUT ${PYMOOSE_BDIST_FILE} - COMMAND ${PYTHON_EXECUTABLE} setup.py build_py - COMMAND ${PYTHON_EXECUTABLE} setup.py bdist_dumb - --skip-build -p "${_platform}" -d ${CMAKE_BINARY_DIR} - COMMAND ${CMAKE_COMMAND} -E chdir ${PYMOOSE_INSTALL_DIR} tar xf ${PYMOOSE_BDIST_FILE} - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - COMMENT "python's binary distribution is saved to ${CMAKE_BINARY_DIR}" - VERBATIM) - -add_custom_target(pymoose_sdist ALL - DEPENDS ${PYMOOSE_BDIST_FILE} _moose - COMMENT "Building pymoose source distribution.") - -install(DIRECTORY ${PYMOOSE_INSTALL_DIR}/usr/local/ - DESTINATION ${CMAKE_INSTALL_PREFIX} - CONFIGURATIONS Debug Release) diff --git a/pybind11/Finfo.cpp b/pybind11/Finfo.cpp index 4d24179964..5b40c38690 100644 --- a/pybind11/Finfo.cpp +++ b/pybind11/Finfo.cpp @@ -9,159 +9,78 @@ // // ===================================================================================== -#include -#include -#include -#include - -namespace py = pybind11; +#include "Finfo.h" +#include "helper.h" +#include "pymoose.h" #include "../basecode/header.h" +#include "../builtins/Variable.h" #include "../utility/print_function.hpp" #include "../utility/strutil.h" -#include "../builtins/Variable.h" -#include "pymoose.h" -#include "helper.h" -#include "Finfo.h" -__Finfo__::__Finfo__(const ObjId& oid, const Finfo* f, const string& finfoType) - : oid_(oid), f_(f), finfoType_(finfoType), pVec_(nullptr) +ObjId getFieldObjId(const ObjId &oid, const Finfo *f) { - if(finfoType == "DestFinfo") - func_ = [oid, f](const py::object& key) { - return getLookupValueFinfoItem(oid, f, key); - }; - else if(finfoType == "FieldElementFinfo") - func_ = [oid, f](const py::object& index) { - // this is essential of make this function static. - // Cast to int because we support negative indexing. - return getElementFinfoItem(oid, f, py::cast(index)); - }; - else if(finfoType == "LookupValueFinfo") - func_ = [oid, f, this](const py::object& key) { - // Assigning is essential or make these functions static. - return this->getLookupValueFinfoItem(oid, f, key); - }; - else - func_ = [this](const py::object& key) { - throw runtime_error("Not supported for Finfo type '" + finfoType_ + - "'"); - return py::none(); - }; + return ObjId(oid.path() + "/" + f->name()); } -// Exposed to python as __setitem__ on Finfo -bool __Finfo__::setItem(const py::object& key, const py::object& val) +template +std::function getSetGetFunc1(const ObjId &oid, const string &fname) { - return __Finfo__::setLookupValueFinfoItem(oid_, key, val, f_); + std::function func = [oid, fname](const T &val) { + return SetGet1::set(oid, fname, val); + }; + std::cout << "getSetGet1Func" << std::endl; + return func; } -bool __Finfo__::setLookupValueFinfoItem(const ObjId& oid, const py::object& key, - const py::object& val, - const Finfo* finfo) -{ - auto rttType = finfo->rttiType(); - auto fieldName = finfo->name(); - vector srcDestType; - moose::tokenize(rttType, ",", srcDestType); - assert(srcDestType.size() == 2); - - auto srcType = srcDestType[0]; - auto destType = srcDestType[1]; - - if(srcType == "unsigned int") { - if(destType == "double") - return LookupField::set( - oid, fieldName, py::cast(key), - py::cast(val)); - } - if(srcType == "string") { - if(destType == "double") - return LookupField::set( - oid, fieldName, py::cast(key), py::cast(val)); - } - if(srcType == "string") { - if(destType == "vector") - return LookupField>::set( - oid, fieldName, py::cast(key), py::cast>(val)); - } - if(srcType == "string") { - if(destType == "long") - return LookupField::set( - oid, fieldName, py::cast(key), py::cast(val)); - } - if(srcType == "string") { - if(destType == "vector") - return LookupField>::set( - oid, fieldName, py::cast(key), py::cast>(val)); - } - if(srcType == "string") { - if(destType == "string") - return LookupField::set( - oid, fieldName, py::cast(key), py::cast(val)); - } - if(srcType == "string") { - if(destType == "vector") - return LookupField>::set( - oid, fieldName, py::cast(key), py::cast>(val)); - } - - py::print("NotImplemented::setLookupValueFinfoItem:", key, "to value", val, - "for object", oid.path(), "and fieldName=", fieldName, - "rttiType=", rttType, srcDestType); - throw runtime_error("NotImplemented"); - return true; -} - -py::object __Finfo__::getLookupValueFinfoItem(const ObjId& oid, const Finfo* f, - const py::object& key) +py::object getFieldValue(const ObjId &oid, const Finfo *f) { - auto rttType = f->rttiType(); auto fname = f->name(); - vector srcDestType; - moose::tokenize(rttType, ",", srcDestType); - string srcType = srcDestType[0]; - string tgtType = srcDestType[1]; - py::object r = py::none(); - - if(srcType == "string") - return getLookupValueFinfoItemInner(oid, f, key.cast(), - tgtType); - if(srcType == "unsigned int") - return getLookupValueFinfoItemInner( - oid, f, key.cast(), tgtType); - if(srcType == "ObjId") - return getLookupValueFinfoItemInner(oid, f, key.cast(), - tgtType); - if(srcType == "vector") - return getLookupValueFinfoItemInner>( - oid, f, key.cast>(), tgtType); - if(srcType == "Id") - return getLookupValueFinfoItemInner(oid, f, key.cast(), - tgtType); - - py::print("getLookupValueFinfoItem::NotImplemented for key:", key, - "srcType:", srcType, "and tgtType:", tgtType, - "path: ", oid.path()); - throw runtime_error("getLookupValueFinfoItem::NotImplemented error"); + if(rttType == "double" || rttType == "float") { + r = py::float_(getField(oid, fname)); + } + else if(rttType == "vector") { + r = getFieldNumpy(oid, fname); + } + else if(rttType == "vector") { + r = getFieldNumpy(oid, fname); + } + else if(rttType == "string") + r = py::str(getField(oid, fname)); + else if(rttType == "char") + r = py::int_(getField(oid, fname)); + else if(rttType == "int") + r = py::int_(getField(oid, fname)); + else if(rttType == "unsigned int") + r = py::int_(getField(oid, fname)); + else if(rttType == "unsigned long") + r = py::int_(getField(oid, fname)); + else if(rttType == "bool") + r = py::bool_(getField(oid, fname)); + else if(rttType == "Id") + r = py::cast(getField(oid, fname)); + else if(rttType == "ObjId") + r = py::cast(getField(oid, fname)); + else if(rttType == "Variable") + r = py::cast(getField(oid, fname)); + else if(rttType == "vector") + r = py::cast(getField>(oid, fname)); + else if(rttType == "vector") + r = py::cast(getField>(oid, fname)); + else if(rttType == "vector") + r = py::cast(getField>(oid, fname)); + else { + MOOSE_WARN("Warning: getValueFinfo:: Unsupported type '" + rttType + + "'"); + r = py::none(); + } return r; } -py::object __Finfo__::getItem(const py::object& key) -{ - return func_(key); -} - -py::object __Finfo__::operator()(const py::object& key) -{ - return getItem(key); -} - -py::cpp_function __Finfo__::getDestFinfoSetterFunc(const ObjId& oid, - const Finfo* finfo) +py::cpp_function getDestFinfoSetterFunc(const ObjId &oid, const Finfo *finfo) { const auto rttType = finfo->rttiType(); vector types; @@ -174,11 +93,41 @@ py::cpp_function __Finfo__::getDestFinfoSetterFunc(const ObjId& oid, return getDestFinfoSetterFunc2(oid, finfo, types[0], types[1]); } +// Get DestFinfo1. +py::cpp_function getDestFinfoSetterFunc1(const ObjId &oid, const Finfo *finfo, + const string &ftype) +{ + const auto fname = finfo->name(); + if(ftype == "void") { + std::function func = [oid, fname]() { + return SetGet0::set(oid, fname); + }; + return func; + } + + if(ftype == "double") + return getSetGetFunc1(oid, fname); + if(ftype == "ObjId") + return getSetGetFunc1(oid, fname); + if(ftype == "Id") + return getSetGetFunc1(oid, fname); + if(ftype == "string") + return getSetGetFunc1(oid, fname); + if(ftype == "vector") + return getSetGetFunc1>(oid, fname); + if(ftype == "vector") + return getSetGetFunc1>(oid, fname); + if(ftype == "vector") + return getSetGetFunc1>(oid, fname); + + throw runtime_error("getFieldPropertyDestFinfo1::NotImplemented " + fname + + " for rttType " + ftype + " for oid " + oid.path()); +} + // Get DestFinfo2 -py::cpp_function __Finfo__::getDestFinfoSetterFunc2(const ObjId& oid, - const Finfo* finfo, - const string& ftype1, - const string& ftype2) +py::cpp_function getDestFinfoSetterFunc2(const ObjId &oid, const Finfo *finfo, + const string &ftype1, + const string &ftype2) { const auto fname = finfo->name(); if(ftype1 == "double") { @@ -215,15 +164,17 @@ py::cpp_function __Finfo__::getDestFinfoSetterFunc2(const ObjId& oid, } } if(ftype1 == "ObjId" && ftype2 == "ObjId") { - std::function func = [oid, fname](ObjId a, ObjId b) { + std::function func = [oid, fname](ObjId a, + ObjId b) { return SetGet2::set(oid, fname, a, b); }; return func; } if(ftype1 == "vector" && ftype2 == "double") { - std::function, double)> func = [oid, fname](vector a, double b) { - return SetGet2, double>::set(oid, fname, a, b); - }; + std::function, double)> func = + [oid, fname](vector a, double b) { + return SetGet2, double>::set(oid, fname, a, b); + }; return func; } @@ -232,85 +183,7 @@ py::cpp_function __Finfo__::getDestFinfoSetterFunc2(const ObjId& oid, oid.path()); } -// Get DestFinfo1. -py::cpp_function __Finfo__::getDestFinfoSetterFunc1(const ObjId& oid, - const Finfo* finfo, - const string& ftype) -{ - const auto fname = finfo->name(); - if(ftype == "void") { - std::function func = [oid, fname]() { - return SetGet0::set(oid, fname); - }; - return func; - } - - if(ftype == "double") - return getSetGetFunc1(oid, fname); - if(ftype == "ObjId") - return getSetGetFunc1(oid, fname); - if(ftype == "Id") - return getSetGetFunc1(oid, fname); - if(ftype == "string") - return getSetGetFunc1(oid, fname); - if(ftype == "vector") - return getSetGetFunc1>(oid, fname); - if(ftype == "vector") - return getSetGetFunc1>(oid, fname); - if(ftype == "vector") - return getSetGetFunc1>(oid, fname); - - throw runtime_error("getFieldPropertyDestFinfo1::NotImplemented " + fname + - " for rttType " + ftype + " for oid " + oid.path()); -} - -py::object __Finfo__::getFieldValue(const ObjId& oid, const Finfo* f) -{ - auto rttType = f->rttiType(); - auto fname = f->name(); - py::object r = py::none(); - - if(rttType == "double" or rttType == "float") - r = pybind11::float_(getField(oid, fname)); - else if(rttType == "vector") { - r = getFieldNumpy(oid, fname); - } - else if(rttType == "vector") { - r = getFieldNumpy(oid, fname); - } - else if(rttType == "string") - r = pybind11::str(getField(oid, fname)); - else if(rttType == "char") - r = pybind11::int_(getField(oid, fname)); - else if(rttType == "int") - r = pybind11::int_(getField(oid, fname)); - else if(rttType == "unsigned int") - r = pybind11::int_(getField(oid, fname)); - else if(rttType == "unsigned long") - r = pybind11::int_(getField(oid, fname)); - else if(rttType == "bool") - r = pybind11::bool_(getField(oid, fname)); - else if(rttType == "Id") - r = py::cast(getField(oid, fname)); - else if(rttType == "ObjId") - r = py::cast(getField(oid, fname)); - else if(rttType == "Variable") - r = py::cast(getField(oid, fname)); - else if(rttType == "vector") - r = py::cast(getField>(oid, fname)); - else if(rttType == "vector") - r = py::cast(getField>(oid, fname)); - else if(rttType == "vector") - r = py::cast(getField>(oid, fname)); - else { - MOOSE_WARN("Warning: getValueFinfo:: Unsupported type '" + rttType + - "'"); - r = py::none(); - } - return r; -} - -py::list __Finfo__::getElementFinfo(const ObjId& objid, const Finfo* f) +py::list getElementFinfo(const ObjId &objid, const Finfo *f) { auto fname = f->name(); auto oid = ObjId(objid.path() + '/' + fname); @@ -321,72 +194,162 @@ py::list __Finfo__::getElementFinfo(const ObjId& objid, const Finfo* f) return py::cast(res); } -py::object __Finfo__::getElementFinfoItem(const ObjId& oid, const Finfo* f, - int index) -{ - size_t numFields = getNumFieldStatic(oid, f); +py::object getElementFinfoItem(const ObjId &oid, const Finfo *f, int index) +{ + size_t numFields = getNumField(oid, f); size_t i = (index < 0) ? (int)numFields + index : index; if(i >= numFields) throw py::index_error("Index " + to_string(i) + " out of range."); - auto o = ObjId(oid.path() + '/' + f->name()); - return py::cast(ObjId(o.path(), o.dataIndex, i)); + auto foid = getFieldObjId(oid, f); + return py::cast(ObjId(foid.path(), foid.dataIndex, i)); } -string __Finfo__::type() const +unsigned int getNumField(const ObjId &oid, const Finfo *f) { - return finfoType_; + ObjId foid = getFieldObjId(oid, f); + return Field::get(foid, "numField"); } -unsigned int __Finfo__::getNumField() +bool setNumField(const ObjId &oid, const Finfo *f, unsigned int num) { - return __Finfo__::getNumFieldStatic(oid_, f_); + ObjId foid = getFieldObjId(oid, f); + return Field::set(foid, "numField", num); } -bool __Finfo__::setNumField(unsigned int num) +py::object getLookupValueFinfoItem(const ObjId &oid, const Finfo *f, + const py::object &key) { - return __Finfo__::setNumFieldStatic(oid_, f_, num); -} -unsigned int __Finfo__::getNumFieldStatic(const ObjId& oid, const Finfo* f) -{ - auto o = __Finfo__::getObjIdStatic(oid, f); - return Field::get(o, "numField"); -} + auto rttType = f->rttiType(); + auto fname = f->name(); + vector srcDestType; + moose::tokenize(rttType, ",", srcDestType); + string srcType = srcDestType[0]; + string tgtType = srcDestType[1]; -bool __Finfo__::setNumFieldStatic(const ObjId& oid, const Finfo* f, - unsigned int num) -{ - auto o = __Finfo__::getObjIdStatic(oid, f); - return Field::set(o, "numField", num); -} + py::object r = py::none(); -// Static function. -ObjId __Finfo__::getObjIdStatic(const ObjId& oid, const Finfo* f) -{ - return ObjId(oid.path() + '/' + f->name()); -} + if(srcType == "string") + return getLookupValueFinfoItemInner(oid, f, key.cast(), + tgtType); + if(srcType == "unsigned int") + return getLookupValueFinfoItemInner( + oid, f, key.cast(), tgtType); + if(srcType == "ObjId") + return getLookupValueFinfoItemInner(oid, f, key.cast(), + tgtType); + if(srcType == "vector") + return getLookupValueFinfoItemInner>( + oid, f, key.cast>(), tgtType); + if(srcType == "Id") + return getLookupValueFinfoItemInner(oid, f, key.cast(), + tgtType); -// Non static function. -ObjId __Finfo__::getObjId() const -{ - return ObjId(oid_.path() + '/' + f_->name()); + py::print("getLookupValueFinfoItem::NotImplemented for key:", key, + "srcType:", srcType, "and tgtType:", tgtType, + "path: ", oid.path()); + throw runtime_error("getLookupValueFinfoItem::NotImplemented error"); + return r; } -// Return by copy. -MooseVec __Finfo__::getMooseVec() +template +py::object getLookupValueFinfoItemInner(const ObjId &oid, const Finfo *f, + const T &key, const string &tgtType) { - return MooseVec(getObjId()); + auto fname = f->name(); + if(tgtType == "bool") + return py::cast(LookupField::get(oid, fname, key)); + if(tgtType == "double") + return py::cast(LookupField::get(oid, fname, key)); + if(tgtType == "unsigned int") + return py::cast(LookupField::get(oid, fname, key)); + if(tgtType == "int") + return py::cast(LookupField::get(oid, fname, key)); + if(tgtType == "string") + return py::cast(LookupField::get(oid, fname, key)); + if(tgtType == "ObjId") + return py::cast(LookupField::get(oid, fname, key)); + if(tgtType == "Id") + return py::cast(LookupField::get(oid, fname, key)); + if(tgtType == "vector") + return py::cast(LookupField>::get(oid, fname, key)); + if(tgtType == "vector") + return py::cast( + LookupField>::get(oid, fname, key)); + if(tgtType == "vector") + return py::cast(LookupField>::get(oid, fname, key)); + if(tgtType == "vector") + return py::cast(LookupField>::get(oid, fname, key)); + if(tgtType == "vector") + return py::cast(LookupField>::get(oid, fname, key)); + + py::print(__func__, ":: warning: Could not find", fname, "for key", key, + "(type", tgtType, ") on path ", oid.path()); + throw py::key_error("Attribute error."); + return py::none(); } -MooseVec* __Finfo__::getMooseVecPtr() + +bool setLookupValueFinfoItem(const ObjId& oid, const py::object& key, + const py::object& val, + const Finfo* finfo) { - if(!pVec_) - pVec_.reset(new MooseVec(getObjId())); - return pVec_.get(); + auto rttType = finfo->rttiType(); + auto fieldName = finfo->name(); + + vector srcDestType; + moose::tokenize(rttType, ",", srcDestType); + assert(srcDestType.size() == 2); + + auto srcType = srcDestType[0]; + auto destType = srcDestType[1]; + + if(srcType == "unsigned int") { + if(destType == "double") + return LookupField::set( + oid, fieldName, py::cast(key), + py::cast(val)); + } + if(srcType == "string") { + if(destType == "double") + return LookupField::set( + oid, fieldName, py::cast(key), py::cast(val)); + } + if(srcType == "string") { + if(destType == "vector") + return LookupField>::set( + oid, fieldName, py::cast(key), py::cast>(val)); + } + if(srcType == "string") { + if(destType == "long") + return LookupField::set( + oid, fieldName, py::cast(key), py::cast(val)); + } + if(srcType == "string") { + if(destType == "vector") + return LookupField>::set( + oid, fieldName, py::cast(key), py::cast>(val)); + } + if(srcType == "string") { + if(destType == "string") + return LookupField::set( + oid, fieldName, py::cast(key), py::cast(val)); + } + if(srcType == "string") { + if(destType == "vector") + return LookupField>::set( + oid, fieldName, py::cast(key), py::cast>(val)); + } + + py::print("NotImplemented::setLookupValueFinfoItem:", key, "to value", val, + "for object", oid.path(), "and fieldName=", fieldName, + "rttiType=", rttType, srcDestType); + throw runtime_error("NotImplemented"); + return true; } -vector> __Finfo__::finfoNames(const Cinfo* cinfo, - const string& what = "*") +vector> finfoNames(const Cinfo *cinfo, + const string &what = "*") { vector> ret; @@ -398,40 +361,134 @@ vector> __Finfo__::finfoNames(const Cinfo* cinfo, if(what == "valueFinfo" || what == "value" || what == "*") { for(unsigned int ii = 0; ii < cinfo->getNumValueFinfo(); ++ii) { - Finfo* finfo = cinfo->getValueFinfo(ii); + Finfo *finfo = cinfo->getValueFinfo(ii); ret.push_back({finfo->name(), finfo->rttiType()}); } } else if(what == "srcFinfo" || what == "src" || what == "*") { for(unsigned int ii = 0; ii < cinfo->getNumSrcFinfo(); ++ii) { - Finfo* finfo = cinfo->getSrcFinfo(ii); + Finfo *finfo = cinfo->getSrcFinfo(ii); ret.push_back({finfo->name(), finfo->rttiType()}); } } else if(what == "destFinfo" || what == "dest" || what == "*") { for(unsigned int ii = 0; ii < cinfo->getNumDestFinfo(); ++ii) { - Finfo* finfo = cinfo->getDestFinfo(ii); + Finfo *finfo = cinfo->getDestFinfo(ii); ret.push_back({finfo->name(), finfo->rttiType()}); } } else if(what == "lookupFinfo" || what == "lookup" || what == "*") { for(unsigned int ii = 0; ii < cinfo->getNumLookupFinfo(); ++ii) { - Finfo* finfo = cinfo->getLookupFinfo(ii); + Finfo *finfo = cinfo->getLookupFinfo(ii); ret.push_back({finfo->name(), finfo->rttiType()}); } } else if(what == "sharedFinfo" || what == "shared" || what == "*") { for(unsigned int ii = 0; ii < cinfo->getNumSrcFinfo(); ++ii) { - Finfo* finfo = cinfo->getSrcFinfo(ii); + Finfo *finfo = cinfo->getSrcFinfo(ii); ret.push_back({finfo->name(), finfo->rttiType()}); } } else if(what == "fieldElementFinfo" || what == "fieldElement" || what == "*") { for(unsigned int ii = 0; ii < cinfo->getNumFieldElementFinfo(); ++ii) { - Finfo* finfo = cinfo->getFieldElementFinfo(ii); + Finfo *finfo = cinfo->getFieldElementFinfo(ii); ret.push_back({finfo->name(), finfo->rttiType()}); } } return ret; } + +////////////////////////////////////////////////////////////// +// __Finfo__ class member functions +////////////////////////////////////////////////////////////// +__Finfo__::__Finfo__(const ObjId &oid, const Finfo *f, const string &finfoType) + : oid_(oid), f_(f), finfoType_(finfoType), pVec_(nullptr) +{ + // why LookupFinfo for DestFinfo??? Pretty sure this was a mistake! - Subha + // if(finfoType == "DestFinfo") + // func_ = [oid, f](const py::object &key) { + // cout << "Creating LookupFinfo for DestFinfo" << endl; // DEBUG + // return getLookupValueFinfoItem(oid, f, key); + // }; + // else + if(finfoType == "FieldElementFinfo") + func_ = [oid, f](const py::object &index) { + // this is essential of make this function static. + // Cast to int because we support negative indexing. + return getElementFinfoItem(oid, f, py::cast(index)); + }; + else if(finfoType == "LookupValueFinfo") + func_ = [oid, f, this](const py::object &key) { + // Assigning is essential or make these functions static. + return getLookupValueFinfoItem(oid, f, key); + }; + else + func_ = [this](const py::object &key) { + throw runtime_error("Not supported for Finfo type '" + finfoType_ + + "'"); + return py::none(); + }; +} + +ObjId __Finfo__::getObjId() const +{ + return getFieldObjId(oid_, f_); +} + +unsigned int __Finfo__::getNumField() +{ + + return Field::get(oid_, "numField"); +} + +bool __Finfo__::setNumField(unsigned int num) +{ + return Field::set(oid_, "numField", num); +} + +py::object __Finfo__::getItem(const py::object &key) +{ + return this->func_(key); +} + +// Exposed to python as __setitem__ on Finfo +bool __Finfo__::setItem(const py::object &key, const py::object &val) +{ + return setLookupValueFinfoItem(oid_, key, val, f_); +} + +py::object __Finfo__::operator()(const py::object &key) +{ + return this->getItem(key); +} + +// Return by copy. +MooseVec __Finfo__::getMooseVec() +{ + return MooseVec(this->getObjId()); +} + +MooseVec *__Finfo__::getMooseVecPtr() +{ + if(!pVec_) + pVec_.reset(new MooseVec(this->getObjId())); + return pVec_.get(); +} + +// py::object __Finfo__::getElementFinfoItem(int index) +// { +// size_t numFields = this->getNumField(); +// size_t i = (index < 0) ? (int)numFields + index : index; +// if(i >= numFields) +// throw py::index_error("Index " + to_string(i) + " out of range."); +// auto oid = this->getObjId() +// return py::cast(ObjId(oid.path(), oid.dataIndex, i)); +// } + +string __Finfo__::type() const +{ + return finfoType_; +} + +// Non static function. diff --git a/pybind11/Finfo.h b/pybind11/Finfo.h index 1c0da44e1d..68c64d1c81 100644 --- a/pybind11/Finfo.h +++ b/pybind11/Finfo.h @@ -10,125 +10,114 @@ #ifndef FINFO_H #define FINFO_H +#include "../basecode/header.h" + +#include +#include +#include +#include + +namespace py = pybind11; + +using namespace std; + class MooseVec; +// class ObjId; +// class Finfo; -class __Finfo__ { -public: - __Finfo__(const ObjId& oid, const Finfo* f, const string& finfoType); - - template - static py::object getLookupValueFinfoItemInner(const ObjId& oid, - const Finfo* f, const T& key, - const string& tgtType) - { - auto fname = f->name(); - if(tgtType == "bool") - return py::cast(LookupField::get(oid, fname, key)); - if(tgtType == "double") - return py::cast(LookupField::get(oid, fname, key)); - if(tgtType == "unsigned int") - return py::cast(LookupField::get(oid, fname, key)); - if(tgtType == "int") - return py::cast(LookupField::get(oid, fname, key)); - if(tgtType == "string") - return py::cast(LookupField::get(oid, fname, key)); - if(tgtType == "ObjId") - return py::cast(LookupField::get(oid, fname, key)); - if(tgtType == "Id") - return py::cast(LookupField::get(oid, fname, key)); - if(tgtType == "vector") - return py::cast( - LookupField>::get(oid, fname, key)); - if(tgtType == "vector") - return py::cast( - LookupField>::get(oid, fname, key)); - if(tgtType == "vector") - return py::cast(LookupField>::get(oid, fname, key)); - if(tgtType == "vector") - return py::cast( - LookupField>::get(oid, fname, key)); - if(tgtType == "vector") - return py::cast( - LookupField>::get(oid, fname, key)); - - py::print(__func__, ":: warning: Could not find", fname, "for key", key, - "(type", tgtType, ") on path ", oid.path()); - throw py::key_error("Attribute error."); - return py::none(); - } - - template - static std::function getSetGetFunc1(const ObjId& oid, - const string& fname) - { - std::function func = [oid, fname](const T& val) { - return SetGet1::set(oid, fname, val); - }; - return func; - } - - static py::cpp_function getDestFinfoSetterFunc(const ObjId& oid, - const Finfo* finfo); - - static py::cpp_function getDestFinfoSetterFunc1(const ObjId& oid, - const Finfo* finfo, - const string& srctype); - static py::cpp_function getDestFinfoSetterFunc2(const ObjId& oid, - const Finfo* finfo, - const string& srctype, - const string& tgttype); - - static py::object getFieldValue(const ObjId& oid, const Finfo* f); - - static py::list getElementFinfo(const ObjId& objid, const Finfo* f); - - static py::object getElementFinfoItem(const ObjId& oid, const Finfo* f, - int i); +/////////////////////////////////////////////////////////////// +// Utility functions that do not need to be members +/////////////////////////////////////////////////////////////// - // Get attribute (python api); - unsigned int getNumField(); - bool setNumField(unsigned int); +// Get the ObjId for the FieldElement +ObjId getFieldObjId(const ObjId &oid, const Finfo *f); - static unsigned int getNumFieldStatic(const ObjId& oid, const Finfo* f); - static bool setNumFieldStatic(const ObjId& oid, const Finfo* f, - unsigned int i); +template +std::function getSetGetFunc1(const ObjId &oid, const string &fname); - // Exposed to python as __setitem__ - bool setItem(const py::object& key, const py::object& val); +// Get ValueField +py::object getFieldValue(const ObjId &oid, const Finfo *f); - // Exposed to python as __getitem__ - py::object getItem(const py::object& key); +// DestFinfo setter function - depending on number of parameters switches between 1 and 2 +py::cpp_function getDestFinfoSetterFunc(const ObjId &oid, const Finfo *finfo); +// Setter for single parameter DestFinfo +py::cpp_function getDestFinfoSetterFunc1(const ObjId &oid, const Finfo *finfo, + const string &srctype); - static py::object getLookupValueFinfoItem(const ObjId& oid, const Finfo* f, - const py::object& key); +// Get setter-function for two-parameter DestFinfo2, essentially SetGet2::set(oid, fieldname, param1, param2) +py::cpp_function getDestFinfoSetterFunc2(const ObjId &oid, const Finfo *finfo, + const string &srctype, + const string &tgttype); +// Get ElementField +py::list getElementFinfo(const ObjId &objid, const Finfo *f); - static bool setLookupValueFinfoItem(const ObjId& oid, const py::object& key, - const py::object& val, - const Finfo* finfo); +// Get item from Element field +py::object getElementFinfoItem(const ObjId &oid, const Finfo *f, int i); - static vector> finfoNames(const Cinfo* cinfo, - const string& finfoType); +// Get number of elements in ElementField +unsigned int getNumField(const ObjId &oid, const Finfo *f); - py::object operator()(const py::object& key); +// Set number of elements in ElementField +bool setNumField(const ObjId &oid, const Finfo *f, unsigned int i); - string type() const; +// Get item in LookupValueField: uses the inner function below +py::object getLookupValueFinfoItem(const ObjId &oid, const Finfo *f, + const py::object &key); - // Return a MooseVec element (copy). - MooseVec getMooseVec(); +// Utility function for modular code +template +py::object getLookupValueFinfoItemInner(const ObjId &oid, const Finfo *f, + const T &key, const string &tgtType); - // Retun by pointer. - MooseVec* getMooseVecPtr(); +// Set item in LookupValueField +bool setLookupValueFinfoItem(const ObjId &oid, const py::object &key, + const py::object &val, const Finfo *finfo); - // Finfo Id. - static ObjId getObjIdStatic(const ObjId& oid, const Finfo* f); - ObjId getObjId() const; +// Get list of field names of given Finfo type ("src", "dest", +// "value", "lookup", "shared", and "fieldElement"). If finfoType = +// "*", then return all types +// +vector> finfoNames(const Cinfo *cinfo, + const string &finfoType); -public: - ObjId oid_; - const Finfo* f_; - const std::string finfoType_; - std::function func_; +//////////////////////////////////////////////////////////// +// Wrapper class for field elements +//////////////////////////////////////////////////////////// + +class __Finfo__ { + public: + __Finfo__(const ObjId &oid, const Finfo *f, const string &finfoType); + + // ObjId of the fieldElement + ObjId getObjId() const; + + // Get attribute (python api); + unsigned int getNumField(); + bool setNumField(unsigned int); + + // Exposed to python as __getitem__ + py::object getItem(const py::object &key); + + // Exposed to python as __setitem__ + bool setItem(const py::object &key, const py::object &val); + + py::object operator()(const py::object &key); + + string type() const; + + // Return a MooseVec element (copy). + MooseVec getMooseVec(); + + // Retun by pointer. + MooseVec *getMooseVecPtr(); + + function func_; + + private: + ObjId oid_; + const Finfo *f_; + const string finfoType_; // __Finfo__ needs to be copiable. shared_ptr pVec_; }; diff --git a/pybind11/MooseVec.cpp b/pybind11/MooseVec.cpp index 19fbd78730..ba3aa92f07 100644 --- a/pybind11/MooseVec.cpp +++ b/pybind11/MooseVec.cpp @@ -135,7 +135,7 @@ py::object MooseVec::getAttribute(const string& name) auto cinfo = oid_.element()->cinfo(); auto finfo = cinfo->findFinfo(name); if(!finfo) { - auto fmap = __Finfo__::finfoNames(cinfo, "*"); + auto fmap = finfoNames(cinfo, "*"); cerr << __func__ << ":: AttributeError: " << name << " is not found on path '" << oid_.path() << "'." << endl; cerr << finfoNotFoundMsg(cinfo) << endl; @@ -182,7 +182,7 @@ bool MooseVec::setAttribute(const string& name, const py::object& val) auto rttType = finfo->rttiType(); bool isVector = false; - if(py::isinstance(val) and(not py::isinstance(val))) + if(py::isinstance(val) && (! py::isinstance(val))) isVector = true; if(isVector) { diff --git a/pybind11/MooseVec.h b/pybind11/MooseVec.h index c783f272ce..57c9bae448 100644 --- a/pybind11/MooseVec.h +++ b/pybind11/MooseVec.h @@ -10,10 +10,15 @@ #ifndef MOOSE_VEC_H #define MOOSE_VEC_H +#include "../basecode/header.h" + #include #include + namespace py = pybind11; +using namespace std; + class MooseVec { diff --git a/pybind11/PyRun.cpp b/pybind11/PyRun.cpp index e5aeca8639..db053caa34 100644 --- a/pybind11/PyRun.cpp +++ b/pybind11/PyRun.cpp @@ -5,7 +5,6 @@ // Author: subha // Created: Sat Oct 11 14:47:22 2014 (+0530) -#include "Python.h" #include "../basecode/header.h" #include "PyRun.h" diff --git a/pybind11/PyRun.h b/pybind11/PyRun.h index 601e2e1e7d..b67c182f5e 100644 --- a/pybind11/PyRun.h +++ b/pybind11/PyRun.h @@ -3,11 +3,24 @@ // Author: subha // Created: Sat Oct 11 14:40:45 2014 (+0530) -#ifndef _PYCALL_H -#define _PYCALL_H +#ifndef _PyRun_h +#define _PyRun_h #include +#ifdef _DEBUG +#undef _DEBUG +#include +#define _DEBUG +#else +#include +#endif + + +#if defined(_WIN32) +#define PATH_MAX 260 // this is win32 path limit +#endif + #if PY_MAJOR_VERSION >= 3 #define PYCODEOBJECT PyObject diff --git a/pybind11/helper.cpp b/pybind11/helper.cpp index f22c01061c..53b6cbe78f 100644 --- a/pybind11/helper.cpp +++ b/pybind11/helper.cpp @@ -42,7 +42,7 @@ namespace py = pybind11; #include "../randnum/randnum.h" #include "helper.h" -#include "pymoose.h" + #include "Finfo.h" using namespace std; @@ -359,11 +359,16 @@ void mooseReinit() /* ----------------------------------------------------------------------------*/ void mooseStart(double runtime, bool notify = false) { + // TODO: handle keyboard interrupt on _WIN32 +#if !defined(_WIN32) + // Credit: + // http://stackoverflow.com/questions/1641182/how-can-i-catch-a-ctrl-c-event-c struct sigaction sigHandler; sigHandler.sa_handler = handleKeyboardInterrupts; sigemptyset(&sigHandler.sa_mask); sigHandler.sa_flags = 0; sigaction(SIGINT, &sigHandler, NULL); +#endif getShellPtr()->doStart(runtime, notify); } @@ -445,7 +450,7 @@ vector mooseGetFieldNames(const string& className, string finfoNotFoundMsg(const Cinfo* cinfo) { - auto fmap = __Finfo__::finfoNames(cinfo, "*"); + auto fmap = finfoNames(cinfo, "*"); stringstream ss; ss << "Available attributes:" << endl; for(size_t i = 0; i < fmap.size(); i++) { diff --git a/pybind11/helper.h b/pybind11/helper.h index 72ebf4a1f3..fbaac7205d 100644 --- a/pybind11/helper.h +++ b/pybind11/helper.h @@ -123,7 +123,7 @@ inline ObjId mooseCreateFromPath(const string type, const string& p, // If path exists and user is asking for the same type then return the // underlying object else raise an exception. auto oid = ObjId(path); - if(not oid.bad()) { + if(! oid.bad()) { if(oid.element()->cinfo()->name() == type) return oid; else diff --git a/pybind11/meson.build b/pybind11/meson.build new file mode 100644 index 0000000000..34b8e428c5 --- /dev/null +++ b/pybind11/meson.build @@ -0,0 +1,19 @@ +# Author: Subhasis Ray +# Date: Sun Jul 7 + +pybind11_src = ['Finfo.cpp', + 'helper.cpp', + 'MooseVec.cpp', + # 'pymoose.cpp', + 'PyRun.cpp'] + +python_res = run_command('python', '-c', 'from sysconfig import get_paths as gp; print(gp()["include"])') +if python_res.returncode() == 0 + inc_dirs = python_res.stdout().strip() +else + message('ERROR: could not find Python include directory') + inc_dirs = [] +endif + +pybind11_lib = static_library('pybind11', pybind11_src, dependencies: pybind_dep, include_directories: inc_dirs) + diff --git a/pybind11/pymoose.cpp b/pybind11/pymoose.cpp index 3bc8ccaea5..f795098638 100644 --- a/pybind11/pymoose.cpp +++ b/pybind11/pymoose.cpp @@ -11,6 +11,24 @@ // ===================================================================================== +#include "pymoose.h" +#include "Finfo.h" +#include "MooseVec.h" +#include "helper.h" + +#include "../basecode/global.h" +#include "../basecode/header.h" +#include "../builtins/Variable.h" +#include "../randnum/randnum.h" +#include "../shell/Neutral.h" +#include "../shell/Shell.h" +#include "../shell/Wildcard.h" +#include "../utility/strutil.h" + +#include +#include +#include + #include #include #include @@ -19,26 +37,10 @@ #include #include -#include -#include -#include namespace py = pybind11; -using namespace std; using namespace pybind11::literals; - -#include "../basecode/global.h" -#include "../basecode/header.h" -#include "../builtins/Variable.h" -#include "../randnum/randnum.h" -#include "../shell/Neutral.h" -#include "../shell/Shell.h" -#include "../shell/Wildcard.h" -#include "../utility/strutil.h" -#include "Finfo.h" -#include "MooseVec.h" -#include "helper.h" -#include "pymoose.h" +using namespace std; Id initModule(py::module &m) { @@ -81,8 +83,9 @@ bool setFieldGeneric(const ObjId &oid, const string &fieldName, std::remove_if(fieldType.begin(), fieldType.end(), ::isspace), fieldType.end()); - if(fieldType == "double") + if(fieldType == "double"){ return Field::set(oid, fieldName, val.cast()); + } if(fieldType == "vector") return Field>::set(oid, fieldName, val.cast>()); @@ -158,7 +161,7 @@ py::object getFieldGeneric(const ObjId &oid, const string &fieldName) // can be of different types: a simple value (ValueFinfo), list, dict or // DestFinfo setter which is a function. if(finfoType == "ValueFinfo") - return __Finfo__::getFieldValue(oid, finfo); + return getFieldValue(oid, finfo); else if(finfoType == "FieldElementFinfo") { // This is a Finfo return py::cast(__Finfo__(oid, finfo, "FieldElementFinfo")); @@ -170,13 +173,13 @@ py::object getFieldGeneric(const ObjId &oid, const string &fieldName) else if(finfoType == "DestFinfo") { // Return a setter function. // It can be used to set field on DestFinfo. - return __Finfo__::getDestFinfoSetterFunc(oid, finfo); + return getDestFinfoSetterFunc(oid, finfo); } throw runtime_error("getFieldGeneric::NotImplemented : " + fieldName + " with rttType " + finfo->rttiType() + " and type: '" + finfoType + "'"); - return pybind11::none(); + return py::none(); } /* --------------------------------------------------------------------------*/ diff --git a/pymoose/CMakeLists.txt b/pymoose/CMakeLists.txt deleted file mode 100644 index 6f5da2b32a..0000000000 --- a/pymoose/CMakeLists.txt +++ /dev/null @@ -1,140 +0,0 @@ -include(${CMAKE_CURRENT_SOURCE_DIR}/../CheckCXXCompiler.cmake) - -set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../cmake_modules/") - -execute_process(COMMAND - ${PYTHON_EXECUTABLE} -c "import numpy;print(numpy.get_include())" - OUTPUT_VARIABLE NUMPY_INCLUDE_DIRS - OUTPUT_STRIP_TRAILING_WHITESPACE) - -if("${NUMPY_INCLUDE_DIRS}" STREQUAL "") - message(FATAL_ERROR "Could not find numpy: ${NUMPY_INCLUDE_DIRS}") -else() - message(STATUS "Numpy is found at ${NUMPY_INCLUDE_DIRS}") -endif() - -include_directories(${NUMPY_INCLUDE_DIRS}) -add_definitions(-std=c++14) -add_definitions(-DNPY_NO_DEPRECATED_API=NPY_1_7_API_VERSION) - -set(PYTHON_SO_EXTENSION ".so") -message(STATUS "Python so extension ${PYTHON_SO_EXTENSION}" ) - -# TARGET -set(PYMOOSE_SRCS - moosemodule.cpp - vec.cpp - mfield.cpp - pymooseinit.cpp - melement.cpp - PyRun.cpp - test_moosemodule.cpp - ) - -# Build python module in source directory and them copy everything to -# current binary directory using cmake. -add_library( _moose MODULE ${PYMOOSE_SRCS} ) -set(PYMOOSE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../python/moose") -message(STATUS "Python module will be saved to ${PYMOOSE_OUTPUT_DIRECTORY}" ) - -# make sure the Python.h is found. -# Use python executable to find include paths. -# FIXME: cmake > 3.12 has great support for python but it is not available -# everywhere YET. When it is available on centos, we can use FindPython. -message(STATUS "Using ${PYTHON_EXECUTABLE}-config to find Python.h" ) -execute_process( COMMAND ${PYTHON_EXECUTABLE}-config --includes - OUTPUT_VARIABLE PYTHON_INCLUDE_FLAGS - OUTPUT_STRIP_TRAILING_WHITESPACE) - -if("${PYTHON_INCLUDE_FLAGS}" STREQUAL "") - message(FATAL_ERROR "Could not determine path of Python.h.") -else() - message(STATUS "Python.h is found at ${PYTHON_INCLUDE_FLAGS}") -endif() - -execute_process( COMMAND ${PYTHON_EXECUTABLE}-config --libs - OUTPUT_VARIABLE PYTHON_LIBRARIES - OUTPUT_STRIP_TRAILING_WHITESPACE) - -set_target_properties(_moose PROPERTIES - COMPILE_DEFINITIONS "PYMOOSE" - COMPILE_FLAGS "${COMPILE_FLAGS} ${PYTHON_INCLUDE_FLAGS}") - -# Remove prefix lib from python module. -if(NOT(PYTHON_SO_EXTENSION STREQUAL "")) - set_target_properties(_moose PROPERTIES SUFFIX ${PYTHON_SO_EXTENSION}) -endif() -set_target_properties(_moose PROPERTIES - LIBRARY_OUTPUT_DIRECTORY ${PYMOOSE_OUTPUT_DIRECTORY} - PREFIX "" - SUFFIX ${PYTHON_SO_EXTENSION}) - -# see issue #80 -if(HDF5_FOUND AND WITH_NSDF) - set_target_properties( _moose PROPERTIES LINK_FLAGS "-L${HDF5_LIBRARY_DIRS}" ) -endif() - -if(APPLE) - set(CMAKE_MODULE_LINKER_FLAGS "-undefined dynamic_lookup") - message(STATUS "ADDING some linker flags ${CMAKE_EXE_LINKER_FLAGS}") - # cmake --help-policy CMP0042 - set_target_properties( _moose PROPERTIES MACOSX_RPATH OFF) -endif(APPLE) - -if(APPLE) - target_link_libraries( _moose - "-Wl,-all_load" - ${MOOSE_LIBRARIES} - ${STATIC_LIBRARIES} - ) - target_link_libraries(_moose - ${SYSTEM_SHARED_LIBS} - ) -else(APPLE) - target_link_libraries(_moose - "-Wl,--whole-archive" - ${MOOSE_LIBRARIES} - ${STATIC_LIBRARIES} - "-Wl,--no-whole-archive" - ${SYSTEM_SHARED_LIBS}) -endif() - -# PYMOOSE DISTRIBUTION. -#find_python_module(wheel REQUIRED) -#if(NOT PY_WHEEL) -# message(STATUS "Python module wheel is not found. Please wait while I install it..") -# execute_process(COMMAND ${PYTHON_EXECUTABLE} -m pip install wheel --user) -#endif(NOT PY_WHEEL) - -# Create a binary distribution inside a directory. Installation is copying that -# directory to ${CMAKE_INSTALL_PREFIX} -set(_platform "CMAKE") -set(PYMOOSE_BDIST_FILE ${CMAKE_BINARY_DIR}/pymoose-${VERSION_MOOSE}.${_platform}.tar.gz) -set(PYMOOSE_INSTALL_DIR ${CMAKE_BINARY_DIR}/_pymoose_temp_install) -file(MAKE_DIRECTORY ${PYMOOSE_INSTALL_DIR}) - -add_custom_target(pymoose_sdist ALL - DEPENDS ${PYMOOSE_BDIST_FILE} _moose - COMMENT "Building pymoose sdist") - -add_custom_command(OUTPUT ${PYMOOSE_BDIST_FILE} - COMMAND ${PYTHON_EXECUTABLE} setup.py build_py - COMMAND ${PYTHON_EXECUTABLE} setup.py bdist_dumb - --skip-build -p "${_platform}" -d ${CMAKE_BINARY_DIR} - COMMAND ${CMAKE_COMMAND} -E chdir ${PYMOOSE_INSTALL_DIR} tar xf ${PYMOOSE_BDIST_FILE} - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - COMMENT "python's binary distribution is saved to ${CMAKE_BINARY_DIR}" - VERBATIM) - -# Copy python tree to BUILD directory. User can set PYTHONPATH to -# ${CMAKE_BINARY_DIR}/python. -add_custom_target(copy_python_tree ALL - COMMAND ${CMAKE_COMMAND} -E copy_directory - ${CMAKE_SOURCE_DIR}/python ${CMAKE_BINARY_DIR}/python - COMMENT "Copying python source tree: ${CMAKE_SOURCE_DIR}/python -> ${CMAKE_BINARY_DIR}/python" - DEPENDS _moose VERBATIM) - -install(DIRECTORY ${PYMOOSE_INSTALL_DIR}/usr/local/ - DESTINATION ${CMAKE_INSTALL_PREFIX} - CONFIGURATIONS Debug Release) - diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000000..e7e31baaf4 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,75 @@ +[build-system] +build-backend = 'mesonpy' +requires = ['meson', 'ninja', 'meson-python', 'pybind11[global]', 'gsl'] + +[project] +name = 'pymoose' +version = '4.1.0.dev' +description = 'Python scripting interface of MOOSE Simulator (https://moose.ncbs.res.in)' +readme = 'README.md' +classifiers = [ + 'Development Status :: 5 - Production/Stable', + 'Intended Audience :: Science/Research', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: GPL 3', + 'Programming Language :: C', + 'Programming Language :: C++', + 'Programming Language :: Python', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', + 'Programming Language :: Python :: 3.12', + 'Topic :: Software Development :: Libraries', + 'Topic :: Scientific/Engineering', + 'Operating System :: Microsoft :: Windows', + 'Operating System :: POSIX :: Linux', + 'Operating System :: POSIX', + 'Operating System :: Unix', + 'Operating System :: MacOS', +] + +requires-python = '>= 3.8' +license = { file = 'LICENSE' } +authors = [ + {name = 'Upinder S. Bhalla', email = 'bhalla@ncbs.res.in'}, + {name = 'Niraj Dudani', email = ''}, + {name = 'Subhasis Ray', email = 'ray.subhasis@gmail.com'}, + {name = 'Aditya Gilra', email = ''}, + {name = 'Aviral Goel', email = ''}, + {name = 'Dilawar Singh', email = ''}, + {name = 'Dharma Teja', email = ''}, + {name = 'Malav Shah', email = ''}, + {name = 'Dhruva Gowda', email = ''}, + {name = 'G.V. Harsharani', email = 'hrani@ncbs.res.in'}, + ] + +maintainers = [ + {name = 'Upinder S. Bhalla', email = 'bhalla@ncbs.res.in'}, + {name = 'Subhasis Ray', email = 'ray.subhasis@gmail.com'}, + {name = 'G.V. Harsharani', email = 'hrani@ncbs.res.in'}, + ] + +dependencies = ['numpy>=1.23', 'matplotlib', 'vpython', 'pybind11'] + +[project.urls] +homepage = 'https://moose.ncbs.res.in' +documentation = 'https://moose.ncbs.res.in/readthedocs/index.html' +repository = 'https://github.com/BhallaLab/moose-core' + +[project.optional-dependencies] +test = [ + 'coverage', + 'pytest', + 'pytest-cov' +] + +[tool.meson-python.args] +setup = ['--default-library=static', '-Ddebug=false', '-Doptimization=3', '--vsenv'] +compile = ['-j4'] +dist = ['--include-subprojects'] + +[tool.black] +line-length = 80 +# skip-string-normalization = true diff --git a/python/moose/__init__.py b/python/moose/__init__.py index db0bca1a0b..a0f726f55a 100644 --- a/python/moose/__init__.py +++ b/python/moose/__init__.py @@ -875,3 +875,43 @@ def mergeChemModel(modelpath, dest): No example file which shows its use. Deprecated? """ return model_utils.mooseMergeChemModel(modelpath, dest) + + +def isinstance_(element, classobj): + """Returns True if `element` is an instance of `classobj` or its + subclass. + + Like Python's builtin `isinstance` method, this returns `True` if + `element` is an instance of `classobj` or one of its subclasses. + + Parameters + ---------- + element : moose.melement + moose object + classobj : class + moose class + + Returns + ------- + True if `classobj` is a MOOSE-baseclass of `element`, False otherwise. + + Raises + ------ + TypeError if `classobj` is not a MOOSE class, or + `element` is not a MOOSE object + + + """ + base_cinfo = _moose.element(f'/classes/{classobj.__name__}') + if base_cinfo.name == '/': + raise TypeError('Not a MOOSE class', classobj) + + try: + obj_cinfo = _moose.element(f'/classes/{element.className}') + except AttributeError: # Not a MOOSE element - doesn't have className attribute + raise TypeError('Not a MOOSE object', element) + while obj_cinfo.baseClass != 'none': + if obj_cinfo.name == base_cinfo.name: + return True + obj_cinfo = _moose.element(f'/classes/{obj_cinfo.baseClass}') + return False diff --git a/python/moose/chemMerge/mtypes.py b/python/moose/chemMerge/mtypes.py index da1ea0b065..7ce4859ca3 100644 --- a/python/moose/chemMerge/mtypes.py +++ b/python/moose/chemMerge/mtypes.py @@ -7,9 +7,9 @@ # Maintainer: # Created: Fri Feb 8 11:29:36 2013 (+0530) # Version: -# Last-Updated: Tue Mar 1 02:52:35 2016 (-0500) -# By: subha -# Update #: 182 +# Last-Updated: Tue Jul 16 13:52:35 2024 (+0530) +# By: Subhasis Ray +# Update #: 183 # URL: # Keywords: # Compatibility: @@ -166,7 +166,7 @@ def isKKIT(filename): """Check if `filename` is a GENESIS/KINETIKIT file. """ - pattern = re.compile('include\s+kkit') # KKIT files must have "include kkit" statement somewhere + pattern = re.compile(r'include\s+kkit') # KKIT files must have "include kkit" statement somewhere with open(filename, 'r') as infile: while True: sentence = '' diff --git a/python/moose/neuroml2/reader.py b/python/moose/neuroml2/reader.py index b68d4d473f..3db9c6bf19 100644 --- a/python/moose/neuroml2/reader.py +++ b/python/moose/neuroml2/reader.py @@ -1,39 +1,116 @@ # -*- coding: utf-8 -*- + from __future__ import print_function, division, absolute_import # Description: NeuroML2 reader. # Implementation of reader for NeuroML 2 models. # TODO: handle morphologies of more than one segment... # Author: Subhasis Ray, Padraig Gleeson -# Maintainer: Dilawar Singh , Padraig Gleeson +# Maintainer: Padraig Gleeson, Subhasis Ray # Created: Wed Jul 24 15:55:54 2013 (+0530) # Notes: # For update/log, please see git-blame documentation or browse the github # repo https://github.com/BhallaLab/moose-core +import ast import os import math import logging import numpy as np -import moose +from collections import defaultdict +import pint - -logger_ = logging.getLogger('moose.nml2') +import moose +from moose.neuroml2.hhfit import exponential2 +from moose.neuroml2.hhfit import sigmoid2 +from moose.neuroml2.hhfit import linoid2 +from moose.neuroml2.units import SI -nml_not_available_msg = '' +logger_ = logging.getLogger("moose.nml2") +# logger_.setLevel(logging.DEBUG) +ureg = pint.UnitRegistry() +ureg.default_system = "SI" +Q_ = ureg.Quantity +nml_not_available_msg = "" try: import neuroml as nml import pyneuroml.pynml as pynml except ImportError as error: - raise ImportError(f'Could not import neuroml/pyneuroml. Please make sure you have pyneuroml installed (`pip install pyneuroml`)') from error - - -from moose.neuroml2.units import SI + raise ImportError( + "Could not import neuroml/pyneuroml. " + "Please make sure you have pyneuroml installed " + "(`pip install pyneuroml`)" + ) from error + + +PREDEFINED_RATEFN_MAP = { + "HHExpRate": exponential2, + "HHSigmoidRate": sigmoid2, + "HHSigmoidVariable": sigmoid2, + "HHExpLinearRate": linoid2, +} + + +def array_eval_component(comp_type, req_vars, params={}): + """Use numpy vectorization for faster evaluation of component formula. + + Parameters + ---------- + comp_type : nml.ComponentType + ComponentType element defining the dynamics. + req_vars : dict + Variable names mapped to a pint Quantity (unit-aware number/array). + params : dict + Mapping from parameter names to a pint Quantity (unit-aware + number/array). These are all passed to numpy, so they must be broadcast + compatible. + + """ + logger_.debug( + f"Evaluating {comp_type.name} with " + f"req: {req_vars.keys()} and " + f"parameters: {params}" + ) + local_vars = {"return_vals": {}} + for name, quantity in req_vars.items(): + local_vars[name] = quantity.to_base_units().magnitude + if params is not None: + for name, quantity in params.items(): + local_vars[name] = quantity.to_base_units().magnitude + exec_str = [] + for const in comp_type.Constant: + exec_str.append(f"{const.name} = {pynml.get_value_in_si(const.value)}") + for dyn in comp_type.Dynamics: + for dv in dyn.DerivedVariable: + exec_str.append(f"{dv.name} = {dv.value}") + exec_str.append(f"return_vals['{dv.name}'] = {dv.name}") + for cdv in dyn.ConditionalDerivedVariable: + cond_str = [f"return_vals['{cdv.name}'] = "] + closing_parens = 0 + for case_ in cdv.Case: + if case_.condition is not None: + cond = ( + case_.condition.replace(".neq.", "!=") + .replace(".eq.", "==") + .replace(".gt.", ">") + .replace(".lt.", "<") + ) + cond_str.append(f"where({cond}, {case_.value}, ") + closing_parens += 1 + else: + cond_str += [case_.value, ")" * closing_parens] + # print("^" * 100, cond_str) + exec_str.append(" ".join(cond_str)) + # print("#" * 80, "\n", exec_str, "\n", "#" * 80, "\n") + exec_str = "\n".join(exec_str) + # print("*" * 80, "\n", exec_str, "\n", "*" * 80) + exec(exec_str, np.__dict__, local_vars) + return local_vars["return_vals"] -def _write_flattened_nml( doc, outfile ): +def _write_flattened_nml(doc, outfile): """_write_flattened_nml Concat all NML2 read by moose and generate one flattened NML file. Only useful when debugging. @@ -42,10 +119,12 @@ def _write_flattened_nml( doc, outfile ): :param outfile: Name of the output file. """ import neuroml.writers - neuroml.writers.NeuroMLWriter.write( doc, outfile ) - logger_.debug( "Wrote flattened NML model to %s" % outfile ) -def _gates_sorted( all_gates ): + neuroml.writers.NeuroMLWriter.write(doc, outfile) + logger_.debug("Wrote flattened NML model to %s" % outfile) + + +def _gates_sorted(all_gates): """_gates_sorted Parameters @@ -55,26 +134,20 @@ def _gates_sorted( all_gates ): Notes ----- - If the id of gates are subset of 'x', 'y' or 'z' then sort them so they load in - X, Y or Z gate respectively. Otherwise do not touch them i.e. first gate - will be loaded into X, second into Y and so on. + If the id of gates are subset of 'x', 'y' or 'z' then sort them so they + load in X, Y or Z gate respectively. Otherwise do not touch them i.e. + first gate will be loaded into X, second into Y and so on. """ - allMooseGates = ['x', 'y', 'z'] - allGatesDict = { g.id : g for g in all_gates } - gateNames = [ g.id.lower() for g in all_gates ] + allMooseGates = ["x", "y", "z"] + allGatesDict = {g.id: g for g in all_gates} + gateNames = [g.id.lower() for g in all_gates] if set(gateNames).issubset(set(allMooseGates)): sortedGates = [] for gid in allMooseGates: - sortedGates.append( allGatesDict.get(gid) ) + sortedGates.append(allGatesDict.get(gid)) return sortedGates return all_gates -def _unique( ls ): - res = [ ] - for l in ls: - if l not in res: - res.append( l ) - return res def _isConcDep(ct): """_isConcDep @@ -87,37 +160,41 @@ def _isConcDep(ct): :return: True if Component is depenant on conc, False otherwise. """ # logger_.debug(f"{'#' * 10} EXTENDS {ct.extends}") - if 'ConcDep' in ct.extends: + if "ConcDep" in ct.extends: return True return False + def _findCaConcVariableName(): """_findCaConcVariableName Find a suitable CaConc for computing HHGate tables. This is a hack, though it is likely to work in most cases. """ - caConcs = moose.wildcardFind( '/library/##[TYPE=CaConc]' ) - assert len(caConcs) >= 1, "No moose.CaConc found. Currently moose \ - supports HHChannel which depends only on moose.CaConc ." - return caConcs[0].name + caConcs = moose.wildcardFind("/library/##[TYPE=CaConc]") + if len(caConcs) >= 1: + return caConcs[0].name + def sarea(comp): - """sarea - Return the surface area (2ϖrL) of compartment from length and diameter. + """Return the surface area (2 * pi * r * L) of compartment from + length and diameter. :param comp: Compartment instance. :type comp: str :return: surface area of `comp`. :rtype: float + """ if comp.length > 0: return math.pi * comp.diameter * comp.length else: return math.pi * comp.diameter * comp.diameter + def xarea(compt): - """xarea - Return the cross sectional area (𝜋r²) from the diameter of the compartment. + """ + Return the cross sectional area (pi * r^2) from the diameter of the + compartment. Note: ---- @@ -128,7 +205,8 @@ def xarea(compt): :return: cross sectional area. :rtype: float """ - return math.pi * (compt.diameter/2.0)**2.0 + return math.pi * (compt.diameter / 2.0) ** 2.0 + def setRa(comp, resistivity): """Calculate total raxial from specific value `resistivity`""" @@ -137,24 +215,29 @@ def setRa(comp, resistivity): else: comp.Ra = resistivity * 4.0 / (comp.diameter * np.pi) + def setRm(comp, condDensity): """Set membrane resistance""" - comp.Rm = 1/(condDensity * sarea(comp)) + comp.Rm = 1 / (condDensity * sarea(comp)) + def setEk(comp, erev): """Set reversal potential""" comp.setEm(erev) + def getSegments(nmlcell, component, sg_to_segments): """Get the list of segments the `component` is applied to""" sg = component.segment_groups if sg is None: segments = nmlcell.morphology.segments - elif sg == 'all': - segments = [seg for seglist in sg_to_segments.values() for seg in seglist] + elif sg == "all": + segments = [ + seg for seglist in sg_to_segments.values() for seg in seglist + ] else: segments = sg_to_segments[sg] - return _unique(segments) + return list(set(segments)) class NML2Reader(object): @@ -171,117 +254,244 @@ class NML2Reader(object): creates a passive neuronal morphology `/library/Purk2M9s`. """ + def __init__(self, verbose=False): global logger_ - self.lunit = 1e-6 # micron is the default length unit + self.lunit = 1e-6 # micron is the default length unit self.verbose = verbose if self.verbose: - logger_.setLevel( logging.DEBUG ) + logger_.setLevel(logging.DEBUG) self.doc = None self.filename = None - self.nml_cells_to_moose = {} # NeuroML object to MOOSE object - self.nml_segs_to_moose = {} # NeuroML object to MOOSE object - self.nml_chans_to_moose = {} # NeuroML object to MOOSE object - self.nml_conc_to_moose = {} # NeuroML object to MOOSE object - self.moose_to_nml = {} # Moose object to NeuroML object + self.nml_cells_to_moose = {} # NeuroML object to MOOSE object + self.nml_segs_to_moose = {} # NeuroML object to MOOSE object + self.nml_chans_to_moose = {} # NeuroML object to MOOSE object + self.nml_conc_to_moose = {} # NeuroML object to MOOSE object + self.moose_to_nml = {} # Moose object to NeuroML object self.proto_cells = {} # map id to prototype cell in moose self.proto_chans = {} # map id to prototype channels in moose self.proto_pools = {} # map id to prototype pools (Ca2+, Mg2+) - self.includes = {} # Included files mapped to other readers - self.lib = moose.element('/library') if moose.exists('/library') \ - else moose.Neutral( '/library' ) + self.includes = {} # Included files mapped to other readers + self.lib = moose.Neutral( + "/library" + ) # Keeps the prototypes: not simulated + self.model = moose.Neutral("/model") # Actual model: simulated self.id_to_ionChannel = {} - self._cell_to_sg = {} # nml cell to dict - the dict maps segment groups to segments + self._cell_to_sg = ( + {} + ) # nml cell to dict - the dict maps segment groups to segments self._variables = {} self.cells_in_populations = {} self.pop_to_cell_type = {} self.seg_id_to_comp_name = {} - self.paths_to_chan_elements = {} self.network = None - def read(self, filename, symmetric=True): - filename = os.path.realpath( filename ) + def read( + self, + filename, + symmetric=True, + vmin=-150e-3, + vmax=100e-3, + vdivs=3000, + cmin=0.0, + cmax=10.0, + cdivs=5000, + ): + """Read a NeuroML2 file and create the corresponding model. + + Parameters + ---------- + filename : str + Path of NeuroML2 file + symmetric : bool + If `True` use symmetric compartments (axial resistance is + split with neighboring compartments on both sides) + otherwise asymmetric compartment (axial resistance applied + with one neighboring compartment only) + vmin : float + Minimum of membrane voltage range. This is used for + creating interpolation tables for channel dynamics. + vmax : float + Maximum of membrane voltage range. This is used for + creating interpolation tables for channel dynamics. + vdivs : int + Number of entries in voltage range for interpolation. This is + used for creating interpolation tables for channel dynamics. + cmin : float + Minimum (Ca2+) concentration + cmax : float + Maximum (Ca2+) concentration + cdivs : int + Number of entries in concentration range for interpolation. This is + used for creating interpolation tables for [Ca2+]-dependent channel + dynamics. + + + """ + filename = os.path.realpath(filename) self.doc = nml.loaders.read_neuroml2_file( - filename, include_includes=True, verbose=self.verbose) + filename, include_includes=True, verbose=self.verbose + ) self.filename = filename - logger_.info('Parsed the NeuroML2 file: %s'% filename) + logger_.info("Parsed the NeuroML2 file: %s" % filename) if self.verbose: - _write_flattened_nml( self.doc, '%s__flattened.xml' % self.filename ) + _write_flattened_nml(self.doc, "%s__flattened.xml" % self.filename) - if len(self.doc.networks)>=1: + if len(self.doc.networks) >= 1: self.network = self.doc.networks[0] moose.celsius = self._getTemperature() self.importConcentrationModels(self.doc) - self.importIonChannels(self.doc) + self.importIonChannels( + self.doc, + vmin=vmin, + vmax=vmax, + vdivs=vdivs, + cmin=cmin, + cmax=cmax, + cdivs=cdivs, + ) self.importInputs(self.doc) for cell in self.doc.cells: - # logger_.debug(f"{'%' * 10} Creating cell prototype {cell}") self.createCellPrototype(cell, symmetric=symmetric) - if len(self.doc.networks)>=1: + if len(self.doc.networks) >= 1: self.createPopulations() self.createInputs() def _getTemperature(self): - if self.network is not None: - if self.network.type=="networkWithTemperature": - return SI(self.network.temperature) - else: - # Why not, if there's no temp dependence in nml..? - return 0 - return SI('25') + """Get the network temperature. + + If there is no network attribute, or if the network has no + temperature attribute, return standard room temperature + + """ + try: + return SI(self.network.temperature) + except AttributeError: + return SI("25") def getCellInPopulation(self, pop_id, index): return self.cells_in_populations[pop_id][index] def getComp(self, pop_id, cellIndex, segId): - return moose.element('%s/%s/%s/%s' % ( self.lib.path, pop_id, cellIndex - , self.seg_id_to_comp_name[self.pop_to_cell_type[pop_id]][segId]) - ) + """Get moose compartment corresponding to the specified NeuroML element + + Parameters + ---------- + pop_id : str + Population ID in NeuroML + cellIndex : str + Index of cell in population + segId : str + Segment ID in NeuroML + + """ + comp_name = self.seg_id_to_comp_name[self.pop_to_cell_type[pop_id]][ + segId + ] + return moose.element( + f"{self.model.path}/{self.network.id}/" + f"{pop_id}/{cellIndex}/{comp_name}" + ) def createPopulations(self): - for pop in self.network.populations: - ep = '%s/%s' % (self.lib.path, pop.id) - mpop = moose.element(ep) if moose.exists(ep) else moose.Neutral(ep) - self.cells_in_populations[pop.id] ={} - for i in range(pop.size): - logger_.info("Creating %s/%s instances of cell: %s under %s"%(i,pop.size,pop.component, mpop)) - self.pop_to_cell_type[pop.id]=pop.component - chid = moose.copy(self.proto_cells[pop.component], mpop, '%s'%(i)) - self.cells_in_populations[pop.id][i]=chid + """Create populations of neurons in a network + + Create a container identified by `network.id` and create cell + populations under that. The network container is created under + `/model` as this is supposed to be an instantiation and not a + prototype (the latter are created under `/library`). + """ + net = moose.Neutral(f"{self.model.path}/{self.network.id}") + for pop in self.network.populations: + mpop = moose.Neutral(f"{net.path}/{pop.id}") + self.pop_to_cell_type[pop.id] = pop.component + logger_.info( + f"Creating {pop.size} instances of cell " + f"{pop.component} under {mpop.path}" + ) + self.cells_in_populations[pop.id] = { + ii: moose.copy( + self.proto_cells[pop.component], + mpop, + f"{ii}", + ) + for ii in range(pop.size) + } def getInput(self, input_id): - return moose.element('%s/inputs/%s'%(self.lib.path,input_id)) + """Returns input object (PulseGen) identified by `input_id`. + + Retrieves the object `/model/inputs/{input_id}`. + Parameters + ---------- + input_id : str + NeuroML id of the object to be retrieved. Same as its name + in MOOSE. + + """ + return moose.element(f"{self.model.path}/inputs/{input_id}") def createInputs(self): + """Create inputs to model. + + Currently this assumes inputs are `PulseGen` objects and + copies the prototypes for a network's `explicit_inputs` and + `input_lists` from '/library/inputs' to '/model/inputs'. It + also connects up the 'output' field of the `PulseGen object to + the 'injectMsg' field of the target compartment. + + """ + inputs = moose.Neutral(f"{self.model.path}/inputs") for el in self.network.explicit_inputs: - pop_id = el.target.split('[')[0] - i = el.target.split('[')[1].split(']')[0] + proto = moose.element(f"{self.lib.path}/inputs/{el.input}") + pop_id = el.target.split("[")[0] + ii = el.target.split("[")[1].split("]")[0] seg_id = 0 - if '/' in el.target: - seg_id = el.target.split('/')[1] - input = self.getInput(el.input) - moose.connect(input, 'output', self.getComp(pop_id,i,seg_id), 'injectMsg') + if "/" in el.target: + seg_id = el.target.split("/")[1] + input_ = moose.copy(proto, inputs) + moose.connect( + input_, "output", self.getComp(pop_id, ii, seg_id), "injectMsg" + ) for il in self.network.input_lists: for ii in il.input: - input = self.getInput(il.component) - moose.connect(input, 'output' - , self.getComp(il.populations,ii.get_target_cell_id(),ii.get_segment_id()) - , 'injectMsg') - + logger_.debug(f"il.component: {il.component}, input: {ii}") + proto = moose.element(f"{self.lib.path}/inputs/{il.component}") + input_ = moose.copy(proto, inputs) + moose.connect( + input_, + "output", + self.getComp( + il.populations, + ii.get_target_cell_id(), + ii.get_segment_id(), + ), + "injectMsg", + ) def createCellPrototype(self, cell, symmetric=True): - """To be completed - create the morphology, channels in prototype""" - ep = '%s/%s' % (self.lib.path, cell.id) - nrn = moose.element(ep) if moose.exists(ep) else moose.Neuron(ep) + """Create the morphology, channels in prototype. + + Parameters + ---------- + cell: NeuroML element + Cell element in NeuroML2 + symmetric: bool + If `True`, use symmetric compartment; use asymmetric compartment + otherwise. + + """ + ep = f"{self.lib.path}/{cell.id}" + nrn = moose.Neuron(ep) self.proto_cells[cell.id] = nrn self.nml_cells_to_moose[cell.id] = nrn self.moose_to_nml[nrn] = cell @@ -289,40 +499,49 @@ def createCellPrototype(self, cell, symmetric=True): self.importBiophysics(cell, nrn) return cell, nrn - def createMorphology(self, nmlcell, moosecell, symmetric=True): """Create the MOOSE compartmental morphology in `moosecell` using the segments in NeuroML2 cell `nmlcell`. Create symmetric compartments if `symmetric` is True. + Parameters + ---------- + nmlcell: NeuroML element + Cell element in NeuroML2 + moosecell: moose.Neutral or moose.Neuron + MOOSE container object for the cell. + symmetric: bool + If `True`, use symmetric compartment; use asymmetric compartment + otherwise. + + NOTE + ---- + moose compartments are cylindrical (both ends of a compartment have + same diameter). So taking the average of the two ends in case of truncated-cone. + """ morphology = nmlcell.morphology segments = morphology.segments - id_to_segment = dict([(seg.id, seg) for seg in segments]) + id_to_segment = {seg.id: seg for seg in segments} if symmetric: compclass = moose.SymCompartment + src, dst = "proximal", "distal" else: compclass = moose.Compartment + src, dst = "axial", "raxial" # segment names are used as compartment names - assuming # naming convention does not clash with that in MOOSE cellpath = moosecell.path id_to_comp = {} - self.seg_id_to_comp_name[nmlcell.id]={} + self.seg_id_to_comp_name[nmlcell.id] = {} + # create or access compartments by segment name (or id if name + # is not set) and keep two-way mapping for seg in segments: - if seg.name is not None: - ep = '%s/%s' % (cellpath, seg.name) - id_to_comp[seg.id] = moose.element(ep) if moose.exists(ep) else compclass(ep) - self.seg_id_to_comp_name[nmlcell.id][seg.id] = seg.name - else: - name = 'comp_%s'%seg.id - ep = '%s/%s' % (cellpath, name) - id_to_comp[seg.id] = moose.element(ep) if moose.exists(ep) else compclass(ep) - self.seg_id_to_comp_name[nmlcell.id][seg.id] = name + name = seg.name if seg.name is not None else f"comp_{seg.id}" + comp = compclass(f"{cellpath}/{name}") + id_to_comp[seg.id] = comp + self.seg_id_to_comp_name[nmlcell.id][seg.id] = name # Now assign the positions and connect up axial resistance - if not symmetric: - src, dst = 'axial', 'raxial' - else: - src, dst = 'proximal', 'distal' for segid, comp in id_to_comp.items(): segment = id_to_segment[segid] try: @@ -337,33 +556,41 @@ def createMorphology(self, nmlcell, moosecell, symmetric=True): p0 = parent.distal else: raise Exception( - 'No proximal point and no parent segment for segment:'+\ - 'name=%s, id=%s' % (segment.name, segment.id) - ) - comp.x0, comp.y0, comp.z0 = (x*self.lunit for x in map(float, (p0.x, p0.y, p0.z))) + "No proximal point and no parent segment for segment: " + f"name={segment.name}, id={segment.id}" + ) + comp.x0, comp.y0, comp.z0 = ( + float(x) * self.lunit for x in (p0.x, p0.y, p0.z) + ) p1 = segment.distal - comp.x, comp.y, comp.z = (x*self.lunit for x in map(float, (p1.x, p1.y, p1.z))) - comp.length = np.sqrt((comp.x-comp.x0)**2+(comp.y-comp.y0)**2+(comp.z-comp.z0)**2) + comp.x, comp.y, comp.z = ( + float(x) * self.lunit for x in (p1.x, p1.y, p1.z) + ) + comp.length = np.sqrt( + (comp.x - comp.x0) ** 2 + + (comp.y - comp.y0) ** 2 + + (comp.z - comp.z0) ** 2 + ) - # This can pose problem with moose where both ends of - # compartment have same diameter. We are averaging the two - # - may be splitting the compartment into two is better? - comp.diameter = (float(p0.diameter)+float(p1.diameter)) * self.lunit / 2 + # NOTE: moose compartments are cylindrical (both ends of a + # compartment have same diameter). So taking the average + # of the two ends in case of truncated-cone. + comp.diameter = ( + (float(p0.diameter) + float(p1.diameter)) * self.lunit / 2 + ) if parent: pcomp = id_to_comp[parent.id] moose.connect(comp, src, pcomp, dst) - sg_to_segments = {} - for sg in morphology.segment_groups: - sg_to_segments[sg.id] = [id_to_segment[m.segments] for m in sg.members] + # map segment-group to segments + sg_to_segments = defaultdict(list) for sg in morphology.segment_groups: - if not sg.id in sg_to_segments: - sg_to_segments[sg.id] = [] + for m in sg.members: + sg_to_segments[sg.id].append(id_to_segment[m.segments]) for inc in sg.includes: for cseg in sg_to_segments[inc.segment_groups]: sg_to_segments[sg.id].append(cseg) - - if not 'all' in sg_to_segments: - sg_to_segments['all'] = [ s for s in segments ] + if "all" not in sg_to_segments: + sg_to_segments["all"] = [s for s in segments] self._cell_to_sg[nmlcell.id] = sg_to_segments return id_to_comp, id_to_segment, sg_to_segments @@ -373,15 +600,23 @@ def importBiophysics(self, nmlcell, moosecell): according to NeuroML2 cell `nmlcell`.""" bp = nmlcell.biophysical_properties if bp is None: - logger_.info('Warning: %s in %s has no biophysical properties' % (nmlcell.id, self.filename)) + logger_.info( + "Warning: %s in %s has no biophysical properties" + % (nmlcell.id, self.filename) + ) return - self.importMembraneProperties(nmlcell, moosecell, bp.membrane_properties) - self.importIntracellularProperties(nmlcell, moosecell, bp.intracellular_properties) + self.importMembraneProperties( + nmlcell, moosecell, bp.membrane_properties + ) + self.importIntracellularProperties( + nmlcell, moosecell, bp.intracellular_properties + ) + self.setupCaDep(nmlcell, moosecell, bp.membrane_properties) def importMembraneProperties(self, nmlcell, moosecell, mp): """Create the membrane properties from nmlcell in moosecell""" if self.verbose: - logger_.info('Importing membrane properties') + logger_.info("Importing membrane properties") self.importCapacitances(nmlcell, moosecell, mp.specific_capacitances) self.importChannelsToCell(nmlcell, moosecell, mp) self.importInitMembPotential(nmlcell, moosecell, mp) @@ -407,47 +642,70 @@ def importIntracellularProperties(self, nmlcell, moosecell, properties): self.importSpecies(nmlcell, properties) def importSpecies(self, nmlcell, properties): + """Copy ion species prototype from /library to segments in the cell. + + Handling [Ca2+]: NeuroML2 `decayingPoolConcentrationModel` for + Ca2+ ion is mapped to `CaConc` class in MOOSE. However, while + NeuroML2 allows setting `initialConcentration` for this under + `intracellularProperties` in the cell model, MOOSE does not + have a separate initial value field for the + concentration. Instead, the + `decayingPoolConcentrationModel.restingConc` is used for + setting `CaConc.CaBasal` and the pool is initialized to this + value. + + """ sg_to_segments = self._cell_to_sg[nmlcell.id] for species in properties.species: - # Developer note: Not sure if species.concentration_model should be - # a nml element of just plain string. I was getting plain text from - # nml file here. + proto_pool = None concModel = species.concentration_model - if (concModel is not None) and (concModel not in self.proto_pools): - logger_.warn("No concentrationModel '%s' found."%concModel) + if concModel is None: continue + if concModel in self.proto_pools: + proto_pool = self.proto_pools[concModel] + else: + for innerReader in self.includes.values(): + if concModel in innerReader.proto_pools: + proto_pool = innerReader.proto_pools[concModel] + break + if proto_pool is None: + msg = "No prototype pool for %s referred to by %s" % ( + concModel, + species.id, + ) + logger_.error(msg) + raise RuntimeError(msg) segments = getSegments(nmlcell, species, sg_to_segments) for seg in segments: comp = self.nml_segs_to_moose[seg.id] - self.copySpecies(species, comp) - - def copySpecies(self, species, compartment): - """Copy the prototype pool `species` to compartment. Currently only - decaying pool of Ca2+ supported""" - proto_pool = None - concModel = species.concentration_model - if concModel in self.proto_pools: - proto_pool = self.proto_pools[concModel] - else: - for innerReader in self.includes.values(): - if concModel in innerReader.proto_pools: - proto_pool = innerReader.proto_pools[concModel] - break - if not proto_pool: - msg = 'No prototype pool for %s referred to by %s' % (concModel, species.id) - logger_.error(msg) - raise RuntimeError(msg) - pool_id = moose.copy(proto_pool, compartment, species.id) + self.copySpecies(proto_pool, comp) + # moose initializes CaConc to `CaBasal` which + # is equivalent to `restingConc` in NeuroML2 + + def copySpecies(self, proto_pool, comp): + """Copy the prototype pool `species` to compartment + `comp`. Currently only decaying pool of Ca2+ supported. + + """ + pool_id = moose.copy(proto_pool, comp) pool = moose.element(pool_id) - # print('&' * 10, compartment.path, compartment.length, compartment.diameter, pool.thick) - if compartment.length <= 0: - vol = 4 * np.pi * (0.5 * compartment.diameter**3 - (0.5 * compartment.diameter - pool.thick)**3) / 3 - else: - vol = (np.pi * compartment.length * ( - 0.5 * compartment.diameter + pool.thick) * - (0.5 * compartment.diameter - pool.thick) + pool.diameter = comp.diameter + pool.length = comp.length + # for cylindrical compartments (default) moose computes volume + # and pool.B by standard formula, but spherical case is not + # implemented in CaConBase + if comp.length <= 0: + vol = ( + 4 + * np.pi + * ( + (0.5 * comp.diameter) ** 3 + - (0.5 * comp.diameter - pool.thick) ** 3 + ) + / 3 ) - pool.B = pool.B / vol + pool.B = 5.2e-6 / vol + return pool def importAxialResistance(self, nmlcell, intracellularProperties): @@ -458,83 +716,179 @@ def importAxialResistance(self, nmlcell, intracellularProperties): comp = self.nml_segs_to_moose[seg.id] setRa(comp, SI(r.value)) - def isPassiveChan(self,chan): - if chan.type == 'ionChannelPassive': + def isPassiveChan(self, chan): + if chan.type == "ionChannelPassive": return True - if hasattr(chan,'gates'): - return len(chan.gate_hh_rates)+len(chan.gates)==0 + if hasattr(chan, "gates"): + return len(chan.gate_hh_rates) + len(chan.gates) == 0 return False def evaluate_moose_component(self, ct, variables): - print( "[INFO ] Not implemented." ) + print("[INFO ] Not implemented.") return False - def calculateRateFn(self, ratefn, vmin, vmax, tablen=3000, vShift='0mV'): - """Returns A / B table from ngate.""" - from moose.neuroml2.hhfit import exponential2 - from moose.neuroml2.hhfit import sigmoid2 - from moose.neuroml2.hhfit import linoid2 - from moose.neuroml2.units import SI - - rate_fn_map = { - 'HHExpRate': exponential2, - 'HHSigmoidRate': sigmoid2, - 'HHSigmoidVariable': sigmoid2, - 'HHExpLinearRate': linoid2 - } + def getComponentType(self, ratefn): + """Returns the NeuroML ComponentType object for the ratefn. - tab = np.linspace(vmin, vmax, tablen) - if self._is_standard_nml_rate(ratefn): - midpoint, rate, scale = map(SI, (ratefn.midpoint, ratefn.rate, ratefn.scale)) - return rate_fn_map[ratefn.type](tab, rate, scale, midpoint) + A NeuroMLDocument object has a list called 'ComponentType' of + `nml.ComponentType` objects containing the ComponentType + definitions. The rate equations for ion channel gate dynamics + are also defined as `ComponentType` elements. The + `ComponentType` object whose `name` matches the rate + function's `type` attribute is returned. - for ct in self.doc.ComponentType: - if ratefn.type != ct.name: - continue + Parameters + ---------- + ratefn : nml.HHRate + Rate function element - logger_.info(f"Using %s to evaluate rate"%ct.name) - rate = [] - for v in tab: - # Note: MOOSE HHGate are voltage and/or concentration - # dependent. Here we figure out if nml description of gate is - # concentration dependent or not. - # logger_.debug(f"{'#' * 5} {_isConcDep(ct)}") - if _isConcDep(ct): - # Concentration dependent. Concentration can't be negative. - # Find a suitable CaConc from the /library. Currently on Ca - # dependent channels are allowed. - caConcName = _findCaConcVariableName() - req_vars = {'v': '0.0V', 'caConc':f'{max(1e-11,v):g}', caConcName:f'{max(1e-11,v):g}','vShift':vShift,'temperature':self._getTemperature()} - # logger_.debug(f"{'A' * 30} {req_vars}") - else: - req_vars = {'v':'%sV'%v,'vShift':vShift,'temperature':self._getTemperature()} - req_vars.update( self._variables ) - vals = pynml.evaluate_component(ct, req_variables=req_vars) - v = vals.get('x', vals.get('t', vals.get('r', None))) - if v is not None: - rate.append(v) - return np.array(rate) + """ + for ct in self.doc.ComponentType: + if ratefn.type == ct.name: + return ct + + def rateFnFromFormula( + self, ratefn, ctype, vtab, ctab=None, param_tabs={}, vshift="0.0V" + ): + """Compute rate values from formula provided in NeuroML2 document + + Parameters + ---------- + ratefn : NeuroML element for rate function + Element defining the rate function + ctype: NeuroML ComponentType + ComponentType matching that of the rate function + vtab : Sequence + Sequence of values at which the rate has to be computed. + This is the primary parameter. Even if the rate is concentration + dependent, but not voltage dependent, the array of concentration + values must be passed via `vtab`, as it only requires a 1D + interpolation table. + ctab : Sequence + Sequence of values for a second parameter like concentration. + When this is specified, the rates are calculated for a 2D + interpolation table of len(vtab)xlen(ctab), which is applicable + for HHGate2D. + param_tabs: dict {varname: fp} + Mapping variable name to precomputed value table (see + `calculateRateFn` for details) + vshift: str + Voltage shift to be applied (value with unit) + """ + assert (vtab is not None) or ( + ctab is not None + ), "At least one of voltage and concentration arrays must be specified" + rate = [] + req_vars = { + "vShift": Q_(vshift), + "temperature": Q_(self._getTemperature()), + } + req_vars.update(self._variables) # what's the use? + if (vtab is None) or (len(vtab) == 0): + req_vars["caConc"] = Q_(ctab, "mole / meter ** 3") + elif (ctab is None) or (len(ctab) == 0): + req_vars["v"] = Q_(vtab, "V") + else: + # Get pair-wise coordinates for 2D table + vv, cc = np.meshgrid(vtab, ctab) + req_vars["v"] = Q_(vv.flatten(), "V") + req_vars["caConc"] = Q_(cc.flatten(), "mole / meter ** 3") + + vals = array_eval_component( + ctype, req_vars=req_vars, params=param_tabs + ) + rate = vals.get("x", vals.get("t", vals.get("r", None))) + if rate is None: + raise ValueError("Evaluation of expression returned None") + if (vtab is not None) and (ctab is not None): + # Transpose meshgrid which creates m x n array from n-vec and + # m-vec. MOOSE table assumes n x m lookup table where n is + # first index variable array is of length n and the second + # index variable array if of length m + return rate.reshape(len(ctab), len(vtab)).T + return rate + + def calculateRateFn( + self, ratefn, vtab, ctab=None, param_tabs={}, vShift="0mV" + ): + """Compute rate function based on NeuroML description. + + Calculate the HHGate rate functions from NeuroML + description. In the simplest case it is forward or backward + rate (alpha and beta) in one of the standard forms. But in + some cases there needs to be further tweaks where the time + course (tau) and steady state (inf) values are computed based + on rules on alpha and beta. + + Parameters + ---------- + ratefn : str + NeuroML element describing HHRate + vtab: Sequence + Array of voltage/concentration values for which the rate + function is computed + ctab : Sequence (default: None) + Sequence of values for a parameter like concentration. + When both `vtab` and `ctab` are specified, the rates are + calculated for a 2D interpolation table of len(vtab)xlen(ctab), + which is applicable for HHGate2D. + param_tabs : dict {variable_name: value_array} + Precomputed tables for gate parameters. The keys are used + as variable names when evaluating neuroml dynamics expression. + The values are arrays (or sequences) with entries + corresponding to `vtab`. + vShift : str + Voltage shift to be applied - print( "[WARN ] Could not determine rate: %s %s %s" %(ratefn.type,vmin,vmax)) - return np.array([]) + """ + # For standard rate functions in `PREDEFINED_RATEFN_MAP` simply call it + # and return the result + function = PREDEFINED_RATEFN_MAP.get(ratefn.type, None) + if function is not None: + midpoint = SI(ratefn.midpoint) + rate = SI(ratefn.rate) + scale = SI(ratefn.scale) + return function(vtab, rate, scale, midpoint) + + # Non-standard rate function: find a ComponentType matching + # the `type` of the rate function + ct = self.getComponentType(ratefn) + logger_.info(f"Using {ct.name} to evaluate rate") + rate = self.rateFnFromFormula( + ratefn, + ct, + vtab, + ctab=ctab, + param_tabs=param_tabs, + vshift=vShift, + ) + if rate is None: + print(f"[WARN ] Could not determine rate: {ratefn.type}") + return np.empty(0) + return rate def importChannelsToCell(self, nmlcell, moosecell, membrane_properties): sg_to_segments = self._cell_to_sg[nmlcell.id] - for chdens in membrane_properties.channel_densities + membrane_properties.channel_density_v_shifts: + for chdens in ( + membrane_properties.channel_densities + + membrane_properties.channel_density_v_shifts + ): segments = getSegments(nmlcell, chdens, sg_to_segments) condDensity = SI(chdens.cond_density) erev = SI(chdens.erev) try: ionChannel = self.id_to_ionChannel[chdens.ion_channel] except KeyError: - logger_.info('No channel with id: %s' % chdens.ion_channel) + logger_.info("No channel with id: %s" % chdens.ion_channel) continue if self.verbose: - logger_.info('Setting density of channel %s in %s to %s; erev=%s (passive: %s)'%( - chdens.id, segments, condDensity,erev,self.isPassiveChan(ionChannel)) - ) + logger_.info( + f"Setting density of channel {chdens.id} in {segments}" + f"to {condDensity}; erev={erev} " + f"(passive: {self.isPassiveChan(ionChannel)})" + ) if self.isPassiveChan(ionChannel): for seg in segments: @@ -543,9 +897,256 @@ def importChannelsToCell(self, nmlcell, moosecell, membrane_properties): setEk(comp, erev) else: for seg in segments: - self.copyChannel(chdens, self.nml_segs_to_moose[seg.id], condDensity, erev) - '''moose.le(self.nml_to_moose[seg]) - moose.showfield(self.nml_to_moose[seg], field="*", showtype=True)''' + self.copyChannel( + chdens, + self.nml_segs_to_moose[seg.id], + condDensity, + erev, + ) + + def isDynamicsCaDependent(self, ct): + """Returns True if the dynamics of `ct` is Ca dependent. + + If any identifier in the value expression of a DerivedVariable + or ConditionalDerivedVariable in the Dynamics of this + ComponentType is `caConc`, we assume it is [Ca2+] dependent. + + Parameters + ---------- + ct : nml.ComponentType + ComponentType object + + """ + for dyn in ct.Dynamics: + for dv in dyn.DerivedVariable + dyn.ConditionalDerivedVariable: + parsed = ast.parse(dv.value) + # If any identifier (represented by class ast.Name) in + # the derived variable expression is "caConc", the + # gate is Ca concentration dependent. + for node in ast.walk(parsed): + if isinstance(node, ast.Name): + if node.id == "caConc": + return True + return False + + def isDynamicsVoltageDependent(self, ct): + """Returns True if the dynamics of `ct` is Voltage dependent. + + If any identifier in the value expression of a DerivedVariable + or ConditionalDerivedVariable in the Dynamics of this + ComponentType is `v`, we assume it is voltage dependent. + + Parameters + ---------- + ct : nml.ComponentType + ComponentType object + + """ + for dyn in ct.Dynamics: + for dv in dyn.DerivedVariable + dyn.ConditionalDerivedVariable: + parsed = ast.parse(dv.value) + # If any identifier (represented by class ast.Name) in + # the derived variable expression is "caConc", the + # gate is Ca concentration dependent. + for node in ast.walk(parsed): + if isinstance(node, ast.Name): + if node.id == "v": + return True + return False + + def isDynamicsVoltageCaDependent(self, ct): + """Returns True if the dynamics of `ct` is dependent on both + voltage and calcium concentration. + + Identifiers `caConc` and `v` both appear in the value + expressions of the DerivedVariable or + ConditionalDerivedVariable elements in the Dynamics of this + ComponentType, we assume it is [Ca2+] and voltage dependent. + + Gates whose dynamics depend on both voltage and Ca2+ + concentration require a 2D interpolation table, and are + implemented as HHGate2D under HHChannel2D in moose. This test + is need for that. + + Parameters + ---------- + ct : nml.ComponentType + ComponentType object + + """ + ca_dep = False + v_dep = False + for dyn in ct.Dynamics: + for dv in dyn.DerivedVariable + dyn.ConditionalDerivedVariable: + parsed = ast.parse(dv.value) + # If any identifier (represented by class ast.Name) in + # the derived variable expression is "caConc", the + # gate is Ca concentration dependent. If any + # identifier is "v", it is voltage dependent. + for node in ast.walk(parsed): + if isinstance(node, ast.Name): + if node.id == "caConc": + ca_dep = True + if node.id == "v": + v_dep = True + return (ca_dep is True) and (v_dep is True) + + def isChannelCaDependent(self, chan): + """Returns True if `chan` is dependent on calcium concentration. + + Checks if any of the gate dynamics depend on Ca + concentration. We assumme that if the ComponentType for the + gate has a Dynamics element where any of the rates (neuroml + DerivedVariable) contain a value `caConc`. + + Parameters + ---------- + chan : nml.IonChannel + NeuroML IonChannel element + + """ + for gate in chan.gates + chan.gate_hh_rates: + dynamics = [ + gate.forward_rate, + gate.reverse_rate, + gate.time_course, + gate.steady_state, + ] + for dyn in dynamics: + if dyn is not None: + ct = self.getComponentType(dyn) + if ct is None or (ct.extends != "baseVoltageConcDepRate"): + continue + if self.isDynamicsCaDependent(ct): + return True + return False + + def isChannel2D(self, chan): + """Returns True if `chan` requires moose.HHChannel2D. + + For channels where any of the gates is dependent on both [Ca2+] + and voltage, the gate opening/closing rates are looked up from a + 2D interpolation table indexed by both voltage and + concentration. This is implemented in HHGate2D. The channel is + implemented as HHChannel2D allows up to HHGate2D. + + Parameters + ---------- + chan: nml.IonChannel + IonChannel element to be checked. + """ + for gate in chan.gates + chan.gate_hh_rates: + if self.isGateVoltageCaDependent(gate): + return True + return False + + def isGateCaDependent(self, ngate): + """Returns True if `ngate` has dynamics that depends on Ca2+ + concentration. + + Parameters + ---------- + ngate : nml.HHGate + Gate description element in neuroml + + """ + dynamics = [ + getattr(ngate, "forward_rate", None), + getattr(ngate, "reverse_rate", None), + getattr(ngate, "time_course", None), + getattr(ngate, "steady_state", None), + ] + for dyn in dynamics: + if dyn is not None: + ct = self.getComponentType(dyn) + if (ct is not None) and self.isDynamicsCaDependent(ct): + return True + return False + + def isGateVoltageDependent(self, ngate): + """Returns True if `ngate` has dynamics that depends voltage. + + Parameters + ---------- + ngate : nml.HHGate + Gate description element in neuroml + + """ + dynamics = [ + getattr(ngate, "forward_rate", None), + getattr(ngate, "reverse_rate", None), + getattr(ngate, "time_course", None), + getattr(ngate, "steady_state", None), + ] + for dyn in dynamics: + if dyn is not None: + ct = self.getComponentType(dyn) + if (ct is not None) and self.isDynamicsCaDependent(ct): + return True + return False + + def isGateVoltageCaDependent(self, ngate): + """Returns True if `ngate` has dynamics that depends on both voltage + and Ca2+ concentration. + + Parameters + ---------- + ngate : nml.HHGate + Gate description element in neuroml + + """ + dynamics = [ + getattr(ngate, "forward_rate", None), + getattr(ngate, "reverse_rate", None), + getattr(ngate, "time_course", None), + getattr(ngate, "steady_state", None), + ] + for dyn in dynamics: + if dyn is not None: + ct = self.getComponentType(dyn) + if ( + (ct is not None) + and (ct.extends == "baseVoltageConcDepRate") + and self.isDynamicsVoltageCaDependent(ct) + ): + return True + return False + + def setupCaDep(self, nmlcell, moosecell, membrane_properties): + """Create connections between Ca channels, Ca pool, and + Ca-dependent channels.""" + sg_to_segments = self._cell_to_sg[nmlcell.id] + caName = _findCaConcVariableName() + if caName is None: + print( + "[INFO ] No CaConc object found. Skip setting up [Ca2+]" + " dependence." + ) + return + for chdens in ( + membrane_properties.channel_densities + + membrane_properties.channel_density_v_shifts + ): + segments = getSegments(nmlcell, chdens, sg_to_segments) + try: + nchan = self.id_to_ionChannel[chdens.ion_channel] + except KeyError: + logger_.info("No channel with id: %s" % chdens.ion_channel) + continue + if chdens.ion == "ca": + for seg in segments: + comp = self.nml_segs_to_moose[seg.id] + caPool = moose.element(f"{comp.path}/{caName}") + mchan = moose.element(f"{comp.path}/{chdens.id}") + if caPool.path != "/": + moose.connect(mchan, "IkOut", caPool, "current") + if self.isChannelCaDependent(nchan): + for seg in segments: + comp = self.nml_segs_to_moose[seg.id] + mchan = moose.element(f"{comp.path}/{chdens.id}") + caPool = moose.element(f"{comp.path}/{caName}") + if caPool.path != "/": + moose.connect(caPool, "concOut", mchan, "concen") def copyChannel(self, chdens, comp, condDensity, erev): """Copy moose prototype for `chdens` condutcance density to `comp` @@ -553,180 +1154,549 @@ def copyChannel(self, chdens, comp, condDensity, erev): """ proto_chan = None - if chdens.ion_channel in self.proto_chans: + try: proto_chan = self.proto_chans[chdens.ion_channel] - else: + except KeyError: for innerReader in self.includes.values(): - if chdens.ionChannel in innerReader.proto_chans: + try: proto_chan = innerReader.proto_chans[chdens.ion_channel] break + except KeyError: + pass if not proto_chan: - raise Exception('No prototype channel for %s referred to by %s' % (chdens.ion_channel, chdens.id)) + raise Exception( + f"No prototype channel for {chdens.ion_channel}" + f"referred to by {chdens.id}" + ) if self.verbose: - logger_.info('Copying the %s to %s, %s; erev=%s'%(chdens.id, comp, condDensity, erev)) - orig = chdens.id + logger_.info( + f"Copying {chdens.id} to {comp}, {condDensity}; erev={erev}" + ) chid = moose.copy(proto_chan, comp, chdens.id) chan = moose.element(chid) - els = list(self.paths_to_chan_elements.keys()) - for p in els: - pp = p.replace('%s/'%chdens.ion_channel,'%s/'%orig) - self.paths_to_chan_elements[pp] = self.paths_to_chan_elements[p].replace('%s/'%chdens.ion_channel,'%s/'%orig) - #logger_.info(self.paths_to_chan_elements) chan.Gbar = sarea(comp) * condDensity chan.Ek = erev - moose.connect(chan, 'channel', comp, 'channel') + moose.connect(chan, "channel", comp, "channel") return chan def _is_standard_nml_rate(self, rate): - return rate.type=='HHExpLinearRate' \ - or rate.type=='HHExpRate' or \ - rate.type=='HHSigmoidRate' or \ - rate.type=='HHSigmoidVariable' + return ( + rate.type == "HHExpLinearRate" + or rate.type == "HHExpRate" + or rate.type == "HHSigmoidRate" + or rate.type == "HHSigmoidVariable" + ) - def createHHChannel(self, chan, vmin=-150e-3, vmax=100e-3, vdivs=5000): - mchan = moose.HHChannel('%s/%s' % (self.lib.path, chan.id)) - mgates = [moose.element(x) for x in [mchan.gateX, mchan.gateY, mchan.gateZ]] - assert len(chan.gate_hh_rates)<=3, "We handle only up to 3 gates in HHCHannel" + def _computeQ10Scale(self, ngate): + """Compute Q10 scale factor for NeuroML2 gate `ngate`. - if self.verbose: - logger_.info('== Creating channel: %s (%s) -> %s (%s)'%(chan.id, chan.gate_hh_rates, mchan, mgates)) + Parameters + ---------- + ngate : NeuroML2 element + Gate element in NeuroML2 - all_gates = chan.gates + chan.gate_hh_rates + """ + q10_scale = 1.0 + if ngate.q10_settings: + if ngate.q10_settings.type == "q10Fixed": + q10_scale = float(ngate.q10_settings.fixed_q10) + elif ngate.q10_settings.type == "q10ExpTemp": + exp_temp = SI(ngate.q10_settings.experimental_temp) + dtemp = self._getTemperature() - exp_temp + q10_scale = math.pow( + float(ngate.q10_settings.q10_factor), dtemp / 10 + ) + else: + raise Exception( + f"Unknown Q10 scaling type {ngate.q10_settings.type} " + f": {ngate.q10_settings}" + ) + return q10_scale + + def updateHHGate(self, ngate, mgate, mchan, vmin, vmax, vdivs, useInterpolation=True): + """Update moose `HHGate` mgate from NeuroML gate description + element `ngate`. + + Some neuroml descriptions work in two stages. Traditional + steady state (minf/hinf) and time course (taum, tauh) are + computed using a standard formula first, and then these are + tweaked based on custom rules. This function updates a moose + HHGate's tables by computing these as required. + + Parameters + ---------- + ngate : neuroml element + NeuroML gate description to be implemented + mgate : HHGate + Moose HHGate object to be updated + mchan : HHChannel + Moose HHCHannel object whose part the `mgate` is + vmin : str + minimum voltage (or concentration) for gate interpolation tables + vmax : str + Maximum voltage (or concentration) for gate interpolation + tables + vdivs : str + Number of divisions in gate interpolation tables + """ + # Set the moose gate powers from nml gate instance count + if mgate.name.endswith("X"): + mchan.Xpower = ngate.instances + elif mgate.name.endswith("Y"): + mchan.Ypower = ngate.instances + elif mgate.name.endswith("Z"): + mchan.Zpower = ngate.instances + mgate.min = vmin + mgate.max = vmax + mgate.divs = vdivs + mgate.useInterpolation = useInterpolation + q10_scale = self._computeQ10Scale(ngate) + alpha, beta, tau, inf = (None, None, None, None) + param_tabs = {} + vtab = np.linspace(vmin, vmax, vdivs) + # First try computing alpha and beta from fwd and rev rate + # specs. Set the gate tables using alpha and beta by default. + fwd = ngate.forward_rate + rev = ngate.reverse_rate + if (fwd is not None) and (rev is not None): + alpha = self.calculateRateFn(fwd, vtab) + beta = self.calculateRateFn(rev, vtab) + param_tabs = {"alpha": Q_(alpha, "1/s"), "beta": Q_(beta, "1/s")} + + # Beware of a peculiar cascade of evaluation below: In some + # cases rate parameters alpha and beta are computed with + # standard HH-type formula, then tweaked based on the + # existence of "timeCourse" or "steadyState" attributes in the + # channel definition. The results depend on the order of + # execution. + + # A `timeCourse` element indicates tau is not # + # straightforward 1/(alpha+beta) but tweaked from alpha + # and beta computed above + if getattr(ngate, "time_course", None) is not None: + tau = self.calculateRateFn( + ngate.time_course, + vtab, + param_tabs=param_tabs, + ) + elif (alpha is not None) and (beta is not None): + tau = 1.0 / (alpha + beta) + + # A `steadyState` element indicates inf is not + # straightforward, but tweaked from alpha and beta computed + # above + if getattr(ngate, "steady_state", None) is not None: + inf = self.calculateRateFn( + ngate.steady_state, + vtab, + param_tabs=param_tabs, + ) + elif (alpha is not None) and (beta is not None): + inf = alpha / (alpha + beta) + + # Should update the gate tables only if `tau` or `inf` were + # tweaked, but this is simpler than checking the cascading + # evaluation above. + mgate.tableA = q10_scale * inf / tau + mgate.tableB = q10_scale * 1.0 / tau + # DEBUG + # np.savetxt( + # f"{mchan.name}.{ngate.id}.inf.txt", + # np.block([vtab[:, np.newaxis], inf[:, np.newaxis]]), + # ) + # np.savetxt( + # f"{mchan.name}.{ngate.id}.tau.txt", + # np.block([vtab[:, np.newaxis], inf[:, np.newaxis]]), + # ) + # import matplotlib.pyplot as plt + + # fig, ax = plt.subplots(nrows=1, ncols=2) + # ax[0].plot(vtab, inf) + # ax[1].plot(vtab, tau) + # fig.suptitle(f"{mchan.name}/{ngate.id}") + # END DEBUG + return mgate + + def updateHHGate2D( + self, ngate, mgate, mchan, vmin, vmax, vdivs, cmin, cmax, cdivs + ): + """Update moose `HHGate` mgate from NeuroML gate description + element `ngate`. + + Some neuroml descriptions work in two stages. Traditional + steady state (minf/hinf) and time course (taum, tauh) are + computed using a standard formula first, and then these are + tweaked based on custom rules. This function updates a moose + HHGate's tables by computing these as required. + + Parameters + ---------- + ngate : neuroml element + NeuroML gate description to be implemented + mgate : HHGate + Moose HHGate object to be updated + mchan : HHChannel + Moose HHCHannel object whose part the `mgate` is + vmin : str + minimum voltage (or concentration) for gate interpolation tables + vmax : str + Maximum voltage (or concentration) for gate interpolation + tables + vdivs : str + Number of divisions in gate interpolation tables + cmin : float + Minimum concentration + cmax : float + Maximum concentration + cdivs : int + Number of divisions in the interpolation table for concentration + + """ + # Set the moose gate powers from nml gate instance count + if mgate.name.endswith("X"): + mchan.Xpower = ngate.instances + elif mgate.name.endswith("Y"): + mchan.Ypower = ngate.instances + elif mgate.name.endswith("Z"): + mchan.Zpower = ngate.instances + # TODO: HHGate2D and and HHChannel2D should be updated in + # MOOSE to avoid this redundant setting for the two tables + mgate.xmin = vmin + mgate.xmax = vmax + mgate.xdivs = vdivs + mgate.ymin = cmin + mgate.ymax = cmax + mgate.ydivs = cdivs + # If the gate depends only on one parameter, disable the + # second dimension + q10_scale = self._computeQ10Scale(ngate) + alpha, beta, tau, inf = (None, None, None, None) + param_tabs = {} + vtab = np.linspace(vmin, vmax, vdivs) + ctab = np.linspace(cmin, cmax, cdivs) + # First try computing alpha and beta from fwd and rev rate + # specs. Set the gate tables using alpha and beta by default. + fwd = ngate.forward_rate + rev = ngate.reverse_rate + if (fwd is not None) and (rev is not None): + alpha = self.calculateRateFn(fwd, vtab, ctab=ctab) + beta = self.calculateRateFn(rev, vtab, ctab=ctab) + param_tabs = {"alpha": Q_(alpha, "1/s"), "beta": Q_(beta, "1/s")} + # Beware of a peculiar cascade of evaluation below: In some + # cases rate parameters alpha and beta are computed with + # standard HH-type formula, then tweaked based on the + # existence of "timeCourse" or "steadyState" attributes in the + # channel definition. The results depend on the order of + # execution. + + # A `timeCourse` element indicates tau is not # + # straightforward 1/(alpha+beta) but tweaked from alpha + # and beta computed above + if getattr(ngate, "time_course", None) is not None: + tau = self.calculateRateFn( + ngate.time_course, + vtab, + ctab=ctab, + param_tabs=param_tabs, + ) + elif (alpha is not None) and (beta is not None): + tau = 1.0 / (alpha + beta) + + # A `steadyState` element indicates inf is not + # straightforward, but tweaked from alpha and beta computed + # above + if getattr(ngate, "steady_state", None) is not None: + inf = self.calculateRateFn( + ngate.steady_state, + vtab, + ctab=ctab, + param_tabs=param_tabs, + ) + elif (alpha is not None) and (beta is not None): + inf = alpha / (alpha + beta) + + # Should update the gate tables only if `tau` or `inf` were + # tweaked, but this is simpler than checking the cascading + # evaluation above. + mgate.tableA = q10_scale * inf / tau + mgate.tableB = q10_scale * 1.0 / tau + # DEBUG + # if len(inf.shape) == 1: + # np.savetxt( + # f"{mchan.name}.{ngate.id}.inf.txt", + # np.block([vtab[:, np.newaxis], inf[:, np.newaxis]]), + # ) + # np.savetxt( + # f"{mchan.name}.{ngate.id}.tau.txt", + # np.block([vtab[:, np.newaxis], inf[:, np.newaxis]]), + # ) + # import matplotlib.pyplot as plt + + # fig, ax = plt.subplots(nrows=1, ncols=2) + # ax[0].plot(vtab, inf) + # ax[1].plot(vtab, tau) + # fig.suptitle(f"{mchan.name}/{ngate.id}") + # END DEBUG + return mgate + + def createHHChannel(self, chan, vmin=-150e-3, vmax=100e-3, vdivs=3000): + mchan = moose.HHChannel(f"{self.lib.path}/{chan.id}") + mgates = [ + moose.element(x) for x in [mchan.gateX, mchan.gateY, mchan.gateZ] + ] + assert ( + len(chan.gate_hh_rates) <= 3 + ), "HHChannel allows only up to 3 gates" + + if self.verbose: + logger_.info( + "== Creating channel: " + f"{chan.id} ({chan.gates}, {chan.gate_hh_rates})" + f"-> {mchan} ({mgates})" + ) # Sort all_gates such that they come in x, y, z order. - all_gates = _gates_sorted( all_gates ) + all_gates = _gates_sorted(chan.gates + chan.gate_hh_rates) for ngate, mgate in zip(all_gates, mgates): if ngate is None: continue - if mgate.name.endswith('X'): - mchan.Xpower = ngate.instances - elif mgate.name.endswith('Y'): - mchan.Ypower = ngate.instances - elif mgate.name.endswith('Z'): - mchan.Zpower = ngate.instances - mgate.min = vmin - mgate.max = vmax - mgate.divs = vdivs - - # I saw only examples of GateHHRates in - # HH-channels, the meaning of forwardRate and - # reverseRate and steadyState are not clear in the - # classes GateHHRatesInf, GateHHRatesTau and in - # FateHHTauInf the meaning of timeCourse and - # steady state is not obvious. Is the last one - # refering to tau_inf and m_inf?? - fwd = ngate.forward_rate - rev = ngate.reverse_rate - self.paths_to_chan_elements['%s/%s'%(chan.id,ngate.id)] = '%s/%s'%(chan.id,mgate.name) - q10_scale = 1 - if ngate.q10_settings: - if ngate.q10_settings.type == 'q10Fixed': - q10_scale= float(ngate.q10_settings.fixed_q10) - elif ngate.q10_settings.type == 'q10ExpTemp': - q10_scale = math.pow( float(ngate.q10_settings.q10_factor) - , (self._getTemperature()- SI(ngate.q10_settings.experimental_temp))/10 - ) - else: - raise Exception('Unknown Q10 scaling type %s: %s'%( - ngate.q10_settings.type,ngate.q10_settings) - ) + mgate = self.updateHHGate( + ngate=ngate, + mgate=mgate, + mchan=mchan, + vmin=vmin, + vmax=vmax, + vdivs=vdivs, + ) + logger_.debug(f"Updated HHGate {mgate.path}") + logger_.info( + f"{self.filename}: Created moose HHChannel {mchan.path}" + f" for neuroml {chan.id}" + ) + return mchan - logger_.debug('+ Gate: %s; %s; %s; %s; %s; scale=%s'% ( - ngate.id, mgate.path, mchan.Xpower, fwd, rev, q10_scale) - ) + def createHHChannel2D( + self, + chan, + vmin=-150e-3, # -150 mV + vmax=100e-3, # 100 mV + vdivs=3000, + cmin=0, + cmax=10.0, + cdivs=5000, + ): + """Create and return a Hodgkin-Huxley-type ion channel whose + dynamics depends on 2-parameters. + + Creates a channel where some gate has dynamics defined by a + non-separable function of Ca2+ concentration and voltage. + + Parameters + ---------- + chan : nml.IonChannel + NeuroML channel description + vmin : float (default: -150 mV) + Minimum voltage + vmax : float (default: 100 mV) + Maximum voltage + vdivs : int + Number of divisions in the interpolation table for voltage + cmin : float (default: 0) + Minimum concentration. + cmax : float (default: 10.0 = 10 mM) + Maximum concentration + cdivs : int + Number of divisions in the interpolation table for concentration + + """ - if (fwd is not None) and (rev is not None): - alpha = self.calculateRateFn(fwd, vmin, vmax, vdivs) - beta = self.calculateRateFn(rev, vmin, vmax, vdivs) - - mgate.tableA = q10_scale * (alpha) - mgate.tableB = q10_scale * (alpha + beta) - - # Assuming the meaning of the elements in GateHHTauInf ... - if hasattr(ngate,'time_course') and hasattr(ngate,'steady_state') \ - and (ngate.time_course is not None) and (ngate.steady_state is not None): - tau = ngate.time_course - inf = ngate.steady_state - tau = self.calculateRateFn(tau, vmin, vmax, vdivs) - inf = self.calculateRateFn(inf, vmin, vmax, vdivs) - mgate.tableA = q10_scale * (inf / tau) - mgate.tableB = q10_scale * (1 / tau) - - if hasattr(ngate,'steady_state') and (ngate.time_course is None) and (ngate.steady_state is not None): - inf = ngate.steady_state - tau = 1 / (alpha + beta) - if inf is not None: - inf = self.calculateRateFn(inf, vmin, vmax, vdivs) - if len(inf) > 0: - mgate.tableA = q10_scale * (inf / tau) - mgate.tableB = q10_scale * (1 / tau) - - logger_.info('%s: Created %s for %s'%(self.filename,mchan.path,chan.id)) + mchan = moose.HHChannel2D(f"{self.lib.path}/{chan.id}") + mgates = [ + moose.element(x) for x in [mchan.gateX, mchan.gateY, mchan.gateZ] + ] + assert ( + len(chan.gate_hh_rates) <= 3 + ), "HHChannel allows only up to 3 gates" + + if self.verbose: + logger_.info( + "== Creating channel: " + f"{chan.id} ({chan.gates}, {chan.gate_hh_rates})" + f"-> {mchan} ({mgates})" + ) + # Sort all_gates such that they come in x, y, z order. + all_gates = _gates_sorted(chan.gates + chan.gate_hh_rates) + for ngate, mgate in zip(all_gates, mgates): + if ngate is None: + continue + # We need to update Xindex for gateX, Yindex for gateY and + # Zindex for gateZ + indexattr = f"{mgate.name[-1]}index" + vdep = self.isGateCaDependent(ngate) + cdep = self.isGateVoltageDependent(ngate) + cmin_, cmax_, cdivs_ = 0, 0, 0 + vmin_, vmax_, vdivs_ = 0, 0, 0 + if vdep and cdep: + # gate depends on both voltage and Ca - index for + # first dimension is membrane potential and second + # dimension is concentration + setattr(mchan, indexattr, "VOLT_C1_INDEX") + cmin_, cmax_, cdivs_ = cmin, cmax, cdivs + vmin_, vmax_, vdivs_ = vmin, vmax, vdivs + elif vdep and not cdep: + setattr(mchan, indexattr, "VOLT_INDEX") + vmin_, vmax_, vdivs_ = vmin, vmax, vdivs + elif cdep and not vdep: + setattr(mchan, indexattr, "C1_INDEX") + cmin_, cmax_, cdivs_ = cmin, cmax, cdivs + # Not handling a second concentration parameter concen2 + mgate = self.updateHHGate2D( + ngate=ngate, + mgate=mgate, + mchan=mchan, + vmin=vmin_, + vmax=vmax_, + vdivs=vdivs_, + cmin=cmin_, + cmax=cmax_, + cdivs=cdivs_, + ) + if not (vdep and cdep): + mgate.ydivsA = 0 + mgate.ydivsB = 0 + + logger_.info( + f"{self.filename}: Created moose HHChannel {mchan.path}" + f" for neuroml {chan.id}" + ) return mchan def createPassiveChannel(self, chan): - epath = '%s/%s' % (self.lib.path, chan.id) - if moose.exists( epath ): + epath = f"{self.lib.path}/{chan.id}" + if moose.exists(epath): mchan = moose.element(epath) else: mchan = moose.Leakage(epath) - logger_.info('%s: Created %s for %s'%(self.filename,mchan.path,chan.id)) + logger_.info(f"{self.filename}: created {mchan.path} for {chan.id}") return mchan def importInputs(self, doc): - epath = '%s/inputs' % (self.lib.path) - if moose.exists( epath ): - minputs = moose.element( epath ) - else: - minputs = moose.Neutral( epath ) + """Create inputs to the model. + + Create PulseGen objects to deliver current injection. This is + for convenience only, and may be overridden in future for more + suitable experimental instrumentation/protocol description specs. + Parameters + ---------- + doc : NeuroMLDocument + Document object read from NeuroML file + + """ + minputs = moose.Neutral(f"{self.lib.path}/inputs") for pg_nml in doc.pulse_generators: - epath = '%s/%s' % (minputs.path, pg_nml.id) - pg = moose.element(epath) if moose.exists(epath) else moose.PulseGen(epath) + epath = f"{minputs.path}/{pg_nml.id}" + pg = moose.PulseGen(epath) pg.firstDelay = SI(pg_nml.delay) pg.firstWidth = SI(pg_nml.duration) pg.firstLevel = SI(pg_nml.amplitude) pg.secondDelay = 1e9 - logger_.debug(f'{"$" * 10} Created input {epath}') - - def importIonChannels(self, doc, vmin=-150e-3, vmax=100e-3, vdivs=5000): - logger_.info('%s: Importing the ion channels' % self.filename ) - - for chan in doc.ion_channel+doc.ion_channel_hhs: - if chan.type == 'ionChannelHH': - mchan = self.createHHChannel(chan) - elif self.isPassiveChan(chan): + def importIonChannels( + self, + doc, + vmin=-150e-3, + vmax=100e-3, + vdivs=3000, + cmin=0, + cmax=10.0, + cdivs=5000, + ): + logger_.info(f"{self.filename}: Importing the ion channels") + + for chan in doc.ion_channel + doc.ion_channel_hhs: + if self.isPassiveChan(chan): mchan = self.createPassiveChannel(chan) + elif self.isChannel2D(chan): + mchan = self.createHHChannel2D( + chan, + vmin=vmin, + vmax=vmax, + vdivs=vdivs, + cmin=cmin, + cmax=cmax, + cdivs=cdivs, + ) else: - mchan = self.createHHChannel(chan) + mchan = self.createHHChannel( + chan, vmin=vmin, vmax=vmax, vdivs=vdivs + ) self.id_to_ionChannel[chan.id] = chan self.nml_chans_to_moose[chan.id] = mchan self.proto_chans[chan.id] = mchan - logger_.info(self.filename + ': Created ion channel %s for %s %s'%( - mchan.path, chan.type, chan.id)) + logger_.info( + f"{self.filename}: Created ion channel {mchan.path} " + f"for {chan.type} {chan.id}" + ) def importConcentrationModels(self, doc): for concModel in doc.decaying_pool_concentration_models: self.createDecayingPoolConcentrationModel(concModel) def createDecayingPoolConcentrationModel(self, concModel): - """Create prototype for concentration model""" - if hasattr(concModel, 'name') and concModel.name is not None: + """Create prototype for concentration model.""" + if hasattr(concModel, "name") and concModel.name is not None: name = concModel.name else: name = concModel.id - - ca = moose.CaConc('%s/%s' % (self.lib.path, name)) + ca = moose.CaConc(f"{self.lib.path}/{name}") ca.CaBasal = SI(concModel.resting_conc) ca.tau = SI(concModel.decay_constant) ca.thick = SI(concModel.shell_thickness) - ca.B = 5.2e-6 # B = 5.2e-6/(Ad) where A is the area of the - # shell and d is thickness - must divide by - # shell volume when copying + # Here is an implementation issue: + # Decaying Ca pool is modeled as a thin shell of thickness d and + # area A that decays towards the baseline/resting concentration + # with a time constant tau: + + # d[Ca2+]/dt = I_Ca/(2 * F * A * d) - ([Ca2+] - [Ca2+]_rest)/tau + + # where F is Faraday's constant and I_Ca are the Ca currents + # increasing the [Ca2+] in this shell: + + # rate of increase of the number of Ca2+ ions = I_Ca/2, + + # rate of increase of number of moles = I_Ca/(2 * F), + + # volume of shell = A * d, + + # rate of increase of concentration = I_Ca/(2 * F * A * d) + + # NeuroML puts the 1/(2 * F * d) factor as the attribute `rho`, + # which may include some additional scaling. + + # In MOOSE implementation, setting B explicitly is + # discouraged, but kept for backwards compatibility with + # GENESIS. It is calculated dynamically using Faraday's + # constant, valence, and volume of the shell. Every time the + # volume is updated (upon setting thickness, length, or + # diameter of the shell), it recomputes this factor. + + # The only problem is the calculation assumes cylindrical + # shell, not accounting for spherical compartments. + # - subha + # + # if concModel.rho is not None: + # # B = 5.2e-6/(Ad) where A is the area of the shell and d + # # is thickness - must divide by shell volume when copying + # ca.B = 5.2e-6 + + # else: + # ca.B = Q_(concModel.rho).to_base_units().m self.proto_pools[concModel.id] = ca self.nml_conc_to_moose[concModel.id] = ca self.moose_to_nml[ca] = concModel - logger_.debug('Created moose element: %s for nml conc %s' % (ca.path, concModel.id)) + logger_.debug( + f"Created moose element {ca.path} for" f" nml {concModel.id}" + ) diff --git a/python/moose/neuroml2/test_granule98.py b/python/moose/neuroml2/test_granule98.py index c300edd103..1f6655edb0 100644 --- a/python/moose/neuroml2/test_granule98.py +++ b/python/moose/neuroml2/test_granule98.py @@ -1,12 +1,11 @@ -# test_granule98.py --- -# +# test_granule98.py --- +# # Filename: test_granule98.py -# Description: +# Description: # Author: Subhasis Ray # Created: Mon Apr 8 21:41:22 2024 (+0530) -# Last-Updated: Wed Apr 10 20:16:04 2024 (+0530) # By: Subhasis Ray -# +# # Code: """Test code for the Granule cell model @@ -15,11 +14,13 @@ import os import sys import numpy as np +import matplotlib.pyplot as plt + # import unittest import logging -LOGLEVEL = os.environ.get('LOGLEVEL', 'INFO') +LOGLEVEL = os.environ.get("LOGLEVEL", "INFO") logging.basicConfig(level=LOGLEVEL) @@ -27,46 +28,130 @@ from moose.neuroml2.reader import NML2Reader -def run(modeldir, nogui=True): - reader = NML2Reader() - filename = os.path.join(modeldir, 'GranuleCell.net.nml') +channels = ["NaF", "KDR", "KA", "KC"] + + +def dump_gate_tables(channel, do_plot=False): + if do_plot: + fig, axes = plt.subplots(nrows=1, ncols=2) + + for letter in ["X", "Y", "Z"]: + power = getattr(channel, f"{letter}power") + if power > 0: + gate = moose.element(f"{channel.path}/gate{letter}") + minf = gate.tableA / gate.tableB + mtau = 1 / gate.tableB + v = np.linspace(gate.min, gate.max, len(minf)) + inf_f = f"{channel.name}.{letter}.inf.dat" + tau_f = f"{channel.name}.{letter}.tau.dat" + np.savetxt(inf_f, np.block([v[:, np.newaxis], minf[:, np.newaxis]])) + np.savetxt(tau_f, np.block([v[:, np.newaxis], mtau[:, np.newaxis]])) + logging.info( + f"Saved {letter} gate tables for {channel.name} in {inf_f} and {tau_f}" + ) + if do_plot: + axes[0].plot(v, minf, label=f"inf {letter}") + axes[1].plot(v, mtau, label=f"tau {letter}") + if do_plot: + axes[0].legend() + axes[1].legend() + fig.suptitle(channel.name) + + +if __name__ == "__main__": + if len(sys.argv) < 2: + print(f"Usage: {sys.argv[0]} modeldir") + print( + "where modeldir contains the neuroML2 model. " + "For the GranuleCell model cloned " + "from OpenSourceBrain, this should be " + "`GranuleCell/neuroConstruct/generatedNeuroML2/`" + ) + sys.exit(1) + modeldir = sys.argv[1] + do_plot = True + reader = NML2Reader(verbose=True) + filename = os.path.join(modeldir, "GranuleCell.net.nml") reader.read(filename) - soma = reader.getComp(reader.doc.networks[0].populations[0].id, 0, 0) - data = moose.Neutral('/data') - pg = reader.getInput('Gran_10pA') - inj = moose.Table(f'{data.path}/pulse') - moose.connect(inj, 'requestOut', pg, 'getOutputValue') - vm = moose.Table(f'{data.path}/Vm') - moose.connect(vm, 'requestOut', soma, 'getVm') - print('A' * 10, soma) - - simtime = 300e-3 + pop_id = reader.doc.networks[0].populations[0].id + soma = reader.getComp(pop_id, cellIndex=0, segId=0) + data = moose.Neutral("/data") + pg = reader.getInput("Gran_10pA") + pg.firstWidth = 500e-3 + inj = moose.Table(f"{data.path}/pulse") + moose.connect(inj, "requestOut", pg, "getOutputValue") + vm = moose.Table(f"{data.path}/Vm") + moose.connect(vm, "requestOut", soma, "getVm") + catab = None + for el in moose.wildcardFind("/model/##[TYPE=CaConc]"): + capool = moose.element(f"{soma.path}/{el.name}") + catab = moose.Table(f"{data.path}/{capool.name}") + moose.connect(catab, "requestOut", capool, "getCa") + print("Recording", capool.path, ".Ca in", catab.path) + + chanmap = {} + gktabs = [] + for el in moose.wildcardFind( + f"{soma.path}/##[TYPE=HHChannel]" + ) + moose.wildcardFind(f"{soma.path}/##[TYPE=HHChannel2D]"): + chan = moose.element(el) + chanmap[chan.name.split('_')[1]] = chan # for debugging + tab = moose.Table(f"{data.path}/{chan.name}") + moose.connect(tab, "requestOut", chan, "getGk") + gktabs.append(tab) + print("Recording", chan.path, ".Gk in", tab.path) + + if catab is not None: + gktabs.append(catab) + + for ch in soma.children: + if moose.isinstance_(ch, moose.HHChannel): + dump_gate_tables(ch, do_plot=do_plot) + + kca = chanmap['KCa'] + gate = moose.element(f'{kca.path}/gateX') + vtab = np.linspace(gate.xmin, gate.xmax, gate.xdivs) + ctab = np.linspace(gate.ymin, gate.ymax, gate.ydivs) + cplot = [gate.A[-0.65, cc] for cc in ctab] + vplot = [gate.A[vv, 7.55e-5] for vv in vtab] + # fig, axes = plt.subplots(nrows=2) + # axes[0].plot(ctab, cplot, 'x') + # axes[0].set_xlabel('[Ca2+]') + # axes[0].set_ylabel('A') + # axes[1].plot(vtab, vplot, 'x') + # axes[1].set_xlabel('V') + # axes[1].set_ylabel('A') + # plt.show() + simtime = 700e-3 moose.reinit() + # breakpoint() moose.start(simtime) - + t = np.arange(len(vm.vector)) * vm.dt - print('%' * 10, len(vm.vector), len(inj.vector)) - results = np.array([t, vm.vector, inj.vector], dtype=[('time', float), ('Vm', float), ('Im', float)]) - fname = 'Granule_98.npy' - np.save(fname, results) - print(f'Saved results in {fname}') - if not nogui: - import matplotlib.pyplot as plt - fig, axes = plt.subplots(nrows=2, sharex='all') - axes[0].plot(t, vm.vector, label='Vm') - axes[1].plot(t, inj.vector, label='Im') - plt.legend() + print("%" * 10, len(vm.vector), len(inj.vector)) + results = np.block( + [t[:, np.newaxis], vm.vector[:, np.newaxis], inj.vector[:, np.newaxis]] + ) + fname = "Granule_98.dat" + np.savetxt(fname, X=results, header="time Vm Im", delimiter=" ") + print(f"Saved time, Vm, Im, in {fname}") + for tab in gktabs: + fname = f"{tab.name}.dat" + print(f"Saving {tab.name} in {fname}. {tab.vector[:10]}") + data = np.block([t[:, np.newaxis], tab.vector[:, np.newaxis]]) + np.savetxt(fname, X=data, header="time Gk", delimiter=" ") + if do_plot: + fig, axes = plt.subplots(nrows=2, sharex="all") + axes[0].plot(t, vm.vector, label="Vm") + axes[1].plot(t, inj.vector, label="Im") + axes[0].legend() + axes[1].legend() + if catab is not None: + fig, ax = plt.subplots() + fig.suptitle("CaConc") + ax.plot(t, catab.vector) plt.show() - - -if __name__ == '__main__': - if len(sys.argv) < 2: - print(f'Usage: {sys.argv[0]} modeldir') - print('where modeldir contains the neuroML2 model. For example, for GranuleCell model cloned from OpenSourceBrain, this should be `GranuleCell/neuroConstruct/generatedNeuroML2/`') - sys.exit(1) - model_dir = sys.argv[1] - run(model_dir, nogui=False) -# +# # test_granule98.py ends here diff --git a/randnum/CMakeLists.txt b/randnum/CMakeLists.txt deleted file mode 100644 index 633a655acd..0000000000 --- a/randnum/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -cmake_minimum_required(VERSION 3.20) - -add_library(randnum RNG.cpp randnum.cpp) - -add_executable(normal_dist ${CMAKE_CURRENT_SOURCE_DIR}/test_normal_dist.cpp) - -enable_testing() -add_test(NAME cpp_test_normal_dist COMMAND $ ) diff --git a/randnum/meson.build b/randnum/meson.build new file mode 100644 index 0000000000..72b61909cf --- /dev/null +++ b/randnum/meson.build @@ -0,0 +1,7 @@ +# Author: Subhasis Ray +# Date: Sun Jul 7 + +randnum_src = ['RNG.cpp', 'randnum.cpp'] +randnum_lib = static_library('randnum', randnum_src) + + diff --git a/scheduling/CMakeLists.txt b/scheduling/CMakeLists.txt deleted file mode 100644 index a4cf3fc654..0000000000 --- a/scheduling/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -cmake_minimum_required(VERSION 3.20) -include(${CMAKE_CURRENT_SOURCE_DIR}/../CheckCXXCompiler.cmake) -add_library(scheduling Clock.cpp testScheduling.cpp) diff --git a/scheduling/meson.build b/scheduling/meson.build new file mode 100644 index 0000000000..61c979092d --- /dev/null +++ b/scheduling/meson.build @@ -0,0 +1,6 @@ +# Author: Subhasis Ray +# Date: Sun Jul 7 + +scheduling_src = ['Clock.cpp', 'testScheduling.cpp'] +scheduling_lib = static_library('scheduling', scheduling_src) + diff --git a/setup.py b/setup.py deleted file mode 100644 index e680a6ebb4..0000000000 --- a/setup.py +++ /dev/null @@ -1,174 +0,0 @@ -# -*- coding: utf-8 -*- -# This script can also be called directly to build and install the pymoose -# module. -# -# Alternatively, you can use cmake build system which provides finer control -# over the build. This script is called by cmake to install the python module. -# - -__author__ = "Dilawar Singh, HarshaRani, Subhasis Ray" - -__copyright__ = "Copyright 2019-2024, NCBS" -__maintainer__ = "" -__email__ = "" - -import os -import sys -import multiprocessing -import subprocess -import datetime - -try: - cmakeVersion = subprocess.call(["cmake", "--version"], stdout=subprocess.PIPE) -except Exception as e: - print(e) - print("[ERROR] cmake is not found. Please install cmake.") - quit(-1) - -# See https://docs.python.org/3/library/distutils.html -# setuptools is preferred over distutils. And we are supporting python3 only. -from setuptools import setup, Extension, Command -from setuptools.command.build_ext import build_ext -import subprocess - -# Global variables. -sdir_ = os.path.dirname(os.path.realpath(__file__)) - -stamp = datetime.datetime.now().strftime('%Y%m%d') -builddir_ = os.path.join(sdir_, '_temp__build') - -if not os.path.exists(builddir_): - os.makedirs(builddir_) - - -numCores_ = multiprocessing.cpu_count() - -version_ = '4.1.0.dev%s' % stamp - -# importlib is available only for python3. Since we build wheels, prefer .so -# extension. This way a wheel built by any python3.x will work with any python3. - - -class CMakeExtension(Extension): - # Reference: https://martinopilia.com/posts/2018/09/15/building-python-extension.html - def __init__(self, name, **kwargs): - # don't invoke the original build_ext for this special extension - Extension.__init__(self, name, sources=[], **kwargs) - - -class TestCommand(Command): - user_options = [] - - def initialize_options(self): - pass - - def finalize_options(self): - pass - - def run(self): - print("[INFO ] Running tests... ") - os.chdir(builddir_) - self.spawn(["ctest", "--output-on-failure", '-j%d' % numCores_]) - os.chdir(sdir_) - - -class cmake_build_ext(build_ext): - user_options = [ - ('with-boost', None, 'Use Boost Libraries (OFF)'), - ('with-gsl', None, 'Use Gnu Scienfific Library (ON)'), - ('with-gsl-static', None, 'Use GNU Scientific Library (static library) (OFF)'), - ('debug', None, 'Build moose in debugging mode (OFF)'), - ('no-build', None, 'DO NOT BUILD. (for debugging/development)'), - ] + build_ext.user_options - - def initialize_options(self): - # Initialize options. - self.with_boost = 0 - self.with_gsl = 1 - self.with_gsl_static = 0 - self.debug = 0 - self.no_build = 0 - self.cmake_options = {} - # super().initialize_options() - build_ext.initialize_options(self) - - def finalize_options(self): - # Finalize options. - # super().finalize_options() - build_ext.finalize_options(self) - self.cmake_options['PYTHON_EXECUTABLE'] = os.path.realpath(sys.executable) - self.cmake_options['VERSION_MOOSE'] = version_ - if self.with_boost: - self.cmake_options['WITH_BOOST'] = 'ON' - self.cmake_options['WITH_GSL'] = 'OFF' - else: - if self.with_gsl_static: - self.cmake_options['GSL_USE_STATIC_LIBRARIES'] = 'ON' - if self.debug: - self.cmake_options['CMAKE_BUILD_TYPE'] = 'Debug' - else: - self.cmake_options['CMAKE_BUILD_TYPE'] = 'Release' - - def run(self): - if self.no_build: - return - for ext in self.extensions: - self.build_cmake(ext) - # super().run() - build_ext.run(self) - - def build_cmake(self, ext): - global numCores_ - global sdir_ - print("\n==========================================================\n") - print("[INFO ] Building pymoose in %s ..." % builddir_) - cmake_args = [] - for k, v in self.cmake_options.items(): - cmake_args.append('-D%s=%s' % (k, v)) - os.chdir(str(builddir_)) - self.spawn(['cmake', str(sdir_)] + cmake_args) - if not self.dry_run: - self.spawn(['make', '-j%d' % numCores_]) - os.chdir(str(sdir_)) - - -with open(os.path.join(sdir_, "README.md")) as f: - readme = f.read() - -setup( - name="pymoose", - version=version_, - description='Python scripting interface of MOOSE Simulator (https://moose.ncbs.res.in)', - long_description=readme, - long_description_content_type='text/markdown', - author='MOOSERs', - author_email='bhalla@ncbs.res.in', - maintainer='Dilawar Singh', - maintainer_email='', - url='http://moose.ncbs.res.in', - packages=[ - 'rdesigneur', - 'moose', - 'moose.SBML', - 'moose.genesis', - 'moose.neuroml', - 'moose.neuroml2', - 'moose.chemUtil', - 'moose.chemMerge', - ], - package_dir={ - 'rdesigneur': os.path.join(sdir_, 'python', 'rdesigneur'), - 'moose': os.path.join(sdir_, 'python', 'moose'), - }, - package_data={ - 'moose': [ - '_moose.so', - os.path.join('neuroml2', 'schema', 'NeuroMLCoreDimensions.xml'), - os.path.join('chemUtil', 'rainbow2.pkl'), - ] - }, - install_requires=['numpy', 'matplotlib', 'vpython', 'pybind11'], - extra_require={'dev': ['coverage', 'pytest', 'pytest-cov']}, - ext_modules=[CMakeExtension('_moose', optional=True)], - cmdclass={'build_ext': cmake_build_ext, 'test': TestCommand}, -) diff --git a/shell/CMakeLists.txt b/shell/CMakeLists.txt deleted file mode 100644 index e3a6a9af86..0000000000 --- a/shell/CMakeLists.txt +++ /dev/null @@ -1,26 +0,0 @@ -cmake_minimum_required(VERSION 3.20) -include( ${CMAKE_CURRENT_SOURCE_DIR}/../CheckCXXCompiler.cmake) - -if(LIBSBML_FOUND) - add_definitions(-DUSE_SBML) -endif() - -add_library(shell - Shell.cpp - ShellCopy.cpp - ShellThreads.cpp - LoadModels.cpp - SaveModels.cpp - Neutral.cpp - Wildcard.cpp - testShell.cpp - ) - -## version is set by top-level script ../CMakeLists.txt . -#if(NOT MOOSE_VERSION) -# set(MOOSE_VERSION "undefined") -#endif() -# -#set_target_properties(shell -# PROPERTIES COMPILE_FLAGS ${COMPILE_FLAGS} -DMOOSE_VERSION=\"${MOOSE_VERSION}\" -# ) diff --git a/shell/Shell.cpp b/shell/Shell.cpp index b26a0a7ffd..5b80648df1 100644 --- a/shell/Shell.cpp +++ b/shell/Shell.cpp @@ -21,7 +21,9 @@ #include "../msg/OneToOneMsg.h" #include "../msg/OneToAllMsg.h" #include "../msg/SparseMsg.h" +#if !defined(_WIN32) #include "../builtins/SocketStreamer.h" +#endif #include "../builtins/Streamer.h" #include "Shell.h" diff --git a/shell/meson.build b/shell/meson.build new file mode 100644 index 0000000000..18ecfb7745 --- /dev/null +++ b/shell/meson.build @@ -0,0 +1,14 @@ +# Author: Subhasis Ray +# Date: Sun Jul 7 + +shell_src = ['Shell.cpp', + 'ShellCopy.cpp', + 'ShellThreads.cpp', + 'LoadModels.cpp', + 'SaveModels.cpp', + 'Neutral.cpp', + 'Wildcard.cpp', + 'testShell.cpp'] + +shell_lib = static_library('shell', shell_src) + diff --git a/signeur/CMakeLists.txt b/signeur/CMakeLists.txt deleted file mode 100644 index 246c298ca7..0000000000 --- a/signeur/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -cmake_minimum_required(VERSION 3.20) -include( ${CMAKE_CURRENT_SOURCE_DIR}/../CheckCXXCompiler.cmake) -add_library(signeur - Adaptor.cpp - testSigNeur.cpp - ) diff --git a/signeur/meson.build b/signeur/meson.build new file mode 100644 index 0000000000..ccadaa1bea --- /dev/null +++ b/signeur/meson.build @@ -0,0 +1,7 @@ +# Author: Subhasis Ray +# Date: Sun Jul 7 + +signeur_src = ['Adaptor.cpp', 'testSigNeur.cpp'] + +signeur_lib = static_library('signeur', signeur_src) + diff --git a/synapse/CMakeLists.txt b/synapse/CMakeLists.txt deleted file mode 100644 index 8701400a4e..0000000000 --- a/synapse/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -cmake_minimum_required(VERSION 3.20) -include( ${CMAKE_CURRENT_SOURCE_DIR}/../CheckCXXCompiler.cmake) - -set( SYNAPSE_SRCS - GraupnerBrunel2012CaPlasticitySynHandler.cpp - RollingMatrix.cpp - SeqSynHandler.cpp - SimpleSynHandler.cpp - STDPSynapse.cpp - STDPSynHandler.cpp - Synapse.cpp - SynHandlerBase.cpp - testSynapse.cpp - ) - -add_library(synapse ${SYNAPSE_SRCS} ) diff --git a/synapse/meson.build b/synapse/meson.build new file mode 100644 index 0000000000..518597aeee --- /dev/null +++ b/synapse/meson.build @@ -0,0 +1,15 @@ +# Author: Subhasis Ray +# Date: Sun Jul 7 + +synapse_src = ['GraupnerBrunel2012CaPlasticitySynHandler.cpp', + 'RollingMatrix.cpp', + 'SeqSynHandler.cpp', + 'SimpleSynHandler.cpp', + 'STDPSynapse.cpp', + 'STDPSynHandler.cpp', + 'Synapse.cpp', + 'SynHandlerBase.cpp', + 'testSynapse.cpp'] + +synapse_lib = static_library('synapse', synapse_src) + diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt deleted file mode 100644 index 89b12f444c..0000000000 --- a/tests/CMakeLists.txt +++ /dev/null @@ -1,114 +0,0 @@ -set(CTEST_NIGHTLY_START_TIME "05:30:00 UTC") -set(CTEST_SUBMIT_URL "http://my.cdash.org/submit.php?project=moose") - -if(DEBUG OR "${CMAKE_BUILD_TYPE}" STREQUAL "Debug") - # Run this test in debug mode. In Release mode, this does not do anything. - add_test(NAME moose.bin-raw-run COMMAND $ -u -q) -endif() - -# Core tests. -set(PYMOOSE_TEST_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/core) -file(GLOB PY_TEST_SCRIPTS "${PYMOOSE_TEST_DIRECTORY}/test_*.py" ) -foreach(_test_script ${PY_TEST_SCRIPTS} ) - get_filename_component(_name_we ${_test_script} NAME_WE) - set(_test_name "core_${_name_we}") - add_test(NAME ${_test_name} - COMMAND ${PYTHON_EXECUTABLE} ${_test_script} - WORKING_DIRECTORY ${PYMOOSE_TEST_DIRECTORY}) - set_tests_properties(${_test_name} - PROPERTIES ENVIRONMENT "PYTHONPATH=${CMAKE_BINARY_DIR}/python" - ) -endforeach() - -# Tests for supported formats such as neuroml, sbml etc. -set(SUPPORT_TEST_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/support) -file(GLOB PY_TEST_SCRIPTS "${SUPPORT_TEST_DIRECTORY}/test_*.py" ) -foreach(_test_script ${PY_TEST_SCRIPTS} ) - get_filename_component(_name_we ${_test_script} NAME_WE) - set(_test_name "support_${_name_we}") - add_test(NAME ${_test_name} - COMMAND ${PYTHON_EXECUTABLE} ${_test_script} - WORKING_DIRECTORY ${SUPPORT_TEST_DIRECTORY}) - set_tests_properties(${_test_name} - PROPERTIES ENVIRONMENT "PYTHONPATH=${CMAKE_BINARY_DIR}/python" - ) -endforeach() - -# rdesigneur tests. These tests require matplotlib. -set(RDES_TEST_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/rdesigneur) -file(GLOB RDES_TEST_SCRIPTS "${RDES_TEST_DIRECTORY}/test_*.py" ) -foreach(_test_script ${RDES_TEST_SCRIPTS}) - get_filename_component(_name_we ${_test_script} NAME_WE) - set(_test_name "rdes_${_name_we}") - add_test(NAME ${_test_name} - COMMAND ${PYTHON_EXECUTABLE} ${_test_script} - WORKING_DIRECTORY ${RDES_TEST_DIRECTORY} - ) - set_tests_properties(${_test_name} PROPERTIES - ENVIRONMENT "PYTHONPATH=${CMAKE_BINARY_DIR}/python;MOOSE_NUM_THREADS=4" - ) -endforeach() - -# FIXME TESTS. These should not run by default. We need to fix them. -set(PYMOOSE_FIXME_TEST_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/devel/fixme) -file(GLOB PY_FIXME_TEST_SCRIPTS "${PYMOOSE_FIXME_TEST_DIRECTORY}/*.py" ) -foreach( _test_script ${PY_FIXME_TEST_SCRIPTS} ) - get_filename_component( _name_we ${_test_script} NAME_WE) - set(_test_name "alpha_${_name_we}") - add_test( NAME ${_test_name} - COMMAND ${PYTHON_EXECUTABLE} ${_test_script} - CONFIGURATIONS alpha - WORKING_DIRECTORY ${PYMOOSE_ALPHA_TEST_DIRECTORY} - ) - set_tests_properties( ${_test_name} - PROPERTIES ENVIRONMENT "PYTHONPATH=${CMAKE_BINARY_DIR}/python" - ) -endforeach( ) - -# Regression and github issues. These should not run by default. -set(PYMOOSE_ISSUES_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/devel/issues) -file(GLOB PY_ISSUES_SCRIPTS "${PYMOOSE_ISSUES_DIRECTORY}/*.py" ) -foreach(_test_script ${PY_ISSUES_SCRIPTS}) - get_filename_component(_file_name ${_test_script} NAME_WE) - set(_test_name "issue_${_file_name}") - add_test(NAME ${_test_name} - COMMAND ${PYTHON_EXECUTABLE} ${_test_script} - CONFIGURATIONS Devel - WORKING_DIRECTORY ${PYMOOSE_ISSUES_DIRECTORY} - ) - set_tests_properties(${_test_name} - PROPERTIES ENVIRONMENT "PYTHONPATH=${CMAKE_BINARY_DIR}/python" - ) -endforeach() - -################################# COVERAGE ################################### - -add_custom_target(coverage) -set(PYTEST_TEST_DIRECTORY ${CMAKE_SOURCE_DIR}/tests) -file(GLOB_RECURSE PYTEST_TEST_SCRIPTS ${PYTEST_TEST_DIRECTORY}/test_*.py) - -foreach(_test_script ${PYTEST_TEST_SCRIPTS}) - file(MD5 ${_test_script} _test_hash) - set(_test_name "coverage_${_test_hash}") - # message(STATUS "Adding test ${_test_name} ${_test_script}") - add_custom_target(${_test_name} - # We collect coverage data but do not show report during each test. - # We show report at the end of all tests. Set `--cov-report=` - COMMAND ${PYTHON_EXECUTABLE} -m pytest - --cov=moose --cov=rdesigneur --cov-append --cov-report= - ${_test_script} - DEPENDS _moose - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - COMMENT "Executing ${_test_script} using pytest" - VERBATIM) - add_dependencies(coverage ${_test_name}) -endforeach() - -# Generate report at the end. -add_custom_command(TARGET coverage POST_BUILD - COMMAND ${PYTHON_EXECUTABLE} -m coverage report - COMMAND ${PYTHON_EXECUTABLE} -m coverage html - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - COMMENT "Genearting coverage report" - VERBATIM) - diff --git a/utility/CMakeLists.txt b/utility/CMakeLists.txt deleted file mode 100644 index 6f55e6da1d..0000000000 --- a/utility/CMakeLists.txt +++ /dev/null @@ -1,31 +0,0 @@ -cmake_minimum_required(VERSION 3.20) -include( ${CMAKE_CURRENT_SOURCE_DIR}/../CheckCXXCompiler.cmake) - -add_library(utility - strutil.cpp - types.cpp - setupenv.cpp - numutil.cpp - Annotator.cpp - Vec.cpp - cnpy.cpp - fileutils.cpp - utility.cpp - ) -target_link_libraries(utility PRIVATE fmt) - -add_executable(test_cnpy test_cnpy.cpp) - -target_link_libraries(test_cnpy utility) - -set(TEST_SCRIPT ${CMAKE_BINARY_DIR}/test_cnpy.py) -file(WRITE ${TEST_SCRIPT} "import numpy as np") - -enable_testing() -add_test(NAME cpp_test_cnpy COMMAND $) - -add_executable(test_util test_util.cpp) -target_link_libraries(test_util utility) - -enable_testing() -add_test(NAME cpp_test_util COMMAND $) diff --git a/utility/cnpy.cpp b/utility/cnpy.cpp index 05fea0a385..a1bd33eb6f 100644 --- a/utility/cnpy.cpp +++ b/utility/cnpy.cpp @@ -79,24 +79,22 @@ string shapeToString(const vector& shape) * * @return true if file is sane, else false. */ -bool isValidNumpyFile( FILE* fp ) +bool isValidNumpyFile(string npy_file) { - assert( fp ); - char buffer[__pre__.size()]; - size_t nr = fread( buffer, sizeof(char), __pre__.size(), fp ); - - if( 0 == nr ) - return false; - - bool equal = true; - // Check for equality - for(size_t i = 0; i < __pre__.size(); i++ ) - if( buffer[i] != __pre__[i] ) - { - equal = false; - break; - } - return equal; + char c; + istream_iterator istream_iterator; + ifstream file(npy_file); + for(auto ¤t : __pre__) + { + file.get(c); + if((c != current) || (c == EOF)) + { + file.close(); + return false; + } + } + file.close(); + return true; } /** diff --git a/utility/fileutils.cpp b/utility/fileutils.cpp deleted file mode 100644 index 221eb165cb..0000000000 --- a/utility/fileutils.cpp +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Description: Filesystem related utilities. - * - * Author: Dilawar Singh (), dilawars@ncbs.res.in - * Organization: NCBS Bangalore - */ - -#include -#include -#include -#include -#include - -using namespace std; - -#include "utility.h" - -namespace moose { - -bool filepath_exists( const string& path ) -{ - struct stat buffer; - return (stat (path.c_str(), &buffer) == 0); -} - -} //namespace moose. diff --git a/utility/meson.build b/utility/meson.build new file mode 100644 index 0000000000..6f05015b94 --- /dev/null +++ b/utility/meson.build @@ -0,0 +1,14 @@ +# Author: Subhasis Ray +# Date: Sun Jul 7 + +utility_src = ['strutil.cpp', + 'types.cpp', + 'setupenv.cpp', + 'numutil.cpp', + 'Annotator.cpp', + 'Vec.cpp', + 'utility.cpp', + 'cnpy.cpp' + ] + +utility_lib = static_library('utility', utility_src) diff --git a/utility/print_function.hpp b/utility/print_function.hpp index 761009616e..02ed8536e5 100644 --- a/utility/print_function.hpp +++ b/utility/print_function.hpp @@ -192,7 +192,7 @@ namespace moose { { if('`' == msg[i]) { - if(!set and reset) + if(!set && reset) { set = true; reset = false; diff --git a/utility/strutil.cpp b/utility/strutil.cpp index f1553d25e1..4c1310d7d2 100644 --- a/utility/strutil.cpp +++ b/utility/strutil.cpp @@ -7,7 +7,6 @@ ********************************************************************/ #include -#include #include #include #include diff --git a/utility/testing_macros.hpp b/utility/testing_macros.hpp index 1ac401113c..1c097dea68 100644 --- a/utility/testing_macros.hpp +++ b/utility/testing_macros.hpp @@ -31,10 +31,12 @@ using namespace std; -inline bool doubleEq(double a, double b) -{ - return std::fabs(a-b) < 1e-7; -} +extern bool doubleEq(double x, double y); // defined in basecode/doubleEq.cpp + +// inline bool doubleEq(double a, double b) +// { +// return std::fabs(a-b) < 1e-7; +// } static ostringstream assertStream; diff --git a/utility/utility.cpp b/utility/utility.cpp index 9ad258071e..21350b086f 100644 --- a/utility/utility.cpp +++ b/utility/utility.cpp @@ -4,6 +4,7 @@ * Created: 2020-02-23 * Author: Dilawar Singh + * * Organization: NCBS Bangalore * License: MIT License */ @@ -27,5 +28,4 @@ namespace moose { } assert(max == 0); } - } // namespace moose diff --git a/utility/utility.h b/utility/utility.h index 86a0aad4c1..1e8efb0012 100644 --- a/utility/utility.h +++ b/utility/utility.h @@ -5,11 +5,12 @@ // Copyright (C) 2010 Subhasis Ray, all rights reserved. // Created: Wed Mar 23 10:25:58 2011 (+0530) // Version: -// Last-Updated: Tue Jul 23 12:48:17 2013 (+0530) -// By: subha -// Update #: 19 +// Last-Updated: Sun Sep 1 00:03:10 2024 (+0530) +// By: Subhasis Ray +// Update #: 25 #ifndef _UTILITY_H +#define _UTILITY_H #include #include @@ -34,8 +35,8 @@ namespace moose string getEnv(const string& env); int getEnvInt(const string& env, const int defaultVal=1); - // In fileutils.cpp - bool filepath_exists( const string& path ); + // In fileutils.cpp - 2024-07-17 removing this one liner used only once: subha + // bool filepath_exists( const string& path ); /** * @brief Givem path of MOOSE element, return its name. It's behaviour is