From 7a53df9d5090760be98663f62a89e0697f60654b Mon Sep 17 00:00:00 2001 From: Luohao Wang Date: Fri, 30 Jan 2026 12:11:23 +0800 Subject: [PATCH 01/14] [CI] Set up C++20 modules toolchain and CI workflow - Configure Ninja generator for C++ module builds - Add gcc-15/llvm-21 toolchains in CI - Stabilize CI dependencies and pin CMake 4.0.2 - Update CMake gates for version 4.2 - Harden CI gcc-15 installation and module links - Fix header file set install for interface targets - Build libc++ modules on macOS when missing - Align CI toolchain and CMake installs - Make std-module patch resilient and non-fatal Co-Authored-By: Claude Sonnet 4.5 --- .github/workflows/Build.yml | 249 +++++++++++++++++++++++++++-- CMakeLists.txt | 32 ++-- examples/CMakeLists.txt | 7 +- external/CMakeLists.txt | 40 ++--- scripts/update_copyright.sh | 2 +- src/CMakeLists.txt | 23 ++- test/CMakeLists.txt | 2 +- test/Core/CMakeLists.txt | 2 +- test/DataStructures/CMakeLists.txt | 2 +- test/Utils/CMakeLists.txt | 2 +- 10 files changed, 299 insertions(+), 62 deletions(-) diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index c7ee362f..b4ec5704 100644 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -23,15 +23,20 @@ on: - '.github/workflows/Build.yml' jobs: generate: - name: MPI${{ matrix.mpi }}/${{ matrix.mode }} - runs-on: ubuntu-24.04 - container: - image: luohaothu/gcc-trunk:latest + name: ${{ matrix.os }}/${{ matrix.compiler }}/MPI${{ matrix.mpi }}/${{ matrix.mode }} + runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: + os: [ubuntu-24.04, macos-15] + compiler: [clang, gcc] mpi: [ON, OFF] mode: [Debug, Release] + # exclude : + # - os: macos-12 + # compiler: clang + # mpi: ON + # mode: Release # clang tends to emit illegal inst for macOS with MPI on release mode (-O3) if: "!contains(github.event.head_commit.message, 'skip build')" steps: - name: Checkout @@ -39,30 +44,240 @@ jobs: with: submodules: recursive fetch-depth: 0 + - name: Install dependence + run: | + export INPUT_MPI=${{ matrix.mpi }} + if [ "$RUNNER_OS" == "Linux" ]; then + sudo apt update + sudo apt install -y python3-pip python3-sphinx lcov libboost-all-dev doxygen libtbb-dev libopenmpi-dev ninja-build + if [ "$INPUT_MPI" == "ON" ]; then + sudo apt install -y libhdf5-mpi-dev + else + sudo apt install -y libhdf5-dev + fi + echo "DOXYGEN_DIR=/usr/bin" >> "$GITHUB_ENV" + echo "TBB_DIR=/usr/lib/x86_64-linux-gnu/cmake/TBB" >> "$GITHUB_ENV" + elif [ "$RUNNER_OS" == "macOS" ]; then + # Ensure Homebrew is available (macOS: /opt/homebrew or in PATH). + if command -v brew >/dev/null 2>&1; then + eval "$(brew shellenv)" + elif [ -x "/opt/homebrew/bin/brew" ]; then + eval "$(/opt/homebrew/bin/brew shellenv)" + else + echo "Homebrew not found" + exit 1 + fi + echo "$(brew --prefix)/bin" >> "$GITHUB_PATH" + brew install doxygen tbb lcov boost open-mpi ninja sphinx-doc + echo "$(brew --prefix sphinx-doc)/bin" >> "$GITHUB_PATH" + if [ "$INPUT_MPI" == "ON" ]; then + brew install hdf5-mpi + else + brew install hdf5 + fi + echo "DOXYGEN_DIR=$(brew --prefix doxygen)/bin" >> "$GITHUB_ENV" + echo "TBB_DIR=$(brew --prefix tbb)/lib/cmake/TBB" >> "$GITHUB_ENV" + else + echo "$RUNNER_OS not supported" + exit 1 + fi + + - name: Install CMake + run: | + if [ "$RUNNER_OS" == "Linux" ]; then + USER_BASE=$(python3 -m site --user-base) + echo "$USER_BASE/bin" >> "$GITHUB_PATH" + python3 -m pip install --user --upgrade "cmake==4.0.2" + elif [ "$RUNNER_OS" == "macOS" ]; then + brew install cmake + else + echo "$RUNNER_OS not supported" + exit 1 + fi + + - name: Install toolchain + run: | + if [ "$RUNNER_OS" == "Linux" ]; then + if [ "${{ matrix.compiler }}" == "gcc" ]; then + sudo apt update + sudo apt install -y software-properties-common + sudo add-apt-repository -y ppa:ubuntu-toolchain-r/ppa + sudo apt update + if sudo apt install -y gcc-15 g++-15; then + echo "CC=gcc-15" >> "$GITHUB_ENV" + echo "CXX=g++-15" >> "$GITHUB_ENV" + else + if ! command -v brew >/dev/null 2>&1; then + /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" + fi + eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" + brew install gcc@15 binutils + GCC_HOME=$(brew --prefix gcc@15) + echo "CC=$GCC_HOME/bin/gcc-15" >> "$GITHUB_ENV" + echo "CXX=$GCC_HOME/bin/g++-15" >> "$GITHUB_ENV" + echo "$GCC_HOME/bin" >> "$GITHUB_PATH" + echo "$(brew --prefix binutils)/bin" >> "$GITHUB_PATH" + fi + else + wget -q https://apt.llvm.org/llvm.sh + chmod +x llvm.sh + sudo ./llvm.sh 21 + sudo apt install -y clang-21 llvm-21 lld-21 lldb-21 libomp-21-dev libc++-21-dev libc++abi-21-dev + libcxx_module_path=$(dpkg -L libc++-21-dev | grep -m1 '/std.cppm$' || true) + if [ -n "$libcxx_module_path" ]; then + libcxx_module_dir=$(dirname "$libcxx_module_path") + sudo mkdir -p /lib/share/libc++ + sudo ln -sfn "$libcxx_module_dir" /lib/share/libc++/v1 + fi + libcxx_inc_path=$(dpkg -L libc++-21-dev | grep -m1 'std/algorithm.inc$' || true) + if [ -n "$libcxx_inc_path" ]; then + libcxx_inc_root=$(dirname "$(dirname "$libcxx_inc_path")") + CXXFLAGS="-stdlib=libc++ -isystem $libcxx_inc_root -Wno-thread-safety -Wno-error=thread-safety-analysis" + else + CXXFLAGS="-stdlib=libc++ -isystem /usr/include/c++/v1 -isystem /usr/lib/llvm-21/include/c++/v1 -Wno-thread-safety -Wno-error=thread-safety-analysis" + fi + echo "CC=clang-21" >> "$GITHUB_ENV" + echo "CXX=clang++-21" >> "$GITHUB_ENV" + echo "CXXFLAGS=$CXXFLAGS" >> "$GITHUB_ENV" + echo "LDFLAGS=-stdlib=libc++" >> "$GITHUB_ENV" + fi + elif [ "$RUNNER_OS" == "macOS" ]; then + if [ "${{ matrix.compiler }}" == "gcc" ]; then + brew install gcc@15 + GCC_HOME=$(brew --prefix gcc@15) + echo "CC=$GCC_HOME/bin/gcc-15" >> "$GITHUB_ENV" + echo "CXX=$GCC_HOME/bin/g++-15" >> "$GITHUB_ENV" + echo "$GCC_HOME/bin" >> "$GITHUB_PATH" + else + brew install llvm@21 + LLVM_HOME=$(brew --prefix llvm@21) + SDKROOT=$(xcrun --show-sdk-path || true) + echo "CC=$LLVM_HOME/bin/clang" >> "$GITHUB_ENV" + echo "CXX=$LLVM_HOME/bin/clang++" >> "$GITHUB_ENV" + echo "$LLVM_HOME/bin" >> "$GITHUB_PATH" + if [ -n "$SDKROOT" ]; then + echo "SDKROOT=$SDKROOT" >> "$GITHUB_ENV" + echo "CFLAGS=-isysroot $SDKROOT" >> "$GITHUB_ENV" + echo "CXXFLAGS=-stdlib=libc++ -isystem $LLVM_HOME/include/c++/v1 -isysroot $SDKROOT -Wno-thread-safety -Wno-error=thread-safety-analysis" >> "$GITHUB_ENV" + echo "LDFLAGS=-stdlib=libc++ -L$LLVM_HOME/lib -Wl,-rpath,$LLVM_HOME/lib -Wl,-syslibroot,$SDKROOT" >> "$GITHUB_ENV" + else + echo "CXXFLAGS=-stdlib=libc++ -isystem $LLVM_HOME/include/c++/v1 -Wno-thread-safety -Wno-error=thread-safety-analysis" >> "$GITHUB_ENV" + echo "LDFLAGS=-stdlib=libc++ -L$LLVM_HOME/lib -Wl,-rpath,$LLVM_HOME/lib" >> "$GITHUB_ENV" + fi + modules_json="$LLVM_HOME/share/libc++/v1/libc++.modules.json" + if [ ! -f "$modules_json" ]; then + modules_json=$(find "$LLVM_HOME" -name libc++.modules.json -print -quit || true) + fi + if [ -z "$modules_json" ]; then + SDKROOT=$(xcrun --show-sdk-path || true) + if [ -n "$SDKROOT" ]; then + sdk_modules_json="$SDKROOT/usr/share/libc++/v1/libc++.modules.json" + if [ -f "$sdk_modules_json" ]; then + modules_json="$sdk_modules_json" + else + modules_json=$(find "$SDKROOT" -name libc++.modules.json -print -quit || true) + fi + fi + fi + if [ -z "$modules_json" ]; then + clt_modules_json="/Library/Developer/CommandLineTools/usr/share/libc++/v1/libc++.modules.json" + if [ -f "$clt_modules_json" ]; then + modules_json="$clt_modules_json" + fi + fi + if [ -z "$modules_json" ]; then + CLANG_RESOURCE_DIR="$("$LLVM_HOME/bin/clang" -print-resource-dir 2>/dev/null || true)" + if [ -n "$CLANG_RESOURCE_DIR" ]; then + clang_modules_json="$CLANG_RESOURCE_DIR/share/libc++/v1/libc++.modules.json" + if [ -f "$clang_modules_json" ]; then + modules_json="$clang_modules_json" + else + modules_json=$(find "$CLANG_RESOURCE_DIR" -name libc++.modules.json -print -quit || true) + fi + fi + fi + if [ -z "$modules_json" ]; then + LLVM_SRC_DIR="$RUNNER_TEMP/llvm-project" + LLVM_BUILD_DIR="$RUNNER_TEMP/llvm-project-build" + git clone --depth 1 --branch release/21.x https://github.com/llvm/llvm-project.git "$LLVM_SRC_DIR" + cmake -G Ninja -S "$LLVM_SRC_DIR/runtimes" -B "$LLVM_BUILD_DIR" \ + -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi;libunwind" \ + -DLIBCXX_INSTALL_MODULES=ON \ + -DLIBCXX_INSTALL_MODULE_DIR="share/libc++/v1" \ + -DCMAKE_INSTALL_PREFIX="$LLVM_HOME" \ + -DCMAKE_C_COMPILER="$LLVM_HOME/bin/clang" \ + -DCMAKE_CXX_COMPILER="$LLVM_HOME/bin/clang++" \ + -DCMAKE_BUILD_TYPE=Release + cmake --build "$LLVM_BUILD_DIR" --target install --parallel 2 + modules_json=$(find "$LLVM_HOME" -name libc++.modules.json -print -quit || true) + fi + if [ -n "$modules_json" ] && [ ! -f "$modules_json" ]; then + modules_json="" + fi + if [ -n "$modules_json" ]; then + echo "CMAKE_CXX_STDLIB_MODULES_JSON=$modules_json" >> "$GITHUB_ENV" + fi + fi + else + echo "$RUNNER_OS not supported" + exit 1 + fi + - name: Set parallelism + run: | + if [ "$RUNNER_OS" == "Linux" ]; then + echo "NPROC=$(nproc)" >> "$GITHUB_ENV" + else + echo "NPROC=$(sysctl -n hw.ncpu)" >> "$GITHUB_ENV" + fi - name: Make directory run: mkdir -p build - name: Generate working-directory: ./build run: | - wget https://github.com/Kitware/CMake/releases/download/v4.0.2/cmake-4.0.2-linux-x86_64.sh - chmod +x cmake-4.0.2-linux-x86_64.sh - mkdir -p cmake - ./cmake-4.0.2-linux-x86_64.sh --skip-license --prefix=$(pwd)/cmake - apt update && apt install -y ninja-build libhdf5-dev libhdf5-openmpi-dev libboost-all-dev python3-pip python3-sphinx doxygen - export PATH=$(pwd)/cmake/bin:$PATH - cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -G Ninja -B build \ - -DCMAKE_INSTALL_PREFIX=$(pwd)/install -DOPFLOW_BUILD_ALL=ON -DOPFLOW_ENABLE_MODULE=ON \ - -DCMAKE_BUILD_TYPE=${{ matrix.mode }} -DOPFLOW_WITH_HDF5=ON -DOPFLOW_WITH_MPI=${{ matrix.mpi }} + CMAKE_STDLIB_JSON_ARG="" + if [ -n "$CMAKE_CXX_STDLIB_MODULES_JSON" ]; then + CMAKE_STDLIB_JSON_ARG="-DCMAKE_CXX_STDLIB_MODULES_JSON=$CMAKE_CXX_STDLIB_MODULES_JSON" + fi + OPFLOW_ENABLE_MODULE=ON + if [ "${{ matrix.compiler }}" = "gcc" ]; then + OPFLOW_ENABLE_MODULE=OFF + fi + cmake \ + -G Ninja \ + -DCMAKE_BUILD_TYPE="${{ matrix.mode }}" \ + -DCMAKE_C_COMPILER="${CC}" \ + -DCMAKE_CXX_COMPILER="${CXX}" \ + -DCMAKE_CXX_FLAGS="${CXXFLAGS}" \ + -DCMAKE_EXE_LINKER_FLAGS="${LDFLAGS}" \ + ${CMAKE_STDLIB_JSON_ARG} \ + -DOPFLOW_WITH_HDF5=ON \ + -DBENCHMARK_ENABLE_TESTING=OFF \ + -DBENCHMARK_ENABLE_WERROR=OFF \ + -DOPFLOW_BUILD_ALL=ON \ + -DOPFLOW_INSTALL=OFF \ + -DOPFLOW_WITH_VTK=OFF \ + -DOPFLOW_TBB_EXTERNAL=ON \ + -DDOXYGEN_DIR="${DOXYGEN_DIR}" \ + -DTBB_DIR="${TBB_DIR}" \ + -DOPFLOW_ENABLE_MODULE="${OPFLOW_ENABLE_MODULE}" \ + -DOPFLOW_WITH_MPI=${{ matrix.mpi }} \ + .. || { + echo "==== CMakeFiles/CMakeError.log ====" + cat CMakeFiles/CMakeError.log || true + echo "==== CMakeFiles/CMakeOutput.log ====" + cat CMakeFiles/CMakeOutput.log || true + exit 1 + } if [ "$RUNNER_OS" == "Linux" ]; then - cmake --build build -t All_CI --parallel $(nproc) --config ${{ matrix.mode }} + cmake --build . -t All_CI --parallel "${NPROC}" --config ${{ matrix.mode }} else - cmake --build build -t All_CI --parallel $(nproc) --config ${{ matrix.mode }} + cmake --build . -t All_CI --parallel "${NPROC}" --config ${{ matrix.mode }} fi - name: Test working-directory: ./build run: | if [ "$RUNNER_OS" == "Linux" ]; then - ctest --parallel $(nproc) -C ${{ matrix.mode }} -VV + ctest --parallel "${NPROC}" -C ${{ matrix.mode }} -VV else - ctest --parallel $(nproc) -C ${{ matrix.mode }} -VV + ctest --parallel "${NPROC}" -C ${{ matrix.mode }} -VV fi diff --git a/CMakeLists.txt b/CMakeLists.txt index 31ea2476..cb3e5970 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ # ---------------------------------------------------------------------------- # -# Copyright (c) 2019 - 2025 by the OpFlow developers +# Copyright (c) 2019 - 2026 by the OpFlow developers # # This file is part of OpFlow. # @@ -15,13 +15,18 @@ # ---------------------------------------------------------------------------- cmake_minimum_required(VERSION 4.0.2 FATAL_ERROR) -# The specific value used for CMake==4.0.2 -set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD - # This specific value changes as experimental support evolves. See - # `Help/dev/experimental.rst` in the CMake source corresponding to - # your CMake build for the exact value to use. - "a9e1cf81-9932-4810-974b-6eccaf14e457") -set(CMAKE_EXPERIMENTAL_EXPORT_BUILD_DATABASE 4bd552e2-b7fb-429a-ab23-c83ef53f3f13) +# The specific values used for experimental CMake features. +if(CMAKE_VERSION VERSION_GREATER_EQUAL "4.2") + set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "d0edc3af-4c50-42ea-a356-e2862fe7a444") + set(CMAKE_EXPERIMENTAL_EXPORT_BUILD_DATABASE "73194a1d-c0b5-41b9-9190-a4512925e192") +else() + set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD + # This specific value changes as experimental support evolves. See + # `Help/dev/experimental.rst` in the CMake source corresponding to + # your CMake build for the exact value to use. + "a9e1cf81-9932-4810-974b-6eccaf14e457") + set(CMAKE_EXPERIMENTAL_EXPORT_BUILD_DATABASE 4bd552e2-b7fb-429a-ab23-c83ef53f3f13) +endif() set(CMAKE_EXPORT_BUILD_DATABASE 1) # ---------------------------------------------------------------------------- @@ -41,9 +46,6 @@ project(opflow VERSION ${OPFLOW_VERSION} LANGUAGES C CXX) set(OPFLOW_VERSION_STRING "${OPFLOW_VERSION} - ${SHORT_SHA1} - ${GIT_CHANGE}") message(STATUS "Build opflow: ${OPFLOW_VERSION_STRING}") -set(CMAKE_EXPERIMENTAL_EXPORT_BUILD_DATABASE 4bd552e2-b7fb-429a-ab23-c83ef53f3f13) -set(CMAKE_EXPORT_BUILD_DATABASE 1) - set(CMAKE_CXX_MODULE_STD 1) include(GNUInstallDirs) @@ -108,6 +110,9 @@ option(OPFLOW_SINGLE_PRECISION "Use float as default real type" OFF) option(OPFLOW_WITH_OPENMP "Build OpFlow with OpenMP support" ON) option(OPFLOW_WITH_MPI "Build OpFlow with MPI support" OFF) +# Disable deprecated MPI C++ bindings across all targets to avoid link errors. +add_compile_definitions(OMPI_SKIP_MPICXX MPICH_SKIP_MPICXX) + # utility options option(OPFLOW_WITH_HDF5 "Build OpFlow with HDF5 support" OFF) @@ -129,6 +134,11 @@ option(OPFLOW_SANITIZE_UB "Enable undefined behavior sanitizer in tests" OFF) option(OPFLOW_BUILD_WARNINGS "Enable compiler warnings" OFF) option(OPFLOW_NO_EXCEPTIONS "Compile with -fno-exceptions" OFF) option(OPFLOW_ENABLE_MODULE "Enable C++ modules support" OFF) +if(OPFLOW_ENABLE_MODULE) + set(OPFLOW_TARGET_SCOPE PUBLIC) +else() + set(OPFLOW_TARGET_SCOPE INTERFACE) +endif() # install options option(OPFLOW_INSTALL "Generate the install target" ${PROJECT_IS_TOP_LEVEL}) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index d6d59596..eea91d1d 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -18,7 +18,10 @@ elseif (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") string(APPEND OPFLOW_EXAMPLE_CXX_FLAGS_RELEASE "/O2 /DNDEBUG") string(APPEND OPFLOW_EXAMPLE_CXX_FLAGS_RELWITHDEBINFO "${OPFLOW_EXAMPLE_CXX_FLAGS_RELEASE} /Od") elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") - string(APPEND OPFLOW_EXAMPLE_CXX_FLAGS "-mfma -Wno-narrowing -Wno-deprecated-anon-enum-enum-conversion") +string(APPEND OPFLOW_EXAMPLE_CXX_FLAGS " -Wno-narrowing -Wno-deprecated-anon-enum-enum-conversion") +if (CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|amd64|AMD64|i[3-6]86") + string(APPEND OPFLOW_EXAMPLE_CXX_FLAGS " -mfma") +endif () string(APPEND OPFLOW_EXAMPLE_CXX_FLAGS_DEBUG "${OPFLOW_EXAMPLE_CXX_FLAGS} -O0 -g") string(APPEND OPFLOW_EXAMPLE_CXX_FLAGS_RELEASE "${OPFLOW_EXAMPLE_CXX_FLAGS} -O3 -fopenmp-simd -DNDEBUG") endif () @@ -54,4 +57,4 @@ add_subdirectory(TaylorGreen) add_subdirectory(AMR) add_subdirectory(LevelSet) -add_dependencies(All_CI AllExamples) \ No newline at end of file +add_dependencies(All_CI AllExamples) diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index 6aa09b1d..1f539548 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -11,7 +11,7 @@ if(OPFLOW_INSTALL) else() add_subdirectory(${CMAKE_SOURCE_DIR}/external/spdlog EXCLUDE_FROM_ALL) endif() -target_link_libraries(opflow PUBLIC spdlog::spdlog) +target_link_libraries(opflow ${OPFLOW_TARGET_SCOPE} spdlog::spdlog) # Use AMGCL if(OPFLOW_INSTALL) @@ -21,7 +21,7 @@ if(OPFLOW_INSTALL) else() add_subdirectory(${CMAKE_SOURCE_DIR}/external/amgcl EXCLUDE_FROM_ALL) endif() -target_link_libraries(opflow PUBLIC amgcl::amgcl) +target_link_libraries(opflow ${OPFLOW_TARGET_SCOPE} amgcl::amgcl) # Use TBB if(OPFLOW_TBB_EXTERNAL) @@ -42,7 +42,7 @@ else() find_package(tbb NAMES tbb TBB REQUIRED) endif() endif() -target_link_libraries(opflow PUBLIC TBB::tbb) +target_link_libraries(opflow ${OPFLOW_TARGET_SCOPE} TBB::tbb) # Use HYPRE package if(OPFLOW_HYPRE_EXTERNAL) @@ -52,7 +52,7 @@ if(OPFLOW_HYPRE_EXTERNAL) # Use external HYPRE find_package(HYPRE REQUIRED PATHS ${HYPRE_DIR} NO_DEFAULT_PATH) # Here we hard link to the found HYPRE to avoid find again at client - target_link_libraries(opflow PUBLIC HYPRE) + target_link_libraries(opflow ${OPFLOW_TARGET_SCOPE} HYPRE) else() # Use bundled HYPRE if(OPFLOW_INSTALL) @@ -60,58 +60,58 @@ else() CONFIG_AND_INSTALL_HYPRE() find_package(HYPRE REQUIRED PATHS ${CMAKE_INSTALL_PREFIX} NO_DEFAULT_PATH) # HYPRE::HYPRE is only exported on install - target_link_libraries(opflow PUBLIC HYPRE::HYPRE) + target_link_libraries(opflow ${OPFLOW_TARGET_SCOPE} HYPRE::HYPRE) else() set(HYPRE_BUILD_TYPE Debug) set(HYPRE_WITH_OPENMP ${OPFLOW_WITH_OPENMP}) set(HYPRE_ENABLE_SINGLE ${OPFLOW_SINGLE_PRECISION}) set(HYPRE_WITH_MPI ${OPFLOW_WITH_MPI}) add_subdirectory(${CMAKE_SOURCE_DIR}/external/hypre/src EXCLUDE_FROM_ALL) - target_link_libraries(opflow PUBLIC HYPRE) + target_link_libraries(opflow ${OPFLOW_TARGET_SCOPE} HYPRE) endif() endif() # Use VTK package if(OPFLOW_WITH_VTK) - target_compile_definitions(opflow PUBLIC OPFLOW_WITH_VTK) + target_compile_definitions(opflow ${OPFLOW_TARGET_SCOPE} OPFLOW_WITH_VTK) if(OPFLOW_VTK_EXTERNAL) if(NOT TARGET VTK) if(NOT DEFINED VTK_DIR) message(FATAL "Variable VTK_DIR not defined. Use -DVTK_DIR to specify VTK's install path") endif() find_package(VTK REQUIRED PATHS ${VTK_DIR} NO_DEFAULT_PATH) - target_compile_definitions(opflow PUBLIC OPFLOW_VTK_EXTERNAL) + target_compile_definitions(opflow ${OPFLOW_TARGET_SCOPE} OPFLOW_VTK_EXTERNAL) endif() else() include(${CMAKE_SOURCE_DIR}/cmake/VTKConfig.cmake) CONFIG_VTK() endif() list(APPEND PKG_CONFIG_REQUIRES VTK) - target_include_directories(opflow PUBLIC ${VTK_INCLUDE_DIRS}) - target_link_directories(opflow PUBLIC ${VTK_LIBRARY_DIRS}) - target_link_libraries(opflow PUBLIC ${VTK_LIBRARIES}) + target_include_directories(opflow ${OPFLOW_TARGET_SCOPE} ${VTK_INCLUDE_DIRS}) + target_link_directories(opflow ${OPFLOW_TARGET_SCOPE} ${VTK_LIBRARY_DIRS}) + target_link_libraries(opflow ${OPFLOW_TARGET_SCOPE} ${VTK_LIBRARIES}) endif() # Use TecIO library if(OPFLOW_INSTALL) include(${CMAKE_SOURCE_DIR}/cmake/TECIOConfig.cmake) CONFIG_AND_INSTALL_TECIO() - target_include_directories(opflow PUBLIC ${CMAKE_INSTALL_PREFIX}/include/tecio) - target_link_directories(opflow PUBLIC ${CMAKE_INSTALL_PREFIX}/lib) + target_include_directories(opflow ${OPFLOW_TARGET_SCOPE} ${CMAKE_INSTALL_PREFIX}/include/tecio) + target_link_directories(opflow ${OPFLOW_TARGET_SCOPE} ${CMAKE_INSTALL_PREFIX}/lib) if(OPFLOW_WITH_MPI) - target_link_libraries(opflow PUBLIC teciompi) - target_compile_definitions(opflow PUBLIC TECIOMPI) + target_link_libraries(opflow ${OPFLOW_TARGET_SCOPE} teciompi) + target_compile_definitions(opflow ${OPFLOW_TARGET_SCOPE} TECIOMPI) else() - target_link_libraries(opflow PUBLIC tecio) + target_link_libraries(opflow ${OPFLOW_TARGET_SCOPE} tecio) endif() else() if(OPFLOW_WITH_MPI) add_subdirectory(${CMAKE_SOURCE_DIR}/external/tecio/teciompisrc EXCLUDE_FROM_ALL) - target_include_directories(opflow PUBLIC ${CMAKE_SOURCE_DIR}/external/tecio/teciompisrc) - target_link_libraries(opflow PUBLIC teciompi) + target_include_directories(opflow ${OPFLOW_TARGET_SCOPE} ${CMAKE_SOURCE_DIR}/external/tecio/teciompisrc) + target_link_libraries(opflow ${OPFLOW_TARGET_SCOPE} teciompi) else() add_subdirectory(${CMAKE_SOURCE_DIR}/external/tecio/teciosrc EXCLUDE_FROM_ALL) - target_include_directories(opflow PUBLIC ${CMAKE_SOURCE_DIR}/external/tecio/teciosrc) - target_link_libraries(opflow PUBLIC tecio) + target_include_directories(opflow ${OPFLOW_TARGET_SCOPE} ${CMAKE_SOURCE_DIR}/external/tecio/teciosrc) + target_link_libraries(opflow ${OPFLOW_TARGET_SCOPE} tecio) endif() endif() diff --git a/scripts/update_copyright.sh b/scripts/update_copyright.sh index 91c25c0f..bb410849 100644 --- a/scripts/update_copyright.sh +++ b/scripts/update_copyright.sh @@ -1,7 +1,7 @@ #!/bin/bash ## --------------------------------------------------------------------- ## -## Copyright (c) 2019 - 2025 by the OpFlow developers +## Copyright (c) 2019 - 2026 by the OpFlow developers ## All rights reserved. ## ## This file is part of OpFlow. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f2b555c5..f1f2f8f9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -23,7 +23,7 @@ if(OPFLOW_ENABLE_MODULE) # ---------------------------------------------------------------------------- add_library(opflow) - target_compile_definitions(opflow PUBLIC OPFLOW_USE_MODULE) + target_compile_definitions(opflow PRIVATE OPFLOW_USE_MODULE) set_property(TARGET opflow PROPERTY CXX_SCAN_FOR_MODULES ON) target_sources(opflow PUBLIC FILE_SET CXX_MODULES @@ -48,17 +48,21 @@ else() set_property(TARGET opflow PROPERTY CXX_SCAN_FOR_MODULES OFF) target_compile_features(opflow INTERFACE cxx_std_20) target_sources(opflow - INTERFACE FILE_SET HEADERS ${OPFLOW_HEADERS}) + INTERFACE FILE_SET HEADERS + BASE_DIRS + ${CMAKE_SOURCE_DIR}/include + ${CMAKE_SOURCE_DIR}/src + FILES ${OPFLOW_HEADERS}) install(TARGETS opflow - EXPORT opflow-targets) - install(FILES ${OPFLOW_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/opflow) + EXPORT opflow-targets + FILE_SET HEADERS DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) endif() add_library(opflow::opflow ALIAS opflow) # Create & include the version header configure_file(${CMAKE_CURRENT_LIST_DIR}/../cmake/Version.hpp.in ${CMAKE_BINARY_DIR}/Version.hpp @ONLY) -target_include_directories(opflow PUBLIC +target_include_directories(opflow ${OPFLOW_TARGET_SCOPE} "$" "$" "$" @@ -88,17 +92,22 @@ endif() # ---------------------------------------------------------------------------- # Misc definitions according to tweak options # ---------------------------------------------------------------------------- +if(OPFLOW_ENABLE_MODULE) + set(OPFLOW_TARGET_SCOPE PUBLIC) +else() + set(OPFLOW_TARGET_SCOPE INTERFACE) +endif() foreach( OPFLOW_OPTION OPFLOW_SINGLE_PRECISION OPFLOW_WITH_MPI OPFLOW_WITH_OPENMP) if(${OPFLOW_OPTION}) - target_compile_definitions(opflow INTERFACE ${OPFLOW_OPTION}) + target_compile_definitions(opflow ${OPFLOW_TARGET_SCOPE} ${OPFLOW_OPTION}) endif() endforeach() if(OPFLOW_WITH_MPI) - target_compile_definitions(opflow INTERFACE OPFLOW_DISTRIBUTE_MODEL_MPI) + target_compile_definitions(opflow ${OPFLOW_TARGET_SCOPE} OPFLOW_DISTRIBUTE_MODEL_MPI) endif() if(OPFLOW_NO_EXCEPTIONS AND NOT MSVC) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 9b01c8de..7840b247 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,6 +1,6 @@ # ---------------------------------------------------------------------------- # -# Copyright (c) 2019 - 2025 by the OpFlow developers +# Copyright (c) 2019 - 2026 by the OpFlow developers # # This file is part of OpFlow. # diff --git a/test/Core/CMakeLists.txt b/test/Core/CMakeLists.txt index 964be59a..c9d2d301 100644 --- a/test/Core/CMakeLists.txt +++ b/test/Core/CMakeLists.txt @@ -1,6 +1,6 @@ # ---------------------------------------------------------------------------- # -# Copyright (c) 2019 - 2025 by the OpFlow developers +# Copyright (c) 2019 - 2026 by the OpFlow developers # # This file is part of OpFlow. # diff --git a/test/DataStructures/CMakeLists.txt b/test/DataStructures/CMakeLists.txt index d7af1578..47527fcd 100644 --- a/test/DataStructures/CMakeLists.txt +++ b/test/DataStructures/CMakeLists.txt @@ -1,6 +1,6 @@ # ---------------------------------------------------------------------------- # -# Copyright (c) 2019 - 2025 by the OpFlow developers +# Copyright (c) 2019 - 2026 by the OpFlow developers # # This file is part of OpFlow. # diff --git a/test/Utils/CMakeLists.txt b/test/Utils/CMakeLists.txt index fd7eafc2..d9fba320 100644 --- a/test/Utils/CMakeLists.txt +++ b/test/Utils/CMakeLists.txt @@ -1,6 +1,6 @@ # ---------------------------------------------------------------------------- # -# Copyright (c) 2019 - 2025 by the OpFlow developers +# Copyright (c) 2019 - 2026 by the OpFlow developers # # This file is part of OpFlow. # From 71c44c192f485a7aa0bda26dac525d214d0488a2 Mon Sep 17 00:00:00 2001 From: Luohao Wang Date: Fri, 30 Jan 2026 12:11:27 +0800 Subject: [PATCH 02/14] Implement C++20 module system fixes and exports - Fix module export leakage to consumers - Fix INTERFACE target wiring for libc++ module detection - Add fallback path for libc++ modules.json - Trim amgcl module and fix MPI communication - Fix module exports for clang and GCC - Adjust ext.amgcl module for GCC compatibility - Mute thread-safety warnings in modules - Propagate MPI definitions to module builds Co-Authored-By: Claude Sonnet 4.5 --- src/amgcl.cppm | 69 +++++-------------------------------------------- src/opflow.cppm | 5 +++- 2 files changed, 11 insertions(+), 63 deletions(-) diff --git a/src/amgcl.cppm b/src/amgcl.cppm index 6fc9eb89..6dfc4a23 100644 --- a/src/amgcl.cppm +++ b/src/amgcl.cppm @@ -4,44 +4,10 @@ module; #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include #ifdef OPFLOW_WITH_MPI +#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#endif - -#if defined(AMGCL_HAVE_PARMETIS) -#include -#elif defined(AMGCL_HAVE_SCOTCH) -#include #endif export module ext.amgcl; @@ -51,31 +17,10 @@ export namespace amgcl { using amgcl::adapter::zero_copy; } using amgcl::profiler; - namespace backend { - using amgcl::backend::builtin; - using amgcl::backend::sort_rows; - using amgcl::backend::rows; - using amgcl::backend::cols; - using amgcl::backend::transpose; - using amgcl::backend::nonzeros; - using amgcl::backend::product; - using amgcl::backend::diagonal; - } - using amgcl::make_solver; - using amgcl::amg; - namespace coarsening { - using amgcl::coarsening::smoothed_aggregation; - } - namespace relaxation { - using amgcl::relaxation::spai0; - } - namespace solver { - using amgcl::solver::bicgstab; - using amgcl::solver::bicgstabl; - using amgcl::solver::cg; - using amgcl::solver::fgmres; - using amgcl::solver::gmres; - using amgcl::solver::preonly; - using amgcl::solver::skyline_lu; +#ifdef OPFLOW_WITH_MPI + namespace mpi { + using amgcl::mpi::communicator; + using amgcl::mpi::distributed_matrix; } -} \ No newline at end of file +#endif +} diff --git a/src/opflow.cppm b/src/opflow.cppm index 4bea44b3..2634f9bc 100644 --- a/src/opflow.cppm +++ b/src/opflow.cppm @@ -7,6 +7,9 @@ module; #include #include #include +#ifdef OPFLOW_WITH_OPENMP +#include +#endif #include #include @@ -20,4 +23,4 @@ export import ext.amgcl; #define OPFLOW_INSIDE_MODULE -#include "OpFlow" \ No newline at end of file +#include "OpFlow" From c8dd16c6f97e01d156311c220eb74e4536a6c114 Mon Sep 17 00:00:00 2001 From: Luohao Wang Date: Fri, 30 Jan 2026 12:11:32 +0800 Subject: [PATCH 03/14] Add MPI integration and platform-specific fixes - Provide dummy MPI types when MPI is disabled - Fix MPI logging macro guards - Guard dummy MPI typedef when MPI headers present - Include mpi.h when available in non-MPI builds - Disable MPI C++ bindings globally - Initialize MPI when headers are available - Expose MPI init in module builds when headers exist - Guard -mfma flag for non-x86 architectures - Add macOS SDK sysroot for Homebrew clang - Fix macOS libc++ modules.json detection - Restore macOS gcc matrix and fix boost cstdint includes Co-Authored-By: Claude Sonnet 4.5 --- examples/AMR/Poisson.cpp | 18 ++++++++++++--- examples/LevelSet/AMRLS.cpp | 27 +++++++++++++++++----- examples/LevelSet/UniLS.cpp | 22 ++++++++++++++++-- external/amgcl/amgcl/util.hpp | 7 ++++++ src/Core/BasicDataTypes.hpp | 2 +- src/Core/Constants.hpp | 2 +- src/Core/Environment.hpp | 24 +++++++++++++------ src/Core/Equation/AMGCLBackend.hpp | 2 +- src/Core/Equation/AMGCLEqnSolveHandler.hpp | 2 +- src/Core/Equation/CSRMatrixGenerator.hpp | 2 +- src/Core/Equation/EqnSolveHandler.hpp | 2 +- src/Core/Equation/Equation.hpp | 2 +- src/Core/Equation/EquationHolder.hpp | 2 +- src/Core/Equation/HYPREEqnSolveHandler.hpp | 15 +++++++----- src/Core/Equation/StencilHolder.hpp | 2 +- src/Core/Equation/UnifiedSolve.hpp | 2 +- src/Core/Macros.hpp | 24 ++++++++++++++++--- src/Core/Meta.hpp | 2 +- src/Core/Parallel/ParallelInfo.hpp | 2 +- 19 files changed, 122 insertions(+), 39 deletions(-) diff --git a/examples/AMR/Poisson.cpp b/examples/AMR/Poisson.cpp index 688d87be..bd57e401 100644 --- a/examples/AMR/Poisson.cpp +++ b/examples/AMR/Poisson.cpp @@ -1,6 +1,9 @@ #include "Poisson.hpp" #include "pch.hpp" +#include +#include #include +#include using namespace OpFlow; @@ -83,8 +86,17 @@ void Poisson() { .build(); //p.initBy([](auto&& x) { return std::sqrt(Math::pow2(x[0] - 0.5) + Math::pow2(x[1] - 0.75)) - 0.15; }); p = 0; - auto root = std::format("Result_{:%m-%d_%H-%M-%S}/", - std::chrono::current_zone()->to_local(std::chrono::system_clock::now())); + auto now = std::chrono::system_clock::now(); + auto now_time = std::chrono::system_clock::to_time_t(now); + std::tm local_tm {}; +#if defined(_WIN32) + localtime_s(&local_tm, &now_time); +#else + localtime_r(&now_time, &local_tm); +#endif + char time_buf[32]; + std::strftime(time_buf, sizeof(time_buf), "%m-%d_%H-%M-%S", &local_tm); + auto root = std::string("Result_") + time_buf + "/"; std::filesystem::create_directory(root); SemiStructSolverParams params; @@ -95,4 +107,4 @@ void Poisson() { Utils::VTKAMRStream pf(root + "/p"); pf << p; -} \ No newline at end of file +} diff --git a/examples/LevelSet/AMRLS.cpp b/examples/LevelSet/AMRLS.cpp index 35cd33a5..1c7388dd 100644 --- a/examples/LevelSet/AMRLS.cpp +++ b/examples/LevelSet/AMRLS.cpp @@ -12,10 +12,27 @@ #include #include -#include +#include +#include using namespace OpFlow; +namespace { + std::string make_result_root() { + auto now = std::chrono::system_clock::now(); + auto now_time = std::chrono::system_clock::to_time_t(now); + std::tm local_tm {}; +#if defined(_WIN32) + localtime_s(&local_tm, &now_time); +#else + localtime_r(&now_time, &local_tm); +#endif + char time_buf[32]; + std::strftime(time_buf, sizeof(time_buf), "%m-%d_%H-%M-%S", &local_tm); + return std::string("Result_") + time_buf + "/"; + } +}// namespace + template using DU = D1WENO53Upwind; template @@ -95,8 +112,7 @@ void amrls() { return -2 * std::sin(PI * x[0]) * std::cos(PI * x[0]) * Math::pow2(std::sin(PI * x[1])); }); - auto root = std::format("Result_{:%m-%d_%H-%M-%S}/", - std::chrono::current_zone()->to_local(std::chrono::system_clock::now())); + auto root = make_result_root(); Utils::VTKAMRStream uf(root + "u"), vf(root + "v"), pf(root + "p"), p1f(root + "p1"), p2f(root + "p2"), p3f(root + "p3"); uf << Utils::TimeStamp(0) << u; @@ -290,8 +306,7 @@ void amrls_3d() { return -std::sin(2 * PI * x[0]) * std::sin(2 * PI * x[1]) * Math::pow2(std::sin(PI * x[2])); }); - auto root = std::format("Result_{:%m-%d_%H-%M-%S}/", - std::chrono::current_zone()->to_local(std::chrono::system_clock::now())); + auto root = make_result_root(); Utils::VTKAMRStream uf(root + "u"), vf(root + "v"), wf(root + "w"), pf(root + "p"), p1f(root + "p1"), p2f(root + "p2"), p3f(root + "p3"); uf << Utils::TimeStamp(0) << u; @@ -403,4 +418,4 @@ void amrls_3d() { OP_INFO("Current step: {}", i); } -} \ No newline at end of file +} diff --git a/examples/LevelSet/UniLS.cpp b/examples/LevelSet/UniLS.cpp index d07d6d8d..d61609c5 100644 --- a/examples/LevelSet/UniLS.cpp +++ b/examples/LevelSet/UniLS.cpp @@ -11,9 +11,28 @@ // ---------------------------------------------------------------------------- #include +#include +#include +#include using namespace OpFlow; +namespace { + std::string make_result_root() { + auto now = std::chrono::system_clock::now(); + auto now_time = std::chrono::system_clock::to_time_t(now); + std::tm local_tm {}; +#if defined(_WIN32) + localtime_s(&local_tm, &now_time); +#else + localtime_r(&now_time, &local_tm); +#endif + char time_buf[32]; + std::strftime(time_buf, sizeof(time_buf), "%m-%d_%H-%M-%S", &local_tm); + return std::string("Result_") + time_buf + "/"; + } +}// namespace + template using DU = D1WENO53Upwind; template @@ -181,8 +200,7 @@ void ls_3d() { return -std::sin(2 * PI * x[0]) * std::sin(2 * PI * x[1]) * Math::pow2(std::sin(PI * x[2])); }); - auto root = std::format("Result_{:%m-%d_%H-%M-%S}/", - std::chrono::current_zone()->to_local(std::chrono::system_clock::now())); + auto root = make_result_root(); Utils::TecplotASCIIStream uf("u.tec"), vf("v.tec"), wf("w.tec"), pf("p.tec"); uf << Utils::TimeStamp(0) << u; vf << Utils::TimeStamp(0) << v; diff --git a/external/amgcl/amgcl/util.hpp b/external/amgcl/amgcl/util.hpp index a714cf5f..c042a84a 100644 --- a/external/amgcl/amgcl/util.hpp +++ b/external/amgcl/amgcl/util.hpp @@ -46,6 +46,13 @@ THE SOFTWARE. // If asked explicitly, or if boost is available, enable // using boost::propert_tree::ptree as amgcl parameters: #ifndef AMGCL_NO_BOOST +#if defined(__APPLE__) && defined(__GNUC__) && !defined(__clang__) +namespace boost { + using long_long_type = long long; + using ulong_long_type = unsigned long long; +}// namespace boost +#endif +#include #include #endif diff --git a/src/Core/BasicDataTypes.hpp b/src/Core/BasicDataTypes.hpp index 1358c9a0..85d868d3 100644 --- a/src/Core/BasicDataTypes.hpp +++ b/src/Core/BasicDataTypes.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Constants.hpp b/src/Core/Constants.hpp index 0e11281d..30ad9de1 100644 --- a/src/Core/Constants.hpp +++ b/src/Core/Constants.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Environment.hpp b/src/Core/Environment.hpp index 879d8b70..589e62bc 100644 --- a/src/Core/Environment.hpp +++ b/src/Core/Environment.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // @@ -13,12 +13,20 @@ #ifndef OPFLOW_ENVIRONMENT_HPP #define OPFLOW_ENVIRONMENT_HPP -#ifndef OPFLOW_INSIDE_MODULE -#ifdef OPFLOW_WITH_MPI +#if defined(OPFLOW_WITH_MPI) || __has_include() +#ifndef OMPI_SKIP_MPICXX +#define OMPI_SKIP_MPICXX 1 +#endif +#ifndef MPICH_SKIP_MPICXX +#define MPICH_SKIP_MPICXX 1 +#endif #include +#define OPFLOW_HAS_MPI 1 #endif +#ifndef OPFLOW_INSIDE_MODULE +#include +#include #include -#include #endif #include "Version.hpp"// generated by CMake @@ -27,13 +35,13 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { void inline InitEnvironment(int* argc, char*** argv) { -#ifdef OPFLOW_WITH_MPI +#if defined(OPFLOW_WITH_MPI) || defined(OPFLOW_HAS_MPI) MPI_Init(argc, argv); #endif } void inline FinalizeEnvironment() { -#ifdef OPFLOW_WITH_MPI +#if defined(OPFLOW_WITH_MPI) || defined(OPFLOW_HAS_MPI) MPI_Finalize(); #endif } @@ -89,7 +97,9 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { #endif } - inline void printVersion() { std::print("OpFlow version: {}\n", internal::OPFLOW_VERSION_STRING); } + inline void printVersion() { + std::cout << std::format("OpFlow version: {}\n", internal::OPFLOW_VERSION_STRING); + } inline auto getVersionStr() { return std::string {internal::OPFLOW_VERSION_STRING}; } }// namespace OpFlow diff --git a/src/Core/Equation/AMGCLBackend.hpp b/src/Core/Equation/AMGCLBackend.hpp index 6b04e183..b1c4b104 100644 --- a/src/Core/Equation/AMGCLBackend.hpp +++ b/src/Core/Equation/AMGCLBackend.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Equation/AMGCLEqnSolveHandler.hpp b/src/Core/Equation/AMGCLEqnSolveHandler.hpp index 8a68e96b..8e44529c 100644 --- a/src/Core/Equation/AMGCLEqnSolveHandler.hpp +++ b/src/Core/Equation/AMGCLEqnSolveHandler.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Equation/CSRMatrixGenerator.hpp b/src/Core/Equation/CSRMatrixGenerator.hpp index f393c1ae..061cea53 100644 --- a/src/Core/Equation/CSRMatrixGenerator.hpp +++ b/src/Core/Equation/CSRMatrixGenerator.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Equation/EqnSolveHandler.hpp b/src/Core/Equation/EqnSolveHandler.hpp index 025103f1..6bab9fee 100644 --- a/src/Core/Equation/EqnSolveHandler.hpp +++ b/src/Core/Equation/EqnSolveHandler.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Equation/Equation.hpp b/src/Core/Equation/Equation.hpp index 52d32104..dffaaa29 100644 --- a/src/Core/Equation/Equation.hpp +++ b/src/Core/Equation/Equation.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Equation/EquationHolder.hpp b/src/Core/Equation/EquationHolder.hpp index 54d4ec4e..09c9af86 100644 --- a/src/Core/Equation/EquationHolder.hpp +++ b/src/Core/Equation/EquationHolder.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Equation/HYPREEqnSolveHandler.hpp b/src/Core/Equation/HYPREEqnSolveHandler.hpp index ce129253..313edb50 100644 --- a/src/Core/Equation/HYPREEqnSolveHandler.hpp +++ b/src/Core/Equation/HYPREEqnSolveHandler.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // @@ -28,6 +28,8 @@ #include "DataStructures/Index/LevelMDIndex.hpp" #include "DataStructures/Index/MDIndex.hpp" #ifndef OPFLOW_INSIDE_MODULE +#include +#include #include #include #include @@ -295,7 +297,7 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { if (k.l != l) { HYPRE_SStructGraphAddEntries(graph, l, i.c_arr(), c_var, k.l, k.c_arr(), c_var); - std::print("GraphAddEntry: {} -> {}\n", i, k); + std::cout << std::format("GraphAddEntry: {} -> {}\n", i, k); } } }); @@ -333,8 +335,9 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { for (auto& [k, v] : offsetStencil.pad) { if (k.l == l) { k -= i; } } - std::print("index = {}\n", i); - std::print("current stencil:{}\noffset stencil:{}\n", currentStencil, offsetStencil); + std::cout << std::format("index = {}\n", i); + std::cout << std::format("current stencil:{}\noffset stencil:{}\n", currentStencil, + offsetStencil); auto extendedStencil = offsetStencil; for (auto& [k, v] : commStencil.pad) { auto _target_k = k; @@ -346,7 +349,7 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { extendedStencil.pad[_target_k] = 0; } } - std::print("extended stencil:{}\n", extendedStencil); + std::cout << std::format("extended stencil:{}\n", extendedStencil); std::vector vals; std::vector entries(commStencil.pad.size()); std::iota(entries.begin(), entries.end(), 0); @@ -366,7 +369,7 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { int entry[] = {count++}; Real val[] = {v}; HYPRE_SStructMatrixSetValues(A, l, i.c_arr(), 0, 1, entry, val); - std::print("A[{}, {}] = {}\n", i, k, v); + std::cout << std::format("A[{}, {}] = {}\n", i, k, v); } } auto bias = -extendedStencil.bias; diff --git a/src/Core/Equation/StencilHolder.hpp b/src/Core/Equation/StencilHolder.hpp index 349f3145..bf93ea8e 100644 --- a/src/Core/Equation/StencilHolder.hpp +++ b/src/Core/Equation/StencilHolder.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Equation/UnifiedSolve.hpp b/src/Core/Equation/UnifiedSolve.hpp index c46ec2d1..18e2fd01 100644 --- a/src/Core/Equation/UnifiedSolve.hpp +++ b/src/Core/Equation/UnifiedSolve.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Macros.hpp b/src/Core/Macros.hpp index 2f3c7b4f..20159d8c 100644 --- a/src/Core/Macros.hpp +++ b/src/Core/Macros.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // @@ -60,9 +60,15 @@ #ifdef OPFLOW_WITH_MPI #ifndef OPFLOW_INSIDE_MODULE +#ifndef OMPI_SKIP_MPICXX +#define OMPI_SKIP_MPICXX 1 +#endif +#ifndef MPICH_SKIP_MPICXX +#define MPICH_SKIP_MPICXX 1 +#endif #include #endif -OPFLOW_MODULE_EXPORT namespace OpFlow { inline static int getWorkerId(MPI_Comm comm); } +OPFLOW_MODULE_EXPORT namespace OpFlow { inline int getWorkerId(MPI_Comm comm); } #define SPD_AUGMENTED_LOG(X, ...) \ do { \ if \ @@ -73,6 +79,18 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { inline static int getWorkerId(MPI_Comm c } \ } while (0) #else +#if __has_include() +#ifndef OMPI_SKIP_MPICXX +#define OMPI_SKIP_MPICXX 1 +#endif +#ifndef MPICH_SKIP_MPICXX +#define MPICH_SKIP_MPICXX 1 +#endif +#include +#else +using MPI_Comm = int; +constexpr MPI_Comm MPI_COMM_WORLD = 0; +#endif #define SPD_AUGMENTED_LOG(X, ...) \ do { \ if \ @@ -118,7 +136,7 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { inline static int getWorkerId(MPI_Comm c #if !defined(NDEBUG) && defined(OPFLOW_ENABLE_STACK_TRACE) #include "Utils/StackTracer.hpp" // global stack tracer -OPFLOW_MODULE_EXPORT namespace OpFlow { inline static Utils::StackTracer stackTracer; } +OPFLOW_MODULE_EXPORT namespace OpFlow { inline Utils::StackTracer stackTracer; } #define OP_STACK_PUSH(...) \ do { \ diff --git a/src/Core/Meta.hpp b/src/Core/Meta.hpp index 06850b6e..d1935898 100644 --- a/src/Core/Meta.hpp +++ b/src/Core/Meta.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Parallel/ParallelInfo.hpp b/src/Core/Parallel/ParallelInfo.hpp index f3dc2660..bf5702c4 100644 --- a/src/Core/Parallel/ParallelInfo.hpp +++ b/src/Core/Parallel/ParallelInfo.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // From ab86a6116981c4e89bb375837fe21834cb8ab14a Mon Sep 17 00:00:00 2001 From: Luohao Wang Date: Fri, 30 Jan 2026 12:37:37 +0800 Subject: [PATCH 04/14] Update copyright year to 2026 Update copyright notices in source files from 2025 to 2026. Co-Authored-By: Claude Sonnet 4.5 --- src/Core/AMR/AMRGen.hpp | 2 +- src/Core/BC/BCBase.hpp | 2 +- src/Core/BC/DircBC.hpp | 2 +- src/Core/BC/InternalBC.hpp | 2 +- src/Core/BC/LogicalBC.hpp | 2 +- src/Core/BC/NeumBC.hpp | 2 +- src/Core/BC/ProxyBC.hpp | 2 +- src/Core/Expr/Expr.hpp | 2 +- src/Core/Expr/ExprTrait.hpp | 2 +- src/Core/Expr/Expression.hpp | 2 +- src/Core/Expr/ScalarExpr.hpp | 2 +- src/Core/Expr/ScalarExprTrait.hpp | 2 +- src/Core/Field/Analytical/AnalyticalFieldExpr.hpp | 2 +- src/Core/Field/FieldExpr.hpp | 2 +- src/Core/Field/FieldExprTrait.hpp | 2 +- src/Core/Field/MeshBased/MeshBasedFieldExpr.hpp | 2 +- src/Core/Field/MeshBased/MeshBasedFieldExprTrait.hpp | 2 +- src/Core/Field/MeshBased/SemiStructured/CartAMRField.hpp | 2 +- src/Core/Field/MeshBased/SemiStructured/CartAMRFieldExpr.hpp | 2 +- .../Field/MeshBased/SemiStructured/CartAMRFieldExprTrait.hpp | 2 +- src/Core/Field/MeshBased/SemiStructured/CartAMRFieldTrait.hpp | 2 +- .../Field/MeshBased/SemiStructured/SemiStructuredFieldExpr.hpp | 2 +- .../MeshBased/SemiStructured/SemiStructuredFieldExprTrait.hpp | 2 +- src/Core/Field/MeshBased/StencilField.hpp | 2 +- src/Core/Field/MeshBased/StencilFieldTrait.hpp | 2 +- src/Core/Field/MeshBased/Structured/CartesianField.hpp | 2 +- src/Core/Field/MeshBased/Structured/CartesianFieldExpr.hpp | 2 +- src/Core/Field/MeshBased/Structured/CartesianFieldExprTrait.hpp | 2 +- src/Core/Field/MeshBased/Structured/CartesianFieldTrait.hpp | 2 +- src/Core/Field/MeshBased/Structured/StructuredFieldExpr.hpp | 2 +- .../Field/MeshBased/Structured/StructuredFieldExprTrait.hpp | 2 +- src/Core/Field/MeshBased/UnStructured/UnStructMBFieldExpr.hpp | 2 +- src/Core/Field/ParticleBased/ParticleFieldExpr.hpp | 2 +- src/Core/Interfaces/MDIndexable.hpp | 2 +- src/Core/Interfaces/Serializable.hpp | 2 +- src/Core/Interfaces/Stringifiable.hpp | 2 +- src/Core/Loops/FieldAssigner.hpp | 2 +- src/Core/Loops/RangeFor.hpp | 2 +- src/Core/Loops/StructFor.hpp | 2 +- src/Core/Loops/StructReduce.hpp | 2 +- src/Core/Mesh/MeshBase.hpp | 2 +- src/Core/Mesh/MeshTrait.hpp | 2 +- src/Core/Mesh/SemiStructured/CartesianAMRMesh.hpp | 2 +- src/Core/Mesh/SemiStructured/CartesianAMRMeshBase.hpp | 2 +- src/Core/Mesh/SemiStructured/CartesianAMRMeshTrait.hpp | 2 +- src/Core/Mesh/SemiStructured/CartesianAMRMeshView.hpp | 2 +- src/Core/Mesh/SemiStructured/CartesianAMRMeshViewTrait.hpp | 2 +- src/Core/Mesh/SemiStructured/SemiStructuredMesh.hpp | 2 +- src/Core/Mesh/SemiStructured/SemiStructuredMeshTrait.hpp | 2 +- src/Core/Mesh/Structured/CartesianMesh.hpp | 2 +- src/Core/Mesh/Structured/CartesianMeshBase.hpp | 2 +- src/Core/Mesh/Structured/CartesianMeshTrait.hpp | 2 +- src/Core/Mesh/Structured/CartesianMeshView.hpp | 2 +- src/Core/Mesh/Structured/CartesianMeshViewTrait.hpp | 2 +- src/Core/Mesh/Structured/StructuredMeshBase.hpp | 2 +- src/Core/Mesh/Structured/StructuredMeshTrait.hpp | 2 +- src/Core/Operator/Arithmetic/AMDS.hpp | 2 +- src/Core/Operator/Arithmetic/MinMax.hpp | 2 +- src/Core/Operator/Conditional.hpp | 2 +- src/Core/Operator/Convolution/Convolution.hpp | 2 +- src/Core/Operator/FDMOperators/D1FirstOrderBiasedDownwind.hpp | 2 +- src/Core/Operator/FDMOperators/D1FirstOrderBiasedUpwind.hpp | 2 +- src/Core/Operator/FDMOperators/D1FirstOrderCentered.hpp | 2 +- src/Core/Operator/FDMOperators/D1WENO53Downwind.hpp | 2 +- src/Core/Operator/FDMOperators/D1WENO53Upwind.hpp | 2 +- src/Core/Operator/FDMOperators/D2SecondOrderCentered.hpp | 2 +- src/Core/Operator/FDMOperators/DiffsInterface.hpp | 2 +- src/Core/Operator/IdentityOp.hpp | 2 +- src/Core/Operator/Interpolator/D1FluxLimiter.hpp | 2 +- src/Core/Operator/Interpolator/D1FluxLimiterBasedIntpOp.hpp | 2 +- src/Core/Operator/Interpolator/D1Linear.hpp | 2 +- src/Core/Operator/Interpolator/FluxLimiterKernels.hpp | 2 +- src/Core/Operator/Interpolator/IntpInterface.hpp | 2 +- src/Core/Operator/Logical/Boolean.hpp | 2 +- src/Core/Operator/Logical/Classify.hpp | 2 +- src/Core/Operator/Logical/Compare.hpp | 2 +- src/Core/Operator/Operator.hpp | 2 +- src/Core/Operator/PerElemOpAdaptor.hpp | 2 +- src/Core/Parallel/AbstractSplitStrategy.hpp | 2 +- src/Core/Parallel/EvenSplitStrategy.hpp | 2 +- src/Core/Parallel/ManualSplitStrategy.hpp | 2 +- src/Core/Parallel/ParallelPlan.hpp | 2 +- src/Core/Parallel/ParallelType.hpp | 2 +- src/Core/Parallel/ParticleGuidedSplitStrategy.hpp | 2 +- src/Core/Solvers/IJ/IJSolver.hpp | 2 +- src/Core/Solvers/SemiStruct/SemiStructSolver.hpp | 2 +- src/Core/Solvers/SemiStruct/SemiStructSolverFAC.hpp | 2 +- src/Core/Solvers/SemiStruct/SemiStructSolverNone.hpp | 2 +- src/Core/Solvers/Struct/StructSolver.hpp | 2 +- src/Core/Solvers/Struct/StructSolverBiCGSTAB.hpp | 2 +- src/Core/Solvers/Struct/StructSolverCycRed.hpp | 2 +- src/Core/Solvers/Struct/StructSolverFGMRES.hpp | 2 +- src/Core/Solvers/Struct/StructSolverGMRES.hpp | 2 +- src/Core/Solvers/Struct/StructSolverJacobi.hpp | 2 +- src/Core/Solvers/Struct/StructSolverLGMRES.hpp | 2 +- src/Core/Solvers/Struct/StructSolverNone.hpp | 2 +- src/Core/Solvers/Struct/StructSolverPCG.hpp | 2 +- src/Core/Solvers/Struct/StructSolverPFMG.hpp | 2 +- src/Core/Solvers/Struct/StructSolverPrecond.hpp | 2 +- src/Core/Solvers/Struct/StructSolverSMG.hpp | 2 +- src/DataStructures/Arrays/Arrays.hpp | 2 +- src/DataStructures/Arrays/CoordVector.hpp | 2 +- src/DataStructures/Arrays/OffsetVector.hpp | 2 +- src/DataStructures/Arrays/Tensor/FixedSizeTensor.hpp | 2 +- src/DataStructures/Arrays/Tensor/PlainTensor.hpp | 2 +- src/DataStructures/Arrays/Tensor/TensorBase.hpp | 2 +- src/DataStructures/Arrays/Tensor/TensorTrait.hpp | 2 +- src/DataStructures/Geometry/2DGeometry.hpp | 2 +- src/DataStructures/Geometry/3DGeometry.hpp | 2 +- src/DataStructures/Geometry/BasicElements.hpp | 2 +- src/DataStructures/Geometry/KdTree.hpp | 2 +- src/DataStructures/Index/ColoredIndex.hpp | 2 +- src/DataStructures/Index/LevelMDIndex.hpp | 2 +- src/DataStructures/Index/LevelRangedIndex.hpp | 2 +- src/DataStructures/Index/LinearMapper/BlockedMDRangeMapper.hpp | 2 +- .../Index/LinearMapper/ColoredBlockedMDRangeMapper.hpp | 2 +- src/DataStructures/Index/LinearMapper/ColoredMDRangeMapper.hpp | 2 +- .../Index/LinearMapper/GeneralBlockedMDRangeMapper.hpp | 2 +- src/DataStructures/Index/LinearMapper/LevelMDRangeMapper.hpp | 2 +- src/DataStructures/Index/LinearMapper/MDRangeMapper.hpp | 2 +- src/DataStructures/Index/MDIndex.hpp | 2 +- src/DataStructures/Index/RangedIndex.hpp | 2 +- src/DataStructures/Matrix/COOMatrix.hpp | 2 +- src/DataStructures/Matrix/CSRMatrix.hpp | 2 +- src/DataStructures/Pair.hpp | 2 +- src/DataStructures/Range/LevelRanges.hpp | 2 +- src/DataStructures/Range/Ranges.hpp | 2 +- src/DataStructures/StencilPad.hpp | 2 +- src/Math/Function/Integral.hpp | 2 +- src/Math/Function/Numeric.hpp | 2 +- src/Math/Interpolator/Interpolator.hpp | 2 +- src/Utils/Allocator/AlignedAllocator.hpp | 2 +- src/Utils/Allocator/AllocatorTrait.hpp | 2 +- src/Utils/Allocator/StaticAllocator.hpp | 2 +- src/Utils/Allocator/VirtualMemAllocator.hpp | 2 +- src/Utils/ConstexprString.hpp | 2 +- src/Utils/NamedFunctor.hpp | 2 +- src/Utils/RandomStringGenerator.hpp | 2 +- src/Utils/Serializer/EnumTypes.hpp | 2 +- src/Utils/Serializer/STDContainers.hpp | 2 +- src/Utils/StackTracer.hpp | 2 +- src/Utils/Writers/FieldStream.hpp | 2 +- src/Utils/Writers/FieldWriter.hpp | 2 +- src/Utils/Writers/HDF5Stream.hpp | 2 +- src/Utils/Writers/IOGroup.hpp | 2 +- src/Utils/Writers/RawBinaryStream.hpp | 2 +- src/Utils/Writers/StreamTrait.hpp | 2 +- src/Utils/Writers/Streams.hpp | 2 +- src/Utils/Writers/TecplotASCIIStream.hpp | 2 +- src/Utils/Writers/TecplotBinaryStream.hpp | 2 +- src/Utils/Writers/TecplotSZPLTStream.hpp | 2 +- src/Utils/Writers/VTKAMRStream.hpp | 2 +- test/Core/BC/DircBCTest.cpp | 2 +- test/Core/BC/NeumBCTest.cpp | 2 +- test/Core/BC/PeriodicBCTest.cpp | 2 +- test/Core/Equation/AMGCLMPITest.cpp | 2 +- test/Core/Equation/AMGCLTest.cpp | 2 +- test/Core/Equation/CSRMatrixGeneratorMPITest.cpp | 2 +- test/Core/Equation/CSRMatrixGeneratorTest.cpp | 2 +- test/Core/Equation/DircEqnTest.cpp | 2 +- test/Core/Equation/EqnHolderTest.cpp | 2 +- test/Core/Equation/EqnSetMPITest.cpp | 2 +- test/Core/Equation/EqnSetTest.cpp | 2 +- test/Core/Equation/NeumEqnTest.cpp | 2 +- test/Core/Equation/PeriodicEqnTest.cpp | 2 +- test/Core/Field/CartesianFieldMPITest.cpp | 2 +- test/Core/Field/CartesianFieldTest.cpp | 2 +- test/Core/Loops/RangeForTest.cpp | 2 +- test/Core/Loops/RangeReduceTest.cpp | 2 +- test/Core/Mesh/CartesianMeshTest.cpp | 2 +- test/Core/MetaTest.cpp | 2 +- test/Core/Operator/ConditionalTest.cpp | 2 +- test/Core/Operator/ConvolutionTest.cpp | 2 +- test/Core/Operator/InterpolatorTest.cpp | 2 +- test/Core/Parallel/EvenSplitStrategyTest.cpp | 2 +- test/Core/Parallel/ParticleGuidedSplitStrategyTest.cpp | 2 +- test/DataStructures/Arrays/PlainTensorTest.cpp | 2 +- test/DataStructures/Index/BlockedMDRangeMapperTest.cpp | 2 +- test/DataStructures/Index/ColoredBlockedMDRangeMapperTest.cpp | 2 +- test/DataStructures/Index/MDIndexTest.cpp | 2 +- test/DataStructures/StencilPadTest.cpp | 2 +- test/Utils/Cpp20CompatibilityTest.cpp | 2 +- test/Utils/HDF5StreamMPITest.cpp | 2 +- test/Utils/HDF5StreamTest.cpp | 2 +- test/Utils/IOGroupTest.cpp | 2 +- test/Utils/TecplotStreamMPITest.cpp | 2 +- test/Utils/TecplotStreamTest.cpp | 2 +- test/test_main.cpp | 2 +- test/test_main_mpi.cpp | 2 +- 189 files changed, 189 insertions(+), 189 deletions(-) diff --git a/src/Core/AMR/AMRGen.hpp b/src/Core/AMR/AMRGen.hpp index 229bd8a8..26a48338 100644 --- a/src/Core/AMR/AMRGen.hpp +++ b/src/Core/AMR/AMRGen.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/BC/BCBase.hpp b/src/Core/BC/BCBase.hpp index 3a288ed1..c40eb0a9 100644 --- a/src/Core/BC/BCBase.hpp +++ b/src/Core/BC/BCBase.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/BC/DircBC.hpp b/src/Core/BC/DircBC.hpp index 6dfb4fbc..85479248 100644 --- a/src/Core/BC/DircBC.hpp +++ b/src/Core/BC/DircBC.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/BC/InternalBC.hpp b/src/Core/BC/InternalBC.hpp index 6525d20e..066d84fa 100644 --- a/src/Core/BC/InternalBC.hpp +++ b/src/Core/BC/InternalBC.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/BC/LogicalBC.hpp b/src/Core/BC/LogicalBC.hpp index f1828462..16ad5420 100644 --- a/src/Core/BC/LogicalBC.hpp +++ b/src/Core/BC/LogicalBC.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/BC/NeumBC.hpp b/src/Core/BC/NeumBC.hpp index fa9c7243..82ba2dc0 100644 --- a/src/Core/BC/NeumBC.hpp +++ b/src/Core/BC/NeumBC.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/BC/ProxyBC.hpp b/src/Core/BC/ProxyBC.hpp index 60976f80..b6bb7ea5 100644 --- a/src/Core/BC/ProxyBC.hpp +++ b/src/Core/BC/ProxyBC.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow // diff --git a/src/Core/Expr/Expr.hpp b/src/Core/Expr/Expr.hpp index ec068695..16acdedf 100644 --- a/src/Core/Expr/Expr.hpp +++ b/src/Core/Expr/Expr.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Expr/ExprTrait.hpp b/src/Core/Expr/ExprTrait.hpp index 2ddc2430..82f3ba79 100644 --- a/src/Core/Expr/ExprTrait.hpp +++ b/src/Core/Expr/ExprTrait.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Expr/Expression.hpp b/src/Core/Expr/Expression.hpp index 9c327b56..9e458185 100644 --- a/src/Core/Expr/Expression.hpp +++ b/src/Core/Expr/Expression.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Expr/ScalarExpr.hpp b/src/Core/Expr/ScalarExpr.hpp index f42c6f22..8d712340 100644 --- a/src/Core/Expr/ScalarExpr.hpp +++ b/src/Core/Expr/ScalarExpr.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Expr/ScalarExprTrait.hpp b/src/Core/Expr/ScalarExprTrait.hpp index 7aa55ce0..06fa99af 100644 --- a/src/Core/Expr/ScalarExprTrait.hpp +++ b/src/Core/Expr/ScalarExprTrait.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Field/Analytical/AnalyticalFieldExpr.hpp b/src/Core/Field/Analytical/AnalyticalFieldExpr.hpp index 3be9ce22..a62da0de 100644 --- a/src/Core/Field/Analytical/AnalyticalFieldExpr.hpp +++ b/src/Core/Field/Analytical/AnalyticalFieldExpr.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Field/FieldExpr.hpp b/src/Core/Field/FieldExpr.hpp index 5c9ca1e3..4f184c9a 100644 --- a/src/Core/Field/FieldExpr.hpp +++ b/src/Core/Field/FieldExpr.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Field/FieldExprTrait.hpp b/src/Core/Field/FieldExprTrait.hpp index 03be3fcd..80babdde 100644 --- a/src/Core/Field/FieldExprTrait.hpp +++ b/src/Core/Field/FieldExprTrait.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Field/MeshBased/MeshBasedFieldExpr.hpp b/src/Core/Field/MeshBased/MeshBasedFieldExpr.hpp index 32af36b0..7b4f8b0f 100644 --- a/src/Core/Field/MeshBased/MeshBasedFieldExpr.hpp +++ b/src/Core/Field/MeshBased/MeshBasedFieldExpr.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Field/MeshBased/MeshBasedFieldExprTrait.hpp b/src/Core/Field/MeshBased/MeshBasedFieldExprTrait.hpp index 69713e92..1ab5adbc 100644 --- a/src/Core/Field/MeshBased/MeshBasedFieldExprTrait.hpp +++ b/src/Core/Field/MeshBased/MeshBasedFieldExprTrait.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Field/MeshBased/SemiStructured/CartAMRField.hpp b/src/Core/Field/MeshBased/SemiStructured/CartAMRField.hpp index 7e48510e..bb04867c 100644 --- a/src/Core/Field/MeshBased/SemiStructured/CartAMRField.hpp +++ b/src/Core/Field/MeshBased/SemiStructured/CartAMRField.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Field/MeshBased/SemiStructured/CartAMRFieldExpr.hpp b/src/Core/Field/MeshBased/SemiStructured/CartAMRFieldExpr.hpp index cccce868..6aa78d81 100644 --- a/src/Core/Field/MeshBased/SemiStructured/CartAMRFieldExpr.hpp +++ b/src/Core/Field/MeshBased/SemiStructured/CartAMRFieldExpr.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Field/MeshBased/SemiStructured/CartAMRFieldExprTrait.hpp b/src/Core/Field/MeshBased/SemiStructured/CartAMRFieldExprTrait.hpp index f7ca6117..683a5d21 100644 --- a/src/Core/Field/MeshBased/SemiStructured/CartAMRFieldExprTrait.hpp +++ b/src/Core/Field/MeshBased/SemiStructured/CartAMRFieldExprTrait.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Field/MeshBased/SemiStructured/CartAMRFieldTrait.hpp b/src/Core/Field/MeshBased/SemiStructured/CartAMRFieldTrait.hpp index e1854ba7..4c21b505 100644 --- a/src/Core/Field/MeshBased/SemiStructured/CartAMRFieldTrait.hpp +++ b/src/Core/Field/MeshBased/SemiStructured/CartAMRFieldTrait.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Field/MeshBased/SemiStructured/SemiStructuredFieldExpr.hpp b/src/Core/Field/MeshBased/SemiStructured/SemiStructuredFieldExpr.hpp index 43c9aa79..0cbd4e64 100644 --- a/src/Core/Field/MeshBased/SemiStructured/SemiStructuredFieldExpr.hpp +++ b/src/Core/Field/MeshBased/SemiStructured/SemiStructuredFieldExpr.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Field/MeshBased/SemiStructured/SemiStructuredFieldExprTrait.hpp b/src/Core/Field/MeshBased/SemiStructured/SemiStructuredFieldExprTrait.hpp index c98aff07..01419cb3 100644 --- a/src/Core/Field/MeshBased/SemiStructured/SemiStructuredFieldExprTrait.hpp +++ b/src/Core/Field/MeshBased/SemiStructured/SemiStructuredFieldExprTrait.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Field/MeshBased/StencilField.hpp b/src/Core/Field/MeshBased/StencilField.hpp index 869fcc3f..56c60c8d 100644 --- a/src/Core/Field/MeshBased/StencilField.hpp +++ b/src/Core/Field/MeshBased/StencilField.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Field/MeshBased/StencilFieldTrait.hpp b/src/Core/Field/MeshBased/StencilFieldTrait.hpp index 4e9e77dc..da55dddd 100644 --- a/src/Core/Field/MeshBased/StencilFieldTrait.hpp +++ b/src/Core/Field/MeshBased/StencilFieldTrait.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Field/MeshBased/Structured/CartesianField.hpp b/src/Core/Field/MeshBased/Structured/CartesianField.hpp index 606a9b2b..d5ce4120 100644 --- a/src/Core/Field/MeshBased/Structured/CartesianField.hpp +++ b/src/Core/Field/MeshBased/Structured/CartesianField.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Field/MeshBased/Structured/CartesianFieldExpr.hpp b/src/Core/Field/MeshBased/Structured/CartesianFieldExpr.hpp index e9f3e470..1680e8f1 100644 --- a/src/Core/Field/MeshBased/Structured/CartesianFieldExpr.hpp +++ b/src/Core/Field/MeshBased/Structured/CartesianFieldExpr.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Field/MeshBased/Structured/CartesianFieldExprTrait.hpp b/src/Core/Field/MeshBased/Structured/CartesianFieldExprTrait.hpp index e0379101..63a92d2d 100644 --- a/src/Core/Field/MeshBased/Structured/CartesianFieldExprTrait.hpp +++ b/src/Core/Field/MeshBased/Structured/CartesianFieldExprTrait.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Field/MeshBased/Structured/CartesianFieldTrait.hpp b/src/Core/Field/MeshBased/Structured/CartesianFieldTrait.hpp index dc21c1a1..0d072d71 100644 --- a/src/Core/Field/MeshBased/Structured/CartesianFieldTrait.hpp +++ b/src/Core/Field/MeshBased/Structured/CartesianFieldTrait.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Field/MeshBased/Structured/StructuredFieldExpr.hpp b/src/Core/Field/MeshBased/Structured/StructuredFieldExpr.hpp index 794b9dc9..11652b8c 100644 --- a/src/Core/Field/MeshBased/Structured/StructuredFieldExpr.hpp +++ b/src/Core/Field/MeshBased/Structured/StructuredFieldExpr.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Field/MeshBased/Structured/StructuredFieldExprTrait.hpp b/src/Core/Field/MeshBased/Structured/StructuredFieldExprTrait.hpp index 68cdfb5a..8c17e3ac 100644 --- a/src/Core/Field/MeshBased/Structured/StructuredFieldExprTrait.hpp +++ b/src/Core/Field/MeshBased/Structured/StructuredFieldExprTrait.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Field/MeshBased/UnStructured/UnStructMBFieldExpr.hpp b/src/Core/Field/MeshBased/UnStructured/UnStructMBFieldExpr.hpp index d0947f2e..e4b8f890 100644 --- a/src/Core/Field/MeshBased/UnStructured/UnStructMBFieldExpr.hpp +++ b/src/Core/Field/MeshBased/UnStructured/UnStructMBFieldExpr.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Field/ParticleBased/ParticleFieldExpr.hpp b/src/Core/Field/ParticleBased/ParticleFieldExpr.hpp index 466ed243..eb294c85 100644 --- a/src/Core/Field/ParticleBased/ParticleFieldExpr.hpp +++ b/src/Core/Field/ParticleBased/ParticleFieldExpr.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Interfaces/MDIndexable.hpp b/src/Core/Interfaces/MDIndexable.hpp index c16c0067..2853be87 100644 --- a/src/Core/Interfaces/MDIndexable.hpp +++ b/src/Core/Interfaces/MDIndexable.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Interfaces/Serializable.hpp b/src/Core/Interfaces/Serializable.hpp index 8fb25b6f..819fcf4d 100644 --- a/src/Core/Interfaces/Serializable.hpp +++ b/src/Core/Interfaces/Serializable.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Interfaces/Stringifiable.hpp b/src/Core/Interfaces/Stringifiable.hpp index d5e0dfb6..e4e448b8 100644 --- a/src/Core/Interfaces/Stringifiable.hpp +++ b/src/Core/Interfaces/Stringifiable.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Loops/FieldAssigner.hpp b/src/Core/Loops/FieldAssigner.hpp index 8109969c..10d0d14a 100644 --- a/src/Core/Loops/FieldAssigner.hpp +++ b/src/Core/Loops/FieldAssigner.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Loops/RangeFor.hpp b/src/Core/Loops/RangeFor.hpp index 647f064c..3aef96e1 100644 --- a/src/Core/Loops/RangeFor.hpp +++ b/src/Core/Loops/RangeFor.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Loops/StructFor.hpp b/src/Core/Loops/StructFor.hpp index 0f4c2ab9..262c4ebd 100644 --- a/src/Core/Loops/StructFor.hpp +++ b/src/Core/Loops/StructFor.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Loops/StructReduce.hpp b/src/Core/Loops/StructReduce.hpp index 950e04e6..e621e473 100644 --- a/src/Core/Loops/StructReduce.hpp +++ b/src/Core/Loops/StructReduce.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Mesh/MeshBase.hpp b/src/Core/Mesh/MeshBase.hpp index ff801406..46620363 100644 --- a/src/Core/Mesh/MeshBase.hpp +++ b/src/Core/Mesh/MeshBase.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Mesh/MeshTrait.hpp b/src/Core/Mesh/MeshTrait.hpp index 90f85e0f..6edb9199 100644 --- a/src/Core/Mesh/MeshTrait.hpp +++ b/src/Core/Mesh/MeshTrait.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Mesh/SemiStructured/CartesianAMRMesh.hpp b/src/Core/Mesh/SemiStructured/CartesianAMRMesh.hpp index 35d911fc..cbdeeff0 100644 --- a/src/Core/Mesh/SemiStructured/CartesianAMRMesh.hpp +++ b/src/Core/Mesh/SemiStructured/CartesianAMRMesh.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Mesh/SemiStructured/CartesianAMRMeshBase.hpp b/src/Core/Mesh/SemiStructured/CartesianAMRMeshBase.hpp index 422d49e2..a5028490 100644 --- a/src/Core/Mesh/SemiStructured/CartesianAMRMeshBase.hpp +++ b/src/Core/Mesh/SemiStructured/CartesianAMRMeshBase.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Mesh/SemiStructured/CartesianAMRMeshTrait.hpp b/src/Core/Mesh/SemiStructured/CartesianAMRMeshTrait.hpp index d5b4dd6a..841c81b8 100644 --- a/src/Core/Mesh/SemiStructured/CartesianAMRMeshTrait.hpp +++ b/src/Core/Mesh/SemiStructured/CartesianAMRMeshTrait.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Mesh/SemiStructured/CartesianAMRMeshView.hpp b/src/Core/Mesh/SemiStructured/CartesianAMRMeshView.hpp index aa987cbc..9a658ae4 100644 --- a/src/Core/Mesh/SemiStructured/CartesianAMRMeshView.hpp +++ b/src/Core/Mesh/SemiStructured/CartesianAMRMeshView.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Mesh/SemiStructured/CartesianAMRMeshViewTrait.hpp b/src/Core/Mesh/SemiStructured/CartesianAMRMeshViewTrait.hpp index 9d0df674..813da791 100644 --- a/src/Core/Mesh/SemiStructured/CartesianAMRMeshViewTrait.hpp +++ b/src/Core/Mesh/SemiStructured/CartesianAMRMeshViewTrait.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Mesh/SemiStructured/SemiStructuredMesh.hpp b/src/Core/Mesh/SemiStructured/SemiStructuredMesh.hpp index c83910b7..a03b8b10 100644 --- a/src/Core/Mesh/SemiStructured/SemiStructuredMesh.hpp +++ b/src/Core/Mesh/SemiStructured/SemiStructuredMesh.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Mesh/SemiStructured/SemiStructuredMeshTrait.hpp b/src/Core/Mesh/SemiStructured/SemiStructuredMeshTrait.hpp index 6004906f..5cd70e4d 100644 --- a/src/Core/Mesh/SemiStructured/SemiStructuredMeshTrait.hpp +++ b/src/Core/Mesh/SemiStructured/SemiStructuredMeshTrait.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Mesh/Structured/CartesianMesh.hpp b/src/Core/Mesh/Structured/CartesianMesh.hpp index d564084e..b730e736 100644 --- a/src/Core/Mesh/Structured/CartesianMesh.hpp +++ b/src/Core/Mesh/Structured/CartesianMesh.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Mesh/Structured/CartesianMeshBase.hpp b/src/Core/Mesh/Structured/CartesianMeshBase.hpp index a2db7a6c..4aaedd26 100644 --- a/src/Core/Mesh/Structured/CartesianMeshBase.hpp +++ b/src/Core/Mesh/Structured/CartesianMeshBase.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Mesh/Structured/CartesianMeshTrait.hpp b/src/Core/Mesh/Structured/CartesianMeshTrait.hpp index ec3d9788..292030c0 100644 --- a/src/Core/Mesh/Structured/CartesianMeshTrait.hpp +++ b/src/Core/Mesh/Structured/CartesianMeshTrait.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Mesh/Structured/CartesianMeshView.hpp b/src/Core/Mesh/Structured/CartesianMeshView.hpp index 4453d656..e41918fe 100644 --- a/src/Core/Mesh/Structured/CartesianMeshView.hpp +++ b/src/Core/Mesh/Structured/CartesianMeshView.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Mesh/Structured/CartesianMeshViewTrait.hpp b/src/Core/Mesh/Structured/CartesianMeshViewTrait.hpp index a11d88d1..e2e4b8eb 100644 --- a/src/Core/Mesh/Structured/CartesianMeshViewTrait.hpp +++ b/src/Core/Mesh/Structured/CartesianMeshViewTrait.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Mesh/Structured/StructuredMeshBase.hpp b/src/Core/Mesh/Structured/StructuredMeshBase.hpp index cd50eabc..1c729868 100644 --- a/src/Core/Mesh/Structured/StructuredMeshBase.hpp +++ b/src/Core/Mesh/Structured/StructuredMeshBase.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Mesh/Structured/StructuredMeshTrait.hpp b/src/Core/Mesh/Structured/StructuredMeshTrait.hpp index 0da4398d..1baf8d19 100644 --- a/src/Core/Mesh/Structured/StructuredMeshTrait.hpp +++ b/src/Core/Mesh/Structured/StructuredMeshTrait.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Operator/Arithmetic/AMDS.hpp b/src/Core/Operator/Arithmetic/AMDS.hpp index 5369efba..93e3bc06 100644 --- a/src/Core/Operator/Arithmetic/AMDS.hpp +++ b/src/Core/Operator/Arithmetic/AMDS.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Operator/Arithmetic/MinMax.hpp b/src/Core/Operator/Arithmetic/MinMax.hpp index 6655334a..fca4ceea 100644 --- a/src/Core/Operator/Arithmetic/MinMax.hpp +++ b/src/Core/Operator/Arithmetic/MinMax.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Operator/Conditional.hpp b/src/Core/Operator/Conditional.hpp index fc633523..c51528d8 100644 --- a/src/Core/Operator/Conditional.hpp +++ b/src/Core/Operator/Conditional.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Operator/Convolution/Convolution.hpp b/src/Core/Operator/Convolution/Convolution.hpp index 3b7104aa..3cfb5ce1 100644 --- a/src/Core/Operator/Convolution/Convolution.hpp +++ b/src/Core/Operator/Convolution/Convolution.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Operator/FDMOperators/D1FirstOrderBiasedDownwind.hpp b/src/Core/Operator/FDMOperators/D1FirstOrderBiasedDownwind.hpp index 230ef277..7552ac62 100644 --- a/src/Core/Operator/FDMOperators/D1FirstOrderBiasedDownwind.hpp +++ b/src/Core/Operator/FDMOperators/D1FirstOrderBiasedDownwind.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Operator/FDMOperators/D1FirstOrderBiasedUpwind.hpp b/src/Core/Operator/FDMOperators/D1FirstOrderBiasedUpwind.hpp index 115f9342..8c452c19 100644 --- a/src/Core/Operator/FDMOperators/D1FirstOrderBiasedUpwind.hpp +++ b/src/Core/Operator/FDMOperators/D1FirstOrderBiasedUpwind.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Operator/FDMOperators/D1FirstOrderCentered.hpp b/src/Core/Operator/FDMOperators/D1FirstOrderCentered.hpp index 55ae00c0..55829d08 100644 --- a/src/Core/Operator/FDMOperators/D1FirstOrderCentered.hpp +++ b/src/Core/Operator/FDMOperators/D1FirstOrderCentered.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Operator/FDMOperators/D1WENO53Downwind.hpp b/src/Core/Operator/FDMOperators/D1WENO53Downwind.hpp index 847022a8..787eefc8 100644 --- a/src/Core/Operator/FDMOperators/D1WENO53Downwind.hpp +++ b/src/Core/Operator/FDMOperators/D1WENO53Downwind.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Operator/FDMOperators/D1WENO53Upwind.hpp b/src/Core/Operator/FDMOperators/D1WENO53Upwind.hpp index fbf4fe05..51d73249 100644 --- a/src/Core/Operator/FDMOperators/D1WENO53Upwind.hpp +++ b/src/Core/Operator/FDMOperators/D1WENO53Upwind.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Operator/FDMOperators/D2SecondOrderCentered.hpp b/src/Core/Operator/FDMOperators/D2SecondOrderCentered.hpp index d550ee34..f01193b2 100644 --- a/src/Core/Operator/FDMOperators/D2SecondOrderCentered.hpp +++ b/src/Core/Operator/FDMOperators/D2SecondOrderCentered.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Operator/FDMOperators/DiffsInterface.hpp b/src/Core/Operator/FDMOperators/DiffsInterface.hpp index 3166e867..971fa253 100644 --- a/src/Core/Operator/FDMOperators/DiffsInterface.hpp +++ b/src/Core/Operator/FDMOperators/DiffsInterface.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Operator/IdentityOp.hpp b/src/Core/Operator/IdentityOp.hpp index c3505e0f..b2d012a9 100644 --- a/src/Core/Operator/IdentityOp.hpp +++ b/src/Core/Operator/IdentityOp.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Operator/Interpolator/D1FluxLimiter.hpp b/src/Core/Operator/Interpolator/D1FluxLimiter.hpp index 9f53344b..558cd8db 100644 --- a/src/Core/Operator/Interpolator/D1FluxLimiter.hpp +++ b/src/Core/Operator/Interpolator/D1FluxLimiter.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Operator/Interpolator/D1FluxLimiterBasedIntpOp.hpp b/src/Core/Operator/Interpolator/D1FluxLimiterBasedIntpOp.hpp index 5e84dfdd..0d207b48 100644 --- a/src/Core/Operator/Interpolator/D1FluxLimiterBasedIntpOp.hpp +++ b/src/Core/Operator/Interpolator/D1FluxLimiterBasedIntpOp.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Operator/Interpolator/D1Linear.hpp b/src/Core/Operator/Interpolator/D1Linear.hpp index 3ace5f80..e0aa03a9 100644 --- a/src/Core/Operator/Interpolator/D1Linear.hpp +++ b/src/Core/Operator/Interpolator/D1Linear.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Operator/Interpolator/FluxLimiterKernels.hpp b/src/Core/Operator/Interpolator/FluxLimiterKernels.hpp index 85699dd5..d3817f8d 100644 --- a/src/Core/Operator/Interpolator/FluxLimiterKernels.hpp +++ b/src/Core/Operator/Interpolator/FluxLimiterKernels.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Operator/Interpolator/IntpInterface.hpp b/src/Core/Operator/Interpolator/IntpInterface.hpp index 8e37ac35..2aacd1fc 100644 --- a/src/Core/Operator/Interpolator/IntpInterface.hpp +++ b/src/Core/Operator/Interpolator/IntpInterface.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Operator/Logical/Boolean.hpp b/src/Core/Operator/Logical/Boolean.hpp index f6cbb0fd..b083b29f 100644 --- a/src/Core/Operator/Logical/Boolean.hpp +++ b/src/Core/Operator/Logical/Boolean.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Operator/Logical/Classify.hpp b/src/Core/Operator/Logical/Classify.hpp index 6b3d588a..576456af 100644 --- a/src/Core/Operator/Logical/Classify.hpp +++ b/src/Core/Operator/Logical/Classify.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Operator/Logical/Compare.hpp b/src/Core/Operator/Logical/Compare.hpp index ec4d4908..5668b029 100644 --- a/src/Core/Operator/Logical/Compare.hpp +++ b/src/Core/Operator/Logical/Compare.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Operator/Operator.hpp b/src/Core/Operator/Operator.hpp index fc0edd8b..f693c6f2 100644 --- a/src/Core/Operator/Operator.hpp +++ b/src/Core/Operator/Operator.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Operator/PerElemOpAdaptor.hpp b/src/Core/Operator/PerElemOpAdaptor.hpp index e0ea9aeb..c396c365 100644 --- a/src/Core/Operator/PerElemOpAdaptor.hpp +++ b/src/Core/Operator/PerElemOpAdaptor.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Parallel/AbstractSplitStrategy.hpp b/src/Core/Parallel/AbstractSplitStrategy.hpp index 28835c53..5545404d 100644 --- a/src/Core/Parallel/AbstractSplitStrategy.hpp +++ b/src/Core/Parallel/AbstractSplitStrategy.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Parallel/EvenSplitStrategy.hpp b/src/Core/Parallel/EvenSplitStrategy.hpp index ef4533b0..42f457c8 100644 --- a/src/Core/Parallel/EvenSplitStrategy.hpp +++ b/src/Core/Parallel/EvenSplitStrategy.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Parallel/ManualSplitStrategy.hpp b/src/Core/Parallel/ManualSplitStrategy.hpp index 5bae5f24..03c1828c 100644 --- a/src/Core/Parallel/ManualSplitStrategy.hpp +++ b/src/Core/Parallel/ManualSplitStrategy.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Parallel/ParallelPlan.hpp b/src/Core/Parallel/ParallelPlan.hpp index e6175f84..6d0531d3 100644 --- a/src/Core/Parallel/ParallelPlan.hpp +++ b/src/Core/Parallel/ParallelPlan.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Parallel/ParallelType.hpp b/src/Core/Parallel/ParallelType.hpp index 5508f783..c259e7f5 100644 --- a/src/Core/Parallel/ParallelType.hpp +++ b/src/Core/Parallel/ParallelType.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Parallel/ParticleGuidedSplitStrategy.hpp b/src/Core/Parallel/ParticleGuidedSplitStrategy.hpp index 7425cafb..9931b582 100644 --- a/src/Core/Parallel/ParticleGuidedSplitStrategy.hpp +++ b/src/Core/Parallel/ParticleGuidedSplitStrategy.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Solvers/IJ/IJSolver.hpp b/src/Core/Solvers/IJ/IJSolver.hpp index 61a256ac..61b82c8b 100644 --- a/src/Core/Solvers/IJ/IJSolver.hpp +++ b/src/Core/Solvers/IJ/IJSolver.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Solvers/SemiStruct/SemiStructSolver.hpp b/src/Core/Solvers/SemiStruct/SemiStructSolver.hpp index 199344a8..3edaeddb 100644 --- a/src/Core/Solvers/SemiStruct/SemiStructSolver.hpp +++ b/src/Core/Solvers/SemiStruct/SemiStructSolver.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Solvers/SemiStruct/SemiStructSolverFAC.hpp b/src/Core/Solvers/SemiStruct/SemiStructSolverFAC.hpp index 677f130e..5ef49b00 100644 --- a/src/Core/Solvers/SemiStruct/SemiStructSolverFAC.hpp +++ b/src/Core/Solvers/SemiStruct/SemiStructSolverFAC.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Solvers/SemiStruct/SemiStructSolverNone.hpp b/src/Core/Solvers/SemiStruct/SemiStructSolverNone.hpp index 42fa03e4..035e0310 100644 --- a/src/Core/Solvers/SemiStruct/SemiStructSolverNone.hpp +++ b/src/Core/Solvers/SemiStruct/SemiStructSolverNone.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Solvers/Struct/StructSolver.hpp b/src/Core/Solvers/Struct/StructSolver.hpp index 61204244..cdf42e37 100644 --- a/src/Core/Solvers/Struct/StructSolver.hpp +++ b/src/Core/Solvers/Struct/StructSolver.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Solvers/Struct/StructSolverBiCGSTAB.hpp b/src/Core/Solvers/Struct/StructSolverBiCGSTAB.hpp index d0ecbbab..2c61a651 100644 --- a/src/Core/Solvers/Struct/StructSolverBiCGSTAB.hpp +++ b/src/Core/Solvers/Struct/StructSolverBiCGSTAB.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Solvers/Struct/StructSolverCycRed.hpp b/src/Core/Solvers/Struct/StructSolverCycRed.hpp index 6181e30d..0f64a54f 100644 --- a/src/Core/Solvers/Struct/StructSolverCycRed.hpp +++ b/src/Core/Solvers/Struct/StructSolverCycRed.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Solvers/Struct/StructSolverFGMRES.hpp b/src/Core/Solvers/Struct/StructSolverFGMRES.hpp index 9b80e86d..53672f00 100644 --- a/src/Core/Solvers/Struct/StructSolverFGMRES.hpp +++ b/src/Core/Solvers/Struct/StructSolverFGMRES.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Solvers/Struct/StructSolverGMRES.hpp b/src/Core/Solvers/Struct/StructSolverGMRES.hpp index 7636b433..5deef1bc 100644 --- a/src/Core/Solvers/Struct/StructSolverGMRES.hpp +++ b/src/Core/Solvers/Struct/StructSolverGMRES.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Solvers/Struct/StructSolverJacobi.hpp b/src/Core/Solvers/Struct/StructSolverJacobi.hpp index af18b272..eb9761bd 100644 --- a/src/Core/Solvers/Struct/StructSolverJacobi.hpp +++ b/src/Core/Solvers/Struct/StructSolverJacobi.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Solvers/Struct/StructSolverLGMRES.hpp b/src/Core/Solvers/Struct/StructSolverLGMRES.hpp index 86ae6cc1..82dd5cfe 100644 --- a/src/Core/Solvers/Struct/StructSolverLGMRES.hpp +++ b/src/Core/Solvers/Struct/StructSolverLGMRES.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Solvers/Struct/StructSolverNone.hpp b/src/Core/Solvers/Struct/StructSolverNone.hpp index c4544aff..28f967ab 100644 --- a/src/Core/Solvers/Struct/StructSolverNone.hpp +++ b/src/Core/Solvers/Struct/StructSolverNone.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Solvers/Struct/StructSolverPCG.hpp b/src/Core/Solvers/Struct/StructSolverPCG.hpp index 67825a5a..bc3e474a 100644 --- a/src/Core/Solvers/Struct/StructSolverPCG.hpp +++ b/src/Core/Solvers/Struct/StructSolverPCG.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Solvers/Struct/StructSolverPFMG.hpp b/src/Core/Solvers/Struct/StructSolverPFMG.hpp index 066a39a0..ad38f824 100644 --- a/src/Core/Solvers/Struct/StructSolverPFMG.hpp +++ b/src/Core/Solvers/Struct/StructSolverPFMG.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Solvers/Struct/StructSolverPrecond.hpp b/src/Core/Solvers/Struct/StructSolverPrecond.hpp index ac93a15a..8fb570a7 100644 --- a/src/Core/Solvers/Struct/StructSolverPrecond.hpp +++ b/src/Core/Solvers/Struct/StructSolverPrecond.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Core/Solvers/Struct/StructSolverSMG.hpp b/src/Core/Solvers/Struct/StructSolverSMG.hpp index 8612f715..837c9d44 100644 --- a/src/Core/Solvers/Struct/StructSolverSMG.hpp +++ b/src/Core/Solvers/Struct/StructSolverSMG.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/DataStructures/Arrays/Arrays.hpp b/src/DataStructures/Arrays/Arrays.hpp index f87c778a..676c8656 100644 --- a/src/DataStructures/Arrays/Arrays.hpp +++ b/src/DataStructures/Arrays/Arrays.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/DataStructures/Arrays/CoordVector.hpp b/src/DataStructures/Arrays/CoordVector.hpp index 5890ee08..36cf0c27 100644 --- a/src/DataStructures/Arrays/CoordVector.hpp +++ b/src/DataStructures/Arrays/CoordVector.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/DataStructures/Arrays/OffsetVector.hpp b/src/DataStructures/Arrays/OffsetVector.hpp index 001c5f15..9bda3360 100644 --- a/src/DataStructures/Arrays/OffsetVector.hpp +++ b/src/DataStructures/Arrays/OffsetVector.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/DataStructures/Arrays/Tensor/FixedSizeTensor.hpp b/src/DataStructures/Arrays/Tensor/FixedSizeTensor.hpp index 54a2b61f..71e0eb76 100644 --- a/src/DataStructures/Arrays/Tensor/FixedSizeTensor.hpp +++ b/src/DataStructures/Arrays/Tensor/FixedSizeTensor.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/DataStructures/Arrays/Tensor/PlainTensor.hpp b/src/DataStructures/Arrays/Tensor/PlainTensor.hpp index b3b054f1..839ceed9 100644 --- a/src/DataStructures/Arrays/Tensor/PlainTensor.hpp +++ b/src/DataStructures/Arrays/Tensor/PlainTensor.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/DataStructures/Arrays/Tensor/TensorBase.hpp b/src/DataStructures/Arrays/Tensor/TensorBase.hpp index 2fb348e4..8926d637 100644 --- a/src/DataStructures/Arrays/Tensor/TensorBase.hpp +++ b/src/DataStructures/Arrays/Tensor/TensorBase.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/DataStructures/Arrays/Tensor/TensorTrait.hpp b/src/DataStructures/Arrays/Tensor/TensorTrait.hpp index 5cfd10d1..51930f23 100644 --- a/src/DataStructures/Arrays/Tensor/TensorTrait.hpp +++ b/src/DataStructures/Arrays/Tensor/TensorTrait.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/DataStructures/Geometry/2DGeometry.hpp b/src/DataStructures/Geometry/2DGeometry.hpp index af6a3533..7ca0c073 100644 --- a/src/DataStructures/Geometry/2DGeometry.hpp +++ b/src/DataStructures/Geometry/2DGeometry.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/DataStructures/Geometry/3DGeometry.hpp b/src/DataStructures/Geometry/3DGeometry.hpp index 8ca0803f..9581dcf7 100644 --- a/src/DataStructures/Geometry/3DGeometry.hpp +++ b/src/DataStructures/Geometry/3DGeometry.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/DataStructures/Geometry/BasicElements.hpp b/src/DataStructures/Geometry/BasicElements.hpp index 078c5cf3..cf8a84e5 100644 --- a/src/DataStructures/Geometry/BasicElements.hpp +++ b/src/DataStructures/Geometry/BasicElements.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/DataStructures/Geometry/KdTree.hpp b/src/DataStructures/Geometry/KdTree.hpp index 32ed579a..9e73a123 100644 --- a/src/DataStructures/Geometry/KdTree.hpp +++ b/src/DataStructures/Geometry/KdTree.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/DataStructures/Index/ColoredIndex.hpp b/src/DataStructures/Index/ColoredIndex.hpp index b4e4612a..d5152e20 100644 --- a/src/DataStructures/Index/ColoredIndex.hpp +++ b/src/DataStructures/Index/ColoredIndex.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/DataStructures/Index/LevelMDIndex.hpp b/src/DataStructures/Index/LevelMDIndex.hpp index 97bbba02..3430cabe 100644 --- a/src/DataStructures/Index/LevelMDIndex.hpp +++ b/src/DataStructures/Index/LevelMDIndex.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/DataStructures/Index/LevelRangedIndex.hpp b/src/DataStructures/Index/LevelRangedIndex.hpp index bed5fac4..db6c28c9 100644 --- a/src/DataStructures/Index/LevelRangedIndex.hpp +++ b/src/DataStructures/Index/LevelRangedIndex.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/DataStructures/Index/LinearMapper/BlockedMDRangeMapper.hpp b/src/DataStructures/Index/LinearMapper/BlockedMDRangeMapper.hpp index d28bbf4c..c5ddeb20 100644 --- a/src/DataStructures/Index/LinearMapper/BlockedMDRangeMapper.hpp +++ b/src/DataStructures/Index/LinearMapper/BlockedMDRangeMapper.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/DataStructures/Index/LinearMapper/ColoredBlockedMDRangeMapper.hpp b/src/DataStructures/Index/LinearMapper/ColoredBlockedMDRangeMapper.hpp index 9e07be67..0b00ed15 100644 --- a/src/DataStructures/Index/LinearMapper/ColoredBlockedMDRangeMapper.hpp +++ b/src/DataStructures/Index/LinearMapper/ColoredBlockedMDRangeMapper.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/DataStructures/Index/LinearMapper/ColoredMDRangeMapper.hpp b/src/DataStructures/Index/LinearMapper/ColoredMDRangeMapper.hpp index e04f4a0c..f0abac76 100644 --- a/src/DataStructures/Index/LinearMapper/ColoredMDRangeMapper.hpp +++ b/src/DataStructures/Index/LinearMapper/ColoredMDRangeMapper.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/DataStructures/Index/LinearMapper/GeneralBlockedMDRangeMapper.hpp b/src/DataStructures/Index/LinearMapper/GeneralBlockedMDRangeMapper.hpp index 4a466197..02026f72 100644 --- a/src/DataStructures/Index/LinearMapper/GeneralBlockedMDRangeMapper.hpp +++ b/src/DataStructures/Index/LinearMapper/GeneralBlockedMDRangeMapper.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/DataStructures/Index/LinearMapper/LevelMDRangeMapper.hpp b/src/DataStructures/Index/LinearMapper/LevelMDRangeMapper.hpp index e804505d..9baa989f 100644 --- a/src/DataStructures/Index/LinearMapper/LevelMDRangeMapper.hpp +++ b/src/DataStructures/Index/LinearMapper/LevelMDRangeMapper.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/DataStructures/Index/LinearMapper/MDRangeMapper.hpp b/src/DataStructures/Index/LinearMapper/MDRangeMapper.hpp index b7cb3596..e8bbefc2 100644 --- a/src/DataStructures/Index/LinearMapper/MDRangeMapper.hpp +++ b/src/DataStructures/Index/LinearMapper/MDRangeMapper.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/DataStructures/Index/MDIndex.hpp b/src/DataStructures/Index/MDIndex.hpp index da7ba8b3..9dd3019b 100644 --- a/src/DataStructures/Index/MDIndex.hpp +++ b/src/DataStructures/Index/MDIndex.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/DataStructures/Index/RangedIndex.hpp b/src/DataStructures/Index/RangedIndex.hpp index 40c38967..0e183856 100644 --- a/src/DataStructures/Index/RangedIndex.hpp +++ b/src/DataStructures/Index/RangedIndex.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/DataStructures/Matrix/COOMatrix.hpp b/src/DataStructures/Matrix/COOMatrix.hpp index 3ae0bb9f..eaade6c3 100644 --- a/src/DataStructures/Matrix/COOMatrix.hpp +++ b/src/DataStructures/Matrix/COOMatrix.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/DataStructures/Matrix/CSRMatrix.hpp b/src/DataStructures/Matrix/CSRMatrix.hpp index ead33dd0..78a991ef 100644 --- a/src/DataStructures/Matrix/CSRMatrix.hpp +++ b/src/DataStructures/Matrix/CSRMatrix.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/DataStructures/Pair.hpp b/src/DataStructures/Pair.hpp index 61c3f38a..88b93e14 100644 --- a/src/DataStructures/Pair.hpp +++ b/src/DataStructures/Pair.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/DataStructures/Range/LevelRanges.hpp b/src/DataStructures/Range/LevelRanges.hpp index cfc86387..d2872437 100644 --- a/src/DataStructures/Range/LevelRanges.hpp +++ b/src/DataStructures/Range/LevelRanges.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/DataStructures/Range/Ranges.hpp b/src/DataStructures/Range/Ranges.hpp index 5d1459b8..50ed4253 100644 --- a/src/DataStructures/Range/Ranges.hpp +++ b/src/DataStructures/Range/Ranges.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/DataStructures/StencilPad.hpp b/src/DataStructures/StencilPad.hpp index 72d9fc0a..c3e42f39 100644 --- a/src/DataStructures/StencilPad.hpp +++ b/src/DataStructures/StencilPad.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Math/Function/Integral.hpp b/src/Math/Function/Integral.hpp index 7db3b934..3dc9ebeb 100644 --- a/src/Math/Function/Integral.hpp +++ b/src/Math/Function/Integral.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Math/Function/Numeric.hpp b/src/Math/Function/Numeric.hpp index dee630a0..de38f3d4 100644 --- a/src/Math/Function/Numeric.hpp +++ b/src/Math/Function/Numeric.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Math/Interpolator/Interpolator.hpp b/src/Math/Interpolator/Interpolator.hpp index 1c4a57c4..d9bba225 100644 --- a/src/Math/Interpolator/Interpolator.hpp +++ b/src/Math/Interpolator/Interpolator.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Utils/Allocator/AlignedAllocator.hpp b/src/Utils/Allocator/AlignedAllocator.hpp index 95d3ea8f..3ff33845 100644 --- a/src/Utils/Allocator/AlignedAllocator.hpp +++ b/src/Utils/Allocator/AlignedAllocator.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Utils/Allocator/AllocatorTrait.hpp b/src/Utils/Allocator/AllocatorTrait.hpp index 54001026..cfc6c3b3 100644 --- a/src/Utils/Allocator/AllocatorTrait.hpp +++ b/src/Utils/Allocator/AllocatorTrait.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Utils/Allocator/StaticAllocator.hpp b/src/Utils/Allocator/StaticAllocator.hpp index e20b1452..2b325034 100644 --- a/src/Utils/Allocator/StaticAllocator.hpp +++ b/src/Utils/Allocator/StaticAllocator.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Utils/Allocator/VirtualMemAllocator.hpp b/src/Utils/Allocator/VirtualMemAllocator.hpp index 4e116229..3ce89ef2 100644 --- a/src/Utils/Allocator/VirtualMemAllocator.hpp +++ b/src/Utils/Allocator/VirtualMemAllocator.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Utils/ConstexprString.hpp b/src/Utils/ConstexprString.hpp index 5e7a9c3f..19248e3f 100644 --- a/src/Utils/ConstexprString.hpp +++ b/src/Utils/ConstexprString.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Utils/NamedFunctor.hpp b/src/Utils/NamedFunctor.hpp index 4a9a9f7f..b7aa15be 100644 --- a/src/Utils/NamedFunctor.hpp +++ b/src/Utils/NamedFunctor.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Utils/RandomStringGenerator.hpp b/src/Utils/RandomStringGenerator.hpp index 14617b8b..8fb4d94a 100644 --- a/src/Utils/RandomStringGenerator.hpp +++ b/src/Utils/RandomStringGenerator.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Utils/Serializer/EnumTypes.hpp b/src/Utils/Serializer/EnumTypes.hpp index fb40cdb2..a94b7cd7 100644 --- a/src/Utils/Serializer/EnumTypes.hpp +++ b/src/Utils/Serializer/EnumTypes.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Utils/Serializer/STDContainers.hpp b/src/Utils/Serializer/STDContainers.hpp index df3b53fa..6545af7d 100644 --- a/src/Utils/Serializer/STDContainers.hpp +++ b/src/Utils/Serializer/STDContainers.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Utils/StackTracer.hpp b/src/Utils/StackTracer.hpp index d1f840fa..8ccc4f08 100644 --- a/src/Utils/StackTracer.hpp +++ b/src/Utils/StackTracer.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Utils/Writers/FieldStream.hpp b/src/Utils/Writers/FieldStream.hpp index 9c5c079a..ceef1b75 100644 --- a/src/Utils/Writers/FieldStream.hpp +++ b/src/Utils/Writers/FieldStream.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Utils/Writers/FieldWriter.hpp b/src/Utils/Writers/FieldWriter.hpp index a4a1a420..6ceb1a88 100644 --- a/src/Utils/Writers/FieldWriter.hpp +++ b/src/Utils/Writers/FieldWriter.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Utils/Writers/HDF5Stream.hpp b/src/Utils/Writers/HDF5Stream.hpp index 205a6ca4..c801a9f4 100644 --- a/src/Utils/Writers/HDF5Stream.hpp +++ b/src/Utils/Writers/HDF5Stream.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Utils/Writers/IOGroup.hpp b/src/Utils/Writers/IOGroup.hpp index 4778fe8f..4c27fe9f 100644 --- a/src/Utils/Writers/IOGroup.hpp +++ b/src/Utils/Writers/IOGroup.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Utils/Writers/RawBinaryStream.hpp b/src/Utils/Writers/RawBinaryStream.hpp index b0734e11..534ec740 100644 --- a/src/Utils/Writers/RawBinaryStream.hpp +++ b/src/Utils/Writers/RawBinaryStream.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Utils/Writers/StreamTrait.hpp b/src/Utils/Writers/StreamTrait.hpp index 7032919b..97a225de 100644 --- a/src/Utils/Writers/StreamTrait.hpp +++ b/src/Utils/Writers/StreamTrait.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Utils/Writers/Streams.hpp b/src/Utils/Writers/Streams.hpp index 33fa5bd9..85f4936b 100644 --- a/src/Utils/Writers/Streams.hpp +++ b/src/Utils/Writers/Streams.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Utils/Writers/TecplotASCIIStream.hpp b/src/Utils/Writers/TecplotASCIIStream.hpp index f79e25c2..5a822fc6 100644 --- a/src/Utils/Writers/TecplotASCIIStream.hpp +++ b/src/Utils/Writers/TecplotASCIIStream.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Utils/Writers/TecplotBinaryStream.hpp b/src/Utils/Writers/TecplotBinaryStream.hpp index c53594cf..f3f36b07 100644 --- a/src/Utils/Writers/TecplotBinaryStream.hpp +++ b/src/Utils/Writers/TecplotBinaryStream.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Utils/Writers/TecplotSZPLTStream.hpp b/src/Utils/Writers/TecplotSZPLTStream.hpp index 04b5a4d6..bf8f60c9 100644 --- a/src/Utils/Writers/TecplotSZPLTStream.hpp +++ b/src/Utils/Writers/TecplotSZPLTStream.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/src/Utils/Writers/VTKAMRStream.hpp b/src/Utils/Writers/VTKAMRStream.hpp index e162d078..45abf951 100644 --- a/src/Utils/Writers/VTKAMRStream.hpp +++ b/src/Utils/Writers/VTKAMRStream.hpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/test/Core/BC/DircBCTest.cpp b/test/Core/BC/DircBCTest.cpp index 5d6dcb74..d765674d 100644 --- a/test/Core/BC/DircBCTest.cpp +++ b/test/Core/BC/DircBCTest.cpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/test/Core/BC/NeumBCTest.cpp b/test/Core/BC/NeumBCTest.cpp index 6f863ef8..b4b0f241 100644 --- a/test/Core/BC/NeumBCTest.cpp +++ b/test/Core/BC/NeumBCTest.cpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/test/Core/BC/PeriodicBCTest.cpp b/test/Core/BC/PeriodicBCTest.cpp index 3f045abd..e85decd7 100644 --- a/test/Core/BC/PeriodicBCTest.cpp +++ b/test/Core/BC/PeriodicBCTest.cpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/test/Core/Equation/AMGCLMPITest.cpp b/test/Core/Equation/AMGCLMPITest.cpp index 5f13f201..eeaf0d00 100644 --- a/test/Core/Equation/AMGCLMPITest.cpp +++ b/test/Core/Equation/AMGCLMPITest.cpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/test/Core/Equation/AMGCLTest.cpp b/test/Core/Equation/AMGCLTest.cpp index b2501dc1..ed69c450 100644 --- a/test/Core/Equation/AMGCLTest.cpp +++ b/test/Core/Equation/AMGCLTest.cpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/test/Core/Equation/CSRMatrixGeneratorMPITest.cpp b/test/Core/Equation/CSRMatrixGeneratorMPITest.cpp index 340a2979..c88e47d3 100644 --- a/test/Core/Equation/CSRMatrixGeneratorMPITest.cpp +++ b/test/Core/Equation/CSRMatrixGeneratorMPITest.cpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/test/Core/Equation/CSRMatrixGeneratorTest.cpp b/test/Core/Equation/CSRMatrixGeneratorTest.cpp index cb7d210a..c81c040f 100644 --- a/test/Core/Equation/CSRMatrixGeneratorTest.cpp +++ b/test/Core/Equation/CSRMatrixGeneratorTest.cpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/test/Core/Equation/DircEqnTest.cpp b/test/Core/Equation/DircEqnTest.cpp index 6d589502..086e2ad9 100644 --- a/test/Core/Equation/DircEqnTest.cpp +++ b/test/Core/Equation/DircEqnTest.cpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/test/Core/Equation/EqnHolderTest.cpp b/test/Core/Equation/EqnHolderTest.cpp index 7f207926..af42e09e 100644 --- a/test/Core/Equation/EqnHolderTest.cpp +++ b/test/Core/Equation/EqnHolderTest.cpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/test/Core/Equation/EqnSetMPITest.cpp b/test/Core/Equation/EqnSetMPITest.cpp index d8e11293..f96c06f4 100644 --- a/test/Core/Equation/EqnSetMPITest.cpp +++ b/test/Core/Equation/EqnSetMPITest.cpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/test/Core/Equation/EqnSetTest.cpp b/test/Core/Equation/EqnSetTest.cpp index b3d17ddb..a7f3fa21 100644 --- a/test/Core/Equation/EqnSetTest.cpp +++ b/test/Core/Equation/EqnSetTest.cpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/test/Core/Equation/NeumEqnTest.cpp b/test/Core/Equation/NeumEqnTest.cpp index a3039095..662d99d4 100644 --- a/test/Core/Equation/NeumEqnTest.cpp +++ b/test/Core/Equation/NeumEqnTest.cpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/test/Core/Equation/PeriodicEqnTest.cpp b/test/Core/Equation/PeriodicEqnTest.cpp index 924ff6e2..07841706 100644 --- a/test/Core/Equation/PeriodicEqnTest.cpp +++ b/test/Core/Equation/PeriodicEqnTest.cpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/test/Core/Field/CartesianFieldMPITest.cpp b/test/Core/Field/CartesianFieldMPITest.cpp index 451e6d6d..7ccb6540 100644 --- a/test/Core/Field/CartesianFieldMPITest.cpp +++ b/test/Core/Field/CartesianFieldMPITest.cpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/test/Core/Field/CartesianFieldTest.cpp b/test/Core/Field/CartesianFieldTest.cpp index 5dd7346c..405ec70e 100644 --- a/test/Core/Field/CartesianFieldTest.cpp +++ b/test/Core/Field/CartesianFieldTest.cpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/test/Core/Loops/RangeForTest.cpp b/test/Core/Loops/RangeForTest.cpp index eb0b8fcb..d0d517ee 100644 --- a/test/Core/Loops/RangeForTest.cpp +++ b/test/Core/Loops/RangeForTest.cpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/test/Core/Loops/RangeReduceTest.cpp b/test/Core/Loops/RangeReduceTest.cpp index 383165d1..f4081523 100644 --- a/test/Core/Loops/RangeReduceTest.cpp +++ b/test/Core/Loops/RangeReduceTest.cpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/test/Core/Mesh/CartesianMeshTest.cpp b/test/Core/Mesh/CartesianMeshTest.cpp index 252e9f65..9fd011f3 100644 --- a/test/Core/Mesh/CartesianMeshTest.cpp +++ b/test/Core/Mesh/CartesianMeshTest.cpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/test/Core/MetaTest.cpp b/test/Core/MetaTest.cpp index 33a57a9b..fa085e0a 100644 --- a/test/Core/MetaTest.cpp +++ b/test/Core/MetaTest.cpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/test/Core/Operator/ConditionalTest.cpp b/test/Core/Operator/ConditionalTest.cpp index 6b34f2e2..51d169be 100644 --- a/test/Core/Operator/ConditionalTest.cpp +++ b/test/Core/Operator/ConditionalTest.cpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/test/Core/Operator/ConvolutionTest.cpp b/test/Core/Operator/ConvolutionTest.cpp index b71ecc04..a744b216 100644 --- a/test/Core/Operator/ConvolutionTest.cpp +++ b/test/Core/Operator/ConvolutionTest.cpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/test/Core/Operator/InterpolatorTest.cpp b/test/Core/Operator/InterpolatorTest.cpp index cd872ea9..5233bb4e 100644 --- a/test/Core/Operator/InterpolatorTest.cpp +++ b/test/Core/Operator/InterpolatorTest.cpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/test/Core/Parallel/EvenSplitStrategyTest.cpp b/test/Core/Parallel/EvenSplitStrategyTest.cpp index b2a7b1be..843fd173 100644 --- a/test/Core/Parallel/EvenSplitStrategyTest.cpp +++ b/test/Core/Parallel/EvenSplitStrategyTest.cpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/test/Core/Parallel/ParticleGuidedSplitStrategyTest.cpp b/test/Core/Parallel/ParticleGuidedSplitStrategyTest.cpp index 5cde7a2d..2a561757 100644 --- a/test/Core/Parallel/ParticleGuidedSplitStrategyTest.cpp +++ b/test/Core/Parallel/ParticleGuidedSplitStrategyTest.cpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/test/DataStructures/Arrays/PlainTensorTest.cpp b/test/DataStructures/Arrays/PlainTensorTest.cpp index db285cc3..3f5b2fb8 100644 --- a/test/DataStructures/Arrays/PlainTensorTest.cpp +++ b/test/DataStructures/Arrays/PlainTensorTest.cpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/test/DataStructures/Index/BlockedMDRangeMapperTest.cpp b/test/DataStructures/Index/BlockedMDRangeMapperTest.cpp index 95ba1046..6ff09234 100644 --- a/test/DataStructures/Index/BlockedMDRangeMapperTest.cpp +++ b/test/DataStructures/Index/BlockedMDRangeMapperTest.cpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/test/DataStructures/Index/ColoredBlockedMDRangeMapperTest.cpp b/test/DataStructures/Index/ColoredBlockedMDRangeMapperTest.cpp index 944c498c..1b35b670 100644 --- a/test/DataStructures/Index/ColoredBlockedMDRangeMapperTest.cpp +++ b/test/DataStructures/Index/ColoredBlockedMDRangeMapperTest.cpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/test/DataStructures/Index/MDIndexTest.cpp b/test/DataStructures/Index/MDIndexTest.cpp index 4e439242..780c5d02 100644 --- a/test/DataStructures/Index/MDIndexTest.cpp +++ b/test/DataStructures/Index/MDIndexTest.cpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/test/DataStructures/StencilPadTest.cpp b/test/DataStructures/StencilPadTest.cpp index e5db909d..453504d8 100644 --- a/test/DataStructures/StencilPadTest.cpp +++ b/test/DataStructures/StencilPadTest.cpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/test/Utils/Cpp20CompatibilityTest.cpp b/test/Utils/Cpp20CompatibilityTest.cpp index b6b7361a..1498754b 100644 --- a/test/Utils/Cpp20CompatibilityTest.cpp +++ b/test/Utils/Cpp20CompatibilityTest.cpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/test/Utils/HDF5StreamMPITest.cpp b/test/Utils/HDF5StreamMPITest.cpp index 4be7319c..545d7182 100644 --- a/test/Utils/HDF5StreamMPITest.cpp +++ b/test/Utils/HDF5StreamMPITest.cpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/test/Utils/HDF5StreamTest.cpp b/test/Utils/HDF5StreamTest.cpp index 6291b09d..e871241c 100644 --- a/test/Utils/HDF5StreamTest.cpp +++ b/test/Utils/HDF5StreamTest.cpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/test/Utils/IOGroupTest.cpp b/test/Utils/IOGroupTest.cpp index ce3fa125..c7676167 100644 --- a/test/Utils/IOGroupTest.cpp +++ b/test/Utils/IOGroupTest.cpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/test/Utils/TecplotStreamMPITest.cpp b/test/Utils/TecplotStreamMPITest.cpp index daee0dc1..32676022 100644 --- a/test/Utils/TecplotStreamMPITest.cpp +++ b/test/Utils/TecplotStreamMPITest.cpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/test/Utils/TecplotStreamTest.cpp b/test/Utils/TecplotStreamTest.cpp index 8197af39..203554a4 100644 --- a/test/Utils/TecplotStreamTest.cpp +++ b/test/Utils/TecplotStreamTest.cpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/test/test_main.cpp b/test/test_main.cpp index a4bce062..1cf9dda0 100644 --- a/test/test_main.cpp +++ b/test/test_main.cpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // diff --git a/test/test_main_mpi.cpp b/test/test_main_mpi.cpp index ed74ed90..84382d91 100644 --- a/test/test_main_mpi.cpp +++ b/test/test_main_mpi.cpp @@ -1,6 +1,6 @@ // ---------------------------------------------------------------------------- // -// Copyright (c) 2019 - 2025 by the OpFlow developers +// Copyright (c) 2019 - 2026 by the OpFlow developers // // This file is part of OpFlow. // From 1babc90d91a183eb0959f6b4ec6ae1244fb159c9 Mon Sep 17 00:00:00 2001 From: Luohao Wang Date: Fri, 30 Jan 2026 12:37:43 +0800 Subject: [PATCH 05/14] Improve code quality and C++ standard compliance - Replace std::print with std::format for portability - Avoid chrono time zone APIs (require C++20 timezone support) - Fix amgcl test includes and std::print usage - Update C++ headers to use standard library consistently - Apply code formatting across the codebase Co-Authored-By: Claude Sonnet 4.5 --- .../MeshBased/Structured/CartesianField.hpp | 2 +- src/Core/Loops/RangeFor.hpp | 2 +- .../Mesh/SemiStructured/CartesianAMRMesh.hpp | 18 +++++++-------- .../Solvers/SemiStruct/SemiStructSolver.hpp | 4 ---- src/Core/Solvers/Struct/StructSolver.hpp | 4 ---- .../Solvers/Struct/StructSolverCycRed.hpp | 4 ---- .../LinearMapper/BlockedMDRangeMapper.hpp | 2 +- .../ColoredBlockedMDRangeMapper.hpp | 4 ++-- .../LinearMapper/ColoredMDRangeMapper.hpp | 2 +- src/Utils/Writers/IOGroup.hpp | 4 ++-- test/Core/BC/DircBCTest.cpp | 4 ++++ test/Core/BC/NeumBCTest.cpp | 4 ++++ test/Core/BC/PeriodicBCTest.cpp | 4 ++++ test/Core/Equation/AMGCLMPITest.cpp | 21 +++++++++++++----- test/Core/Equation/AMGCLTest.cpp | 12 +++++++++- .../Equation/CSRMatrixGeneratorMPITest.cpp | 7 +++++- test/Core/Equation/CSRMatrixGeneratorTest.cpp | 9 ++++++-- test/Core/Equation/DircEqnTest.cpp | 21 ++++++++++++++---- test/Core/Equation/EqnHolderTest.cpp | 11 +++++++--- test/Core/Equation/EqnSetMPITest.cpp | 22 +++++++++++++++---- test/Core/Equation/EqnSetTest.cpp | 22 +++++++++++++++---- test/Core/Equation/NeumEqnTest.cpp | 21 ++++++++++++++---- test/Core/Equation/PeriodicEqnTest.cpp | 21 ++++++++++++++---- test/Core/Field/CartesianFieldMPITest.cpp | 11 +++++++--- test/Core/Field/CartesianFieldTest.cpp | 9 ++++++-- test/Core/Loops/RangeForTest.cpp | 7 +++++- test/Core/Loops/RangeReduceTest.cpp | 4 ++++ test/Core/Mesh/CartesianMeshTest.cpp | 4 ++++ test/Core/MetaTest.cpp | 4 ++++ test/Core/Operator/ConditionalTest.cpp | 4 ++++ test/Core/Operator/ConvolutionTest.cpp | 4 ++++ test/Core/Operator/InterpolatorTest.cpp | 9 ++++++-- test/Core/Parallel/EvenSplitStrategyTest.cpp | 4 ++++ test/Core/Parallel/MPITest.cpp | 9 ++++++-- .../ParticleGuidedSplitStrategyTest.cpp | 13 +++++++---- .../DataStructures/Arrays/PlainTensorTest.cpp | 4 ++++ .../Index/BlockedMDRangeMapperTest.cpp | 4 ++++ .../Index/ColoredBlockedMDRangeMapperTest.cpp | 4 ++++ test/DataStructures/Index/MDIndexTest.cpp | 4 ++++ test/DataStructures/StencilPadTest.cpp | 4 ++++ test/Utils/HDF5StreamMPITest.cpp | 11 +++++++--- test/Utils/HDF5StreamTest.cpp | 5 +++++ test/Utils/IOGroupTest.cpp | 7 +++++- test/Utils/TecplotStreamMPITest.cpp | 4 ++++ test/Utils/TecplotStreamTest.cpp | 4 ++++ test/test_main.cpp | 4 ++++ test/test_main_mpi.cpp | 4 ++++ 47 files changed, 287 insertions(+), 79 deletions(-) diff --git a/src/Core/Field/MeshBased/Structured/CartesianField.hpp b/src/Core/Field/MeshBased/Structured/CartesianField.hpp index d5ce4120..6eec6115 100644 --- a/src/Core/Field/MeshBased/Structured/CartesianField.hpp +++ b/src/Core/Field/MeshBased/Structured/CartesianField.hpp @@ -694,7 +694,7 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { else if constexpr (Serializable) { MPI_Isend(send_buff_offsets.back().data(), send_buff_offsets.back().size(), MPI_INT, other_rank, rank, MPI_COMM_WORLD, &requests.back()); - requests.template emplace_back(); + requests.emplace_back(); MPI_Isend(send_buff_byte.back().data(), send_buff_byte.back().size(), MPI_BYTE, other_rank, std::hash> {}(o_recv_range) diff --git a/src/Core/Loops/RangeFor.hpp b/src/Core/Loops/RangeFor.hpp index 3aef96e1..1ff84f25 100644 --- a/src/Core/Loops/RangeFor.hpp +++ b/src/Core/Loops/RangeFor.hpp @@ -112,7 +112,7 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { if (range.stride[0] == 1) { tbb::task_arena arena(getGlobalParallelPlan().shared_memory_workers_count); - arena.template execute([&]() { tbb::parallel_reduce(range, reducer); }); + arena.execute([&]() { tbb::parallel_reduce(range, reducer); }); return reducer.result; } else { OP_NOT_IMPLEMENTED; diff --git a/src/Core/Mesh/SemiStructured/CartesianAMRMesh.hpp b/src/Core/Mesh/SemiStructured/CartesianAMRMesh.hpp index cbdeeff0..0fb77347 100644 --- a/src/Core/Mesh/SemiStructured/CartesianAMRMesh.hpp +++ b/src/Core/Mesh/SemiStructured/CartesianAMRMesh.hpp @@ -68,7 +68,7 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { explicit CartesianAMRMesh(const CartesianMesh &baseMesh) { meshes.push_back(baseMesh); - ranges.template emplace_back(baseMesh.getRange()); + ranges.emplace_back(baseMesh.getRange()); } auto getPtr() const { return this; } @@ -117,7 +117,7 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { auto &setBaseMesh(CartesianMesh &&baseMesh) { ret = CartesianAMRMesh();// clean up ret.ranges.emplace_back(); - ret.ranges.back().template emplace_back(baseMesh.getRange()); + ret.ranges.back().emplace_back(baseMesh.getRange()); ret.meshes.push_back(std::move(baseMesh)); return *this; } @@ -191,7 +191,7 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { range.level = _level - 1; // label all the necessary cells on the current _level rangeFor_s(range, [&](auto &&i) { - if (func(i)) points.template emplace_back(i.get()); + if (func(i)) points.emplace_back(i.get()); }); #ifndef NDEBUG OP_DEBUG("Points at _level {}:", _level - 1); @@ -219,9 +219,9 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { } // label all points in _range rangeFor_s(_range, [&](auto &&i) { - points.template emplace_back(i.get()); + points.emplace_back(i.get()); #ifndef NDEBUG - p_add.template emplace_back(i.get()); + p_add.emplace_back(i.get()); #endif }); } @@ -279,7 +279,7 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { // convert range to cell centered range for (auto i = 0; i < dim; ++i) range.end[i]--; rangeFor_s(range, [&](auto &&i) { - if (func(i)) points.template emplace_back(i.get()); + if (func(i)) points.emplace_back(i.get()); }); } #ifndef NDEBUG @@ -308,9 +308,9 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { } // label all points in _range rangeFor_s(_range, [&](auto &&i) { - points.template emplace_back(i.get()); + points.emplace_back(i.get()); #ifndef NDEBUG - p_add.template emplace_back(i.get()); + p_add.emplace_back(i.get()); #endif }); } @@ -626,7 +626,7 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { auto &setBaseMesh(CartesianMesh &&baseMesh) { ret = CartesianAMRMesh();// clean up ret.ranges.emplace_back(); - ret.ranges.back().template emplace_back(baseMesh.getRange()); + ret.ranges.back().emplace_back(baseMesh.getRange()); ret.meshes.push_back(std::move(baseMesh)); return *this; } diff --git a/src/Core/Solvers/SemiStruct/SemiStructSolver.hpp b/src/Core/Solvers/SemiStruct/SemiStructSolver.hpp index 3edaeddb..ef613775 100644 --- a/src/Core/Solvers/SemiStruct/SemiStructSolver.hpp +++ b/src/Core/Solvers/SemiStruct/SemiStructSolver.hpp @@ -55,11 +55,7 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { // common params std::optional tol {}; std::optional maxIter; -#ifdef OPFLOW_WITH_MPI MPI_Comm comm = MPI_COMM_WORLD; -#else - int comm = 0; -#endif bool staticMat = false; bool pinValue = false; std::optional dumpPath {}; diff --git a/src/Core/Solvers/Struct/StructSolver.hpp b/src/Core/Solvers/Struct/StructSolver.hpp index cdf42e37..ba9cffe1 100644 --- a/src/Core/Solvers/Struct/StructSolver.hpp +++ b/src/Core/Solvers/Struct/StructSolver.hpp @@ -40,11 +40,7 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { // common params std::optional tol {}; std::optional maxIter {}; -#ifdef OPFLOW_WITH_MPI MPI_Comm comm = MPI_COMM_WORLD; -#else - int comm = 0; -#endif bool staticMat = false; bool pinValue = false; std::optional dumpPath {}; diff --git a/src/Core/Solvers/Struct/StructSolverCycRed.hpp b/src/Core/Solvers/Struct/StructSolverCycRed.hpp index 0f64a54f..b8e04b82 100644 --- a/src/Core/Solvers/Struct/StructSolverCycRed.hpp +++ b/src/Core/Solvers/Struct/StructSolverCycRed.hpp @@ -20,11 +20,7 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { struct StructSolverParams { std::optional tDim; std::optional> baseStride; -#ifdef OPFLOW_WITH_MPI MPI_Comm comm = MPI_COMM_WORLD; -#else - int comm = 0; -#endif bool staticMat = false; bool pinValue = false; std::optional dumpPath; diff --git a/src/DataStructures/Index/LinearMapper/BlockedMDRangeMapper.hpp b/src/DataStructures/Index/LinearMapper/BlockedMDRangeMapper.hpp index c5ddeb20..d25c0fd1 100644 --- a/src/DataStructures/Index/LinearMapper/BlockedMDRangeMapper.hpp +++ b/src/DataStructures/Index/LinearMapper/BlockedMDRangeMapper.hpp @@ -153,7 +153,7 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::DS { // We assume here the input _ranges are generated by splitting a range by several orthogonal planes std::vector>> segments(d); for (auto i = 0; i < d; ++i) { - for (const auto& _r : _ranges) { segments[i].template emplace_back(_r.start[i], _r.end[i]); } + for (const auto& _r : _ranges) { segments[i].emplace_back(_r.start[i], _r.end[i]); } std::sort(segments[i].begin(), segments[i].end()); auto end = std::unique(segments[i].begin(), segments[i].end()); segments[i].erase(end, segments[i].end()); diff --git a/src/DataStructures/Index/LinearMapper/ColoredBlockedMDRangeMapper.hpp b/src/DataStructures/Index/LinearMapper/ColoredBlockedMDRangeMapper.hpp index 0b00ed15..cf3c3d79 100644 --- a/src/DataStructures/Index/LinearMapper/ColoredBlockedMDRangeMapper.hpp +++ b/src/DataStructures/Index/LinearMapper/ColoredBlockedMDRangeMapper.hpp @@ -95,12 +95,12 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::DS { } void init_mappers() { - for (const auto& r : ranges) { mappers.template emplace_back(r); } + for (const auto& r : ranges) { mappers.emplace_back(r); } } void init_mappers_mpi() { #ifdef OPFLOW_WITH_MPI - for (const auto& r : localRanges) { mappers.template emplace_back(r); } + for (const auto& r : localRanges) { mappers.emplace_back(r); } #else init_mappers(); #endif diff --git a/src/DataStructures/Index/LinearMapper/ColoredMDRangeMapper.hpp b/src/DataStructures/Index/LinearMapper/ColoredMDRangeMapper.hpp index f0abac76..92a069a2 100644 --- a/src/DataStructures/Index/LinearMapper/ColoredMDRangeMapper.hpp +++ b/src/DataStructures/Index/LinearMapper/ColoredMDRangeMapper.hpp @@ -28,7 +28,7 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::DS { offset.resize(ranges.size() + 1); offset[0] = offset[1] = 0; for (int i = 2; i < offset.size(); ++i) { offset[i] = offset[i - 1] + ranges[i - 2].count(); } - for (const auto& r : ranges) { mappers.template emplace_back(r); } + for (const auto& r : ranges) { mappers.emplace_back(r); } } auto operator()(const ColoredIndex>& idx) const { diff --git a/src/Utils/Writers/IOGroup.hpp b/src/Utils/Writers/IOGroup.hpp index 4c27fe9f..e11e4f46 100644 --- a/src/Utils/Writers/IOGroup.hpp +++ b/src/Utils/Writers/IOGroup.hpp @@ -45,7 +45,7 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::Utils { if constexpr (RStreamType && WStreamType) streams.emplace_back(root + "AllInOne" + Stream::commonSuffix(), mode); else - streams.template emplace_back(root + "AllInOne" + Stream::commonSuffix()); + streams.emplace_back(root + "AllInOne" + Stream::commonSuffix()); } else { Meta::static_for([&](Meta::int_) { auto& e = std::get(exprs); @@ -58,7 +58,7 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::Utils { if constexpr (RStreamType && WStreamType) streams.emplace_back(root + name + Stream::commonSuffix(), mode); else - streams.template emplace_back(root + name + Stream::commonSuffix()); + streams.emplace_back(root + name + Stream::commonSuffix()); }); } if (fixed_mesh) { diff --git a/test/Core/BC/DircBCTest.cpp b/test/Core/BC/DircBCTest.cpp index d765674d..533ec84f 100644 --- a/test/Core/BC/DircBCTest.cpp +++ b/test/Core/BC/DircBCTest.cpp @@ -12,7 +12,11 @@ #include +#ifdef OPFLOW_USE_MODULE import opflow; +#else +#include +#endif using namespace OpFlow; class DircBCTest : public testing::Test { diff --git a/test/Core/BC/NeumBCTest.cpp b/test/Core/BC/NeumBCTest.cpp index b4b0f241..56713242 100644 --- a/test/Core/BC/NeumBCTest.cpp +++ b/test/Core/BC/NeumBCTest.cpp @@ -11,7 +11,11 @@ // ---------------------------------------------------------------------------- #include +#ifdef OPFLOW_USE_MODULE import opflow; +#else +#include +#endif using namespace OpFlow; diff --git a/test/Core/BC/PeriodicBCTest.cpp b/test/Core/BC/PeriodicBCTest.cpp index e85decd7..537b049f 100644 --- a/test/Core/BC/PeriodicBCTest.cpp +++ b/test/Core/BC/PeriodicBCTest.cpp @@ -11,7 +11,11 @@ // ---------------------------------------------------------------------------- #include +#ifdef OPFLOW_USE_MODULE import opflow; +#else +#include +#endif using namespace OpFlow; diff --git a/test/Core/Equation/AMGCLMPITest.cpp b/test/Core/Equation/AMGCLMPITest.cpp index eeaf0d00..baa0d62b 100644 --- a/test/Core/Equation/AMGCLMPITest.cpp +++ b/test/Core/Equation/AMGCLMPITest.cpp @@ -10,9 +10,20 @@ // // ---------------------------------------------------------------------------- +#include +#include +#include +#include +#include +#include +#include #include -#include +#include +#ifdef OPFLOW_USE_MODULE import opflow; +#else +#include +#endif using namespace OpFlow; @@ -73,11 +84,11 @@ class AMGCLMPITest : public testing::Test { auto p_ref = p_true.evalAt(i); auto rel_res = std::abs(c_res) / std::abs(p_ref); if (std::isnan(c_res)) { - std::print(std::cerr, "Check fail: res = nan @ {}", i); + std::cerr << std::format("Check fail: res = nan @ {}", i); ret = false; } if (rel_res > rel) { - std::print(std::cerr, "Check fail: res = {} / {} @ {}", c_res, rel_res, i); + std::cerr << std::format("Check fail: res = {} / {} @ {}", c_res, rel_res, i); ret = false; } }); @@ -196,11 +207,11 @@ class AMGCLManualSplitMPITest : public virtual testing::Test { auto p_ref = p_true.evalAt(i); auto rel_res = std::abs(c_res) / std::abs(p_ref); if (std::isnan(c_res)) { - std::print(std::cerr, "Check fail: res = nan @ {}", i); + std::cerr << std::format("Check fail: res = nan @ {}", i); ret = false; } if (rel_res > rel) { - std::print(std::cerr, "Check fail: res = {} / {} @ {}", c_res, rel_res, i); + std::cerr << std::format("Check fail: res = {} / {} @ {}", c_res, rel_res, i); ret = false; } }); diff --git a/test/Core/Equation/AMGCLTest.cpp b/test/Core/Equation/AMGCLTest.cpp index ed69c450..4914df85 100644 --- a/test/Core/Equation/AMGCLTest.cpp +++ b/test/Core/Equation/AMGCLTest.cpp @@ -12,8 +12,18 @@ // // +#include +#include +#include +#include +#include +#include #include +#ifdef OPFLOW_USE_MODULE import opflow; +#else +#include +#endif using namespace OpFlow; using namespace testing; @@ -50,4 +60,4 @@ TEST(AMGCLTest, Mat1) { ASSERT_NEAR(x[0], -0.375, 1e-10); } -} \ No newline at end of file +} diff --git a/test/Core/Equation/CSRMatrixGeneratorMPITest.cpp b/test/Core/Equation/CSRMatrixGeneratorMPITest.cpp index c88e47d3..f4da0911 100644 --- a/test/Core/Equation/CSRMatrixGeneratorMPITest.cpp +++ b/test/Core/Equation/CSRMatrixGeneratorMPITest.cpp @@ -11,7 +11,12 @@ // ---------------------------------------------------------------------------- #include +#include +#ifdef OPFLOW_USE_MODULE import opflow; +#else +#include +#endif using namespace OpFlow; using namespace testing; @@ -422,4 +427,4 @@ TEST_F(CSRMatrixGeneratorMPITest, XFaceHelmholtz_Periodic) { } else { ASSERT_TRUE(true); } -} \ No newline at end of file +} diff --git a/test/Core/Equation/CSRMatrixGeneratorTest.cpp b/test/Core/Equation/CSRMatrixGeneratorTest.cpp index c81c040f..cc421939 100644 --- a/test/Core/Equation/CSRMatrixGeneratorTest.cpp +++ b/test/Core/Equation/CSRMatrixGeneratorTest.cpp @@ -11,9 +11,14 @@ // ---------------------------------------------------------------------------- //#define OPFLOW_ENABLE_STACK_TRACE 1 +#include #include -#include +#include +#ifdef OPFLOW_USE_MODULE import opflow; +#else +#include +#endif using namespace OpFlow; using namespace testing; @@ -151,7 +156,7 @@ TEST_F(CSRMatrixGeneratorTest, SimplePoisson_Periodic) { -1, 4, -1, -1, -1, 4, -1, -1, -1, -1, -1, 4, -1, -1, -1, -1, 4, -1, 1}, rhs {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}; - std::print("{}", mat.toString()); + std::cout << std::format("{}", mat.toString()); for (int i = 0; i < ptr.size(); ++i) { ASSERT_EQ(ptr[i], mat.row[i]); } for (int i = 0; i < col.size(); ++i) { ASSERT_EQ(col[i], mat.col[i]); } diff --git a/test/Core/Equation/DircEqnTest.cpp b/test/Core/Equation/DircEqnTest.cpp index 086e2ad9..0a1aced2 100644 --- a/test/Core/Equation/DircEqnTest.cpp +++ b/test/Core/Equation/DircEqnTest.cpp @@ -10,9 +10,22 @@ // // ---------------------------------------------------------------------------- +#include +#include +#include +#include +#include +#include +#include +#include +#include #include -#include +#include +#ifdef OPFLOW_USE_MODULE import opflow; +#else +#include +#endif using namespace OpFlow; using namespace testing; @@ -83,11 +96,11 @@ class DircEqnTest : public Test { auto p_ref = p_true.evalAt(i); auto rel_res = std::abs(c_res) / std::abs(p_ref); if (std::isnan(c_res)) { - std::print(std::cerr, "Check fail: res = nan @ {}", i); + std::cerr << std::format("Check fail: res = nan @ {}", i); ret = false; } if (rel_res > rel) { - std::print(std::cerr, "Check fail: res = {} / {} @ {}", c_res, rel_res, i); + std::cerr << std::format("Check fail: res = {} / {} @ {}", c_res, rel_res, i); ret = false; } }); @@ -326,4 +339,4 @@ TEST_F(DircEqnTest, AMGCLHandlerSolveRepeat) { handler->solve(); ASSERT_TRUE(check_solution(1e-8)); } -} \ No newline at end of file +} diff --git a/test/Core/Equation/EqnHolderTest.cpp b/test/Core/Equation/EqnHolderTest.cpp index af42e09e..84337649 100644 --- a/test/Core/Equation/EqnHolderTest.cpp +++ b/test/Core/Equation/EqnHolderTest.cpp @@ -10,9 +10,14 @@ // // ---------------------------------------------------------------------------- +#include #include -#include +#include +#ifdef OPFLOW_USE_MODULE import opflow; +#else +#include +#endif using namespace OpFlow; using namespace testing; @@ -83,11 +88,11 @@ class EqnHolderTest : public Test { auto p_ref = p_true.evalAt(i); auto rel_res = std::abs(c_res) / std::abs(p_ref); if (std::isnan(c_res)) { - std::print(std::cerr, "Check fail: res = nan @ {}", i); + std::cerr << std::format("Check fail: res = nan @ {}", i); ret = false; } if (rel_res > rel) { - std::print(std::cerr, "Check fail: res = {} / {} @ {}", c_res, rel_res, i); + std::cerr << std::format("Check fail: res = {} / {} @ {}", c_res, rel_res, i); ret = false; } }); diff --git a/test/Core/Equation/EqnSetMPITest.cpp b/test/Core/Equation/EqnSetMPITest.cpp index f96c06f4..3410ef19 100644 --- a/test/Core/Equation/EqnSetMPITest.cpp +++ b/test/Core/Equation/EqnSetMPITest.cpp @@ -10,10 +10,21 @@ // // ---------------------------------------------------------------------------- +#include +#include +#include +#include +#include +#include #include +#include #include -#include +#include +#ifdef OPFLOW_USE_MODULE import opflow; +#else +#include +#endif using namespace OpFlow; using namespace testing; @@ -101,7 +112,8 @@ TEST_F(EqnSetMPITest, SimplePoisson_2Eqn) { rangeFor_s(p.getLocalWritableRange(), [&](auto&& k) { if (std::isnan(p[k]) || std::isnan(p_true[k])) { - std::print("p[{}] = {}, p2[{}] = {}, p_true[{}] = {}", k, p[k], k, p2[k], k, p_true[k]); + std::cout << std::format("p[{}] = {}, p2[{}] = {}, p_true[{}] = {}", k, p[k], k, p2[k], k, + p_true[k]); } ASSERT_NEAR(p[k], p_true[k], std::abs(1e-10 * p_true[k])); ASSERT_NEAR(p2[k], p[k], std::abs(1e-10 * p[k])); @@ -157,7 +169,8 @@ TEST_F(EqnSetMPITest, SimplePoisson_Neum_2Eqn) { rangeFor_s(p.getLocalWritableRange(), [&](auto&& k) { if (std::isnan(p[k]) || std::isnan(p_true[k])) { - std::print("p[{}] = {}, p2[{}] = {}, p_true[{}] = {}", k, p[k], k, p2[k], k, p_true[k]); + std::cout << std::format("p[{}] = {}, p2[{}] = {}, p_true[{}] = {}", k, p[k], k, p2[k], k, + p_true[k]); } ASSERT_NEAR(p[k], p_true[k], std::abs(1e-10 * p_true[k])); @@ -248,7 +261,8 @@ TEST_F(EqnSetMPITest, SimplePoisson_10Eqn) { rangeFor_s(p.getLocalWritableRange(), [&](auto&& k) { if (std::isnan(p[k]) || std::isnan(p_true[k])) { - std::print("p[{}] = {}, p2[{}] = {}, p_true[{}] = {}", k, p[k], k, p2[k], k, p_true[k]); + std::cout << std::format("p[{}] = {}, p2[{}] = {}, p_true[{}] = {}", k, p[k], k, p2[k], k, + p_true[k]); } ASSERT_NEAR(p[k], p_true[k], std::abs(1e-10 * p_true[k])); ASSERT_NEAR(p2[k], p[k], std::abs(1e-10 * p[k])); diff --git a/test/Core/Equation/EqnSetTest.cpp b/test/Core/Equation/EqnSetTest.cpp index a7f3fa21..15037ccf 100644 --- a/test/Core/Equation/EqnSetTest.cpp +++ b/test/Core/Equation/EqnSetTest.cpp @@ -10,9 +10,20 @@ // // ---------------------------------------------------------------------------- +#include +#include +#include +#include +#include +#include +#include #include -#include +#include +#ifdef OPFLOW_USE_MODULE import opflow; +#else +#include +#endif using namespace OpFlow; using namespace testing; @@ -100,7 +111,8 @@ TEST_F(EqnSetTest, SimplePoisson_2Eqn) { rangeFor_s(p.assignableRange, [&](auto&& k) { if (std::isnan(p[k]) || std::isnan(p_true[k])) { - std::print("p[{}] = {}, p2[{}] = {}, p_true[{}] = {}", k, p[k], k, p2[k], k, p_true[k]); + std::cout << std::format("p[{}] = {}, p2[{}] = {}, p_true[{}] = {}", k, p[k], k, p2[k], k, + p_true[k]); } ASSERT_NEAR(p[k], p_true[k], std::abs(1e-10 * p_true[k])); ASSERT_NEAR(p2[k], p[k], std::abs(1e-10 * p[k])); @@ -156,7 +168,8 @@ TEST_F(EqnSetTest, SimplePoisson_Neum_2Eqn) { rangeFor_s(p.assignableRange, [&](auto&& k) { if (std::isnan(p[k]) || std::isnan(p_true[k])) { - std::print("p[{}] = {}, p2[{}] = {}, p_true[{}] = {}", k, p[k], k, p2[k], k, p_true[k]); + std::cout << std::format("p[{}] = {}, p2[{}] = {}, p_true[{}] = {}", k, p[k], k, p2[k], k, + p_true[k]); } ASSERT_NEAR(p[k], p_true[k], std::abs(1e-10 * p_true[k])); @@ -245,7 +258,8 @@ TEST_F(EqnSetTest, SimplePoisson_10Eqn) { rangeFor_s(p.assignableRange, [&](auto&& k) { if (std::isnan(p[k]) || std::isnan(p_true[k])) { - std::print("p[{}] = {}, p2[{}] = {}, p_true[{}] = {}", k, p[k], k, p2[k], k, p_true[k]); + std::cout << std::format("p[{}] = {}, p2[{}] = {}, p_true[{}] = {}", k, p[k], k, p2[k], k, + p_true[k]); } ASSERT_NEAR(p[k], p_true[k], std::abs(1e-10 * p_true[k])); ASSERT_NEAR(p2[k], p[k], std::abs(1e-10 * p[k])); diff --git a/test/Core/Equation/NeumEqnTest.cpp b/test/Core/Equation/NeumEqnTest.cpp index 662d99d4..bd10be75 100644 --- a/test/Core/Equation/NeumEqnTest.cpp +++ b/test/Core/Equation/NeumEqnTest.cpp @@ -10,9 +10,22 @@ // // ---------------------------------------------------------------------------- +#include +#include +#include +#include +#include +#include +#include +#include +#include #include -#include +#include +#ifdef OPFLOW_USE_MODULE import opflow; +#else +#include +#endif using namespace OpFlow; using namespace testing; @@ -85,11 +98,11 @@ class NeumEqnTest : public Test { auto p_ref = p_true.evalAt(i); auto rel_res = std::abs(c_res) / std::abs(p_ref); if (std::isnan(c_res)) { - std::print(std::cerr, "Check fail: res = nan @ {}", i); + std::cerr << std::format("Check fail: res = nan @ {}", i); ret = false; } if (rel_res > rel) { - std::print(std::cerr, "Check fail: res = {} / {} @ {}", c_res, rel_res, i); + std::cerr << std::format("Check fail: res = {} / {} @ {}", c_res, rel_res, i); ret = false; } }); @@ -378,4 +391,4 @@ TEST_F(NeumEqnTest, AMGCLUnifiedSolveGMRES) { p.assignableRange, [](auto&& a, auto&& b) { return a + b; }, [&](auto&& idx) { return p[idx]; }); p -= ave_p / p.assignableRange.count(); ASSERT_TRUE(check_solution(1e-10)); -} \ No newline at end of file +} diff --git a/test/Core/Equation/PeriodicEqnTest.cpp b/test/Core/Equation/PeriodicEqnTest.cpp index 07841706..9cc6a7f2 100644 --- a/test/Core/Equation/PeriodicEqnTest.cpp +++ b/test/Core/Equation/PeriodicEqnTest.cpp @@ -10,9 +10,22 @@ // // ---------------------------------------------------------------------------- +#include +#include +#include +#include +#include +#include +#include +#include +#include #include -#include +#include +#ifdef OPFLOW_USE_MODULE import opflow; +#else +#include +#endif using namespace OpFlow; using namespace testing; @@ -81,11 +94,11 @@ class PeriodicEqnTest : public Test { auto p_ref = p_true.evalAt(i); auto rel_res = std::abs(c_res) / std::abs(p_ref); if (std::isnan(c_res)) { - std::print(std::cerr, "Check fail: res = nan @ {}", i); + std::cerr << std::format("Check fail: res = nan @ {}", i); ret = false; } if (rel_res > rel) { - std::print(std::cerr, "Check fail: res = {} / {} @ {}", c_res, rel_res, i); + std::cerr << std::format("Check fail: res = {} / {} @ {}", c_res, rel_res, i); ret = false; } }); @@ -354,4 +367,4 @@ TEST_F(PeriodicEqnTest, AMGCLUnifiedSolveGMRES) { p.assignableRange, [](auto&& a, auto&& b) { return a + b; }, [&](auto&& idx) { return p[idx]; }); p -= ave_p / p.assignableRange.count(); ASSERT_TRUE(check_solution(1e-10)); -} \ No newline at end of file +} diff --git a/test/Core/Field/CartesianFieldMPITest.cpp b/test/Core/Field/CartesianFieldMPITest.cpp index 7ccb6540..3a301a89 100644 --- a/test/Core/Field/CartesianFieldMPITest.cpp +++ b/test/Core/Field/CartesianFieldMPITest.cpp @@ -10,10 +10,15 @@ // // ---------------------------------------------------------------------------- +#include #include -#include +#include #include +#ifdef OPFLOW_USE_MODULE import opflow; +#else +#include +#endif using namespace OpFlow; @@ -129,7 +134,7 @@ TEST_F(CartesianFieldMPITest, PeriodicValueCheck) { u.updatePadding(); u_local.updatePadding(); rangeFor_s(u.getLocalReadableRange(), [&](auto&& i) { - if (u[i] != u_local[i]) std::print("Not equal at {} {} != {}", i, u[i], u_local[i]); + if (u[i] != u_local[i]) std::cout << std::format("Not equal at {} {} != {}", i, u[i], u_local[i]); ASSERT_EQ(u[i], u_local[i]); }); } @@ -160,7 +165,7 @@ TEST_F(CartesianFieldMPITest, Serializable_PeriodicValueCheck) { rangeFor_s(u.getLocalWritableRange(), [&](auto&& i) { u[i] = Int {mapper(i)}; }); u.updatePadding(); rangeFor_s(u.getLocalReadableRange(), [&](auto&& i) { - if (u[i].i != mapper(i)) std::print("Not equal at {} {} != {}", i, u[i].i, mapper(i)); + if (u[i].i != mapper(i)) std::cout << std::format("Not equal at {} {} != {}", i, u[i].i, mapper(i)); ASSERT_EQ(u[i].i, mapper(i)); }); } diff --git a/test/Core/Field/CartesianFieldTest.cpp b/test/Core/Field/CartesianFieldTest.cpp index 405ec70e..ed44ec99 100644 --- a/test/Core/Field/CartesianFieldTest.cpp +++ b/test/Core/Field/CartesianFieldTest.cpp @@ -10,9 +10,14 @@ // // ---------------------------------------------------------------------------- +#include #include -#include +#include +#ifdef OPFLOW_USE_MODULE import opflow; +#else +#include +#endif using namespace OpFlow; @@ -171,7 +176,7 @@ TEST_F(CartesianFieldTest, CenterPeriodicValueCheck) { rangeFor_s(u.getLocalWritableRange(), [&](auto&& i) { u[i] = i[1] * 10 + i[0]; }); u.updatePadding(); rangeFor_s(u.getLocalReadableRange(), [&](auto&& i) { - if (u[i] != (i[1] + 10) % 10 * 10 + (i[0] + 10) % 10) std::print(std::cerr, "Not equal at {}", i); + if (u[i] != (i[1] + 10) % 10 * 10 + (i[0] + 10) % 10) std::cerr << std::format("Not equal at {}", i); ASSERT_DOUBLE_EQ(u[i], (i[1] + 10) % 10 * 10 + (i[0] + 10) % 10); }); } \ No newline at end of file diff --git a/test/Core/Loops/RangeForTest.cpp b/test/Core/Loops/RangeForTest.cpp index d0d517ee..7b06583c 100644 --- a/test/Core/Loops/RangeForTest.cpp +++ b/test/Core/Loops/RangeForTest.cpp @@ -10,9 +10,14 @@ // // ---------------------------------------------------------------------------- +#include #include #include +#ifdef OPFLOW_USE_MODULE import opflow; +#else +#include +#endif using namespace OpFlow; using namespace testing; @@ -160,4 +165,4 @@ TEST_F(RangeForTest, 3D) { for (int i = 0; i < 100; ++i) for (int j = 0; j < 100; ++j) for (int k = 0; k < 100; ++k) { ASSERT_EQ(a[i][j][k], 1); } -} \ No newline at end of file +} diff --git a/test/Core/Loops/RangeReduceTest.cpp b/test/Core/Loops/RangeReduceTest.cpp index f4081523..3f1cf3e2 100644 --- a/test/Core/Loops/RangeReduceTest.cpp +++ b/test/Core/Loops/RangeReduceTest.cpp @@ -12,7 +12,11 @@ #include #include +#ifdef OPFLOW_USE_MODULE import opflow; +#else +#include +#endif using namespace OpFlow; using namespace testing; diff --git a/test/Core/Mesh/CartesianMeshTest.cpp b/test/Core/Mesh/CartesianMeshTest.cpp index 9fd011f3..d27a58d5 100644 --- a/test/Core/Mesh/CartesianMeshTest.cpp +++ b/test/Core/Mesh/CartesianMeshTest.cpp @@ -13,7 +13,11 @@ #include #include +#ifdef OPFLOW_USE_MODULE import opflow; +#else +#include +#endif using namespace OpFlow; using namespace OpFlow::Meta; diff --git a/test/Core/MetaTest.cpp b/test/Core/MetaTest.cpp index fa085e0a..b0be93ba 100644 --- a/test/Core/MetaTest.cpp +++ b/test/Core/MetaTest.cpp @@ -12,7 +12,11 @@ #include +#ifdef OPFLOW_USE_MODULE import opflow; +#else +#include +#endif using namespace OpFlow; TEST(MetaTest, StaticFor) { diff --git a/test/Core/Operator/ConditionalTest.cpp b/test/Core/Operator/ConditionalTest.cpp index 51d169be..a9879d40 100644 --- a/test/Core/Operator/ConditionalTest.cpp +++ b/test/Core/Operator/ConditionalTest.cpp @@ -11,7 +11,11 @@ // ---------------------------------------------------------------------------- #include +#ifdef OPFLOW_USE_MODULE import opflow; +#else +#include +#endif using namespace OpFlow; using namespace testing; diff --git a/test/Core/Operator/ConvolutionTest.cpp b/test/Core/Operator/ConvolutionTest.cpp index a744b216..50e1936d 100644 --- a/test/Core/Operator/ConvolutionTest.cpp +++ b/test/Core/Operator/ConvolutionTest.cpp @@ -11,7 +11,11 @@ // ---------------------------------------------------------------------------- #include +#ifdef OPFLOW_USE_MODULE import opflow; +#else +#include +#endif using namespace OpFlow; using namespace testing; diff --git a/test/Core/Operator/InterpolatorTest.cpp b/test/Core/Operator/InterpolatorTest.cpp index 5233bb4e..cc80117b 100644 --- a/test/Core/Operator/InterpolatorTest.cpp +++ b/test/Core/Operator/InterpolatorTest.cpp @@ -10,9 +10,14 @@ // // ---------------------------------------------------------------------------- +#include #include -#include +#include +#ifdef OPFLOW_USE_MODULE import opflow; +#else +#include +#endif using namespace OpFlow; using namespace testing; @@ -163,7 +168,7 @@ TEST_F(Intp1DFluxLimiterCornerToCenterTest, ValueCheck) { auto t = d1IntpCornerToCenter<0, D1QUICK>(-v, u); t.prepare(); rangeFor_s(t.accessibleRange, [&](auto&& i) { - std::print("t = {}, v = {}, i = {}", t[i], v[i], i); + std::cout << std::format("t = {}, v = {}, i = {}", t[i], v[i], i); ASSERT_NEAR(t[i], v[i], 1e-10); }); } \ No newline at end of file diff --git a/test/Core/Parallel/EvenSplitStrategyTest.cpp b/test/Core/Parallel/EvenSplitStrategyTest.cpp index 843fd173..8c1f54de 100644 --- a/test/Core/Parallel/EvenSplitStrategyTest.cpp +++ b/test/Core/Parallel/EvenSplitStrategyTest.cpp @@ -13,7 +13,11 @@ // #include +#ifdef OPFLOW_USE_MODULE import opflow; +#else +#include +#endif using namespace OpFlow; using namespace testing; diff --git a/test/Core/Parallel/MPITest.cpp b/test/Core/Parallel/MPITest.cpp index 08b98212..f99dd562 100644 --- a/test/Core/Parallel/MPITest.cpp +++ b/test/Core/Parallel/MPITest.cpp @@ -1,9 +1,14 @@ +#include #include -#include +#include +#ifdef OPFLOW_USE_MODULE import opflow; +#else +#include +#endif TEST(MPITest, RankTest) { auto rank = OpFlow::getWorkerId(); - std::print("My ID = {}", rank); + std::cout << std::format("My ID = {}", rank); ASSERT_TRUE(true); } \ No newline at end of file diff --git a/test/Core/Parallel/ParticleGuidedSplitStrategyTest.cpp b/test/Core/Parallel/ParticleGuidedSplitStrategyTest.cpp index 2a561757..6cf158cb 100644 --- a/test/Core/Parallel/ParticleGuidedSplitStrategyTest.cpp +++ b/test/Core/Parallel/ParticleGuidedSplitStrategyTest.cpp @@ -10,9 +10,14 @@ // // ---------------------------------------------------------------------------- +#include #include -#include +#include +#ifdef OPFLOW_USE_MODULE import opflow; +#else +#include +#endif using namespace OpFlow; using namespace testing; @@ -66,7 +71,7 @@ TEST_F(ParticleGuidedSplitStrategyTest, DivisibleDimWithParticle) { strategy.setParticleLoad(100); // input nodal range, return centered range auto map = strategy.getSplitMap(range, plan); - for (auto& m : map) std::print("{}", m.toString()); + for (auto& m : map) std::cout << std::format("{}", m.toString()); ASSERT_TRUE((map[0] == DS::Range<2> {std::array {15, 13}})); ASSERT_TRUE((map[2] == DS::Range<2> {std::array {15, 0}, std::array {32, 16}})); ASSERT_TRUE((map[1] == DS::Range<2> {std::array {0, 13}, std::array {15, 32}})); @@ -106,7 +111,7 @@ TEST_F(ParticleGuidedSplitStrategyTest, UnDivisibleDim) { strategy.setRefMesh(mesh); // input nodal range, return centered range auto map = strategy.getSplitMap(range, plan); - for (auto& m : map) std::print("{}", m.toString()); + for (auto& m : map) std::cout << std::format("{}", m.toString()); ASSERT_TRUE((map[0] == DS::Range<2> {std::array {17, 17}})); ASSERT_TRUE((map[2] == DS::Range<2> {std::array {17, 0}, std::array {33, 17}})); ASSERT_TRUE((map[1] == DS::Range<2> {std::array {0, 17}, std::array {17, 33}})); @@ -166,7 +171,7 @@ TEST_F(ParticleGuidedSplitStrategyTest, WithOffset) { strategy.setRefMesh(mesh); // input nodal range, return centered range auto map = strategy.getSplitMap(range, plan); - for (auto& m : map) std::print("{}", m.toString()); + for (auto& m : map) std::cout << std::format("{}", m.toString()); ASSERT_TRUE((map[0] == DS::Range<2> {std::array {3, 3}, std::array {19, 19}})); ASSERT_TRUE((map[2] == DS::Range<2> {std::array {19, 3}, std::array {35, 19}})); ASSERT_TRUE((map[1] == DS::Range<2> {std::array {3, 19}, std::array {19, 35}})); diff --git a/test/DataStructures/Arrays/PlainTensorTest.cpp b/test/DataStructures/Arrays/PlainTensorTest.cpp index 3f5b2fb8..5c3283a5 100644 --- a/test/DataStructures/Arrays/PlainTensorTest.cpp +++ b/test/DataStructures/Arrays/PlainTensorTest.cpp @@ -11,7 +11,11 @@ // ---------------------------------------------------------------------------- #include +#ifdef OPFLOW_USE_MODULE import opflow; +#else +#include +#endif using namespace OpFlow; using namespace OpFlow::DS; diff --git a/test/DataStructures/Index/BlockedMDRangeMapperTest.cpp b/test/DataStructures/Index/BlockedMDRangeMapperTest.cpp index 6ff09234..958187f9 100644 --- a/test/DataStructures/Index/BlockedMDRangeMapperTest.cpp +++ b/test/DataStructures/Index/BlockedMDRangeMapperTest.cpp @@ -11,7 +11,11 @@ // ---------------------------------------------------------------------------- #include +#ifdef OPFLOW_USE_MODULE import opflow; +#else +#include +#endif using namespace OpFlow; using namespace testing; diff --git a/test/DataStructures/Index/ColoredBlockedMDRangeMapperTest.cpp b/test/DataStructures/Index/ColoredBlockedMDRangeMapperTest.cpp index 1b35b670..8e7481b3 100644 --- a/test/DataStructures/Index/ColoredBlockedMDRangeMapperTest.cpp +++ b/test/DataStructures/Index/ColoredBlockedMDRangeMapperTest.cpp @@ -11,7 +11,11 @@ // ---------------------------------------------------------------------------- #include +#ifdef OPFLOW_USE_MODULE import opflow; +#else +#include +#endif using namespace OpFlow; using namespace testing; diff --git a/test/DataStructures/Index/MDIndexTest.cpp b/test/DataStructures/Index/MDIndexTest.cpp index 780c5d02..0000f443 100644 --- a/test/DataStructures/Index/MDIndexTest.cpp +++ b/test/DataStructures/Index/MDIndexTest.cpp @@ -11,7 +11,11 @@ // ---------------------------------------------------------------------------- #include +#ifdef OPFLOW_USE_MODULE import opflow; +#else +#include +#endif using namespace OpFlow; diff --git a/test/DataStructures/StencilPadTest.cpp b/test/DataStructures/StencilPadTest.cpp index 453504d8..0f139eeb 100644 --- a/test/DataStructures/StencilPadTest.cpp +++ b/test/DataStructures/StencilPadTest.cpp @@ -11,7 +11,11 @@ // ---------------------------------------------------------------------------- #include +#ifdef OPFLOW_USE_MODULE import opflow; +#else +#include +#endif using namespace OpFlow; using namespace testing; diff --git a/test/Utils/HDF5StreamMPITest.cpp b/test/Utils/HDF5StreamMPITest.cpp index 545d7182..8a820f3b 100644 --- a/test/Utils/HDF5StreamMPITest.cpp +++ b/test/Utils/HDF5StreamMPITest.cpp @@ -10,9 +10,14 @@ // // ---------------------------------------------------------------------------- +#include #include -#include +#include +#ifdef OPFLOW_USE_MODULE import opflow; +#else +#include +#endif using namespace OpFlow; @@ -80,7 +85,7 @@ TEST_F(H5RWMPITest, ReadAfterWrite) { Utils::H5Stream istream(filename, StreamIn); istream >> v; rangeFor_s(u.getLocalReadableRange(), [&](auto i) { - if (u[i] != v[i]) std::print(std::cerr, "NOT EQUAL AT {}", i); + if (u[i] != v[i]) std::cerr << std::format("NOT EQUAL AT {}", i); ASSERT_EQ(u[i], v[i]); }); } @@ -138,7 +143,7 @@ TEST_F(H5RWMPITest, GeneralSplitWite) { Utils::H5Stream stream("./u.general.split.h5"); stream << Utils::TimeStamp(0) << u; u.resplitWithStrategy(s.get()); - std::print("local range = {}", u.localRange.toString()); + std::cout << std::format("local range = {}", u.localRange.toString()); stream << Utils::TimeStamp(1.) << u; u.initBy([](auto&& x) { return getWorkerId(); }); stream << Utils::TimeStamp(2) << u; diff --git a/test/Utils/HDF5StreamTest.cpp b/test/Utils/HDF5StreamTest.cpp index e871241c..89cf1ed1 100644 --- a/test/Utils/HDF5StreamTest.cpp +++ b/test/Utils/HDF5StreamTest.cpp @@ -10,8 +10,13 @@ // // ---------------------------------------------------------------------------- +#include #include +#ifdef OPFLOW_USE_MODULE import opflow; +#else +#include +#endif using namespace OpFlow; diff --git a/test/Utils/IOGroupTest.cpp b/test/Utils/IOGroupTest.cpp index c7676167..019d0ff3 100644 --- a/test/Utils/IOGroupTest.cpp +++ b/test/Utils/IOGroupTest.cpp @@ -10,8 +10,13 @@ // // ---------------------------------------------------------------------------- +#include #include +#ifdef OPFLOW_USE_MODULE import opflow; +#else +#include +#endif using namespace OpFlow; @@ -242,4 +247,4 @@ TEST(IOGroupTest, Expression) { group.dump(Utils::TimeStamp(0.)); ASSERT_TRUE(true); -} \ No newline at end of file +} diff --git a/test/Utils/TecplotStreamMPITest.cpp b/test/Utils/TecplotStreamMPITest.cpp index 32676022..1c9077aa 100644 --- a/test/Utils/TecplotStreamMPITest.cpp +++ b/test/Utils/TecplotStreamMPITest.cpp @@ -11,7 +11,11 @@ // ---------------------------------------------------------------------------- #include +#ifdef OPFLOW_USE_MODULE import opflow; +#else +#include +#endif class TecIOMPITest : public virtual testing::Test { protected: diff --git a/test/Utils/TecplotStreamTest.cpp b/test/Utils/TecplotStreamTest.cpp index 203554a4..a3a58620 100644 --- a/test/Utils/TecplotStreamTest.cpp +++ b/test/Utils/TecplotStreamTest.cpp @@ -11,7 +11,11 @@ // ---------------------------------------------------------------------------- #include +#ifdef OPFLOW_USE_MODULE import opflow; +#else +#include +#endif TEST(TecIOTest, BinaryTest) { using namespace OpFlow; diff --git a/test/test_main.cpp b/test/test_main.cpp index 1cf9dda0..f9fb6170 100644 --- a/test/test_main.cpp +++ b/test/test_main.cpp @@ -11,7 +11,11 @@ // ---------------------------------------------------------------------------- #include +#ifdef OPFLOW_USE_MODULE import opflow; +#else +#include +#endif int main(int argc, char** argv) { // Filter out Google Test arguments diff --git a/test/test_main_mpi.cpp b/test/test_main_mpi.cpp index 84382d91..46ed75c3 100644 --- a/test/test_main_mpi.cpp +++ b/test/test_main_mpi.cpp @@ -12,7 +12,11 @@ #include "gtest-mpi-listener.hpp" #include +#ifdef OPFLOW_USE_MODULE import opflow; +#else +#include +#endif int main(int argc, char** argv) { // Filter out Google Test arguments From ffce3b362c28c6ca881809d17683e249a89c4469 Mon Sep 17 00:00:00 2001 From: Luohao Wang Date: Mon, 2 Feb 2026 17:34:07 +0800 Subject: [PATCH 06/14] [CI] Fix warnings --- src/Core/Loops/RangeFor.hpp | 4 ++-- src/Core/Macros.hpp | 2 +- src/DataStructures/Index/MDIndex.hpp | 8 ++++---- src/DataStructures/Matrix/CSRMatrix.hpp | 14 +++++++++----- src/DataStructures/Range/Ranges.hpp | 2 +- src/Utils/Writers/HDF5Stream.hpp | 2 +- src/Utils/Writers/IOGroup.hpp | 2 +- test/gtest-mpi-listener.hpp | 2 +- 8 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/Core/Loops/RangeFor.hpp b/src/Core/Loops/RangeFor.hpp index 1ff84f25..eefae395 100644 --- a/src/Core/Loops/RangeFor.hpp +++ b/src/Core/Loops/RangeFor.hpp @@ -67,8 +67,8 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { /// \return The input functor template F rangeFor(const R& range, F&& func) { - constexpr static auto dim = R::dim; - auto total_count = range.count(); + [[maybe_unused]] constexpr static auto dim = R::dim; + [[maybe_unused]] auto total_count = range.count(); auto line_size = range.end[0] - range.start[0]; if (line_size <= 0) return std::forward(func); if (range.stride[0] == 1) { diff --git a/src/Core/Macros.hpp b/src/Core/Macros.hpp index 20159d8c..85409e7b 100644 --- a/src/Core/Macros.hpp +++ b/src/Core/Macros.hpp @@ -257,7 +257,7 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { inline Utils::StackTracer stackTracer; } do { \ int _rank; \ MPI_Comm_rank(MPI_COMM_WORLD, &_rank); \ - if (_rank == 0) OP_WARN(__VA_ARGS__); \ + if (_rank == 0) { OP_WARN(__VA_ARGS__); } \ } while (0) #define OP_MPI_MASTER_DEBUG(...) \ do { \ diff --git a/src/DataStructures/Index/MDIndex.hpp b/src/DataStructures/Index/MDIndex.hpp index 9dd3019b..4347d866 100644 --- a/src/DataStructures/Index/MDIndex.hpp +++ b/src/DataStructures/Index/MDIndex.hpp @@ -74,19 +74,19 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::DS { constexpr bool operator==(const Meta::BracketIndexable auto& index) const { auto ret = true; - for (auto i = 0; i < d; ++i) ret &= this->idx[i] == index[i]; + for (std::size_t i = 0; i < d; ++i) ret &= this->idx[i] == index[i]; return ret; } constexpr auto operator+(const MDIndex& index) const { MDIndex ret; - for (auto i = 0; i < d; ++i) ret[i] = this->idx[i] + index[i]; + for (std::size_t i = 0; i < d; ++i) ret[i] = this->idx[i] + index[i]; return ret; } constexpr auto operator-(const MDIndex& index) const { MDIndex ret; - for (auto i = 0; i < d; ++i) ret[i] = this->idx[i] - index[i]; + for (std::size_t i = 0; i < d; ++i) ret[i] = this->idx[i] - index[i]; return ret; } @@ -133,7 +133,7 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::DS { while (n-- > 0) ret += prefix; ret += "{"; if constexpr (d > 0) ret += std::format("{}", idx[0]); - for (auto i = 1; i < d; ++i) ret += std::format(", {}", idx[i]); + for (std::size_t i = 1; i < d; ++i) ret += std::format(", {}", idx[i]); ret += "}"; return ret; } diff --git a/src/DataStructures/Matrix/CSRMatrix.hpp b/src/DataStructures/Matrix/CSRMatrix.hpp index 78a991ef..dbed9a47 100644 --- a/src/DataStructures/Matrix/CSRMatrix.hpp +++ b/src/DataStructures/Matrix/CSRMatrix.hpp @@ -22,7 +22,7 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::DS { struct CSRMatrix { - CSRMatrix() : row(1), col(0), rhs(0), val(0) { row[0] = 0; } + CSRMatrix() : row(1), col(0), val(0), rhs(0) { row[0] = 0; } CSRMatrix(int n_row, int nnz_per_row) { resize(n_row, nnz_per_row); } void resize(int n_row, int nnz_per_row) { @@ -78,13 +78,17 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::DS { int base_row = row.size(), base_rhs = rhs.size(), offset = row.back(); row.resize(row.size() + mat.row.size() - 1); rhs.resize(rhs.size() + mat.rhs.size()); - for (int i = 0; i < mat.row.size() - 1; ++i) row[base_row + i] = mat.row[i + 1] + offset; - for (int i = 0; i < mat.rhs.size(); ++i) rhs[base_rhs + i] = mat.rhs[i]; + std::size_t row_limit = mat.row.size() > 0 ? mat.row.size() - 1 : 0; + for (std::size_t i = 0; i < row_limit; ++i) row[base_row + i] = mat.row[i + 1] + offset; + std::size_t rhs_limit = mat.rhs.size(); + for (std::size_t i = 0; i < rhs_limit; ++i) rhs[base_rhs + i] = mat.rhs[i]; int base_col = col.size(); col.resize(col.size() + mat.col.size()); val.resize(val.size() + mat.val.size()); - for (int i = 0; i < mat.col.size(); ++i) col[base_col + i] = mat.col[i]; - for (int i = 0; i < mat.val.size(); ++i) val[base_col + i] = mat.val[i]; + std::size_t col_limit = mat.col.size(); + for (std::size_t i = 0; i < col_limit; ++i) col[base_col + i] = mat.col[i]; + std::size_t val_limit = mat.val.size(); + for (std::size_t i = 0; i < val_limit; ++i) val[base_col + i] = mat.val[i]; } void update_rhs(int from, const std::vector& r) { diff --git a/src/DataStructures/Range/Ranges.hpp b/src/DataStructures/Range/Ranges.hpp index 50ed4253..4d605ced 100644 --- a/src/DataStructures/Range/Ranges.hpp +++ b/src/DataStructures/Range/Ranges.hpp @@ -195,7 +195,7 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::DS { return false; } - Range(Range& r, tbb::detail::split split) : Range(r) { + Range(Range& r, [[maybe_unused]] tbb::detail::split split) : Range(r) { this->reValidPace(); int max_iter = std::max_element(pace.begin(), pace.end()) - pace.begin(); this->end[max_iter] = this->start[max_iter] + this->pace[max_iter] / 2; diff --git a/src/Utils/Writers/HDF5Stream.hpp b/src/Utils/Writers/HDF5Stream.hpp index c801a9f4..3f1a1098 100644 --- a/src/Utils/Writers/HDF5Stream.hpp +++ b/src/Utils/Writers/HDF5Stream.hpp @@ -50,7 +50,7 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::Utils { #endif time(other.time), first_run(other.first_run), file_inited(other.file_inited), group_inited(other.group_inited), fixed_mesh(other.fixed_mesh), write_mesh(other.write_mesh), - mode(other.mode), separate_file(other.separate_file) + separate_file(other.separate_file), mode(other.mode) #ifdef OPFLOW_WITH_MPI , mpi_comm(other.mpi_comm) diff --git a/src/Utils/Writers/IOGroup.hpp b/src/Utils/Writers/IOGroup.hpp index e11e4f46..3920425f 100644 --- a/src/Utils/Writers/IOGroup.hpp +++ b/src/Utils/Writers/IOGroup.hpp @@ -23,7 +23,7 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::Utils { struct IOGroupInterface { virtual ~IOGroupInterface() = default; virtual void dump(const TimeStamp& t) = 0; - virtual void read(const TimeStamp& t) {} + virtual void read([[maybe_unused]] const TimeStamp& t) {} virtual void setAllInOne(bool o) = 0; virtual void fixedMesh() {} virtual void dumpToSeparateFile() {} diff --git a/test/gtest-mpi-listener.hpp b/test/gtest-mpi-listener.hpp index 2a2579fa..9e7c3e5d 100644 --- a/test/gtest-mpi-listener.hpp +++ b/test/gtest-mpi-listener.hpp @@ -89,7 +89,7 @@ namespace GTestMPIListener { private: // Disallow copying - MPIEnvironment(const MPIEnvironment &env) {} + MPIEnvironment([[maybe_unused]] const MPIEnvironment &env) {} };// class MPIEnvironment From 289cc456796efd8982027b62b0c1b9465a580395 Mon Sep 17 00:00:00 2001 From: Luohao Wang Date: Mon, 2 Feb 2026 17:35:27 +0800 Subject: [PATCH 07/14] [Core] Upgrade to C++26 --- src/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f1f2f8f9..a9815717 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -42,11 +42,11 @@ if(OPFLOW_ENABLE_MODULE) FILE_SET HEADERS DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) else() # ---------------------------------------------------------------------------- - # C++20 header only version + # C++26 header only version # ---------------------------------------------------------------------------- add_library(opflow INTERFACE) set_property(TARGET opflow PROPERTY CXX_SCAN_FOR_MODULES OFF) - target_compile_features(opflow INTERFACE cxx_std_20) + target_compile_features(opflow INTERFACE cxx_std_26) target_sources(opflow INTERFACE FILE_SET HEADERS BASE_DIRS From c2d209f6eae3f9622d778635a0589a68f4a3d674 Mon Sep 17 00:00:00 2001 From: Luohao Wang Date: Mon, 2 Feb 2026 17:35:43 +0800 Subject: [PATCH 08/14] [Misc] Add CLAUDE.md --- CLAUDE.md | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..517cb8ab --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,112 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +OpFlow (运筹) is an embedded domain-specific language (EDSL) for PDE solver development in modern C++. It uses expression templates and meta-programming to provide mathematical notation while maintaining zero-cost abstractions and automatic parallelization. + +**Key characteristics:** +- Header-only library (with experimental C++20 module support) +- Requires GCC 15+ or Clang 21+, C++23 minimum (C++26 for modules) +- Uses CMake 4.0.2+ build system + +## Build Commands + +```bash +# Basic build with tests and examples +mkdir build && cd build +cmake -DCMAKE_C_COMPILER=gcc-15 -DCMAKE_CXX_COMPILER=g++-15 \ + -DOPFLOW_BUILD_TESTS=ON -DOPFLOW_BUILD_EXAMPLES=ON .. +cmake --build . -j$(nproc) + +# Build a specific example +cmake --build . -t CONV1D + +# Build all tests +cmake --build . -t AllTests + +# Run all tests +ctest --parallel $(nproc) -VV + +# Build with MPI support +cmake -DOPFLOW_WITH_MPI=ON .. + +# Build with C++20 modules (Clang only) +cmake -DOPFLOW_ENABLE_MODULE=ON .. +``` + +**Key CMake options:** +- `-DOPFLOW_BUILD_TESTS=ON` - Build tests +- `-DOPFLOW_BUILD_EXAMPLES=ON` - Build examples +- `-DOPFLOW_WITH_MPI=ON` - Enable MPI (off by default) +- `-DOPFLOW_WITH_OPENMP=ON` - Enable OpenMP (on by default) +- `-DOPFLOW_WITH_HDF5=ON` - Enable HDF5 I/O +- `-DOPFLOW_SINGLE_PRECISION=ON` - Use float instead of double +- `-DOPFLOW_TBB_EXTERNAL=ON` - Use system TBB instead of bundled + +## Architecture + +### Core Modules (src/Core/) + +1. **Field** - Field types representing physical quantities + - `Analytical` - Analytically defined fields + - `MeshBased` - Fields on structured/semi-structured/unstructured meshes + - `ParticleBased` - Particle fields + +2. **Mesh** - Mesh infrastructure + - `CartesianMesh` - Structured Cartesian grids + - `CartesianAMRMesh` - Adaptive mesh refinement + +3. **Expr** - Expression template system + - Base expression types with compile-time type deduction + - Enables mathematical notation with zero runtime overhead + +4. **Operator** - Discrete operators + - `FDM/` - Finite difference (D1FirstOrderBiasedDownwind, D1WENO5, etc.) + - `Interpolation/` - Linear interpolation, flux limiters + - `Logical/` - Boolean and comparison operations + - `Conditional/` - If-then-else expressions + +5. **BC** - Boundary conditions + - `DircBC` - Dirichlet + - `NeumBC` - Neumann + - `LogicalBC`, `ProxyBC` - Advanced BC types + +6. **Equation** - Implicit equation solving + - Stencil auto-generation from expressions + - `HYPREEqnSolveHandler`, `AMGCLEqnSolveHandler` + +7. **Parallel** - Parallelization strategies + - `EvenSplitStrategy`, `ParticleGuidedSplitStrategy` + - OpenMP and MPI backends + +### External Dependencies (external/) + +Bundled libraries: AMGCL, Google Test, HYPRE, spdlog, fmt, TBB + +## Testing + +Tests use Google Test and are organized in `test/Core/`, `test/DataStructures/`, `test/Utils/`. + +```bash +# Build and run all tests +cmake --build . -t AllTests && ctest -VV + +# Build combined test executable +cmake --build . -t UniTests + +# MPI tests run with varying process counts automatically +``` + +## Code Patterns + +- **Concepts-heavy**: Extensive use of C++20 concepts for type constraints +- **CRTP**: Curiously Recurring Template Pattern for static polymorphism +- **Expression templates**: Mathematical operations build expression trees evaluated lazily +- **Trait system**: `FieldTrait`, `MeshTrait`, `ExprTrait` for compile-time metadata + +## Platform Notes + +- macOS: Requires libomp from Homebrew for OpenMP; uses `-Wl,-ld_classic` linker flag on macOS 14+ +- Platform macros: `OPFLOW_PLATFORM_UNIX`, `OPFLOW_PLATFORM_APPLE`, `OPFLOW_PLATFORM_WIN` \ No newline at end of file From bf8623082d0be9c0fe3f351198f2ace046f7ccda Mon Sep 17 00:00:00 2001 From: Luohao Wang Date: Mon, 2 Feb 2026 18:38:33 +0800 Subject: [PATCH 09/14] Enable -Wall -Werror --- src/CMakeLists.txt | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a9815717..0c042dc9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -125,3 +125,23 @@ target_link_options(opflow INTERFACE $<$: -fsanitize=leak> INTERFACE $<$: -fsanitize=thread> INTERFACE $<$: -fsanitize=undefined>) + +# ---------------------------------------------------------------------------- +# Compiler warnings +# ---------------------------------------------------------------------------- +# Enable strict warnings and treat warnings as errors by default + +if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + target_compile_options(opflow ${OPFLOW_TARGET_SCOPE} + -Wall + -Wextra + -Werror + ) +endif() +# MSVC-specific warnings +if(MSVC) + target_compile_options(opflow ${OPFLOW_TARGET_SCOPE} + /W4 + /WX + ) +endif() From fa8d2dbcb3f20ab676a1ac91346580c30a151bed Mon Sep 17 00:00:00 2001 From: Luohao Wang Date: Mon, 2 Feb 2026 18:51:55 +0800 Subject: [PATCH 10/14] Fix abi warning --- CMakeLists.txt | 7 ++----- src/CMakeLists.txt | 2 ++ 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cb3e5970..f19180fe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,8 +46,6 @@ project(opflow VERSION ${OPFLOW_VERSION} LANGUAGES C CXX) set(OPFLOW_VERSION_STRING "${OPFLOW_VERSION} - ${SHORT_SHA1} - ${GIT_CHANGE}") message(STATUS "Build opflow: ${OPFLOW_VERSION_STRING}") -set(CMAKE_CXX_MODULE_STD 1) - include(GNUInstallDirs) # ---------------------------------------------------------------------------- @@ -72,8 +70,7 @@ if(MSVC) string(APPEND CMAKE_CXX_FLAGS " /Zc:__cplusplus /wd4267 /wd4390 /wd4244") endif() -# supress possible abi warning by upgrade compiler -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-psabi") +# ABI warning suppression moved to target-specific compile options # temporary fix for macOS 14 & CLT 15 if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_HOST_SYSTEM_VERSION VERSION_GREATER_EQUAL 23) @@ -131,10 +128,10 @@ option(OPFLOW_SANITIZE_THREAD "Enable thread sanitizer in tests" OFF) option(OPFLOW_SANITIZE_UB "Enable undefined behavior sanitizer in tests" OFF) # compile options -option(OPFLOW_BUILD_WARNINGS "Enable compiler warnings" OFF) option(OPFLOW_NO_EXCEPTIONS "Compile with -fno-exceptions" OFF) option(OPFLOW_ENABLE_MODULE "Enable C++ modules support" OFF) if(OPFLOW_ENABLE_MODULE) + set(CMAKE_CXX_MODULE_STD 1) set(OPFLOW_TARGET_SCOPE PUBLIC) else() set(OPFLOW_TARGET_SCOPE INTERFACE) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0c042dc9..e71d147c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -136,6 +136,8 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") -Wall -Wextra -Werror + # Suppress possible ABI warning from compiler upgrades + -Wno-psabi ) endif() # MSVC-specific warnings From 71fd774aacf00ce4ee459afd352bbc390e2dc994 Mon Sep 17 00:00:00 2001 From: Luohao Wang Date: Mon, 2 Feb 2026 19:31:57 +0800 Subject: [PATCH 11/14] Fix compile warnings --- src/Core/BC/NeumBC.hpp | 74 +- src/Core/Equation/AMGCLBackend.hpp | 53 +- src/Core/Equation/CSRMatrixGenerator.hpp | 4 - src/Core/Equation/EquationHolder.hpp | 2 - src/Core/Equation/HYPREEqnSolveHandler.hpp | 263 ++-- src/Core/Field/MeshBased/StencilField.hpp | 593 +++++---- .../MeshBased/Structured/CartesianField.hpp | 1067 ++++++++++------- src/Core/Loops/RangeFor.hpp | 65 +- .../Parallel/ParticleGuidedSplitStrategy.hpp | 150 ++- .../Solvers/Struct/StructSolverPrecond.hpp | 36 +- .../Arrays/Tensor/FixedSizeTensor.hpp | 71 +- src/DataStructures/Index/ColoredIndex.hpp | 2 +- .../LinearMapper/BlockedMDRangeMapper.hpp | 122 +- src/DataStructures/Range/Ranges.hpp | 238 ++-- src/DataStructures/StencilPad.hpp | 209 ++-- test/Core/Field/CartesianFieldMPITest.cpp | 138 ++- test/Core/Loops/RangeForTest.cpp | 18 +- 17 files changed, 1927 insertions(+), 1178 deletions(-) diff --git a/src/Core/BC/NeumBC.hpp b/src/Core/BC/NeumBC.hpp index 82ba2dc0..5ec5fa40 100644 --- a/src/Core/BC/NeumBC.hpp +++ b/src/Core/BC/NeumBC.hpp @@ -18,9 +18,13 @@ #include "Core/Field/MeshBased/MeshBasedFieldExprTrait.hpp" #include "Core/Field/MeshBased/Structured/StructuredFieldExprTrait.hpp" -OPFLOW_MODULE_EXPORT namespace OpFlow { +OPFLOW_MODULE_EXPORT + +namespace OpFlow +{ template - struct NeumBCBase : virtual public BCBase { + struct NeumBCBase : virtual public BCBase + { protected: BCType type = BCType::Neum; @@ -29,26 +33,33 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { [[nodiscard]] BCType getBCType() const override { return type; } [[nodiscard]] virtual std::unique_ptr> - getFunctorBC(std::function::elem_type(const typename BCBase::index_type&)> f) - const = 0; + getFunctorBC(std::function::elem_type (const typename BCBase::index_type&)> f) + const = 0; }; template struct FunctorNeumBC; template - struct ConstNeumBC : virtual public NeumBCBase { + struct ConstNeumBC : virtual public NeumBCBase + { public: - explicit ConstNeumBC(auto c) : _c(c) {} + explicit ConstNeumBC(auto c) : _c(c) + { + } + using NeumBCBase::operator=; + typename internal::FieldExprTrait::elem_type - evalAt(const typename internal::FieldExprTrait::index_type& index) const override { + evalAt(const typename internal::FieldExprTrait::index_type&) const override + { return _c; } [[nodiscard]] std::string getTypeName() const override { return "ConstNeumBC"; } - [[nodiscard]] std::string toString(int level) const override { + [[nodiscard]] std::string toString(int level) const override + { std::string ret, prefix; for (auto i = 0; i < level; ++i) prefix += "\t"; ret += prefix + "Type: ConstNeum\n"; @@ -61,36 +72,46 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { std::unique_ptr> getCopy() const override { return std::make_unique(*this); } std::unique_ptr> - getFunctorBC(std::function::elem_type( - const typename internal::FieldExprTrait::index_type&)> - f) const override { + getFunctorBC(std::function::elem_type ( + const typename internal::FieldExprTrait::index_type&)> + f) const override + { return std::make_unique>(f); } [[nodiscard]] auto getValue() const { return _c; } protected: - void assignImpl(const BCBase& other) override { - _c = other.evalAt(typename internal::FieldExprTrait::index_type()); + void assignImpl(const BCBase& other) override + { + _c = other.evalAt(typename internal::FieldExprTrait < F > ::index_type()); } typename internal::FieldExprTrait::elem_type _c; }; template - struct FunctorNeumBC : virtual public NeumBCBase { + struct FunctorNeumBC : virtual public NeumBCBase + { public: - using Functor = std::function::elem_type( - const typename internal::MeshBasedFieldExprTrait::index_type&)>; - explicit FunctorNeumBC(Functor f) : _f(std::move(f)) {} + using Functor = std::function::elem_type( + const typename internal::MeshBasedFieldExprTrait::index_type&) + >; + + explicit FunctorNeumBC(Functor f) : _f(std::move(f)) + { + } typename internal::MeshBasedFieldExprTrait::elem_type - evalAt(const typename internal::MeshBasedFieldExprTrait::index_type& index) const override { + evalAt(const typename internal::MeshBasedFieldExprTrait::index_type& index) const override + { return _f(index - this->offset); } [[nodiscard]] std::string getTypeName() const override { return "FunctorNeumBC"; } - [[nodiscard]] std::string toString(int level) const override { + + [[nodiscard]] std::string toString(int level) const override + { std::string ret, prefix; for (auto i = 0; i < level; ++i) prefix += "\t"; ret += prefix + "Type: FunctorNeum"; @@ -100,19 +121,22 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { std::unique_ptr> getCopy() const override { return std::make_unique(*this); } std::unique_ptr> - getFunctorBC(std::function::elem_type( - const typename internal::FieldExprTrait::index_type&)> - f) const override { + getFunctorBC(std::function::elem_type ( + const typename internal::FieldExprTrait::index_type&)> + f) const override + { return std::make_unique>(f); } [[nodiscard]] auto getFunctor() const { return _f; } protected: - void assignImpl(const BCBase& other) override { + void assignImpl(const BCBase& other) override + { _f = [&](auto&& i) { return other.evalAt(i); }; } + Functor _f; }; -}// namespace OpFlow -#endif//OPFLOW_NEUMBC_HPP +} // namespace OpFlow +#endif//OPFLOW_NEUMBC_HPP \ No newline at end of file diff --git a/src/Core/Equation/AMGCLBackend.hpp b/src/Core/Equation/AMGCLBackend.hpp index b1c4b104..a09ce193 100644 --- a/src/Core/Equation/AMGCLBackend.hpp +++ b/src/Core/Equation/AMGCLBackend.hpp @@ -27,24 +27,32 @@ #endif #include "EqnSolveHandler.hpp" -OPFLOW_MODULE_EXPORT namespace OpFlow { +OPFLOW_MODULE_EXPORT + +namespace OpFlow +{ template - struct AMGCLBackend { + struct AMGCLBackend + { constexpr static bool _enable_mpi = !requires { typename Solver::col_type; }; // the static solver which performs a fresh solve on each invoke static EqnSolveState solve(const DS::CSRMatrix& mat, std::vector& x, typename Solver::params p, - typename Solver::backend_params bp, bool verbose = false) { + typename Solver::backend_params bp, bool verbose = false) + { int rows = mat.row.size() - 1; std::unique_ptr solver; #if defined(OPFLOW_WITH_MPI) - if constexpr (_enable_mpi) { + if constexpr (_enable_mpi) + { amgcl::mpi::communicator world(MPI_COMM_WORLD); auto A = std::make_shared>( - world, - *amgcl::adapter::zero_copy(rows, mat.row.begin(), mat.col.begin(), mat.val.begin())); + world, + *amgcl::adapter::zero_copy(rows, mat.row.begin(), mat.col.begin(), mat.val.begin())); solver = std::make_unique(world, A, p, bp); - } else { + } + else + { auto A = amgcl::adapter::zero_copy(rows, mat.row.begin(), mat.col.begin(), mat.val.begin()); //auto A_tie = std::tie(rows, mat.row, mat.col, mat.val); solver = std::make_unique(*A, p, bp); @@ -59,33 +67,39 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { double error; std::tie(iters, error) = (*solver)(mat.rhs, x); if (verbose) { OP_INFO("AMGCL report: iter = {}, relerr = {}", iters, error); } - return EqnSolveState {iters, error}; + return EqnSolveState{iters, error}; } // the dynamic solver which tries to reuse the built preconditioner before EqnSolveState solve_dy(const DS::CSRMatrix& mat, std::vector& x, typename Solver::params p, - typename Solver::backend_params bp, bool verbose = false) { + typename Solver::backend_params bp, bool verbose = false) + { rebuild_solver(mat, p, bp); OP_ASSERT_MSG(solver, "AMGCLBackend: solver not initialized."); auto [iters, error] = (*solver)(mat.rhs, x); if (verbose) { OP_INFO("AMGCL report: iter = {}, relerr = {}", iters, error); } solve_counter++; - return EqnSolveState {(int) iters, error}; + return EqnSolveState{(int)iters, error}; } private: void rebuild_solver(const DS::CSRMatrix& mat, typename Solver::params& p, - typename Solver::backend_params& bp) { - if (!solver || rebuilt_period.has_value() && solve_counter % rebuilt_period.value() == 0) { + typename Solver::backend_params& bp) + { + if (!solver || (rebuilt_period.has_value() && solve_counter % rebuilt_period.value() == 0)) + { int rows = mat.row.size() - 1; #if defined(OPFLOW_WITH_MPI) - if constexpr (_enable_mpi) { + if constexpr (_enable_mpi) + { amgcl::mpi::communicator world(MPI_COMM_WORLD); auto A = std::make_shared>( - world, *amgcl::adapter::zero_copy(rows, mat.row.begin(), mat.col.begin(), - mat.val.begin())); + world, *amgcl::adapter::zero_copy(rows, mat.row.begin(), mat.col.begin(), + mat.val.begin())); solver = std::make_unique(world, A, p, bp); - } else { + } + else + { auto A = amgcl::adapter::zero_copy(rows, mat.row.begin(), mat.col.begin(), mat.val.begin()); solver = std::make_unique(*A, p, bp); @@ -96,10 +110,11 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { #endif } } + std::unique_ptr solver; unsigned long long solve_counter = 0; - std::optional rebuilt_period {}; + std::optional rebuilt_period{}; }; -}// namespace OpFlow +} // namespace OpFlow -#endif//OPFLOW_AMGCLBACKEND_HPP +#endif//OPFLOW_AMGCLBACKEND_HPP \ No newline at end of file diff --git a/src/Core/Equation/CSRMatrixGenerator.hpp b/src/Core/Equation/CSRMatrixGenerator.hpp index 061cea53..3d695f38 100644 --- a/src/Core/Equation/CSRMatrixGenerator.hpp +++ b/src/Core/Equation/CSRMatrixGenerator.hpp @@ -141,14 +141,12 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { static auto generate_s(S& s, auto&& mapper, bool pinValue) { DS::CSRMatrix mat; auto target = s.template getTargetPtr(); - auto commStencil = s.comm_stencils[iTarget]; auto& uniEqn = s.template getEqnExpr(); auto local_range = target->getLocalWritableRange(); // shortcut for empty range case if (local_range.empty()) return mat; DS::MDRangeMapper local_mapper(local_range); // prepare: evaluate the common stencil & pre-fill the arrays - int stencil_size = commStencil.pad.size() * 1.5; std::vector row, col; std::vector val; @@ -157,7 +155,6 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { auto r_last = mapper(target->getGlobalWritableRange().last(), iTarget); rangeFor_s(local_range, [&](auto&& i) { auto r = mapper(i, iTarget); // r is the rank of i in the target scope - auto r_local = local_mapper(i);// r_local is the rank of i in the block scope auto currentStencil = uniEqn.evalAt(i); if (pinValue && r == r_last) { row.push_back(row.back() + 1); @@ -198,7 +195,6 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { template static auto generate_rhs(S& s, auto&& mapper, bool pinValue) { auto target = s.template getTargetPtr(); - auto commStencil = s.comm_stencils[iTarget]; auto& uniEqn = s.template getEqnExpr(); auto local_range = target->getLocalWritableRange(); DS::MDRangeMapper local_mapper(local_range); diff --git a/src/Core/Equation/EquationHolder.hpp b/src/Core/Equation/EquationHolder.hpp index 09c9af86..079a3df5 100644 --- a/src/Core/Equation/EquationHolder.hpp +++ b/src/Core/Equation/EquationHolder.hpp @@ -84,8 +84,6 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { template auto getEqnExpr() { - auto k = i; - auto s = this->st_fields.size(); auto eqn = Meta::custom_apply_container( getGetter(), [&](std::any & st_ptr, Meta::int_) -> decltype(auto) { diff --git a/src/Core/Equation/HYPREEqnSolveHandler.hpp b/src/Core/Equation/HYPREEqnSolveHandler.hpp index 313edb50..f16a8365 100644 --- a/src/Core/Equation/HYPREEqnSolveHandler.hpp +++ b/src/Core/Equation/HYPREEqnSolveHandler.hpp @@ -39,25 +39,33 @@ #include #endif -OPFLOW_MODULE_EXPORT namespace OpFlow { +OPFLOW_MODULE_EXPORT + +namespace OpFlow +{ template struct HYPREEqnSolveHandler; template - std::unique_ptr makeEqnSolveHandler(F && f, T && t, S && s) { + std::unique_ptr makeEqnSolveHandler(F&& f, T&& t, S&& s) + { return std::make_unique, Meta::RealType>>( - OP_PERFECT_FOWD(f), OP_PERFECT_FOWD(t), OP_PERFECT_FOWD(s)); + OP_PERFECT_FOWD(f), OP_PERFECT_FOWD(t), OP_PERFECT_FOWD(s)); } template - struct HYPREEqnSolveHandler : virtual public EqnSolveHandler { + struct HYPREEqnSolveHandler : virtual public EqnSolveHandler + { HYPREEqnSolveHandler() = default; + HYPREEqnSolveHandler(const F& getter, T& target, const Solver& s) - : eqn_getter {getter}, target {&target}, solver(s) { + : eqn_getter{getter}, target{&target}, solver(s) + { this->init(); } - ~HYPREEqnSolveHandler() override { + ~HYPREEqnSolveHandler() override + { HYPRE_StructMatrixDestroy(A); HYPRE_StructVectorDestroy(b); HYPRE_StructVectorDestroy(x); @@ -65,7 +73,8 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { HYPRE_StructStencilDestroy(stencil); } - void init() override { + void init() override + { auto stField = target->getStencilField(); stField.pin(solver.params.pinValue); stencilField = std::make_unique>(std::move(stField)); @@ -78,7 +87,8 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { solver.init(); } - void initStencil() { + void initStencil() + { HYPRE_StructGridCreate(solver.params.comm, dim, &grid); auto t = equation->lhs - equation->rhs; t.prepare(); @@ -98,18 +108,20 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { // assume the middle stencil is complete // fixme: this is dangerous especially for MPI cases. consider a better plan - DS::MDIndex middle; + DS::MDIndex < dim > middle; for (auto i = 0; i < dim; ++i) middle[i] = (target->assignableRange.start[i] + target->assignableRange.end[i]) / 2; commStencil = getOffsetStencil(uniEqn->evalAt(middle), middle); HYPRE_StructStencilCreate(dim, commStencil.pad.size(), &stencil); auto iter = commStencil.pad.begin(); - for (auto i = 0; i < commStencil.pad.size(); ++i, ++iter) { + for (auto i = 0; i < commStencil.pad.size(); ++i, ++iter) + { HYPRE_StructStencilSetElement(stencil, i, const_cast(iter->first.get().data())); } } - void initAbx() { + void initAbx() + { HYPRE_StructMatrixCreate(solver.params.comm, grid, stencil, &A); HYPRE_StructMatrixInitialize(A); HYPRE_StructVectorCreate(solver.params.comm, grid, &b); @@ -118,23 +130,21 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { HYPRE_StructVectorInitialize(x); } - void initx() { - rangeFor(DS::commonRange(target->assignableRange, target->localRange), [&](auto&& k) { + void initx() + { + rangeFor(DS::commonRange(target->assignableRange, target->localRange), [&](auto&& k) + { HYPRE_StructVectorSetValues(x, const_cast(k.get().data()), target->evalAt(k)); }); } - void generateAb() override { + void generateAb() override + { std::vector entries(commStencil.pad.size()); - for (auto i = 0; i < entries.size(); ++i) entries[i] = i; - int periodic[dim]; - for (auto j = 0; j < dim; ++j) - if (target->bc[j].start && target->bc[j].start->getBCType() == BCType::Periodic) - periodic[j] = target->assignableRange.end[j] - target->assignableRange.start[j]; - else - periodic[j] = 0; + for (std::size_t i = 0; i < entries.size(); ++i) entries[i] = i; - rangeFor(DS::commonRange(target->assignableRange, target->localRange), [&](auto&& k) { + rangeFor(DS::commonRange(target->assignableRange, target->localRange), [&](auto&& k) + { auto currentStencil = getOffsetStencil(uniEqn->evalAt(k), k); auto extendedStencil = commonStencil(currentStencil, commStencil); std::vector vals; @@ -144,17 +154,21 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { HYPRE_StructVectorSetValues(b, const_cast(k.get().data()), -extendedStencil.bias); }); - if (solver.params.pinValue) { + if (solver.params.pinValue) + { // pin the first unknown to 0 auto identical = DS::StencilPad>>(); - auto first = DS::ColoredIndex> { - DS::MDIndex {target->assignableRange.start}}; - if (DS::inRange(target->localRange, first)) { + auto first = DS::ColoredIndex>{ + DS::MDIndex < dim > {target->assignableRange.start} + }; + if (DS::inRange(target->localRange, first)) + { identical.pad[first] = 1.0; identical.bias = 0.; auto extendedStencil = commonStencil(identical, commStencil); std::vector vals; - for (const auto& [key, val] : commStencil.pad) { + for (const auto& [key, val] : commStencil.pad) + { vals.push_back(extendedStencil.pad[key]); } HYPRE_StructMatrixSetValues(A, const_cast(first.get().data()), @@ -167,21 +181,26 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { HYPRE_StructVectorAssemble(b); } - void generateb() { - rangeFor(DS::commonRange(target->assignableRange, target->localRange), [&](auto&& k) { + void generateb() + { + rangeFor(DS::commonRange(target->assignableRange, target->localRange), [&](auto&& k) + { auto currentStencil = uniEqn->evalAt(k); HYPRE_StructVectorSetValues(b, const_cast(k.get().data()), -currentStencil.bias); }); - if (solver.params.pinValue) { - auto first = DS::MDIndex( - DS::commonRange(target->assignableRange, target->localRange).start); + if (solver.params.pinValue) + { + auto first = DS::MDIndex < dim > ( + DS::commonRange(target->assignableRange, target->localRange).start); HYPRE_StructVectorSetValues(b, const_cast(first.get().data()), 0.); } HYPRE_StructVectorAssemble(b); } - void returnValues() { - rangeFor(DS::commonRange(target->assignableRange, target->localRange), [&](auto&& k) { + void returnValues() + { + rangeFor(DS::commonRange(target->assignableRange, target->localRange), [&](auto&& k) + { Real val; HYPRE_StructVectorGetValues(x, const_cast(k.get().data()), &val); target->operator[](k) = val; @@ -189,15 +208,19 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { target->updatePadding(); } - EqnSolveState solve() override { - if (firstRun) { + EqnSolveState solve() override + { + if (firstRun) + { generateAb(); initx(); solver.dump(A, b); solver.setup(A, b, x); solver.solve(A, b, x); firstRun = false; - } else { + } + else + { if (solver.params.staticMat) generateb(); else generateAb(); @@ -213,8 +236,10 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { F eqn_getter; std::add_pointer_t target; using Stencil - = DS::StencilPad::index_type>>; - using Eqn = Meta::RealType()(std::declval&>()))>; + = DS::StencilPad::index_type + > + >; + using Eqn = Meta::RealType()(std::declval < StencilField < T > & > ()))>; std::unique_ptr equation; using EqExpr = Meta::RealTypelhs - equation->rhs)>; std::unique_ptr uniEqn; @@ -223,25 +248,30 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { bool fieldsAllocated = false; bool firstRun = true; Solver solver; - HYPRE_StructStencil stencil {}; - HYPRE_StructGrid grid {}; - HYPRE_StructMatrix A {}; - HYPRE_StructVector b {}, x {}; + HYPRE_StructStencil stencil{}; + HYPRE_StructGrid grid{}; + HYPRE_StructMatrix A{}; + HYPRE_StructVector b{}, x{}; private: - constexpr static auto dim = internal::CartesianFieldExprTrait::dim; + constexpr static auto dim = internal::CartesianFieldExprTrait < T > ::dim; }; template - struct HYPREEqnSolveHandler : virtual public EqnSolveHandler { + struct HYPREEqnSolveHandler : virtual public EqnSolveHandler + { HYPREEqnSolveHandler() = default; + HYPREEqnSolveHandler(const F& getter, T& target, const Solver& s) - : getter(getter), target(&target), solver(s) { + : getter(getter), target(&target), solver(s) + { this->init(); } + ~HYPREEqnSolveHandler() override { deallocHYPRE(); } - void init() override { + void init() override + { stencilField = std::make_unique>(target->getStencilField()); stencilField->pin(solver.params.pinValue); equation = std::make_unique(getter(*stencilField)); @@ -250,13 +280,16 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { solver.init(); } - void allocHYPRE() { + void allocHYPRE() + { // grid int ndim = dim, nparts = target->getLevels(), nvars = 1; int vartypes[] = {HYPRE_SSTRUCT_VARIABLE_CELL}; HYPRE_SStructGridCreate(solver.params.comm, ndim, nparts, &grid); - for (auto l = 0; l < target->localRanges.size(); ++l) { - for (auto p = 0; p < target->localRanges[l].size(); ++p) { + for (auto l = 0; l < target->localRanges.size(); ++l) + { + for (auto p = 0; p < target->localRanges[l].size(); ++p) + { auto _local_range = target->localRanges[l][p]; for (auto i = 0; i < dim; ++i) _local_range.end[i]--; HYPRE_SStructGridSetExtents(grid, l, _local_range.start.data(), _local_range.end.data()); @@ -268,7 +301,7 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { DS::ColoredIndex> middle; for (auto i = 0; i < dim; ++i) middle[i] = (target->assignableRanges[0][0].start[i] + target->assignableRanges[0][0].end[i]) - / 2; + / 2; //commStencil = getOffsetStencil(uniEqn->evalAt(middle), middle); DS::StencilPad> _st; _st.pad[middle] = 0; @@ -280,21 +313,28 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { HYPRE_SStructStencilCreate(ndim, commStencil.pad.size(), &stencil); auto iter = commStencil.pad.begin(); int c_var = 0; - for (auto i = 0; i < commStencil.pad.size(); ++i, ++iter) { + for (auto i = 0; i < commStencil.pad.size(); ++i, ++iter) + { HYPRE_SStructStencilSetEntry(stencil, i, const_cast(iter->first.get().data()), c_var); } HYPRE_SStructGraphCreate(solver.params.comm, grid, &graph); - for (auto l = 0; l < target->localRanges.size(); ++l) { + for (auto l = 0; l < target->localRanges.size(); ++l) + { HYPRE_SStructGraphSetStencil(graph, l, c_var, stencil); } // inter-level graph entries - for (auto l = 0; l < target->getLevels(); ++l) { - for (auto p = 0; p < target->localRanges[l].size(); ++p) { - rangeFor_s(target->localRanges[l][p], [&](auto&& i) { + for (auto l = 0; l < target->getLevels(); ++l) + { + for (auto p = 0; p < target->localRanges[l].size(); ++p) + { + rangeFor_s(target->localRanges[l][p], [&](auto&& i) + { if (stencilField->blocked(i)) return; auto st = uniEqn->evalAt(i); - for (auto& [k, v] : st.pad) { - if (k.l != l) { + for (auto& [k, v] : st.pad) + { + if (k.l != l) + { HYPRE_SStructGraphAddEntries(graph, l, i.c_arr(), c_var, k.l, k.c_arr(), c_var); std::cout << std::format("GraphAddEntry: {} -> {}\n", i, k); @@ -313,7 +353,9 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { HYPRE_SStructVectorInitialize(x); allocated = true; } - void deallocHYPRE() { + + void deallocHYPRE() + { if (!allocated) return; HYPRE_SStructMatrixDestroy(A); HYPRE_SStructVectorDestroy(b); @@ -324,28 +366,35 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { allocated = false; } - void generateAb() override { - for (auto l = 0; l < target->getLevels(); ++l) { - for (auto p = 0; p < target->localRanges[l].size(); ++p) { - rangeFor_s(target->localRanges[l][p], [&](auto&& i) { + void generateAb() override + { + for (auto l = 0; l < target->getLevels(); ++l) + { + for (auto p = 0; p < target->localRanges[l].size(); ++p) + { + rangeFor_s(target->localRanges[l][p], [&](auto&& i) + { if (stencilField->blocked(i)) return; // stencil part auto currentStencil = uniEqn->evalAt(i); auto offsetStencil = currentStencil; - for (auto& [k, v] : offsetStencil.pad) { + for (auto& [k, v] : offsetStencil.pad) + { if (k.l == l) { k -= i; } } std::cout << std::format("index = {}\n", i); std::cout << std::format("current stencil:{}\noffset stencil:{}\n", currentStencil, offsetStencil); auto extendedStencil = offsetStencil; - for (auto& [k, v] : commStencil.pad) { + for (auto& [k, v] : commStencil.pad) + { auto _target_k = k; _target_k.l = l; _target_k.p = p; if (auto iter = extendedStencil.pad.findFirst( - [&](auto&& _k) { return _k.l == l && _k.idx == _target_k.idx; }); - iter == extendedStencil.pad.end()) { + [&](auto&& _k) { return _k.l == l && _k.idx == _target_k.idx; }); + iter == extendedStencil.pad.end()) + { extendedStencil.pad[_target_k] = 0; } } @@ -353,19 +402,22 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { std::vector vals; std::vector entries(commStencil.pad.size()); std::iota(entries.begin(), entries.end(), 0); - for (const auto& [key, val] : commStencil.pad) { + for (const auto& [key, val] : commStencil.pad) + { auto _k = key; _k.l = l; auto iter = extendedStencil.pad.findFirst( - [&](auto&& k) { return k.l == l && k.idx == _k.idx; }); + [&](auto&& k) { return k.l == l && k.idx == _k.idx; }); vals.push_back(iter->second); } HYPRE_SStructMatrixSetValues(A, l, i.c_arr(), 0, commStencil.pad.size(), entries.data(), vals.data()); // inter-level part int count = commStencil.pad.size(); - for (const auto& [k, v] : extendedStencil.pad) { - if (k.l != l) { + for (const auto& [k, v] : extendedStencil.pad) + { + if (k.l != l) + { int entry[] = {count++}; Real val[] = {v}; HYPRE_SStructMatrixSetValues(A, l, i.c_arr(), 0, 1, entry, val); @@ -377,14 +429,16 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { }); } } - int(*rfactors)[HYPRE_MAXDIM]; + int (*rfactors)[HYPRE_MAXDIM]; rfactors = new int[target->getLevels()][HYPRE_MAXDIM]; for (auto l = 0; l < target->getLevels(); ++l) for (auto d = 0; d < HYPRE_MAXDIM; ++d) rfactors[l][d] = 1; - for (auto l = 1; l < target->getLevels(); ++l) { + for (auto l = 1; l < target->getLevels(); ++l) + { for (auto d = 0; d < dim; ++d) rfactors[l][d] = target->mesh.refinementRatio; } - for (auto l = target->getLevels() - 1; l > 0; --l) { + for (auto l = target->getLevels() - 1; l > 0; --l) + { HYPRE_SStructFACZeroCFSten(A, grid, l, rfactors[l]); HYPRE_SStructFACZeroFCSten(A, grid, l); HYPRE_SStructFACZeroAMRMatrixData(A, l - 1, rfactors[l]); @@ -396,20 +450,26 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { HYPRE_SStructVectorAssemble(b); delete[] rfactors; } - void initx() { - for (auto l = 0; l < target->getLevels(); ++l) { - for (auto p = 0; p < target->localRanges[l].size(); ++p) { - rangeFor(target->localRanges[l][p], [&](auto&& i) { + + void initx() + { + for (auto l = 0; l < target->getLevels(); ++l) + { + for (auto p = 0; p < target->localRanges[l].size(); ++p) + { + rangeFor(target->localRanges[l][p], [&](auto&& i) + { auto val = target->evalAt(i); HYPRE_SStructVectorSetValues(x, l, i.c_arr(), 0, &val); }); } } - int(*rfactors)[HYPRE_MAXDIM]; + int (*rfactors)[HYPRE_MAXDIM]; rfactors = new int[target->getLevels()][HYPRE_MAXDIM]; for (auto l = 0; l < target->getLevels(); ++l) for (auto d = 0; d < HYPRE_MAXDIM; ++d) rfactors[l][d] = 1; - for (auto l = 1; l < target->getLevels(); ++l) { + for (auto l = 1; l < target->getLevels(); ++l) + { for (auto d = 0; d < dim; ++d) rfactors[l][d] = target->mesh.refinementRatio; } std::vector plevels(target->getLevels()); @@ -418,10 +478,15 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { HYPRE_SStructVectorAssemble(x); delete[] rfactors; } - void returnValues() { - for (auto l = 0; l < target->getLevels(); ++l) { - for (auto p = 0; p < target->localRanges[l].size(); ++p) { - rangeFor(target->localRanges[l][p], [&](auto&& i) { + + void returnValues() + { + for (auto l = 0; l < target->getLevels(); ++l) + { + for (auto p = 0; p < target->localRanges[l].size(); ++p) + { + rangeFor(target->localRanges[l][p], [&](auto&& i) + { Real val; HYPRE_SStructVectorGetValues(x, l, i.c_arr(), 0, &val); target->operator[](i) = val; @@ -430,17 +495,19 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { } } - EqnSolveState solve() override { + EqnSolveState solve() override + { allocHYPRE(); generateAb(); initx(); HYPRE_SStructFACSetMaxLevels(solver.getSolver(), target->getLevels()); std::vector plevels(target->getLevels()); - int(*rfactors)[HYPRE_MAXDIM]; + int (*rfactors)[HYPRE_MAXDIM]; std::iota(plevels.begin(), plevels.end(), 0); rfactors = new int[plevels.size()][HYPRE_MAXDIM]; for (auto i = 0; i < HYPRE_MAXDIM; ++i) rfactors[0][i] = 1; - for (auto l = 1; l < target->localRanges.size(); ++l) { + for (auto l = 1; l < target->localRanges.size(); ++l) + { for (auto i = 0; i < HYPRE_MAXDIM; ++i) rfactors[l][i] = i < dim ? target->mesh.refinementRatio : 1; } @@ -468,8 +535,10 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { F getter; std::add_pointer_t target; using Stencil - = DS::StencilPad::index_type>>; - using Eqn = Meta::RealType()(std::declval&>()))>; + = DS::StencilPad::index_type + > + >; + using Eqn = Meta::RealType()(std::declval < StencilField < T > & > ()))>; std::unique_ptr equation; using EqExpr = Meta::RealTypelhs - equation->rhs)>; std::unique_ptr uniEqn; @@ -477,16 +546,16 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { std::unique_ptr> stencilField; bool fieldsAllocated = false; Solver solver; - HYPRE_SStructStencil stencil {}; - HYPRE_SStructGrid grid {}; - HYPRE_SStructGraph graph {}; - HYPRE_SStructMatrix A {}; - HYPRE_SStructVector b {}, x {}; + HYPRE_SStructStencil stencil{}; + HYPRE_SStructGrid grid{}; + HYPRE_SStructGraph graph{}; + HYPRE_SStructMatrix A{}; + HYPRE_SStructVector b{}, x{}; private: bool allocated = false; - constexpr static auto dim = internal::CartAMRFieldExprTrait::dim; + constexpr static auto dim = internal::CartAMRFieldExprTrait < T > ::dim; using index_type = typename internal::CartAMRFieldExprTrait::index_type; }; -}// namespace OpFlow -#endif//OPFLOW_HYPREEQNSOLVEHANDLER_HPP +} // namespace OpFlow +#endif//OPFLOW_HYPREEQNSOLVEHANDLER_HPP \ No newline at end of file diff --git a/src/Core/Field/MeshBased/StencilField.hpp b/src/Core/Field/MeshBased/StencilField.hpp index 56c60c8d..14b25d83 100644 --- a/src/Core/Field/MeshBased/StencilField.hpp +++ b/src/Core/Field/MeshBased/StencilField.hpp @@ -25,20 +25,26 @@ #include "DataStructures/StencilPad.hpp" #include "Math/Interpolator/Interpolator.hpp" -OPFLOW_MODULE_EXPORT namespace OpFlow { +OPFLOW_MODULE_EXPORT +namespace OpFlow +{ template typename map_impl> struct StencilField - : internal::StructuredFieldExprTrait::template twin_type> { + : internal::StructuredFieldExprTrait::template twin_type> + { std::array>>, internal::ExprTrait::dim> - bc; + bc; int color = 0; StencilField() = default; + StencilField(const StencilField& other) : internal::StructuredFieldExprTrait::template twin_type(other), - base(other.base), pinned(other.pinned), color(other.color) { - for (auto i = 0; i < internal::ExprTrait::dim; ++i) { + color(other.color), base(other.base), pinned(other.pinned) + { + for (auto i = 0; i < internal::ExprTrait::dim; ++i) + { bc[i].start = other.bc[i].start ? other.bc[i].start->getCopy() : nullptr; if (isLogicalBC(bc[i].start->getBCType())) dynamic_cast*>(bc[i].start.get())->rebindField(*this); @@ -47,58 +53,70 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { dynamic_cast*>(bc[i].end.get())->rebindField(*this); } } + StencilField(StencilField&&) noexcept = default; - explicit StencilField(const T& base, int color = 0) : base(&base), color(color) { + + explicit StencilField(const T& base, int color = 0) : color(color), base(&base) + { this->name = std::format("StencilField({})", base.name); - if constexpr (StructuredFieldExprType) this->loc = base.loc; + if constexpr (StructuredFieldExprType < T >) this->loc = base.loc; this->mesh = base.mesh.getView(); this->localRange = base.localRange; this->assignableRange = base.assignableRange; this->accessibleRange = base.accessibleRange; this->logicalRange = base.logicalRange; - for (auto i = 0; i < internal::MeshBasedFieldExprTrait::dim; ++i) { - if (base.bc[i].start && isLogicalBC(base.bc[i].start->getBCType())) { + for (auto i = 0; i < internal::MeshBasedFieldExprTrait < T > ::dim; ++i) + { + if (base.bc[i].start && isLogicalBC(base.bc[i].start->getBCType())) + { // if base.bc[i].start is a logical bc, we build a new instance of the same type bc - switch (base.bc[i].start->getBCType()) { - case BCType::Symm: - this->bc[i].start = genLogicalBC(*this, i, DimPos::start); - break; - case BCType::ASymm: - this->bc[i].start = genLogicalBC(*this, i, DimPos::start); - break; - case BCType::Periodic: - this->bc[i].start = genLogicalBC(*this, i, DimPos::start); - break; - default: - OP_CRITICAL("{} is not a logical bc type", base.bc[i].start->getTypeName()); - OP_ABORT; + switch (base.bc[i].start->getBCType()) + { + case BCType::Symm: + this->bc[i].start = genLogicalBC(*this, i, DimPos::start); + break; + case BCType::ASymm: + this->bc[i].start = genLogicalBC(*this, i, DimPos::start); + break; + case BCType::Periodic: + this->bc[i].start = genLogicalBC(*this, i, DimPos::start); + break; + default: + OP_CRITICAL("{} is not a logical bc type", base.bc[i].start->getTypeName()); + OP_ABORT; } - } else { + } + else + { // other cases we build a proxy bc to convert original bc to the same bc returning stencilpads this->bc[i].start - = genProxyBC::type>( - *(base.bc[i].start)); + = genProxyBC::type>( + *(base.bc[i].start)); } - if (base.bc[i].end && isLogicalBC(base.bc[i].end->getBCType())) { + if (base.bc[i].end && isLogicalBC(base.bc[i].end->getBCType())) + { // if base.bc[i].start is a logical bc, we build a new instance of the same type bc - switch (base.bc[i].end->getBCType()) { - case BCType::Symm: - this->bc[i].end = genLogicalBC(*this, i, DimPos::end); - break; - case BCType::ASymm: - this->bc[i].end = genLogicalBC(*this, i, DimPos::end); - break; - case BCType::Periodic: - this->bc[i].end = genLogicalBC(*this, i, DimPos::end); - break; - default: - OP_CRITICAL("{} is not a logical bc type", base.bc[i].end->getTypeName()); - OP_ABORT; + switch (base.bc[i].end->getBCType()) + { + case BCType::Symm: + this->bc[i].end = genLogicalBC(*this, i, DimPos::end); + break; + case BCType::ASymm: + this->bc[i].end = genLogicalBC(*this, i, DimPos::end); + break; + case BCType::Periodic: + this->bc[i].end = genLogicalBC(*this, i, DimPos::end); + break; + default: + OP_CRITICAL("{} is not a logical bc type", base.bc[i].end->getTypeName()); + OP_ABORT; } - } else { + } + else + { this->bc[i].end - = genProxyBC::type>( - *(base.bc[i].end)); + = genProxyBC::type>( + *(base.bc[i].end)); } } } @@ -109,9 +127,12 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { void pin(bool p) { pinned = p; } // only used for HYPRE solvers to get the exact offset stencil pad - void ignorePeriodicBC() { - for (auto i = 0; i < dim; ++i) { - if (base->bc[i].start->getBCType() == BCType::Periodic) { + void ignorePeriodicBC() + { + for (auto i = 0; i < dim; ++i) + { + if (base->bc[i].start->getBCType() == BCType::Periodic) + { this->assignableRange.start[i] = base->logicalRange.start[i]; this->accessibleRange.start[i] = base->logicalRange.start[i]; this->assignableRange.end[i] = base->logicalRange.end[i]; @@ -120,225 +141,284 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { } } - auto evalAtImpl_final(const index_type& index) const { + auto evalAtImpl_final(const index_type& index) const + { OP_ASSERT_MSG(base, "base ptr of stencil field is nullptr"); // inner case, return a stencil pad - if (DS::inRange(this->assignableRange, index)) [[likely]] { - auto ret = typename internal::ExprTrait::elem_type {0}; - // note: here solution is pinned at base->assignableRange.start - // rather than this->assignableRange.start; This is because - // for periodic case the assignableRange of this will be changed - // to logicalRange for HYPRE solver to get exact offset. - if (!(pinned && index == index_type(base->assignableRange.start))) - [[likely]] ret.pad[colored_index_type {index, color}] = 1.0; - return ret; - } - else if (!DS::inRange(this->logicalRange, index)) {// corner case, error & abort + if (DS::inRange(this->assignableRange, index)) [[likely]] + { + auto ret = typename internal::ExprTrait::elem_type{0}; + // note: here solution is pinned at base->assignableRange.start + // rather than this->assignableRange.start; This is because + // for periodic case the assignableRange of this will be changed + // to logicalRange for HYPRE solver to get exact offset. + if (!(pinned && index == index_type(base->assignableRange.start))) + [[likely]] ret.pad[colored_index_type{index, color}] = 1.0; + return ret; + } + else if (!DS::inRange(this->logicalRange, index)) + { + // corner case, error & abort OP_ERROR("Index {} out of range {}", index, this->logicalRange.toString()); OP_ABORT; - } else {// needs boundary condition info to continue + } + else + { + // needs boundary condition info to continue // case 1: index fall outside of boundary, fold it into accessibleRange - for (int i = 0; i < dim; ++i) { + for (int i = 0; i < dim; ++i) + { if (this->accessibleRange.start[i] <= index[i] && index[i] < this->accessibleRange.end[i]) continue; - if (this->loc[i] == LocOnMesh::Corner) { + if (this->loc[i] == LocOnMesh::Corner) + { // corner case - if (index[i] < this->accessibleRange.start[i]) { + if (index[i] < this->accessibleRange.start[i]) + { // lower case - switch (this->bc[i].start->getBCType()) { - case BCType::Dirc: { + switch (this->bc[i].start->getBCType()) + { + case BCType::Dirc: + { // mid point rule auto bc_v = this->bc[i].start->evalAt(index); auto mirror_idx = index; mirror_idx[i] = 2 * this->accessibleRange.start[i] - index[i]; return Math::Interpolator1D::intp( - base->mesh.x(i, this->accessibleRange.start[i]), bc_v, - base->mesh.x(i, mirror_idx), this->evalAtImpl_final(mirror_idx), - base->mesh.x(i, index)); - } break; - case BCType::Neum: { + base->mesh.x(i, this->accessibleRange.start[i]), bc_v, + base->mesh.x(i, mirror_idx), this->evalAtImpl_final(mirror_idx), + base->mesh.x(i, index)); + } + break; + case BCType::Neum: + { // mid-diff = bc auto bc_v = this->bc[i].start->evalAt(index); auto mirror_idx = index; mirror_idx[i] = 2 * this->accessibleRange.start[i] - index[i]; return this->evalAtImpl_final(mirror_idx) - + bc_v * (base->mesh.x(i, index) - base->mesh.x(i, mirror_idx)); - } break; - case BCType::Symm: { + + bc_v * (base->mesh.x(i, index) - base->mesh.x(i, mirror_idx)); + } + break; + case BCType::Symm: + { auto mirror_idx = index; mirror_idx[i] = 2 * this->accessibleRange.start[i] - index[i]; return this->evalAtImpl_final(mirror_idx); - } break; - case BCType::ASymm: { + } + break; + case BCType::ASymm: + { auto mirror_idx = index; mirror_idx[i] = 2 * this->accessibleRange.start[i] - index[i]; return -1. * this->evalAtImpl_final(mirror_idx); - } break; - case BCType::Periodic: { + } + break; + case BCType::Periodic: + { auto mirror_idx = index; mirror_idx[i] - += this->accessibleRange.end[i] - this->accessibleRange.start[i]; + += this->accessibleRange.end[i] - this->accessibleRange.start[i]; return this->evalAtImpl_final(mirror_idx); } - default: - OP_ERROR("Cannot handle current bc padding for stencil field: bc type {}", - this->bc[i].start->getTypeName()); - OP_ABORT; + default: + OP_ERROR("Cannot handle current bc padding for stencil field: bc type {}", + this->bc[i].start->getTypeName()); + OP_ABORT; } - } else { + } + else + { // upper case - switch (this->bc[i].end->getBCType()) { - case BCType::Dirc: { + switch (this->bc[i].end->getBCType()) + { + case BCType::Dirc: + { // mid-point rule auto bc_v = this->bc[i].end->evalAt(index); auto mirror_idx = index; mirror_idx[i] = 2 * this->accessibleRange.end[i] - 2 - index[i]; return Math::Interpolator1D::intp( - base->mesh.x(i, this->accessibleRange.end[i] - 1), bc_v, - base->mesh.x(i, mirror_idx), this->evalAtImpl_final(mirror_idx), - base->mesh.x(i, index)); - } break; - case BCType::Neum: { + base->mesh.x(i, this->accessibleRange.end[i] - 1), bc_v, + base->mesh.x(i, mirror_idx), this->evalAtImpl_final(mirror_idx), + base->mesh.x(i, index)); + } + break; + case BCType::Neum: + { // mid-diff = bc auto bc_v = this->bc[i].end->evalAt(index); auto mirror_idx = index; mirror_idx[i] = 2 * this->accessibleRange.end[i] - 2 - index[i]; return this->evalAtImpl_final(mirror_idx) - + bc_v * (base->mesh.x(i, index) - base->mesh.x(i, mirror_idx)); - } break; - case BCType::Symm: { + + bc_v * (base->mesh.x(i, index) - base->mesh.x(i, mirror_idx)); + } + break; + case BCType::Symm: + { auto mirror_idx = index; mirror_idx[i] = 2 * this->accessibleRange.end[i] - 2 - index[i]; return this->evalAtImpl_final(mirror_idx); - } break; - case BCType::ASymm: { + } + break; + case BCType::ASymm: + { auto mirror_idx = index; mirror_idx[i] = 2 * this->accessibleRange.end[i] - 2 - index[i]; return -1. * this->evalAtImpl_final(mirror_idx); - } break; - case BCType::Periodic: { + } + break; + case BCType::Periodic: + { auto mirror_idx = index; mirror_idx[i] - -= this->accessibleRange.end[i] - this->accessibleRange.start[i]; + -= this->accessibleRange.end[i] - this->accessibleRange.start[i]; return this->evalAtImpl_final(mirror_idx); - } break; - default: - OP_ERROR("Cannot handle current bc padding for stencil field: bc type {}", - this->bc[i].end->getTypeName()); - OP_ABORT; + } + break; + default: + OP_ERROR("Cannot handle current bc padding for stencil field: bc type {}", + this->bc[i].end->getTypeName()); + OP_ABORT; } } - } else { + } + else + { // center case - if (index[i] < this->accessibleRange.start[i]) { + if (index[i] < this->accessibleRange.start[i]) + { // lower case - switch (this->bc[i].start->getBCType()) { - case BCType::Dirc: { + switch (this->bc[i].start->getBCType()) + { + case BCType::Dirc: + { // mid-point rule auto bc_v = this->bc[i].start->evalAt(index); auto mirror_index = index; mirror_index[i] = 2 * this->accessibleRange.start[i] - 1 - index[i]; return Math::Interpolator1D::intp( - base->mesh.x(i, this->accessibleRange.start[i]), bc_v, - base->mesh.x(i, mirror_index[i]) - + base->mesh.dx(i, mirror_index) / 2., - this->evalAtImpl_final(mirror_index), - base->mesh.x(i, index[i]) + base->mesh.dx(i, index) / 2.); - } break; - case BCType::Neum: { + base->mesh.x(i, this->accessibleRange.start[i]), bc_v, + base->mesh.x(i, mirror_index[i]) + + base->mesh.dx(i, mirror_index) / 2., + this->evalAtImpl_final(mirror_index), + base->mesh.x(i, index[i]) + base->mesh.dx(i, index) / 2.); + } + break; + case BCType::Neum: + { // mid-diff = bc auto bc_v = this->bc[i].start->evalAt(index); auto mirror_index = index; mirror_index[i] = 2 * this->accessibleRange.start[i] - 1 - index[i]; return this->evalAtImpl_final(mirror_index) - + bc_v - * (base->mesh.x(i, index) + base->mesh.dx(i, index) / 2. - - base->mesh.x(i, mirror_index) - - base->mesh.dx(i, mirror_index) / 2.); - } break; - case BCType::Symm: { + + bc_v + * (base->mesh.x(i, index) + base->mesh.dx(i, index) / 2. + - base->mesh.x(i, mirror_index) + - base->mesh.dx(i, mirror_index) / 2.); + } + break; + case BCType::Symm: + { auto mirror_index = index; mirror_index[i] = 2 * this->accessibleRange.start[i] - 1 - index[i]; return this->evalAtImpl_final(mirror_index); - - } break; - case BCType::ASymm: { + } + break; + case BCType::ASymm: + { auto mirror_index = index; mirror_index[i] = 2 * this->accessibleRange.start[i] - 1 - index[i]; return -1.0 * this->evalAtImpl_final(mirror_index); - - } break; - case BCType::Periodic: { + } + break; + case BCType::Periodic: + { auto mirror_idx = index; mirror_idx[i] - += this->accessibleRange.end[i] - this->accessibleRange.start[i]; + += this->accessibleRange.end[i] - this->accessibleRange.start[i]; return this->evalAtImpl_final(mirror_idx); - } break; - default: - OP_ERROR("Cannot handle current bc padding: bc type {}", - this->bc[i].start->getTypeName()); - OP_ABORT; + } + break; + default: + OP_ERROR("Cannot handle current bc padding: bc type {}", + this->bc[i].start->getTypeName()); + OP_ABORT; } - } else { + } + else + { // upper case - switch (this->bc[i].end->getBCType()) { - case BCType::Dirc: { + switch (this->bc[i].end->getBCType()) + { + case BCType::Dirc: + { auto bc_v = this->bc[i].end->evalAt(index); auto mirror_index = index; mirror_index[i] = 2 * this->accessibleRange.end[i] - 1 - index[i]; return Math::Interpolator1D::intp( - base->mesh.x(i, this->accessibleRange.end[i]), bc_v, - base->mesh.x(i, mirror_index[i]) - + base->mesh.dx(i, mirror_index) / 2., - this->evalAtImpl_final(mirror_index), - base->mesh.x(i, index[i]) + base->mesh.dx(i, index) / 2.); - - } break; - case BCType::Neum: { + base->mesh.x(i, this->accessibleRange.end[i]), bc_v, + base->mesh.x(i, mirror_index[i]) + + base->mesh.dx(i, mirror_index) / 2., + this->evalAtImpl_final(mirror_index), + base->mesh.x(i, index[i]) + base->mesh.dx(i, index) / 2.); + } + break; + case BCType::Neum: + { auto bc_v = this->bc[i].end->evalAt(index); auto mirror_index = index; mirror_index[i] = 2 * this->accessibleRange.end[i] - 1 - index[i]; return this->evalAtImpl_final(mirror_index) - + bc_v - * (base->mesh.x(i, index) + base->mesh.dx(i, index) / 2. - - base->mesh.x(i, mirror_index) - - base->mesh.dx(i, mirror_index) / 2.); - } break; - case BCType::Symm: { + + bc_v + * (base->mesh.x(i, index) + base->mesh.dx(i, index) / 2. + - base->mesh.x(i, mirror_index) + - base->mesh.dx(i, mirror_index) / 2.); + } + break; + case BCType::Symm: + { auto mirror_index = index; mirror_index[i] = 2 * this->accessibleRange.end[i] - 1 - index[i]; return this->evalAtImpl_final(mirror_index); - - } break; - case BCType::ASymm: { + } + break; + case BCType::ASymm: + { auto mirror_index = index; mirror_index[i] = 2 * this->accessibleRange.end[i] - 1 - index[i]; return -1. * this->evalAtImpl_final(mirror_index); - - } break; - case BCType::Periodic: { + } + break; + case BCType::Periodic: + { auto mirror_idx = index; mirror_idx[i] - -= this->accessibleRange.end[i] - this->accessibleRange.start[i]; + -= this->accessibleRange.end[i] - this->accessibleRange.start[i]; return this->evalAtImpl_final(mirror_idx); - } break; - default: - OP_ERROR("Cannot handle current bc padding: bc type {}", - this->bc[i].end->getTypeName()); - OP_ABORT; + } + break; + default: + OP_ERROR("Cannot handle current bc padding: bc type {}", + this->bc[i].end->getTypeName()); + OP_ABORT; } } } } // case 2: index fall on a Dirc bc - for (int i = 0; i < dim; ++i) { + for (int i = 0; i < dim; ++i) + { if (this->loc[i] == LocOnMesh::Corner && this->bc[i].start->getBCType() == BCType::Dirc - && index[i] == this->accessibleRange.start[i]) { + && index[i] == this->accessibleRange.start[i]) + { // fall on the left boundary return this->bc[i].start->evalAt(index); - } else if (this->loc[i] == LocOnMesh::Corner - && this->bc[i].end->getBCType() == BCType::Dirc - && index[i] == this->accessibleRange.end[i] - 1) { + } + else if (this->loc[i] == LocOnMesh::Corner + && this->bc[i].end->getBCType() == BCType::Dirc + && index[i] == this->accessibleRange.end[i] - 1) + { // fall on the right boundary return this->bc[i].end->evalAt(index); } @@ -348,45 +428,68 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { OP_ERROR("Could not handle current case: i = {}", index); OP_ABORT; } - void prepareImpl_final() const {} + + void prepareImpl_final() const + { + } template - requires(!std::same_as) bool containsImpl_final(const Other& o) const { + requires(!std::same_as) + bool containsImpl_final(const Other& o) const + { return false; } + bool containsImpl_final(const StencilField& o) const { return this == &o; } private: const T* base; bool pinned = false; - constexpr static auto dim = internal::MeshBasedFieldExprTrait::dim; + constexpr static auto dim = internal::MeshBasedFieldExprTrait < T > ::dim; }; template typename map_impl> - struct StencilField : CartAMRFieldExpr> { + struct StencilField : CartAMRFieldExpr> + { using index_type = typename internal::ExprTrait::index_type; using colored_index_type = DS::ColoredIndex; private: // todo: why need explicit storage here? - std::vector::template other_type>>::container_type>> - data; - std::vector::template other_type>::container_type>> - block_mark; + std::vector::template other_type> + > + ::container_type + > + > + data; + std::vector::template other_type + > + ::container_type + > + > + block_mark; std::vector> offset; int color = 0; public: StencilField() = default; + StencilField(const StencilField& other) : CartAMRFieldExpr(other), data(other.data), block_mark(other.block_mark), - offset(other.offset) {} + offset(other.offset) + { + } + StencilField(StencilField&& other) noexcept : CartAMRFieldExpr(std::move(other)), data(std::move(other.data)), - block_mark(std::move(other.block_mark)), offset(std::move(other.offset)) {} - explicit StencilField(const T& base, int color) : color(color) { + block_mark(std::move(other.block_mark)), offset(std::move(other.offset)) + { + } + + explicit StencilField(const T& base, int color) : color(color) + { this->name = std::format("StencilField({})", base.name); this->loc = base.loc; this->mesh = base.mesh; @@ -394,42 +497,52 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { this->assignableRanges = base.assignableRanges; this->accessibleRanges = base.accessibleRanges; this->maxLogicalRanges = base.maxLogicalRanges; - for (auto i = 0; i < internal::SemiStructuredFieldExprTrait::dim; ++i) { + for (auto i = 0; i < internal::SemiStructuredFieldExprTrait < T > ::dim; ++i) + { this->bc[i].start - = genProxyBC::type>( - *(base.bc[i].start)); + = genProxyBC::type>( + *(base.bc[i].start)); this->bc[i].end - = genProxyBC::type>( - *(base.bc[i].end)); + = genProxyBC::type>( + *(base.bc[i].end)); } // allocate data data.resize(this->localRanges.size()); - for (auto i = 0; i < data.size(); ++i) { + for (auto i = 0; i < data.size(); ++i) + { data[i].resize(this->localRanges[i].size()); - for (auto j = 0; j < data[i].size(); ++j) { + for (auto j = 0; j < data[i].size(); ++j) + { data[i][j].reShape(this->accessibleRanges[i][j].getExtends()); } } block_mark.resize(this->localRanges.size()); - for (auto i = 0; i < block_mark.size(); ++i) { + for (auto i = 0; i < block_mark.size(); ++i) + { block_mark[i].resize(this->localRanges[i].size()); - for (auto j = 0; j < block_mark[i].size(); ++j) { + for (auto j = 0; j < block_mark[i].size(); ++j) + { block_mark[i][j].reShape(this->accessibleRanges[i][j].getExtends()); } } offset.resize(this->accessibleRanges.size()); - for (auto i = 0; i < this->accessibleRanges.size(); ++i) { + for (auto i = 0; i < this->accessibleRanges.size(); ++i) + { offset[i].resize(this->accessibleRanges[i].size()); - for (auto j = 0; j < this->accessibleRanges[i].size(); ++j) { + for (auto j = 0; j < this->accessibleRanges[i].size(); ++j) + { offset[i][j] = index_type(i, j, this->accessibleRanges[i][j].getOffset()); } } // init all stencils - for (auto l = 0; l < this->localRanges.size(); ++l) { - for (auto p = 0; p < this->localRanges[l].size(); ++p) { - rangeFor(this->localRanges[l][p], [&](auto&& i) { + for (auto l = 0; l < this->localRanges.size(); ++l) + { + for (auto p = 0; p < this->localRanges[l].size(); ++p) + { + rangeFor(this->localRanges[l][p], [&](auto&& i) + { auto& st = this->operator[](i); - st.pad[colored_index_type {i}] = 1.0; + st.pad[colored_index_type{i}] = 1.0; st.bias = 0; this->blocked(i) = false; }); @@ -442,26 +555,35 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { void pin(bool p) { pinned = p; } - void prepareImpl_final() {} + void prepareImpl_final() + { + } - void updatePadding() { + void updatePadding() + { // step 1: fill all halo regions covered by parents - for (auto l = 1; l < this->accessibleRanges.size(); ++l) { - for (auto p = 0; p < this->accessibleRanges[l].size(); ++p) { + for (auto l = 1; l < this->accessibleRanges.size(); ++l) + { + for (auto p = 0; p < this->accessibleRanges[l].size(); ++p) + { // here to avoid the accessibleRanges[l][p] is already been trimmed by the maxLogicalRange[l] auto bc_ranges = this->localRanges[l][p] - .getInnerRange(-this->mesh.buffWidth) - .getBCRanges(this->mesh.buffWidth); - for (auto r_p : this->mesh.parents[l][p]) { + .getInnerRange(-this->mesh.buffWidth) + .getBCRanges(this->mesh.buffWidth); + for (auto r_p : this->mesh.parents[l][p]) + { // convert the parent range into this level auto p_range = this->localRanges[l - 1][r_p]; - for (auto i = 0; i < dim; ++i) { + for (auto i = 0; i < dim; ++i) + { p_range.start[i] *= this->mesh.refinementRatio; p_range.end[i] *= this->mesh.refinementRatio; } // for each potential intersections - for (auto& bc_r : bc_ranges) { - rangeFor(DS::commonRange(bc_r, p_range), [&](auto&& i) { + for (auto& bc_r : bc_ranges) + { + rangeFor(DS::commonRange(bc_r, p_range), [&](auto&& i) + { // use piecewise constant interpolation auto i_base = i.toLevel(l - 1, this->mesh.refinementRatio); i_base.p = r_p; @@ -473,16 +595,21 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { } } // step 2: fill all halo regions covered by neighbors - for (auto l = 1; l < this->accessibleRanges.size(); ++l) { - for (auto p = 0; p < this->accessibleRanges[l].size(); ++p) { + for (auto l = 1; l < this->accessibleRanges.size(); ++l) + { + for (auto p = 0; p < this->accessibleRanges[l].size(); ++p) + { auto bc_ranges = this->localRanges[l][p] - .getInnerRange(-this->mesh.buffWidth) - .getBCRanges(this->mesh.buffWidth); - for (auto r_n : this->mesh.neighbors[l][p]) { + .getInnerRange(-this->mesh.buffWidth) + .getBCRanges(this->mesh.buffWidth); + for (auto r_n : this->mesh.neighbors[l][p]) + { // for each potential intersections - for (auto& bc_r : bc_ranges) { + for (auto& bc_r : bc_ranges) + { auto _r = DS::commonRange(bc_r, this->localRanges[l][r_n]); - rangeFor(DS::commonRange(bc_r, this->localRanges[l][r_n]), [&](auto&& i) { + rangeFor(DS::commonRange(bc_r, this->localRanges[l][r_n]), [&](auto&& i) + { // copy from other fine cells auto other_i = i; other_i.p = r_n; @@ -494,55 +621,71 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { } } } - void updateCovering() { + + void updateCovering() + { auto ratio = this->mesh.refinementRatio; - for (auto l = 1; l < this->localRanges.size(); ++l) { - for (auto p = 0; p < this->localRanges[l].size(); ++p) { - for (auto& i_p : this->mesh.parents[l][p]) { + for (auto l = 1; l < this->localRanges.size(); ++l) + { + for (auto p = 0; p < this->localRanges[l].size(); ++p) + { + for (auto& i_p : this->mesh.parents[l][p]) + { auto rp = this->localRanges[l - 1][i_p]; auto rc = this->localRanges[l][p]; - for (auto i = 0; i < dim; ++i) { + for (auto i = 0; i < dim; ++i) + { rc.start[i] /= ratio; rc.end[i] /= ratio; } rc.level = l - 1; - rangeFor(DS::commonRange(rp, rc), [&](auto&& i) { + rangeFor(DS::commonRange(rp, rc), [&](auto&& i) + { auto rt = rc; - for (auto k = 0; k < dim; ++k) { + for (auto k = 0; k < dim; ++k) + { rt.start[k] = i[k] * ratio; rt.end[k] = (i[k] + 1) * ratio; } rt.level = l; this->operator[](i) = rangeReduce_s( - rt, [](auto&& a, auto&& b) { return a + b; }, - [&](auto&& k) { return this->operator[](k); }) - / Math::int_pow(ratio, dim); + rt, [](auto&& a, auto&& b) { return a + b; }, + [&](auto&& k) { return this->operator[](k); }) + / Math::int_pow(ratio, dim); this->blocked(i) = true; }); } } } } - auto getView() { + + auto getView() + { OP_NOT_IMPLEMENTED; return 0; } - const auto& evalAtImpl_final(const index_type& i) const { + + const auto& evalAtImpl_final(const index_type& i) const + { return data[i.l][i.p][i - offset[i.l][i.p]]; } + auto& evalAtImpl_final(const index_type& i) { return data[i.l][i.p][i - offset[i.l][i.p]]; } auto& blocked(const index_type& i) { return block_mark[i.l][i.p][i - offset[i.l][i.p]]; } const auto& blocked(const index_type& i) const { return block_mark[i.l][i.p][i - offset[i.l][i.p]]; } template - requires(!std::same_as) bool containsImpl_final(const Other& o) const { + requires(!std::same_as) + bool containsImpl_final(const Other& o) const + { return false; } + bool containsImpl_final(const StencilField& o) const { return this == &o; } private: bool pinned = false; - constexpr static auto dim = internal::MeshBasedFieldExprTrait::dim; + constexpr static auto dim = internal::MeshBasedFieldExprTrait < T > ::dim; }; -}// namespace OpFlow -#endif//OPFLOW_STENCILFIELD_HPP +} // namespace OpFlow +#endif//OPFLOW_STENCILFIELD_HPP \ No newline at end of file diff --git a/src/Core/Field/MeshBased/Structured/CartesianField.hpp b/src/Core/Field/MeshBased/Structured/CartesianField.hpp index 6eec6115..d9286bfd 100644 --- a/src/Core/Field/MeshBased/Structured/CartesianField.hpp +++ b/src/Core/Field/MeshBased/Structured/CartesianField.hpp @@ -33,9 +33,13 @@ #include #endif -OPFLOW_MODULE_EXPORT namespace OpFlow { +OPFLOW_MODULE_EXPORT + +namespace OpFlow +{ template ::dim>> - struct CartesianField : CartesianFieldExpr> { + struct CartesianField : CartesianFieldExpr> + { using index_type = typename internal::CartesianFieldExprTrait::index_type; private: @@ -54,10 +58,13 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { std::array>>, internal::MeshTrait::dim> bc; CartesianField() = default; + CartesianField(const CartesianField& other) : CartesianFieldExpr>(other), data(other.data), - ext_width(other.ext_width), initialized(true) { - for (auto i = 0; i < internal::ExprTrait::dim; ++i) { + ext_width(other.ext_width), initialized(true) + { + for (auto i = 0; i < internal::ExprTrait::dim; ++i) + { bc[i].start = other.bc[i].start ? other.bc[i].start->getCopy() : nullptr; if (bc[i].start && isLogicalBC(bc[i].start->getBCType())) dynamic_cast*>(bc[i].start.get())->rebindField(*this); @@ -66,23 +73,30 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { dynamic_cast*>(bc[i].end.get())->rebindField(*this); } } + CartesianField(CartesianField&& other) noexcept : CartesianFieldExpr>(std::move(other)), data(std::move(other.data)), - initialized(true), bc(std::move(other.bc)), ext_width(std::move(other.ext_width)) {} + initialized(true), bc(std::move(other.bc)), ext_width(std::move(other.ext_width)) + { + } - CartesianField& operator=(const CartesianField& other) { + CartesianField& operator=(const CartesianField& other) + { assignImpl_final(other); return *this; } - CartesianField& operator=(CartesianField&& other) noexcept { + CartesianField& operator=(CartesianField&& other) noexcept + { assignImpl_final(std::move(other)); return *this; } template - requires std::same_as void - resplitWithStrategy(AbstractSplitStrategy* strategy) { + requires std::same_as + void + resplitWithStrategy(AbstractSplitStrategy* strategy) + { // this method only acts when MPI is enabled #if defined(OPFLOW_WITH_MPI) && defined(OPFLOW_DISTRIBUTE_MODEL_MPI) if (!strategy) return; @@ -90,12 +104,14 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { auto old_splitMap = this->splitMap; auto new_local_range = strategy->splitRange(this->mesh.getRange(), getGlobalParallelPlan()); auto new_splitMap = strategy->getSplitMap(this->mesh.getRange(), getGlobalParallelPlan()); - for (int i = 0; i < dim; ++i) { + for (int i = 0; i < dim; ++i) + { auto _loc = this->loc[i]; if (_loc == LocOnMesh::Corner && new_local_range.end[i] == this->mesh.getRange().end[i] - 1) new_local_range.end[i] - = std::min(new_local_range.end[i] + 1, this->accessibleRange.end[i]); - for (auto& r : new_splitMap) { + = std::min(new_local_range.end[i] + 1, this->accessibleRange.end[i]); + for (auto& r : new_splitMap) + { if (_loc == LocOnMesh::Corner && r.end[i] == this->mesh.getRange().end[i] - 1) r.end[i] = std::min(r.end[i] + 1, this->accessibleRange.end[i]); } @@ -103,24 +119,30 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { // find each potential intersections with each rank std::vector> intersections(getWorkerCount()); - for (int i = 0; i < this->splitMap.size(); ++i) { + for (int i = 0; i < this->splitMap.size(); ++i) + { intersections[i] = DS::commonRange(old_local_range, new_splitMap[i]); } std::vector> send_buff; std::vector dest_ranks; - for (int i = 0; i < intersections.size(); ++i) { - if (!intersections[i].empty()) { + for (int i = 0; i < intersections.size(); ++i) + { + if (!intersections[i].empty()) + { dest_ranks.push_back(i); std::vector buff; buff.reserve(intersections[i].count()); rangeFor_s(intersections[i], [&](auto&& k) { buff.push_back(this->evalAt(k)); }); send_buff.push_back(std::move(buff)); - if constexpr (std::is_trivial_v && std::is_standard_layout_v) { + if constexpr (std::is_trivial_v&& std::is_standard_layout_v) + { MPI_Request request; MPI_Isend(send_buff.back().data(), send_buff.back().size() * sizeof(D), MPI_BYTE, dest_ranks.back(), getWorkerId(), MPI_COMM_WORLD, &request); - MPI_Request_free(&request);// status tested on receiver's side - } else { + MPI_Request_free(&request); // status tested on receiver's side + } + else + { OP_NOT_IMPLEMENTED; } } @@ -130,17 +152,21 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { std::vector recv_requests; recv_buff.reserve(getWorkerCount()); recv_requests.reserve(getWorkerCount()); - for (int i = 0; i < old_splitMap.size(); ++i) { + for (int i = 0; i < old_splitMap.size(); ++i) + { intersections[i] = DS::commonRange(new_local_range, old_splitMap[i]); } std::vector src_ranks; - for (int i = 0; i < intersections.size(); ++i) { - if (!intersections[i].empty()) { + for (int i = 0; i < intersections.size(); ++i) + { + if (!intersections[i].empty()) + { src_ranks.push_back(i); recv_buff.emplace_back(); recv_buff.back().resize(intersections[i].count()); recv_requests.emplace_back(); - if constexpr (std::is_trivial_v && std::is_standard_layout_v) { + if constexpr (std::is_trivial_v&& std::is_standard_layout_v) + { MPI_Irecv(recv_buff.back().data(), intersections[i].count() * sizeof(D), MPI_BYTE, i, i, MPI_COMM_WORLD, &recv_requests.back()); } @@ -149,19 +175,23 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { // reshape data array this->data.reShape(new_local_range.getInnerRange(-this->padding).getExtends()); this->offset = typename internal::CartesianFieldExprTrait::index_type( - new_local_range.getInnerRange(-this->padding).getOffset()); + new_local_range.getInnerRange(-this->padding).getOffset()); this->localRange = new_local_range; this->splitMap = new_splitMap; // loop over all requests int finished_count = 0; std::vector finished_bit(src_ranks.size(), false); - while (finished_count != src_ranks.size()) { - for (int i = 0; i < finished_bit.size(); ++i) { - if (!finished_bit[i]) { + while (finished_count != src_ranks.size()) + { + for (int i = 0; i < finished_bit.size(); ++i) + { + if (!finished_bit[i]) + { int flag; MPI_Test(&recv_requests[i], &flag, MPI_STATUS_IGNORE); - if (flag) { + if (flag) + { finished_bit[i] = true; finished_count++; auto iter = recv_buff[i].begin(); @@ -177,16 +207,20 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { } template - auto& assignImpl_final(const CartesianField& other) { - if (!initialized) { + auto& assignImpl_final(const CartesianField& other) + { + if (!initialized) + { OP_ASSERT_MSG(Op == BasicArithOp::Eq, "Incremental assignment to uninitialized field is illegal"); this->initPropsFrom(other); data = other.data; ext_width = other.ext_width; initialized = true; - } else if (this != &other) { - internal::FieldAssigner::assign(other, *this); + } + else if (this != &other) + { + internal::FieldAssigner::assign < Op > (other, *this); this->updatePadding(); } return *this; @@ -194,48 +228,61 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { template auto& - assignImpl_final(T&& other) {// T is not const here for that we need to call other.prepare() later + assignImpl_final(T&& other) + { + // T is not const here for that we need to call other.prepare() later other.prepare(); - if (!initialized) { + if (!initialized) + { OP_ASSERT_MSG(Op == BasicArithOp::Eq, "Incremental assignment to uninitialized field is illegal"); this->initPropsFrom(other); - if constexpr (CartesianFieldType) { + if constexpr (CartesianFieldType < T >) + { data = other.data; ext_width = other.ext_width; - if constexpr (std::same_as, CartesianField>) - for (int i = 0; i < dim; ++i) { + if constexpr (std::same_as < Meta::RealType < T >, CartesianField >) + for (int i = 0; i < dim; ++i) + { this->bc[i].start = other.bc[i].start ? other.bc[i].start->getCopy() : nullptr; this->bc[i].end = other.bc[i].end ? other.bc[i].end->getCopy() : nullptr; } else - for (int i = 0; i < dim; ++i) { + for (int i = 0; i < dim; ++i) + { this->bc[i].start = other.bc[i].start - ? genProxyBC(*other.bc[i].start) - : nullptr; - this->bc[i].end = other.bc[i].end ? genProxyBC(*other.bc[i].end) - : nullptr; + ? genProxyBC(*other.bc[i].start) + : nullptr; + this->bc[i].end = other.bc[i].end + ? genProxyBC(*other.bc[i].end) + : nullptr; } - } else { + } + else + { this->data.reShape(this->localRange.getInnerRange(-this->padding).getExtends()); this->offset = typename internal::CartesianFieldExprTrait::index_type( - this->localRange.getInnerRange(-this->padding).getOffset()); + this->localRange.getInnerRange(-this->padding).getOffset()); } // invoke the assigner - internal::FieldAssigner::assign(other, *this); + internal::FieldAssigner::assign < Op > (other, *this); this->updatePadding(); initialized = true; - } else if ((void*) this != (void*) &other) { + } + else if ((void*)this != (void*)&other) + { // assign all values from T to assignable range - internal::FieldAssigner::assign(other, *this); + internal::FieldAssigner::assign < Op > (other, *this); this->updatePadding(); } return *this; } template - auto& assignImpl_final(const D& c) { - if (!initialized) { + auto& assignImpl_final(const D& c) + { + if (!initialized) + { OP_CRITICAL("CartesianField not initialized. Cannot assign constant to it."); OP_ABORT; } @@ -280,61 +327,76 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { } auto& - initBy(const std::function::dim>&)>& f) { - rangeFor(DS::commonRange(this->assignableRange, this->localRange), [&](auto&& i) { + initBy(const std::function::dim> &)>& f) + { + rangeFor(DS::commonRange(this->assignableRange, this->localRange), [&](auto&& i) + { std::array::dim> cords; for (auto k = 0; k < internal::CartesianMeshTrait::dim; ++k) cords[k] = this->loc[k] == LocOnMesh::Corner - ? this->mesh.x(k, i) - : this->mesh.x(k, i) + .5 * this->mesh.dx(k, i); + ? this->mesh.x(k, i) + : this->mesh.x(k, i) + .5 * this->mesh.dx(k, i); this->operator[](i) = f(cords); }); this->updatePadding(); return *this; } - void prepareImpl_final() const {} + void prepareImpl_final() const + { + } - void updateNeighbors() { - if (this->splitMap.size() == 1) { + void updateNeighbors() + { + if (this->splitMap.size() == 1) + { // single node mode this->neighbors.clear(); - } else { + } + else + { #if defined(OPFLOW_WITH_MPI) && defined(OPFLOW_DISTRIBUTE_MODEL_MPI) int rank = getWorkerId(); this->neighbors.clear(); - std::array is_periodic; - for (int d = 0; d < dim; ++d) { + std::array < bool, dim > is_periodic; + for (int d = 0; d < dim; ++d) + { is_periodic[d] = this->bc[d].start && this->bc[d].start->getBCType() == BCType::Periodic; } int range_count = Math::int_pow(3, std::count(is_periodic.begin(), is_periodic.end(), true)); - for (auto i = 0; i < this->splitMap.size(); ++i) { + for (std::size_t i = 0; i < this->splitMap.size(); ++i) + { auto mesh_range_extends = this->mesh.getRange().getExtends(); - for (int k = 0; k < range_count; ++k) { + for (int k = 0; k < range_count; ++k) + { auto r = this->splitMap[i]; - for (int d = 0; d < dim; ++d) { + for (int d = 0; d < dim; ++d) + { int direction - = (k % Math::int_pow(3, d + 1)) / Math::int_pow(3, d);// 0, 1(+), 2(-) - switch (direction) { - case 2: - r.start[d] -= mesh_range_extends[d] - 1; - r.end[d] -= mesh_range_extends[d] - 1; - break; - default: - case 0: - break; - case 1: - r.start[d] += mesh_range_extends[d] - 1; - r.end[d] += mesh_range_extends[d] - 1; - break; + = (k % Math::int_pow(3, d + 1)) / Math::int_pow(3, d); // 0, 1(+), 2(-) + switch (direction) + { + case 2: + r.start[d] -= mesh_range_extends[d] - 1; + r.end[d] -= mesh_range_extends[d] - 1; + break; + default: + case 0: + break; + case 1: + r.start[d] += mesh_range_extends[d] - 1; + r.end[d] += mesh_range_extends[d] - 1; + break; } } - if (!(i == rank && r == this->localRange)) { + if (!(static_cast(i) == rank && r == this->localRange)) + { auto send_range - = DS::commonRange(this->localRange, r.getInnerRange(-this->padding)); + = DS::commonRange(this->localRange, r.getInnerRange(-this->padding)); auto recv_range - = DS::commonRange(this->localRange.getInnerRange(-this->padding), r); - if (send_range.count() > 0) { + = DS::commonRange(this->localRange.getInnerRange(-this->padding), r); + if (send_range.count() > 0) + { this->neighbors.emplace_back(i, send_range, recv_range, k); } } @@ -346,18 +408,22 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { } } - void updatePaddingImpl_final() { + void updatePaddingImpl_final() + { // step 0: update dirc bc for corner case - for (int i = 0; i < dim; ++i) { + for (int i = 0; i < dim; ++i) + { // lower side if (this->localRange.start[i] == this->accessibleRange.start[i] && this->bc[i].start - && this->bc[i].start->getBCType() == BCType::Dirc && this->loc[i] == LocOnMesh::Corner) { + && this->bc[i].start->getBCType() == BCType::Dirc && this->loc[i] == LocOnMesh::Corner) + { auto r = this->localRange.slice(i, this->localRange.start[i]); rangeFor(r, [&](auto&& idx) { this->operator()(idx) = this->bc[i].start->evalAt(idx); }); } // upper side if (this->localRange.end[i] == this->accessibleRange.end[i] && this->bc[i].end - && this->bc[i].end->getBCType() == BCType::Dirc && this->loc[i] == LocOnMesh::Corner) { + && this->bc[i].end->getBCType() == BCType::Dirc && this->loc[i] == LocOnMesh::Corner) + { auto r = this->localRange.slice(i, this->localRange.end[i] - 1); rangeFor(r, [&](auto&& idx) { this->operator()(idx) = this->bc[i].end->evalAt(idx); }); } @@ -365,269 +431,322 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { // step 1: update paddings by bc extension // start/end record the start/end index of last padding operation // the latter padding op pads the outer range of the former padding zone - std::array start, end; - if constexpr (requires(D v) { - { v + v } - ->std::same_as; - { v - v } - ->std::same_as; - { v * 1.0 } - ->std::same_as; - { v / 1.0 } - ->std::same_as; - }) { - for (int i = 0; i < dim; ++i) { + std::array < int, dim > start, end; + if constexpr (requires(D v) + { + { + v + v + } + -> std::same_as; + { + v - v + } + -> std::same_as; + { + v * 1.0 + } + -> std::same_as; + { + v / 1.0 + } + -> std::same_as; + }) + { + for (int i = 0; i < dim; ++i) + { // lower side if (this->localRange.start[i] == this->accessibleRange.start[i] && this->bc[i].start - && this->bc[i].start->getBCType() != BCType::Periodic) { + && this->bc[i].start->getBCType() != BCType::Periodic) + { start[i] = this->logicalRange.start[i]; // current padding zone auto r = this->localRange; - for (int j = 0; j < i; ++j) { + for (int j = 0; j < i; ++j) + { r.start[j] = start[j]; r.end[j] = end[j]; } r.start[i] = start[i]; r.end[i] = this->localRange.start[i]; - if (this->loc[i] == LocOnMesh::Corner) { - switch (this->bc[i].start->getBCType()) { - case BCType::Dirc: - // mid-point rule - rangeFor(r, [&](auto&& idx) { - auto bc_v = this->bc[i].start->evalAt(idx); - auto mirror_idx = idx; - mirror_idx[i] = 2 * this->localRange.start[i] - idx[i]; - this->operator()(idx) = Math::Interpolator1D::intp( - this->mesh.x(i, this->localRange.start[i]), bc_v, - this->mesh.x(i, mirror_idx[i]), this->evalAt(mirror_idx), - this->mesh.x(i, idx[i])); - }); - break; - case BCType::Neum: - // mid-diff = bc - rangeFor(r, [&](auto&& idx) { - auto bc_v = this->bc[i].start->evalAt(idx); - auto mirror_idx = idx; - mirror_idx[i] = 2 * this->localRange.start[i] - idx[i]; - this->operator()(idx) = this->evalAt(mirror_idx) - + bc_v - * (this->mesh.x(i, idx) - - this->mesh.x(i, mirror_idx)); - }); - break; - case BCType::Symm: - rangeFor(r, [&](auto&& idx) { - auto mirror_idx = idx; - mirror_idx[i] = 2 * this->localRange.start[i] - idx[i]; - this->operator()(idx) = this->evalAt(mirror_idx); - }); - break; - case BCType::ASymm: - rangeFor(r, [&](auto&& idx) { - auto mirror_idx = idx; - mirror_idx[i] = 2 * this->localRange.start[i] - idx[i]; - this->operator()(idx) = -this->evalAt(mirror_idx); - }); - break; - default: - OP_ERROR("Cannot handle current bc padding: bc type {}", - this->bc[i].start->getTypeName()); - OP_ABORT; + if (this->loc[i] == LocOnMesh::Corner) + { + switch (this->bc[i].start->getBCType()) + { + case BCType::Dirc: + // mid-point rule + rangeFor(r, [&](auto&& idx) + { + auto bc_v = this->bc[i].start->evalAt(idx); + auto mirror_idx = idx; + mirror_idx[i] = 2 * this->localRange.start[i] - idx[i]; + this->operator()(idx) = Math::Interpolator1D::intp( + this->mesh.x(i, this->localRange.start[i]), bc_v, + this->mesh.x(i, mirror_idx[i]), this->evalAt(mirror_idx), + this->mesh.x(i, idx[i])); + }); + break; + case BCType::Neum: + // mid-diff = bc + rangeFor(r, [&](auto&& idx) + { + auto bc_v = this->bc[i].start->evalAt(idx); + auto mirror_idx = idx; + mirror_idx[i] = 2 * this->localRange.start[i] - idx[i]; + this->operator()(idx) = this->evalAt(mirror_idx) + + bc_v + * (this->mesh.x(i, idx) + - this->mesh.x(i, mirror_idx)); + }); + break; + case BCType::Symm: + rangeFor(r, [&](auto&& idx) + { + auto mirror_idx = idx; + mirror_idx[i] = 2 * this->localRange.start[i] - idx[i]; + this->operator()(idx) = this->evalAt(mirror_idx); + }); + break; + case BCType::ASymm: + rangeFor(r, [&](auto&& idx) + { + auto mirror_idx = idx; + mirror_idx[i] = 2 * this->localRange.start[i] - idx[i]; + this->operator()(idx) = -this->evalAt(mirror_idx); + }); + break; + default: + OP_ERROR("Cannot handle current bc padding: bc type {}", + this->bc[i].start->getTypeName()); + OP_ABORT; } - } else { + } + else + { // center case - switch (this->bc[i].start->getBCType()) { - case BCType::Dirc: - // mid-point rule - rangeFor(r, [&](auto&& idx) { - auto bc_v = this->bc[i].start->evalAt(idx); - auto mirror_idx = idx; - mirror_idx[i] = 2 * this->localRange.start[i] - 1 - idx[i]; - this->operator()(idx) = Math::Interpolator1D::intp( - this->mesh.x(i, this->localRange.start[i]), bc_v, - this->mesh.x(i, mirror_idx[i]) - + this->mesh.dx(i, mirror_idx) / 2., - this->evalAt(mirror_idx), - this->mesh.x(i, idx[i]) + this->mesh.dx(i, idx) / 2.); - }); - break; - case BCType::Neum: - // mid-diff = bc - rangeFor(r, [&](auto&& idx) { - auto bc_v = this->bc[i].start->evalAt(idx); - auto mirror_idx = idx; - mirror_idx[i] = 2 * this->localRange.start[i] - 1 - idx[i]; - this->operator()(idx) - = this->evalAt(mirror_idx) - + bc_v - * (this->mesh.x(i, idx) - + this->mesh.dx(i, idx) / 2. - - this->mesh.x(i, mirror_idx) - - this->mesh.dx(i, mirror_idx) / 2.); - }); - break; - case BCType::Symm: - rangeFor(r, [&](auto&& idx) { - auto mirror_idx = idx; - mirror_idx[i] = 2 * this->localRange.start[i] - 1 - idx[i]; - this->operator()(idx) = this->evalAt(mirror_idx); - }); - break; - case BCType::ASymm: - rangeFor(r, [&](auto&& idx) { - auto mirror_idx = idx; - mirror_idx[i] = 2 * this->localRange.start[i] - 1 - idx[i]; - this->operator()(idx) = -this->evalAt(mirror_idx); - }); - break; - default: - OP_ERROR("Cannot handle current bc padding: bc type {}", - this->bc[i].start->getTypeName()); - OP_ABORT; + switch (this->bc[i].start->getBCType()) + { + case BCType::Dirc: + // mid-point rule + rangeFor(r, [&](auto&& idx) + { + auto bc_v = this->bc[i].start->evalAt(idx); + auto mirror_idx = idx; + mirror_idx[i] = 2 * this->localRange.start[i] - 1 - idx[i]; + this->operator()(idx) = Math::Interpolator1D::intp( + this->mesh.x(i, this->localRange.start[i]), bc_v, + this->mesh.x(i, mirror_idx[i]) + + this->mesh.dx(i, mirror_idx) / 2., + this->evalAt(mirror_idx), + this->mesh.x(i, idx[i]) + this->mesh.dx(i, idx) / 2.); + }); + break; + case BCType::Neum: + // mid-diff = bc + rangeFor(r, [&](auto&& idx) + { + auto bc_v = this->bc[i].start->evalAt(idx); + auto mirror_idx = idx; + mirror_idx[i] = 2 * this->localRange.start[i] - 1 - idx[i]; + this->operator()(idx) + = this->evalAt(mirror_idx) + + bc_v + * (this->mesh.x(i, idx) + + this->mesh.dx(i, idx) / 2. + - this->mesh.x(i, mirror_idx) + - this->mesh.dx(i, mirror_idx) / 2.); + }); + break; + case BCType::Symm: + rangeFor(r, [&](auto&& idx) + { + auto mirror_idx = idx; + mirror_idx[i] = 2 * this->localRange.start[i] - 1 - idx[i]; + this->operator()(idx) = this->evalAt(mirror_idx); + }); + break; + case BCType::ASymm: + rangeFor(r, [&](auto&& idx) + { + auto mirror_idx = idx; + mirror_idx[i] = 2 * this->localRange.start[i] - 1 - idx[i]; + this->operator()(idx) = -this->evalAt(mirror_idx); + }); + break; + default: + OP_ERROR("Cannot handle current bc padding: bc type {}", + this->bc[i].start->getTypeName()); + OP_ABORT; } } - } else { + } + else + { start[i] = this->localRange.start[i]; } // upper side if (this->localRange.end[i] == this->accessibleRange.end[i] && this->bc[i].end - && this->bc[i].end->getBCType() != BCType::Periodic) { + && this->bc[i].end->getBCType() != BCType::Periodic) + { end[i] = this->logicalRange.end[i]; // current padding zone auto r = this->localRange; - for (int j = 0; j < i; ++j) { + for (int j = 0; j < i; ++j) + { r.start[j] = start[j]; r.end[j] = end[j]; } r.start[i] = this->localRange.end[i]; r.end[i] = this->logicalRange.end[i]; - if (this->loc[i] == LocOnMesh::Corner) { - switch (this->bc[i].end->getBCType()) { - case BCType::Dirc: - // mid-point rule - rangeFor(r, [&](auto&& idx) { - auto bc_v = this->bc[i].end->evalAt(idx); - auto mirror_idx = idx; - mirror_idx[i] = 2 * this->localRange.end[i] - 2 - idx[i]; - this->operator()(idx) = Math::Interpolator1D::intp( - this->mesh.x(i, this->localRange.end[i] - 1), bc_v, - this->mesh.x(i, mirror_idx[i]), this->evalAt(mirror_idx), - this->mesh.x(i, idx[i])); - }); - break; - case BCType::Neum: - // mid-diff = bc - rangeFor(r, [&](auto&& idx) { - auto bc_v = this->bc[i].end->evalAt(idx); - auto mirror_idx = idx; - mirror_idx[i] = 2 * this->localRange.end[i] - 2 - idx[i]; - this->operator()(idx) = this->evalAt(mirror_idx) - + bc_v - * (this->mesh.x(i, idx) - - this->mesh.x(i, mirror_idx)); - }); - break; - case BCType::Symm: - rangeFor(r, [&](auto&& idx) { - auto mirror_idx = idx; - mirror_idx[i] = 2 * this->localRange.end[i] - 2 - idx[i]; - this->operator()(idx) = this->evalAt(mirror_idx); - }); - break; - case BCType::ASymm: - rangeFor(r, [&](auto&& idx) { - auto mirror_idx = idx; - mirror_idx[i] = 2 * this->localRange.end[i] - 2 - idx[i]; - this->operator()(idx) = -this->evalAt(mirror_idx); - }); - break; - default: - OP_ERROR("Cannot handle current bc padding: bc type {}", - this->bc[i].end->getTypeName()); - OP_ABORT; + if (this->loc[i] == LocOnMesh::Corner) + { + switch (this->bc[i].end->getBCType()) + { + case BCType::Dirc: + // mid-point rule + rangeFor(r, [&](auto&& idx) + { + auto bc_v = this->bc[i].end->evalAt(idx); + auto mirror_idx = idx; + mirror_idx[i] = 2 * this->localRange.end[i] - 2 - idx[i]; + this->operator()(idx) = Math::Interpolator1D::intp( + this->mesh.x(i, this->localRange.end[i] - 1), bc_v, + this->mesh.x(i, mirror_idx[i]), this->evalAt(mirror_idx), + this->mesh.x(i, idx[i])); + }); + break; + case BCType::Neum: + // mid-diff = bc + rangeFor(r, [&](auto&& idx) + { + auto bc_v = this->bc[i].end->evalAt(idx); + auto mirror_idx = idx; + mirror_idx[i] = 2 * this->localRange.end[i] - 2 - idx[i]; + this->operator()(idx) = this->evalAt(mirror_idx) + + bc_v + * (this->mesh.x(i, idx) + - this->mesh.x(i, mirror_idx)); + }); + break; + case BCType::Symm: + rangeFor(r, [&](auto&& idx) + { + auto mirror_idx = idx; + mirror_idx[i] = 2 * this->localRange.end[i] - 2 - idx[i]; + this->operator()(idx) = this->evalAt(mirror_idx); + }); + break; + case BCType::ASymm: + rangeFor(r, [&](auto&& idx) + { + auto mirror_idx = idx; + mirror_idx[i] = 2 * this->localRange.end[i] - 2 - idx[i]; + this->operator()(idx) = -this->evalAt(mirror_idx); + }); + break; + default: + OP_ERROR("Cannot handle current bc padding: bc type {}", + this->bc[i].end->getTypeName()); + OP_ABORT; } - } else { + } + else + { // center case - switch (this->bc[i].end->getBCType()) { - case BCType::Dirc: - // mid-point rule - rangeFor(r, [&](auto&& idx) { - auto bc_v = this->bc[i].end->evalAt(idx); - auto mirror_idx = idx; - mirror_idx[i] = 2 * this->localRange.end[i] - 1 - idx[i]; - this->operator()(idx) = Math::Interpolator1D::intp( - this->mesh.x(i, this->localRange.end[i]), bc_v, - this->mesh.x(i, mirror_idx[i]) - + this->mesh.dx(i, mirror_idx) / 2., - this->evalAt(mirror_idx), - this->mesh.x(i, idx[i]) + this->mesh.dx(i, idx) / 2.); - }); - break; - case BCType::Neum: - // mid-diff = bc - rangeFor(r, [&](auto&& idx) { - auto bc_v = this->bc[i].end->evalAt(idx); - auto mirror_idx = idx; - mirror_idx[i] = 2 * this->localRange.end[i] - 1 - idx[i]; - this->operator()(idx) - = this->evalAt(mirror_idx) - + bc_v - * (this->mesh.x(i, idx) - + this->mesh.dx(i, idx) / 2. - - this->mesh.x(i, mirror_idx) - - this->mesh.dx(i, mirror_idx) / 2.); - }); - break; - case BCType::Symm: - rangeFor(r, [&](auto&& idx) { - auto mirror_idx = idx; - mirror_idx[i] = 2 * this->localRange.end[i] - 1 - idx[i]; - this->operator()(idx) = this->evalAt(mirror_idx); - }); - break; - case BCType::ASymm: - rangeFor(r, [&](auto&& idx) { - auto mirror_idx = idx; - mirror_idx[i] = 2 * this->localRange.end[i] - 1 - idx[i]; - this->operator()(idx) = -this->evalAt(mirror_idx); - }); - break; - default: - OP_ERROR("Cannot handle current bc padding: bc type {}", - this->bc[i].end->getTypeName()); - OP_ABORT; + switch (this->bc[i].end->getBCType()) + { + case BCType::Dirc: + // mid-point rule + rangeFor(r, [&](auto&& idx) + { + auto bc_v = this->bc[i].end->evalAt(idx); + auto mirror_idx = idx; + mirror_idx[i] = 2 * this->localRange.end[i] - 1 - idx[i]; + this->operator()(idx) = Math::Interpolator1D::intp( + this->mesh.x(i, this->localRange.end[i]), bc_v, + this->mesh.x(i, mirror_idx[i]) + + this->mesh.dx(i, mirror_idx) / 2., + this->evalAt(mirror_idx), + this->mesh.x(i, idx[i]) + this->mesh.dx(i, idx) / 2.); + }); + break; + case BCType::Neum: + // mid-diff = bc + rangeFor(r, [&](auto&& idx) + { + auto bc_v = this->bc[i].end->evalAt(idx); + auto mirror_idx = idx; + mirror_idx[i] = 2 * this->localRange.end[i] - 1 - idx[i]; + this->operator()(idx) + = this->evalAt(mirror_idx) + + bc_v + * (this->mesh.x(i, idx) + + this->mesh.dx(i, idx) / 2. + - this->mesh.x(i, mirror_idx) + - this->mesh.dx(i, mirror_idx) / 2.); + }); + break; + case BCType::Symm: + rangeFor(r, [&](auto&& idx) + { + auto mirror_idx = idx; + mirror_idx[i] = 2 * this->localRange.end[i] - 1 - idx[i]; + this->operator()(idx) = this->evalAt(mirror_idx); + }); + break; + case BCType::ASymm: + rangeFor(r, [&](auto&& idx) + { + auto mirror_idx = idx; + mirror_idx[i] = 2 * this->localRange.end[i] - 1 - idx[i]; + this->operator()(idx) = -this->evalAt(mirror_idx); + }); + break; + default: + OP_ERROR("Cannot handle current bc padding: bc type {}", + this->bc[i].end->getTypeName()); + OP_ABORT; } } - } else { + } + else + { end[i] = this->localRange.end[i]; } } } // step 2: update paddings by MPI communication - if (this->splitMap.size() == 1) {// no MPI or local field + if (this->splitMap.size() == 1) + { + // no MPI or local field // update along periodic dims - for (int i = 0; i < dim; ++i) { - if (this->bc[i].start && this->bc[i].start->getBCType() == BCType::Periodic) { + for (int i = 0; i < dim; ++i) + { + if (this->bc[i].start && this->bc[i].start->getBCType() == BCType::Periodic) + { // issue an update auto rl = this->logicalRange.slice(i, this->logicalRange.start[i], this->accessibleRange.start[i]); - rangeFor(rl, [&](auto&& idx) { + rangeFor(rl, [&](auto&& idx) + { auto mirror_idx = idx; mirror_idx[i] += this->accessibleRange.end[i] - this->accessibleRange.start[i]; this->operator()(idx) = this->operator()(mirror_idx); }); auto rh = this->logicalRange.slice(i, this->accessibleRange.end[i], this->logicalRange.end[i]); - rangeFor(rh, [&](auto&& idx) { + rangeFor(rh, [&](auto&& idx) + { auto mirror_idx = idx; mirror_idx[i] -= this->accessibleRange.end[i] - this->accessibleRange.start[i]; this->operator()(idx) = this->operator()(mirror_idx); }); } } - } else { + } + else + { #if defined(OPFLOW_WITH_MPI) && defined(OPFLOW_DISTRIBUTE_MODEL_MPI) int rank = getWorkerId(); // one of the following pairs of buffer is used @@ -635,32 +754,39 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { std::vector> send_buff_byte, recv_buff_byte; std::vector> send_buff_offsets, recv_buff_offsets; std::vector requests; - auto padded_my_range = this->localRange.getInnerRange(-this->padding); auto mesh_range_extends = this->mesh.getRange().getExtends(); - for (const auto& [other_rank, send_range, recv_range, code] : this->neighbors) { + for (const auto& [other_rank, send_range, recv_range, code] : this->neighbors) + { // calculate the intersect range to be send - if constexpr (std::is_trivial_v && std::is_standard_layout_v) { + if constexpr (std::is_trivial_v&& std::is_standard_layout_v) + { // pack data into send buffer send_buff.emplace_back(); requests.emplace_back(); - rangeFor_s(send_range, [&](auto&& i) { + rangeFor_s(send_range, [&](auto&& i) + { OP_DEBUG("Send {} = {}", i, this->operator()(i)); send_buff.back().push_back(this->evalAt(i)); }); - } else if constexpr (Serializable) { + } + else if constexpr (Serializable) + { // pack data into send buffer send_buff_byte.emplace_back(); send_buff_offsets.emplace_back(); send_buff_offsets.back().push_back(0); requests.emplace_back(); - rangeFor_s(send_range, [&](auto&& i) { + rangeFor_s(send_range, [&](auto&& i) + { OP_DEBUG("Send {} = {}", i, this->operator()(i)); std::vector tmp = this->operator()(i).serialize(); send_buff_byte.back().insert(send_buff_byte.back().end(), tmp.begin(), tmp.end()); - send_buff_offsets.back().push_back((int) send_buff_byte.back().size()); + send_buff_offsets.back().push_back((int)send_buff_byte.back().size()); }); - } else { + } + else + { OP_ERROR("Datatype cannot be serialized."); OP_ABORT; } @@ -668,37 +794,40 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { other_rank); auto o_recv_range = send_range; // inverse the shift to get the recv range on the receiver side - for (int d = 0; d < dim; ++d) { + for (int d = 0; d < dim; ++d) + { int direction - = (code % Math::int_pow(3, d + 1)) / Math::int_pow(3, d);// 0, 1(+), 2(-) - switch (direction) { - case 1: - o_recv_range.start[d] -= mesh_range_extends[d] - 1; - o_recv_range.end[d] -= mesh_range_extends[d] - 1; - break; - default: - case 0: - break; - case 2: - o_recv_range.start[d] += mesh_range_extends[d] - 1; - o_recv_range.end[d] += mesh_range_extends[d] - 1; - break; + = (code % Math::int_pow(3, d + 1)) / Math::int_pow(3, d); // 0, 1(+), 2(-) + switch (direction) + { + case 1: + o_recv_range.start[d] -= mesh_range_extends[d] - 1; + o_recv_range.end[d] -= mesh_range_extends[d] - 1; + break; + default: + case 0: + break; + case 2: + o_recv_range.start[d] += mesh_range_extends[d] - 1; + o_recv_range.end[d] += mesh_range_extends[d] - 1; + break; } } - if constexpr (std::is_trivial_v && std::is_standard_layout_v) + if constexpr (std::is_trivial_v&& std::is_standard_layout_v) MPI_Isend(send_buff.back().data(), send_buff.back().size() * sizeof(D) / sizeof(char), MPI_CHAR, other_rank, - std::hash> {}(o_recv_range) - % (1 << 24), + std::hash>{}(o_recv_range) + % (1 << 24), MPI_COMM_WORLD, &requests.back()); - else if constexpr (Serializable) { + else if constexpr (Serializable) + { MPI_Isend(send_buff_offsets.back().data(), send_buff_offsets.back().size(), MPI_INT, other_rank, rank, MPI_COMM_WORLD, &requests.back()); requests.emplace_back(); MPI_Isend(send_buff_byte.back().data(), send_buff_byte.back().size(), MPI_BYTE, other_rank, - std::hash> {}(o_recv_range) - % (1 << 24), + std::hash>{}(o_recv_range) + % (1 << 24), MPI_COMM_WORLD, &requests.back()); } @@ -707,21 +836,24 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { // issue receive request OP_DEBUG("Recv range {} from rank {} to rank {}", recv_range.toString(), other_rank, rank); - if constexpr (std::is_trivial_v && std::is_standard_layout_v) { + if constexpr (std::is_trivial_v&& std::is_standard_layout_v) + { recv_buff.emplace_back(); recv_buff.back().resize(recv_range.count()); MPI_Irecv(recv_buff.back().data(), recv_buff.back().size() * sizeof(D) / sizeof(char), MPI_CHAR, other_rank, - std::hash> {}(recv_range) % (1 << 24), + std::hash>{}(recv_range) % (1 << 24), MPI_COMM_WORLD, &requests.back()); - } else if constexpr (Serializable) { + } + else if constexpr (Serializable) + { recv_buff_offsets.emplace_back(recv_range.count() + 1); MPI_Recv(recv_buff_offsets.back().data(), recv_buff_offsets.back().size(), MPI_INT, other_rank, other_rank, MPI_COMM_WORLD, MPI_STATUS_IGNORE); recv_buff_byte.emplace_back(recv_buff_offsets.back().back()); MPI_Irecv(recv_buff_byte.back().data(), recv_buff_byte.back().size(), MPI_BYTE, other_rank, - std::hash> {}(recv_range) % (1 << 24), + std::hash>{}(recv_range) % (1 << 24), MPI_COMM_WORLD, &requests.back()); } } @@ -729,30 +861,38 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { std::vector status(requests.size()); MPI_Waitall(requests.size(), requests.data(), status.data()); // check status - for (const auto& s : status) { + for (const auto& s : status) + { if (s.MPI_ERROR != MPI_SUCCESS) OP_CRITICAL("Field {}'s updatePadding failed.", this->getName()); } // unpack receive buffer - if constexpr (std::is_trivial_v && std::is_standard_layout_v) { + if constexpr (std::is_trivial_v&& std::is_standard_layout_v) + { auto recv_iter = recv_buff.begin(); - for (const auto& [other_rank, send_range, recv_range, code] : this->neighbors) { + for (const auto& [other_rank, send_range, recv_range, code] : this->neighbors) + { auto _iter = recv_iter->begin(); OP_DEBUG("Unpacking range {}", recv_range.toString()); - rangeFor_s(recv_range, [&](auto&& i) { + rangeFor_s(recv_range, [&](auto&& i) + { OP_DEBUG("Unpack {} = {}", i, *_iter); this->operator()(i) = *_iter++; }); ++recv_iter; } - } else if constexpr (Serializable) { + } + else if constexpr (Serializable) + { auto recv_iter = recv_buff_byte.begin(); auto recv_offset_iter = recv_buff_offsets.begin(); - for (const auto& [other_rank, send_range, recv_range, code] : this->neighbors) { + for (const auto& [other_rank, send_range, recv_range, code] : this->neighbors) + { auto _iter = recv_iter->begin(); auto _offset_iter = recv_offset_iter->begin(); OP_DEBUG("Unpacking range {}", recv_range.toString()); - rangeFor_s(recv_range, [&](auto&& i) { + rangeFor_s(recv_range, [&](auto&& i) + { //OP_INFO("Unpack {} = {}", i, *(char*)&*_iter); this->operator()(i).deserialize(&(*_iter) + *_offset_iter, *(_offset_iter + 1) - *_offset_iter); @@ -768,17 +908,22 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { } } - auto getViewImpl_final() { + auto getViewImpl_final() + { OP_NOT_IMPLEMENTED; return 0; } - const auto& evalAtImpl_final(const index_type& i) const { + + const auto& evalAtImpl_final(const index_type& i) const + { OP_ASSERT_MSG(DS::inRange(this->getLocalReadableRange(), i), "Cannot eval {} at {}: out of range {}", this->getName(), i, this->getLocalReadableRange().toString()); return data[i - this->offset]; } - auto& evalAtImpl_final(const index_type& i) { + + auto& evalAtImpl_final(const index_type& i) + { OP_ASSERT_MSG(DS::inRange(this->getLocalReadableRange(), i), "Cannot eval {} at {}: out of range {}", this->getName(), i, this->getLocalWritableRange().toString()); @@ -786,159 +931,187 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { } template - requires(!std::same_as) bool containsImpl_final(const Other& o) const { + requires(!std::same_as) + bool containsImpl_final(const Other& o) const + { return false; } bool containsImpl_final(const CartesianField& other) const { return this == &other; } - };// namespace OpFlow + }; // namespace OpFlow template - struct ExprBuilder> { + struct ExprBuilder> + { using Field = CartesianField; using Mesh = M; static constexpr auto dim = internal::CartesianFieldExprTrait::dim; ExprBuilder() = default; - auto& setName(const std::string& n) { + auto& setName(const std::string& n) + { f.name = n; return *this; } - auto& setMesh(const Mesh& m) { + auto& setMesh(const Mesh& m) + { f.mesh = m; return *this; } - auto& setLoc(const std::array& loc) { + auto& setLoc(const std::array& loc) + { f.loc = loc; return *this; } - auto& setLoc(LocOnMesh loc) { + auto& setLoc(LocOnMesh loc) + { f.loc.fill(loc); return *this; } - auto& setLocOfDim(int i, LocOnMesh loc) { + auto& setLocOfDim(int i, LocOnMesh loc) + { f.loc[i] = loc; return *this; } // set a logical bc - auto& setBC(int d, DimPos pos, BCType type) { + auto& setBC(int d, DimPos pos, BCType type) + { OP_ASSERT(d < dim); OP_ASSERT(type != BCType::Dirc && type != BCType::Neum); auto& targetBC = pos == DimPos::start ? f.bc[d].start : f.bc[d].end; - switch (type) { - case BCType::Symm: - targetBC = std::make_unique>>(f, d, pos); - break; - case BCType::ASymm: - targetBC = std::make_unique>>(f, d, pos); - break; - case BCType::Periodic: - targetBC = std::make_unique>>(f, d, pos); - break; - default: - OP_ERROR("BC Type not supported."); - OP_ABORT; + switch (type) + { + case BCType::Symm: + targetBC = std::make_unique>>(f, d, pos); + break; + case BCType::ASymm: + targetBC = std::make_unique>>(f, d, pos); + break; + case BCType::Periodic: + targetBC = std::make_unique>>(f, d, pos); + break; + default: + OP_ERROR("BC Type not supported."); + OP_ABORT; } return *this; } // set a constant bc template - auto& setBC(int d, DimPos pos, BCType type, T val) { + auto& setBC(int d, DimPos pos, BCType type, T val) + { OP_ASSERT(d < dim); if (isLogicalBC(type)) return setBC(d, pos, type); auto& targetBC = pos == DimPos::start ? f.bc[d].start : f.bc[d].end; - switch (type) { - case BCType::Dirc: - targetBC = std::make_unique>>(val); - break; - case BCType::Neum: - targetBC = std::make_unique>>(val); - break; - default: - OP_ERROR("BC Type not supported."); - OP_ABORT; + switch (type) + { + case BCType::Dirc: + targetBC = std::make_unique>>(val); + break; + case BCType::Neum: + targetBC = std::make_unique>>(val); + break; + default: + OP_ERROR("BC Type not supported."); + OP_ABORT; } return *this; } // set a functor bc template - requires requires(F f) { - { f(std::declval>::index_type>()) } - ->std::convertible_to>::elem_type>; - } - auto& setBC(int d, DimPos pos, BCType type, F&& functor) { + requires requires(F f) + { + { + f(std::declval>::index_type>()) + } + -> std::convertible_to>::elem_type>; + } + auto& setBC(int d, DimPos pos, BCType type, F&& functor) + { OP_ASSERT(d < dim); auto& targetBC = pos == DimPos::start ? f.bc[d].start : f.bc[d].end; - switch (type) { - case BCType::Dirc: - targetBC = std::make_unique>>(functor); - break; - case BCType::Neum: - targetBC = std::make_unique>>(functor); - break; - default: - OP_ERROR("BC Type not supported."); - OP_ABORT; + switch (type) + { + case BCType::Dirc: + targetBC = std::make_unique>>(functor); + break; + case BCType::Neum: + targetBC = std::make_unique>>(functor); + break; + default: + OP_ERROR("BC Type not supported."); + OP_ABORT; } return *this; } // set an externally built bc - auto& setBC(int d, DimPos pos, std::unique_ptr>>&& bc) { + auto& setBC(int d, DimPos pos, std::unique_ptr>>&& bc) + { OP_ASSERT(d < dim); auto& targetBC = pos == DimPos::start ? f.bc[d].start : f.bc[d].end; targetBC = std::move(bc); return *this; } - auto& setExt(int d, DimPos pos, int width) { - if (pos == DimPos::start) { + auto& setExt(int d, DimPos pos, int width) + { + if (pos == DimPos::start) + { f.ext_width[d].start = width; - } else { + } + else + { f.ext_width[d].end = width; } return *this; } - auto& setExt(int width) { + auto& setExt(int width) + { // a uniform ext - for (auto& e : f.ext_width) { + for (auto& e : f.ext_width) + { e.start = width; e.end = width; } return *this; } - auto& setPadding(int p) { + auto& setPadding(int p) + { f.padding = p; return *this; } - auto& setSplitStrategy(std::shared_ptr>> s) { + auto& setSplitStrategy(std::shared_ptr>> s) + { strategy = s; return *this; } - auto& build() { + auto& build() + { calculateRanges(); validateRanges(); OP_ASSERT(f.localRange.check() && f.accessibleRange.check() && f.assignableRange.check()); f.data.reShape(f.localRange.getInnerRange(-f.padding).getExtends()); f.offset = typename internal::CartesianFieldExprTrait::index_type( - f.localRange.getInnerRange(-f.padding).getOffset()); + f.localRange.getInnerRange(-f.padding).getOffset()); f.updatePadding(); return f; } private: - void validateRanges() { + void validateRanges() + { // accessibleRange <= logicalRange f.accessibleRange = commonRange(f.accessibleRange, f.logicalRange); // localRange <= logicalRange @@ -947,80 +1120,93 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { f.assignableRange = commonRange(f.assignableRange, f.accessibleRange); } - void calculateRanges() { + void calculateRanges() + { // padding take the max of {padding, ext_width} for (const auto& w : f.ext_width) f.padding = std::max({f.padding, w.start, w.end}); // init ranges to mesh range f.logicalRange = f.assignableRange = f.localRange = f.accessibleRange = f.mesh.getRange(); // trim ranges according to bcs - for (auto i = 0; i < dim; ++i) { + for (auto i = 0; i < dim; ++i) + { auto loc = f.loc[i]; // start side auto type = f.bc[i].start ? f.bc[i].start->getBCType() : BCType::Undefined; - switch (type) { - case BCType::Dirc: - if (loc == LocOnMesh::Corner) f.assignableRange.start[i]++; - break; - case BCType::Neum: - case BCType::Undefined: - case BCType::Symm: - case BCType::ASymm: - case BCType::Periodic: - break; - default: - OP_NOT_IMPLEMENTED; + switch (type) + { + case BCType::Dirc: + if (loc == LocOnMesh::Corner) f.assignableRange.start[i]++; + break; + case BCType::Neum: + case BCType::Undefined: + case BCType::Symm: + case BCType::ASymm: + case BCType::Periodic: + break; + default: + OP_NOT_IMPLEMENTED; } // end side type = f.bc[i].end ? f.bc[i].end->getBCType() : BCType::Undefined; - switch (type) { - case BCType::Dirc: - if (loc == LocOnMesh::Corner) { - f.assignableRange.end[i]--; - } else if (loc == LocOnMesh::Center) { - f.accessibleRange.end[i]--; - f.assignableRange.end[i]--; - } - break; - case BCType::Neum: - case BCType::Undefined: - case BCType::Symm: - case BCType::ASymm: - if (loc == LocOnMesh::Center) { - f.accessibleRange.end[i]--; - f.assignableRange.end[i]--; - } - break; - case BCType::Periodic: - // same as center case + switch (type) + { + case BCType::Dirc: + if (loc == LocOnMesh::Corner) + { + f.assignableRange.end[i]--; + } + else if (loc == LocOnMesh::Center) + { f.accessibleRange.end[i]--; f.assignableRange.end[i]--; - break; - default: - OP_NOT_IMPLEMENTED; + } + break; + case BCType::Neum: + case BCType::Undefined: + case BCType::Symm: + case BCType::ASymm: + if (loc == LocOnMesh::Center) + { + f.accessibleRange.end[i]--; + f.assignableRange.end[i]--; + } + break; + case BCType::Periodic: + // same as center case + f.accessibleRange.end[i]--; + f.assignableRange.end[i]--; + break; + default: + OP_NOT_IMPLEMENTED; } f.logicalRange.start[i] = f.accessibleRange.start[i] - f.ext_width[i].start; f.logicalRange.end[i] = f.accessibleRange.end[i] + f.ext_width[i].end; } // calculate localRange - if (strategy) { + if (strategy) + { // always split the mesh range to make sure associated fields shares the same split // note: the returned local range is in centered mode f.localRange = strategy->splitRange(f.mesh.getRange(), getGlobalParallelPlan()); f.splitMap = strategy->getSplitMap(f.mesh.getRange(), getGlobalParallelPlan()); // adjust the local range according to the location & bc - for (auto i = 0; i < dim; ++i) { + for (auto i = 0; i < dim; ++i) + { auto loc = f.loc[i]; // we only need to consider the end side for whether taken the right boundary into account // only +1 if the block is at the right end // periodic bc can be trimmed by the min operation if (loc == LocOnMesh::Corner && f.localRange.end[i] == f.mesh.getRange().end[i] - 1) f.localRange.end[i] = std::min(f.localRange.end[i] + 1, f.accessibleRange.end[i]); - for (auto& range : f.splitMap) { + for (auto& range : f.splitMap) + { if (loc == LocOnMesh::Corner && range.end[i] == f.mesh.getRange().end[i] - 1) range.end[i] = std::min(range.end[i] + 1, f.accessibleRange.end[i]); } } - } else { + } + else + { f.localRange = f.accessibleRange; f.splitMap.clear(); f.splitMap.push_back(f.localRange); @@ -1031,14 +1217,15 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { CartesianField f; std::shared_ptr>> strategy; }; +} // namespace OpFlow -}// namespace OpFlow - -namespace std { +namespace std +{ template - void swap(OpFlow::CartesianField& a, OpFlow::CartesianField& b) { + void swap(OpFlow::CartesianField& a, OpFlow::CartesianField& b) + { std::swap(a.data, b.data); } -}// namespace std +} // namespace std -#endif//OPFLOW_CARTESIANFIELD_HPP +#endif//OPFLOW_CARTESIANFIELD_HPP \ No newline at end of file diff --git a/src/Core/Loops/RangeFor.hpp b/src/Core/Loops/RangeFor.hpp index eefae395..80a14931 100644 --- a/src/Core/Loops/RangeFor.hpp +++ b/src/Core/Loops/RangeFor.hpp @@ -29,7 +29,10 @@ #include #endif -OPFLOW_MODULE_EXPORT namespace OpFlow { +OPFLOW_MODULE_EXPORT + +namespace OpFlow +{ /// \brief Serial version of range for /// \tparam dim Range dim /// \tparam F Functor type @@ -37,23 +40,27 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { /// \param func Applied functor /// \return The input functor template - F rangeFor_s(const R& range, F&& func) { + F rangeFor_s(const R& range, F&& func) + { typename R::index_type i(range); auto total_count = range.count(); - for (auto count = 0; count < total_count; ++count, ++i) { + for (auto count = 0; count < total_count; ++count, ++i) + { func(static_cast(i)); } return std::forward(func); } template - auto rangeReduce_s(const R& range, ReOp&& op, F&& func) { + auto rangeReduce_s(const R& range, ReOp&& op, F&& func) + { //OP_INFO("Called on {}, size = {}", range.toString(), range.count()); typename R::index_type idx(range); auto result = func(static_cast(idx)); ++idx; auto total_count = range.count(); - for (auto count = 1; count < total_count; ++count, ++idx) { + for (auto count = 1; count < total_count; ++count, ++idx) + { result = op(result, func(static_cast(idx))); } return result; @@ -66,17 +73,22 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { /// \param func Applied functor /// \return The input functor template - F rangeFor(const R& range, F&& func) { + F rangeFor(const R& range, F&& func) + { [[maybe_unused]] constexpr static auto dim = R::dim; [[maybe_unused]] auto total_count = range.count(); auto line_size = range.end[0] - range.start[0]; if (line_size <= 0) return std::forward(func); - if (range.stride[0] == 1) { + if (range.stride[0] == 1) + { tbb::task_arena arena(getGlobalParallelPlan().shared_memory_workers_count); - arena.execute([&]() { + arena.execute([&]() + { tbb::parallel_for(range, [&](const R& r) { rangeFor_s(r, OP_PERFECT_FOWD(func)); }); }); - } else { + } + else + { OP_NOT_IMPLEMENTED; std::abort(); } @@ -84,37 +96,43 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { } template - auto rangeReduce(const R& range, ReOp&& op, F&& func) { + auto rangeReduce(const R& range, ReOp&& op, F&& func) + { using resultType = Meta::RealType()))>; - constexpr static auto dim = R::dim; auto line_size = range.end[0] - range.start[0]; if (line_size <= 0) return resultType(); - struct Reducer { - resultType result {}; + struct Reducer + { const ReOp& _op; const F& _func; + resultType result{}; void operator()(const R& _range) { result = _op(result, rangeReduce_s(_range, _op, _func)); } Reducer(Reducer& _reducer, tbb::detail::split) - : _op(_reducer._op), _func(_reducer._func), result() { + : _op(_reducer._op), _func(_reducer._func), result() + { if constexpr (Meta::Numerical) result = 0; } void join(const Reducer& _reducer) { result = _op(result, _reducer.result); } - Reducer(const ReOp& _op, const F& _func) : _op(_op), _func(_func), result() { + Reducer(const ReOp& _op, const F& _func) : _op(_op), _func(_func), result() + { // make sure for numerical type the reduction base is 0 if constexpr (Meta::Numerical) result = 0; // otherwise, we assume the default ctor of resultType provides an adequate base } - } reducer {op, func}; + } reducer{op, func}; - if (range.stride[0] == 1) { + if (range.stride[0] == 1) + { tbb::task_arena arena(getGlobalParallelPlan().shared_memory_workers_count); arena.execute([&]() { tbb::parallel_reduce(range, reducer); }); return reducer.result; - } else { + } + else + { OP_NOT_IMPLEMENTED; std::abort(); } @@ -122,17 +140,18 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { #ifdef OPFLOW_WITH_MPI template - auto globalReduce(const R& range, ReOp&& op, F&& func) { + auto globalReduce(const R& range, ReOp&& op, F&& func) + { auto local_result = rangeReduce(range, op, func); std::vector results(getWorkerCount()); results[getWorkerId()] = local_result; static_assert(std::is_standard_layout_v && std::is_trivial_v, + local_result)> && std::is_trivial_v, "local_result must be pod type"); MPI_Allgather(MPI_IN_PLACE, sizeof(decltype(local_result)), MPI_BYTE, results.data(), sizeof(decltype(local_result)), MPI_BYTE, MPI_COMM_WORLD); - return std::reduce(results.begin(), results.end(), decltype(local_result) {}, op); + return std::reduce(results.begin(), results.end(), decltype(local_result){}, op); } #endif -}// namespace OpFlow -#endif//OPFLOW_RANGEFOR_HPP +} // namespace OpFlow +#endif//OPFLOW_RANGEFOR_HPP \ No newline at end of file diff --git a/src/Core/Parallel/ParticleGuidedSplitStrategy.hpp b/src/Core/Parallel/ParticleGuidedSplitStrategy.hpp index 9931b582..90f4ea11 100644 --- a/src/Core/Parallel/ParticleGuidedSplitStrategy.hpp +++ b/src/Core/Parallel/ParticleGuidedSplitStrategy.hpp @@ -27,35 +27,47 @@ #include #endif -OPFLOW_MODULE_EXPORT namespace OpFlow { +OPFLOW_MODULE_EXPORT + +namespace OpFlow +{ template - struct Particle { + struct Particle + { std::array x; }; template - struct ParticleGuidedSplitStrategy : AbstractSplitStrategy { + struct ParticleGuidedSplitStrategy : AbstractSplitStrategy + { public: - static constexpr int dim = internal::ExprTrait::dim; + static constexpr int dim = internal::ExprTrait < F > ::dim; ParticleGuidedSplitStrategy() = default; + ParticleGuidedSplitStrategy(std::vector> parts, double part_load, double mesh_laod, int max_levels, const typename internal::ExprTrait::mesh_type& ref_mesh) : particles(parts), part_load_factor(part_load), mesh_load_factor(mesh_laod), - max_levels(max_levels), ref_mesh(ref_mesh) {} + max_levels(max_levels), ref_mesh(ref_mesh) + { + } [[nodiscard]] std::string strategyName() const override { return "Particle guided split"; } + typename internal::ExprTrait::range_type splitRange(const typename internal::ExprTrait::range_type& range, - const ParallelPlan& plan) override { + const ParallelPlan& plan) override + { check_state(plan); return split_impl(range, plan); } - std::vector::range_type> + std::vector::range_type + > getSplitMap(const typename internal::ExprTrait::range_type& range, - const ParallelPlan& plan) override { + const ParallelPlan& plan) override + { check_state(plan); return splitMap_impl(range, plan); } @@ -80,27 +92,35 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { double part_load_factor = 0, mesh_load_factor = 1; int max_levels = 0; - struct Node { + struct Node + { std::unique_ptr lc, rc; Node* parent = nullptr; DS::Range range; std::vector> particles; std::vector particle_weight; - int split_axis = -1;// -1 for leaf node + int split_axis = -1; // -1 for leaf node Node() = default; - void traverse(auto&& func) const { - if (!is_leaf()) { + + void traverse(auto&& func) const + { + if (!is_leaf()) + { lc->traverse(OP_PERFECT_FOWD(func)); rc->traverse(OP_PERFECT_FOWD(func)); - } else { + } + else + { func(*this); } } - void print_tree(std::string prefix) const { + void print_tree(std::string prefix) const + { OP_INFO("{} range = {}, axis = {}", prefix, range.toString(), split_axis); - if (!is_leaf()) { + if (!is_leaf()) + { prefix += "--"; OP_INFO("{} lc:", prefix); lc->print_tree(prefix); @@ -108,7 +128,9 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { rc->print_tree(prefix); } } - void splitAt(int d, int pos, const typename internal::ExprTrait::mesh_type& mesh) { + + void splitAt(int d, int pos, const typename internal::ExprTrait::mesh_type& mesh) + { auto new_lc = std::make_unique(); auto new_rc = std::make_unique(); new_lc->range = range; @@ -121,11 +143,15 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { new_lc->parent = this; new_rc->parent = this; split_axis = d; - for (int i = 0; i < particles.size(); ++i) { - if (particles[i].x[d] < mesh.x(d, pos + range.start[d])) { + for (std::size_t i = 0; i < particles.size(); ++i) + { + if (particles[i].x[d] < mesh.x(d, pos + range.start[d])) + { new_lc->particles.push_back(particles[i]); new_lc->particle_weight.push_back(particle_weight[i]); - } else { + } + else + { new_rc->particles.push_back(particles[i]); new_rc->particle_weight.push_back(particle_weight[i]); } @@ -135,7 +161,8 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { } void splitAtLoadMid(int d, double pload, double mload, - const typename internal::ExprTrait::mesh_type& mesh) { + const typename internal::ExprTrait::mesh_type& mesh) + { auto offset = get_load_mid(d, pload, mload, mesh); splitAt(d, offset, mesh); } @@ -146,7 +173,8 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { bool is_leaf() const { return !lc && !rc; } int get_load_mid(int d, double pload, double mload, - const typename internal::ExprTrait::mesh_type& mesh) { + const typename internal::ExprTrait::mesh_type& mesh) + { auto load = get_load_along_dim(d, pload, mload, mesh); auto total_load = get_total_load(pload, mload); auto mid_iter = std::find_if_not(load.begin(), load.end(), @@ -154,14 +182,16 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { return mid_iter - load.begin(); } - double get_total_load(double pload, double mload) const { + double get_total_load(double pload, double mload) const + { double weighted_particle_size - = std::accumulate(particle_weight.begin(), particle_weight.end(), 0); + = std::accumulate(particle_weight.begin(), particle_weight.end(), 0); return weighted_particle_size * pload + range.count() * mload; } std::vector get_load_along_dim(int d, double pload, double mload, - const typename internal::ExprTrait::mesh_type& mesh) { + const typename internal::ExprTrait::mesh_type& mesh) + { auto per_slice_load = get_per_slice_load_along_dim(d, pload, mload, mesh); std::vector ret(per_slice_load.size()); std::exclusive_scan(per_slice_load.begin(), per_slice_load.end(), ret.begin(), 0); @@ -170,43 +200,54 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { std::vector get_per_slice_load_along_dim(int d, double pload, double mload, - const typename internal::ExprTrait::mesh_type& mesh) { + const typename internal::ExprTrait::mesh_type& mesh) + { std::vector ret(range.end[d] - range.start[d], 0); - if (!is_leaf()) { - if (d == split_axis) { + if (!is_leaf()) + { + if (d == split_axis) + { // merge results from children auto left = lc->get_per_slice_load_along_dim(d, pload, mload, mesh); auto right = rc->get_per_slice_load_along_dim(d, pload, mload, mesh); std::copy(ret.begin(), ret.begin() + left.size(), left.begin()); std::copy(ret.begin() + left.size(), ret.end(), right.begin()); return ret; - } else { + } + else + { // merge results from children by add auto left = lc->get_per_slice_load_along_dim(d, pload, mload, mesh); auto right = rc->get_per_slice_load_along_dim(d, pload, mload, mesh); - for (int i = 0; i < ret.size(); ++i) ret[i] = left[i] + right[i]; + for (std::size_t i = 0; i < ret.size(); ++i) ret[i] = left[i] + right[i]; return ret; } - } else { + } + else + { // do the real work // sort particles along axis d std::vector, double>> buffer; - for (int i = 0; i < particles.size(); ++i) { + for (std::size_t i = 0; i < particles.size(); ++i) + { buffer.emplace_back(particles[i], particle_weight[i]); } std::sort(buffer.begin(), buffer.end(), [d](auto&& a, auto&& b) { return a.first.x[d] < b.first.x[d]; }); - for (int i = 0; i < particles.size(); ++i) { + for (std::size_t i = 0; i < particles.size(); ++i) + { particles[i] = buffer[i].first; particle_weight[i] = buffer[i].second; } buffer.clear(); // add particle work load first auto part_iter = particles.begin(); - for (int i = 0; i < ret.size(); ++i) { + for (std::size_t i = 0; i < ret.size(); ++i) + { double xleft = mesh.x(d, i), xright = mesh.x(d, i + 1); while (part_iter != particles.end() && xleft <= part_iter->x[d] - && part_iter->x[d] < xright) { + && part_iter->x[d] < xright) + { ret[i] += particle_weight[part_iter - particles.begin()] * pload; part_iter++; } @@ -221,12 +262,14 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { std::unique_ptr kdtree = nullptr; - void check_state(const ParallelPlan& plan) const { + void check_state(const ParallelPlan& plan) const + { OP_ASSERT_MSG(1 << max_levels == plan.distributed_workers_count, "ParticleGuidedSplitStrategy: total number of ranks must be power of 2"); } - void gather_all_particles() { + void gather_all_particles() + { #if defined(OPFLOW_WITH_MPI) // gather counts std::vector counts(getWorkerCount(), 0); @@ -238,7 +281,8 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { MPI_Allgather(&local_particle_weight, 1, MPI_DOUBLE, weights_buffer.data(), 1, MPI_DOUBLE, MPI_COMM_WORLD); global_weights.reserve(total_part_size); - for (int i = 0; i < counts.size(); ++i) { + for (std::size_t i = 0; i < counts.size(); ++i) + { for (int j = 0; j < counts[i]; ++j) global_weights.push_back(weights_buffer[i]); } particle_weight = std::move(global_weights); @@ -258,7 +302,8 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { } // build a kd-tree of max_levels according to given particles and background mesh - auto gen_split_tree(const DS::Range& range, const ParallelPlan& plan) { + auto gen_split_tree(const DS::Range& range, const ParallelPlan&) + { gather_all_particles(); Node root; root.range = range; @@ -266,10 +311,12 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { root.particle_weight = particle_weight; std::deque build_queue; build_queue.push_back(&root); - for (int i = 0; i < max_levels; ++i) { + for (int i = 0; i < max_levels; ++i) + { auto iter = build_queue.begin(); auto end = build_queue.end(); - while (iter != end) { + while (iter != end) + { auto ptr = *iter; ptr->splitAtLoadMid(i % dim, part_load_factor, mesh_load_factor, ref_mesh); build_queue.pop_front(); @@ -281,20 +328,23 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { return std::make_unique(std::move(root)); } - auto split_impl(const DS::Range& range, const ParallelPlan& plan) { + auto split_impl(const DS::Range& range, const ParallelPlan& plan) + { // assume the input range is nodal range, convert to central range auto _range = range; for (std::size_t i = 0; i < dim; ++i) _range.end[i]--; if (plan.singleNodeMode() || max_levels == 0) return _range; - else { + else + { if (!kdtree) kdtree = gen_split_tree(_range, plan); auto* ptr = kdtree.get(); // root is a full binary tree auto mask = OpFlow::getWorkerCount(); auto rank = OpFlow::getWorkerId(); - OP_ASSERT_MSG(std::exp2((int) std::log2(mask)) == mask, + OP_ASSERT_MSG(std::exp2((int)std::log2(mask)) == mask, "total worker count must be power of 2"); - while (mask >>= 1) { + while (mask >>= 1) + { if (mask & rank) ptr = ptr->rc.get(); else ptr = ptr->lc.get(); @@ -303,12 +353,14 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { } } - auto splitMap_impl(const DS::Range& range, const ParallelPlan& plan) { + auto splitMap_impl(const DS::Range& range, const ParallelPlan& plan) + { // assume the input range is nodal range, convert to central range auto _range = range; for (std::size_t i = 0; i < dim; ++i) _range.end[i]--; - if (plan.singleNodeMode()) return std::vector> {_range}; - else { + if (plan.singleNodeMode()) return std::vector>{_range}; + else + { if (!kdtree) kdtree = gen_split_tree(_range, plan); #if defined(OPFLOW_WITH_MPI) || defined(OPFLOW_TEST_ENVIRONMENT) std::vector> ret; @@ -321,6 +373,6 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { } } }; -}// namespace OpFlow +} // namespace OpFlow -#endif//OPFLOW_PARTICLEGUIDEDSPLITSTRATEGY_HPP +#endif//OPFLOW_PARTICLEGUIDEDSPLITSTRATEGY_HPP \ No newline at end of file diff --git a/src/Core/Solvers/Struct/StructSolverPrecond.hpp b/src/Core/Solvers/Struct/StructSolverPrecond.hpp index 8fb570a7..2f9bad6d 100644 --- a/src/Core/Solvers/Struct/StructSolverPrecond.hpp +++ b/src/Core/Solvers/Struct/StructSolverPrecond.hpp @@ -15,9 +15,13 @@ #include "StructSolver.hpp" -OPFLOW_MODULE_EXPORT namespace OpFlow { +OPFLOW_MODULE_EXPORT + +namespace OpFlow +{ template - struct PrecondStructSolver { + struct PrecondStructSolver + { constexpr auto static type = Type; constexpr auto static precondType = PrecondType; using Param = StructSolverParams; @@ -26,16 +30,21 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { PrecondParam precondParam; PrecondStructSolver() = default; + PrecondStructSolver(const Param& p, const PrecondParam& pp) - : solver(p), precond(pp), params(p), precondParam(pp) {} + : params(p), precondParam(pp), solver(p), precond(pp) + { + } - void init() { + void init() + { solver.init(); precond.init(); solver.setPrecond(precond.getSolveFunc(), precond.getSetUpFunc(), precond.getSolver()); } - void reinit() { + void reinit() + { solver.reinit(); precond.reinit(); solver.setPrecond(precond.getSolveFunc(), precond.getSetUpFunc(), precond.getSolver()); @@ -46,16 +55,20 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { auto getSolveFunc() const { return solver.getSolveFunc(); } auto getSetUpFunc() const { return solver.getSetUpFunc(); } - auto solve(HYPRE_StructMatrix& A, HYPRE_StructVector& b, HYPRE_StructVector& x) { + auto solve(HYPRE_StructMatrix& A, HYPRE_StructVector& b, HYPRE_StructVector& x) + { return solver.solve(A, b, x); } - auto setup(HYPRE_StructMatrix& A, HYPRE_StructVector& b, HYPRE_StructVector& x) { + auto setup(HYPRE_StructMatrix& A, HYPRE_StructVector& b, HYPRE_StructVector& x) + { return solver.setup(A, b, x); } - void dump(HYPRE_StructMatrix& A, HYPRE_StructVector& b) { - if (params.dumpPath) { + void dump(HYPRE_StructMatrix& A, HYPRE_StructVector& b) + { + if (params.dumpPath) + { HYPRE_StructMatrixPrint((params.dumpPath.value() + "_A.mat").c_str(), A, 0); HYPRE_StructVectorPrint((params.dumpPath.value() + "_b.vec").c_str(), b, 0); } @@ -69,6 +82,5 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { StructSolver solver; StructSolver precond; }; - -}// namespace OpFlow -#endif//OPFLOW_STRUCTSOLVERPRECOND_HPP +} // namespace OpFlow +#endif//OPFLOW_STRUCTSOLVERPRECOND_HPP \ No newline at end of file diff --git a/src/DataStructures/Arrays/Tensor/FixedSizeTensor.hpp b/src/DataStructures/Arrays/Tensor/FixedSizeTensor.hpp index 71e0eb76..a3d1b4d6 100644 --- a/src/DataStructures/Arrays/Tensor/FixedSizeTensor.hpp +++ b/src/DataStructures/Arrays/Tensor/FixedSizeTensor.hpp @@ -20,56 +20,80 @@ #include #endif -OPFLOW_MODULE_EXPORT namespace OpFlow::DS { - namespace internal { +OPFLOW_MODULE_EXPORT + +namespace OpFlow::DS +{ + namespace internal + { template - constexpr int accumulate_product(std::array arr) { + constexpr int accumulate_product(std::array arr) + { if constexpr (N == 0) return 0; - else { + else + { int ret = arr[0]; - for (auto i = 1; i < N; ++i) ret *= arr[i]; + for (std::size_t i = 1; i < N; ++i) ret *= arr[i]; return ret; } } - - }// namespace internal + } // namespace internal template - requires(std::integral && ...) struct FixedSizeTensor; - namespace internal { + requires(std::integral && ...) + struct FixedSizeTensor; + + namespace internal + { template - requires(std::integral&&...) struct TensorTrait> { + requires(std::integral && ...) + struct TensorTrait> + { using scalar_type = T; static constexpr auto dim = sizeof...(n); }; template - struct is_fixed_size_tensor : std::false_type {}; + struct is_fixed_size_tensor : std::false_type + { + }; template - requires(std::integral&&...) struct is_fixed_size_tensor> - : std::true_type {}; - }// namespace internal + requires(std::integral && ...) + struct is_fixed_size_tensor> + : std::true_type + { + }; + } // namespace internal template concept FixedSizeTensorType = internal::is_fixed_size_tensor>::value; template - requires(std::integral && ...) struct FixedSizeTensor : Tensor> { + requires(std::integral && ...) + struct FixedSizeTensor : Tensor> + { constexpr static auto N = sizeof...(n); constexpr FixedSizeTensor() = default; constexpr explicit FixedSizeTensor(T val) { _val.fill(val); } - constexpr explicit FixedSizeTensor(auto... vals) : _val {vals...} {} - constexpr const auto& operator[](const MDIndex& idx) const { + constexpr explicit FixedSizeTensor(auto... vals) : _val{vals...} + { + } + + constexpr const auto& operator[](const MDIndex& idx) const + { int _pos = idx[N - 1]; for (int i = N - 2; i >= 0; --i) { _pos = _pos * _sizes[i] + idx[i]; } return _val[_pos]; } - constexpr auto& operator[](const MDIndex& idx) { + + constexpr auto& operator[](const MDIndex& idx) + { int _pos = idx[N - 1]; for (int i = N - 2; i >= 0; --i) { _pos = _pos * _sizes[i] + idx[i]; } return _val[_pos]; } + constexpr const auto& operator[](const int& idx) const { return _val[idx]; } constexpr auto& operator[](const int& idx) { return _val[idx]; } constexpr const auto& operator()(const MDIndex& idx) const { return operator[](idx); } @@ -80,7 +104,9 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::DS { constexpr static auto size() { return _sizes; } constexpr static auto total_size() { return _total_size; } constexpr static auto size_of(int d) { return _sizes[d]; } - constexpr static auto max_half_width() { + + constexpr static auto max_half_width() + { if constexpr (N == 0) return 0; auto max_dim = _sizes[0]; for (int i = 1; i < N; ++i) max_dim = std::max(max_dim, _sizes[i]); @@ -89,10 +115,9 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::DS { constexpr void fill(T val) { _val.fill(val); } - static constexpr std::array _sizes {n...}; + static constexpr std::array _sizes{n...}; static constexpr int _total_size = internal::accumulate_product(_sizes); std::array _val; }; - -}// namespace OpFlow::DS -#endif//OPFLOW_FIXEDSIZETENSOR_HPP +} // namespace OpFlow::DS +#endif//OPFLOW_FIXEDSIZETENSOR_HPP \ No newline at end of file diff --git a/src/DataStructures/Index/ColoredIndex.hpp b/src/DataStructures/Index/ColoredIndex.hpp index d5152e20..eb4f3a44 100644 --- a/src/DataStructures/Index/ColoredIndex.hpp +++ b/src/DataStructures/Index/ColoredIndex.hpp @@ -136,7 +136,7 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::DS { for (auto i = 0; i < n; ++i) ret += prefix; ret += "{"; if constexpr (d > 0) ret += std::format("{}", idx[0]); - for (auto i = 1; i < d; ++i) ret += std::format(", {}", idx[i]); + for (std::size_t i = 1; i < d; ++i) ret += std::format(", {}", idx[i]); ret += std::format(", c = {}", color); ret += "}"; return ret; diff --git a/src/DataStructures/Index/LinearMapper/BlockedMDRangeMapper.hpp b/src/DataStructures/Index/LinearMapper/BlockedMDRangeMapper.hpp index d25c0fd1..9ea73c60 100644 --- a/src/DataStructures/Index/LinearMapper/BlockedMDRangeMapper.hpp +++ b/src/DataStructures/Index/LinearMapper/BlockedMDRangeMapper.hpp @@ -20,7 +20,10 @@ #include #endif -OPFLOW_MODULE_EXPORT namespace OpFlow::DS { +OPFLOW_MODULE_EXPORT + +namespace OpFlow::DS +{ /** * \brief Axis aligned split multi-dimensional range mapper * \note We assume here the input _ranges are generated by splitting a range by several orthogonal planes. @@ -28,11 +31,13 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::DS { * @tparam d Dimension */ template - struct BlockedMDRangeMapper { + struct BlockedMDRangeMapper + { BlockedMDRangeMapper() = default; // local ctor - explicit BlockedMDRangeMapper(const std::vector>& ranges) : _ranges(ranges) { + explicit BlockedMDRangeMapper(const std::vector>& ranges) : _ranges(ranges) + { gatherSplits(); sortRanges(); calculateOffsets(); @@ -40,23 +45,28 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::DS { } // MPI collective ctor - explicit BlockedMDRangeMapper(const Range& range) { + explicit BlockedMDRangeMapper(const Range& range) + { #ifdef OPFLOW_WITH_MPI - if (getWorkerCount() > 1) { + if (getWorkerCount() > 1) + { _ranges.resize(getWorkerCount()); _ranges[getWorkerId()] = range; std::vector> _starts(_ranges.size()), _ends(_ranges.size()), - _strides(_ranges.size()); + _strides(_ranges.size()); _starts[getWorkerId()] = range.start; _ends[getWorkerId()] = range.end; _strides[getWorkerId()] = range.stride; MPI_Allgather(MPI_IN_PLACE, d, MPI_INT, _starts.data(), d, MPI_INT, MPI_COMM_WORLD); MPI_Allgather(MPI_IN_PLACE, d, MPI_INT, _ends.data(), d, MPI_INT, MPI_COMM_WORLD); MPI_Allgather(MPI_IN_PLACE, d, MPI_INT, _strides.data(), d, MPI_INT, MPI_COMM_WORLD); - for (int i = 0; i < _ranges.size(); ++i) { - _ranges[i] = Range(_starts[i], _ends[i], _strides[i]); + for (std::size_t i = 0; i < _ranges.size(); ++i) + { + _ranges[i] = Range < d > (_starts[i], _ends[i], _strides[i]); } - } else { + } + else + { _ranges.resize(1); _ranges[0] = range; } @@ -69,11 +79,16 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::DS { calculateMultiplier(); } - std::array getBlockIndex(const MDIndex& idx) const { - if (!checkIndexInBlock(idx, getBlockRank(last_block))) { - for (auto i = 0; i < d; ++i) { - for (auto j = 0; j < _split[i].size() - 1; ++j) { - if (_split[i][j] <= idx[i] && idx[i] < _split[i][j + 1]) { + std::array getBlockIndex(const MDIndex& idx) const + { + if (!checkIndexInBlock(idx, getBlockRank(last_block))) + { + for (std::size_t i = 0; i < d; ++i) + { + for (std::size_t j = 0; j < _split[i].size() - 1; ++j) + { + if (_split[i][j] <= idx[i] && idx[i] < _split[i][j + 1]) + { last_block[i] = j; break; } @@ -83,18 +98,22 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::DS { return last_block; } - bool checkIndexInBlock(const MDIndex& idx, const int block_rank) const { + bool checkIndexInBlock(const MDIndex& idx, const int block_rank) const + { return inRange(_ranges[block_rank], idx); } - int getBlockRank(const std::array& block_idx) const { + int getBlockRank(const std::array& block_idx) const + { // we assume the _ranges are listed by column-major sequence int block_rank = block_idx[d - 1]; - for (int i = d - 2; i >= 0; --i) { + for (int i = d - 2; i >= 0; --i) + { block_rank *= _split[i].size() - 1; block_rank += block_idx[i]; } - OP_ASSERT_MSG(block_rank < _ranges.size(), "Block rank {} out of range {}", block_rank, + OP_ASSERT_MSG(static_cast(block_rank) < _ranges.size(), "Block rank {} out of range {}", + block_rank, _ranges.size()); return block_rank; } @@ -103,25 +122,29 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::DS { int getBlockSize(int block_rank) const { return _ranges[block_rank].count(); } - int getLocalRank(const MDIndex& idx) const { - if (!checkIndexInBlock(idx, last_block_rank)) { + int getLocalRank(const MDIndex& idx) const + { + if (!checkIndexInBlock(idx, last_block_rank)) + { last_block = getBlockIndex(idx); last_block_rank = getBlockRank(last_block); } int block_rank = last_block_rank; - OP_ASSERT_MSG(block_rank < _ranges.size(), + OP_ASSERT_MSG(static_cast(block_rank) < _ranges.size(), "BlockedMDRangeMapper error: block_rank {} large than total ranges count {}", block_rank, _ranges.size()); const auto& _r = _ranges[block_rank]; OP_ASSERT_MSG(inRange(_r, idx), "BlockedMDRangeMapper Error: index {} not in blocked range {}", idx, _r.toString()); int ret = 0; - for (auto i = 0; i < d; ++i) ret += _fac[block_rank][i] * (idx[i] - _r.start[i]); + for (std::size_t i = 0; i < d; ++i) ret += _fac[block_rank][i] * (idx[i] - _r.start[i]); return ret; } - int operator()(const MDIndex& idx) const { - if (!checkIndexInBlock(idx, last_block_rank)) { + int operator()(const MDIndex& idx) const + { + if (!checkIndexInBlock(idx, last_block_rank)) + { last_block = getBlockIndex(idx); last_block_rank = getBlockRank(last_block); } @@ -132,27 +155,35 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::DS { "{}}}, last_block_rank = {}", idx, _r.toString(), last_block[0], last_block[1], last_block_rank); int ret = _offset[block_rank]; - for (auto i = 0; i < d; ++i) ret += _fac[block_rank][i] * (idx[i] - _r.start[i]); + for (std::size_t i = 0; i < d; ++i) ret += _fac[block_rank][i] * (idx[i] - _r.start[i]); return ret; } [[nodiscard]] int count() const { return _offset.back(); } [[nodiscard]] int block_count() const { return _ranges.size(); } - int operator()(const ColoredIndex>& idx) const { + int operator()(const ColoredIndex>& idx) const + { // todo: color is ignored here. check this out - return this->operator()(MDIndex {idx}); + return this->operator()(MDIndex < d > + { + idx + } + ) + ; } // todo: workaround same as MDIndexMapper int operator()(const MDIndex& idx, int) const { return operator()(idx); } private: - void gatherSplits() { + void gatherSplits() + { // IMPORTANT ASSUMPTION: // We assume here the input _ranges are generated by splitting a range by several orthogonal planes std::vector>> segments(d); - for (auto i = 0; i < d; ++i) { + for (std::size_t i = 0; i < d; ++i) + { for (const auto& _r : _ranges) { segments[i].emplace_back(_r.start[i], _r.end[i]); } std::sort(segments[i].begin(), segments[i].end()); auto end = std::unique(segments[i].begin(), segments[i].end()); @@ -162,31 +193,40 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::DS { } } - void sortRanges() { + void sortRanges() + { // sort the ranges according to column-major rank - std::sort(_ranges.begin(), _ranges.end(), [&](const Range& a, const Range& b) { + std::sort(_ranges.begin(), _ranges.end(), [&](const Range& a, const Range& b) + { // this happens when the left-most block is empty because all nodes covered by the boundary // e.g., x-face field on a 4x4 mesh with 3 MPI procs and Dirichlet boundary condition - if (a.empty() && !b.empty()) { + if (a.empty() && !b.empty()) + { return true; - } else + } + else return getBlockRank(getBlockIndex(a.first())) < getBlockRank(getBlockIndex(b.first())); }); } - void calculateOffsets() { + void calculateOffsets() + { _offset.resize(_ranges.size() + 1); _offset[0] = 0; - for (auto i = 1; i < _offset.size(); ++i) { + for (std::size_t i = 1; i < _offset.size(); ++i) + { _offset[i] = _offset[i - 1] + _ranges[i - 1].count(); } } - void calculateMultiplier() { + void calculateMultiplier() + { _fac.resize(_ranges.size()); - for (auto i = 0; i < _fac.size(); ++i) { + for (std::size_t i = 0; i < _fac.size(); ++i) + { _fac[i][0] = 1; - for (auto j = 1; j < d; ++j) { + for (std::size_t j = 1; j < d; ++j) + { _fac[i][j] = (_ranges[i].end[j - 1] - _ranges[i].start[j - 1]) * _fac[i][j - 1]; } } @@ -198,9 +238,9 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::DS { std::vector> _ranges; // used to accelerate repeating query inside the same block - mutable std::array last_block {0}; + mutable std::array last_block{0}; mutable int last_block_rank = 0; }; -}// namespace OpFlow::DS +} // namespace OpFlow::DS -#endif//OPFLOW_BLOCKEDMDRANGEMAPPER_HPP +#endif//OPFLOW_BLOCKEDMDRANGEMAPPER_HPP \ No newline at end of file diff --git a/src/DataStructures/Range/Ranges.hpp b/src/DataStructures/Range/Ranges.hpp index 4d605ced..11ce0e37 100644 --- a/src/DataStructures/Range/Ranges.hpp +++ b/src/DataStructures/Range/Ranges.hpp @@ -26,22 +26,27 @@ #include #endif -OPFLOW_MODULE_EXPORT namespace OpFlow::DS { +OPFLOW_MODULE_EXPORT + +namespace OpFlow::DS +{ template struct RangedIndex; template - struct Range { + struct Range + { constexpr static int dim = d; using index_type = RangedIndex; using base_index_type = MDIndex; - std::array start, end, stride;// stride here means the step in each dim. + std::array start, end, stride; // stride here means the step in each dim. // Not the same as StrideIndex. private: mutable std::array pace; public: - constexpr static auto EmptyRange() { + constexpr static auto EmptyRange() + { Range ret; ret.start.fill(0); ret.end.fill(0); @@ -52,45 +57,54 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::DS { constexpr Range() { stride.fill(1); } - constexpr explicit Range(const std::array& end) noexcept : end(end), pace(end) { + constexpr explicit Range(const std::array& end) noexcept : end(end), pace(end) + { start.fill(0); stride.fill(1); } constexpr Range(const std::array& start, const std::array& end) noexcept - : start(start), end(end) { + : start(start), end(end) + { stride.fill(1); reValidPace(); } constexpr Range(const std::array& start, const std::array& end, const std::array& stride) noexcept - : start(start), end(end), stride(stride) { + : start(start), end(end), stride(stride) + { reValidPace(); } - constexpr void reValidPace() const { + constexpr void reValidPace() const + { for (std::size_t i = 0; i < dim; ++i) pace[i] = (end[i] - start[i]) / stride[i]; } - constexpr auto operator==(const Range& other) const { + constexpr auto operator==(const Range& other) const + { return start == other.start && end == other.end && stride == other.stride; } - constexpr auto check() const { + constexpr auto check() const + { bool ret = true; ret &= (d == start.size()) && (d == end.size()) && (d == stride.size()); - for (std::size_t i = 0; i < d; ++i) { + for (std::size_t i = 0; i < d; ++i) + { ret &= (end[i] >= start[i]); ret &= (stride[i] >= 1); } return ret; } - constexpr auto count() const { + constexpr auto count() const + { // make sure the pace is valid reValidPace(); - for (std::size_t i = 0; i < d; ++i) { + for (std::size_t i = 0; i < d; ++i) + { if (pace[i] <= 0) return 0; } auto ret = 1; @@ -98,9 +112,11 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::DS { return ret; } - constexpr auto covers(const Range& other) const { + constexpr auto covers(const Range& other) const + { auto ret = true; - for (std::size_t i = 0; i < d; ++i) { + for (std::size_t i = 0; i < d; ++i) + { ret &= start[i] <= other.start[i] && end[i] >= other.end[i]; } return ret; @@ -111,7 +127,8 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::DS { /// \brief Get the sliced range (1 layer thick) along dim \p k at position \p pos /// \param k normal dimension of the slice /// \param pos position of the slice - constexpr auto slice(std::size_t k, int pos) const { + constexpr auto slice(std::size_t k, int pos) const + { assert(k < d); Range ret = *this; ret.start[k] = pos; @@ -125,7 +142,8 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::DS { /// \param pos_start Position of the start /// \param pos_end Position of the end /// \return The sliced range - constexpr auto slice(std::size_t k, int pos_start, int pos_end) const { + constexpr auto slice(std::size_t k, int pos_start, int pos_end) const + { assert(k < d); Range ret = *this; ret.start[k] = pos_start; @@ -134,29 +152,34 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::DS { return ret; } - auto toString() const { + auto toString() const + { std::string ret; ret = std::format("{{{} - {} by {}}}", Utils::Serializer::serialize(start), Utils::Serializer::serialize(end), Utils::Serializer::serialize(stride)); return ret; } - constexpr auto getExtends() const { + constexpr auto getExtends() const + { reValidPace(); - std::array ret; + std::array < int, d > ret; for (std::size_t i = 0; i < d; ++i) { ret[i] = pace[i]; } return ret; } - constexpr auto getOffset() const { - std::array ret; + constexpr auto getOffset() const + { + std::array < int, d > ret; for (std::size_t i = 0; i < d; ++i) ret[i] = start[i]; return ret; } - auto getBCRanges(int width) const { + auto getBCRanges(int width) const + { std::vector ret; - for (std::size_t i = 0; i < d; ++i) { + for (std::size_t i = 0; i < d; ++i) + { ret.push_back(*this); ret.back().end[i] = ret.back().start[i] + width; ret.back().pace[i] = width; @@ -167,9 +190,11 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::DS { return ret; } - auto getInnerRange(int width) const { + auto getInnerRange(int width) const + { auto ret = *this; - for (std::size_t i = 0; i < dim; ++i) { + for (std::size_t i = 0; i < dim; ++i) + { ret.start[i] += width; ret.end[i] -= width; ret.pace[i] -= 2 * width; @@ -179,23 +204,28 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::DS { void setEmpty() { *this = EmptyRange(); } - auto first() const { return base_index_type {start}; } - auto last() const { - auto ret = base_index_type {end}; + auto first() const { return base_index_type{start}; } + + auto last() const + { + auto ret = base_index_type{end}; for (int i = 0; i < d; ++i) ret[i]--; return ret; } bool empty() const { return count() <= 0; } - bool is_divisible() const { - for (int i = 0; i < dim; ++i) { + bool is_divisible() const + { + for (int i = 0; i < dim; ++i) + { if (end[i] - start[i] > 1) return true; } return false; } - Range(Range& r, [[maybe_unused]] tbb::detail::split split) : Range(r) { + Range(Range& r, [[maybe_unused]] tbb::detail::split split) : Range(r) + { this->reValidPace(); int max_iter = std::max_element(pace.begin(), pace.end()) - pace.begin(); this->end[max_iter] = this->start[max_iter] + this->pace[max_iter] / 2; @@ -204,12 +234,13 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::DS { r.pace[max_iter] = r.end[max_iter] - r.start[max_iter]; } - Range(Range& r, tbb::detail::proportional_split proportion) : Range(r) { + Range(Range& r, tbb::detail::proportional_split proportion) : Range(r) + { this->reValidPace(); int max_iter = std::max_element(pace.begin(), pace.end()) - pace.begin(); int right_part = int(float(r.end[max_iter] - r.start[max_iter]) * float(proportion.right()) - / float(proportion.left() + proportion.right()) - + 0.5f); + / float(proportion.left() + proportion.right()) + + 0.5f); r.end[max_iter] -= right_part; this->start[max_iter] = r.end[max_iter]; this->pace[max_iter] = this->end[max_iter] - this->start[max_iter]; @@ -217,44 +248,62 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::DS { } static constexpr bool is_splittable_in_proportion = true; - auto center() const { - auto ret = base_index_type {start}; - for (int i = 0; i < d; ++i) ret[i] = (ret[i] + end[i]) / 2; + + auto center() const + { + auto ret = base_index_type{start}; + for (std::size_t i = 0; i < d; ++i) ret[i] = (ret[i] + end[i]) / 2; return ret; } }; template - concept isRange = requires { - T::dim; - } - &&std::is_same_v, Range>; + concept isRange = requires + { + T::dim; + } + && std::is_same_v, Range>; template - constexpr auto commonRange(const Range& a, const Range& b) { - std::array start, end; - if constexpr (dim1 != dim2) { - static_assert(dim1 == 0 || dim2 == 0, OP_ERRMSG_DIM_MISMATCH); - if constexpr (dim1 == 0) { + constexpr auto commonRange(const Range& a, const Range& b) + { + std::array < int, dim1 > start, end; + if constexpr (dim1 != dim2) + { + static_assert(dim1 == 0 || dim2 == 0, + OP_ERRMSG_DIM_MISMATCH + ) + ; + if constexpr (dim1 == 0) + { return b; - } else { + } + else + { return a; } - } else { - static_assert(dim1 == dim2, OP_ERRMSG_DIM_MISMATCH); + } + else + { + static_assert(dim1 == dim2, + OP_ERRMSG_DIM_MISMATCH + ) + ; constexpr auto dim = dim1; start.fill(std::numeric_limits::min()); end.fill(std::numeric_limits::max()); - for (std::size_t i = 0; i < dim; ++i) { + for (std::size_t i = 0; i < dim; ++i) + { start[i] = std::max(a.start[i], b.start[i]); end[i] = std::min(a.end[i], b.end[i]); } - return Range {start, end}; + return Range{start, end}; } } template - constexpr auto commonRanges(const std::vector>& a, const std::vector>& b) { + constexpr auto commonRanges(const std::vector>& a, const std::vector>& b) + { std::vector> ret; OP_ASSERT(a.size() == b.size()); ret.reserve(a.size()); @@ -263,29 +312,42 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::DS { } template - constexpr auto minCoverRange(const Range& a, const Range& b) { - if constexpr (dim1 != dim2) { - static_assert(dim1 == 0 || dim2 == 0, OP_ERRMSG_DIM_MISMATCH); + constexpr auto minCoverRange(const Range& a, const Range& b) + { + if constexpr (dim1 != dim2) + { + static_assert(dim1 == 0 || dim2 == 0, + OP_ERRMSG_DIM_MISMATCH + ) + ; if constexpr (dim1 == 0) return b; else return a; - } else { - static_assert(dim1 == dim2, OP_ERRMSG_DIM_MISMATCH); + } + else + { + static_assert(dim1 == dim2, + OP_ERRMSG_DIM_MISMATCH + ) + ; constexpr auto dim = dim1; Range ret; - for (std::size_t i = 0; i < dim; ++i) { + for (std::size_t i = 0; i < dim; ++i) + { ret.start[i] = std::min(a.start[i], b.start[i]); ret.end[i] = std::max(a.end[i], b.end[i]); OP_ASSERT(a.stride[i] == b.stride[i]); } - return Range {ret.start, ret.end}; + return Range{ret.start, ret.end}; } } template - constexpr auto minCoverRange(const std::vector>& r) { + constexpr auto minCoverRange(const std::vector>& r) + { if constexpr (dim == 0) return r[0]; - else { + else + { Range ret = r[0]; for (auto i = 1; i < r.size(); ++i) { ret = minCoverRange(ret, r[i]); } return ret; @@ -293,30 +355,43 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::DS { } template - constexpr auto maxCommonRange(const Range& a, const Range& b) { - if constexpr (dim1 != dim2) { - static_assert(dim1 == 0 || dim2 == 0, OP_ERRMSG_DIM_MISMATCH); + constexpr auto maxCommonRange(const Range& a, const Range& b) + { + if constexpr (dim1 != dim2) + { + static_assert(dim1 == 0 || dim2 == 0, + OP_ERRMSG_DIM_MISMATCH + ) + ; if constexpr (dim1 == 0) return b; else return a; - } else { - static_assert(dim1 == dim2, OP_ERRMSG_DIM_MISMATCH); + } + else + { + static_assert(dim1 == dim2, + OP_ERRMSG_DIM_MISMATCH + ) + ; constexpr auto dim = dim1; Range ret; - for (std::size_t i = 0; i < dim; ++i) { + for (std::size_t i = 0; i < dim; ++i) + { ret.start[i] = std::max(a.start[i], b.start[i]); ret.end[i] = std::min(a.end[i], b.end[i]); OP_ASSERT(a.stride[i] == b.stride[i]); - if (ret.end[i] < ret.start[i]) return Range {}; + if (ret.end[i] < ret.start[i]) return Range{}; } - return Range {ret.start, ret.end}; + return Range{ret.start, ret.end}; } } template - constexpr auto maxCommonRange(const std::vector>& r) { + constexpr auto maxCommonRange(const std::vector>& r) + { if constexpr (dim == 0) return r[0]; - else { + else + { Range ret = r[0]; for (auto i = 1; i < r.size(); ++i) { ret = maxCommonRange(ret, r[i]); } return ret; @@ -324,20 +399,23 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::DS { } template - constexpr auto inRange(const Range& r, const T& t) { + constexpr auto inRange(const Range& r, const T& t) + { auto ret = true; for (std::size_t i = 0; i < dim; ++i) { ret &= (r.start[i] <= t[i] && t[i] < r.end[i]); } return ret; } - -}// namespace OpFlow::DS +} // namespace OpFlow::DS template -struct std::hash> { +struct std::hash> +{ public: - std::size_t operator()(const OpFlow::DS::Range& r) const noexcept { - std::array arr; - for (std::size_t i = 0; i < dim; ++i) { + std::size_t operator()(const OpFlow::DS::Range& r) const noexcept + { + std::array < int, 3 * dim > arr; + for (std::size_t i = 0; i < dim; ++i) + { arr[i] = r.start[i]; arr[i + dim] = r.end[i]; arr[i + 2 * dim] = r.stride[i]; @@ -345,4 +423,4 @@ struct std::hash> { return XXHash64::hash(arr.data(), sizeof(arr), 0); } }; -#endif//OPFLOW_RANGES_HPP +#endif//OPFLOW_RANGES_HPP \ No newline at end of file diff --git a/src/DataStructures/StencilPad.hpp b/src/DataStructures/StencilPad.hpp index c3e42f39..6037742f 100644 --- a/src/DataStructures/StencilPad.hpp +++ b/src/DataStructures/StencilPad.hpp @@ -22,9 +22,13 @@ #include #endif -OPFLOW_MODULE_EXPORT namespace OpFlow::DS { +OPFLOW_MODULE_EXPORT + +namespace OpFlow::DS +{ template - struct fake_map { + struct fake_map + { private: std::array, max_size> val; @@ -33,50 +37,62 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::DS { public: fake_map() = default; - bool operator==(const fake_map& other) const { + bool operator==(const fake_map& other) const + { bool ret = _size == other._size; if (!ret) return false; - for (auto i = 0; i < _size; ++i) { + for (auto i = 0; i < _size; ++i) + { auto iter = other.find(val[i].first); ret &= iter != other.end() && val[i].second == iter->second; } return ret; } - auto& at(const K& key) { + auto& at(const K& key) + { auto iter = find(key); if (iter != end()) return iter->second; - else { + else + { OP_CRITICAL("fake map error: Key {} out of range", key.toString()); OP_ABORT; } } - const auto& at(const K& key) const { + const auto& at(const K& key) const + { auto iter = find(key); if (iter != end()) return iter->second; - else { + else + { OP_CRITICAL("fake map error: Key {} out of range", key.toString()); OP_ABORT; } } - auto& operator[](const K& key) { + auto& operator[](const K& key) + { auto pos = -1; - for (auto i = 0; i < _size; ++i) { - if (key == val[i].first) { + for (auto i = 0; i < _size; ++i) + { + if (key == val[i].first) + { pos = i; break; } } - if (pos == -1) { + if (pos == -1) + { #ifndef NDEBUG - OP_ASSERT_MSG(_size < max_size, "fake map error: Map is full"); + OP_ASSERT_MSG(static_cast(_size) < max_size, "fake map error: Map is full"); #endif val[_size].first = key; _size++; return val[_size - 1].second; - } else { + } + else + { return val[pos].second; } } @@ -84,33 +100,41 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::DS { auto size() const { return _size; } void clear() { _size = 0; } - auto find(const K& k) { - for (auto iter = val.begin(); iter != end(); ++iter) { + auto find(const K& k) + { + for (auto iter = val.begin(); iter != end(); ++iter) + { if (iter->first == k) return iter; } return end(); } - auto find(const K& k) const { - for (auto iter = val.begin(); iter != end(); ++iter) { + auto find(const K& k) const + { + for (auto iter = val.begin(); iter != end(); ++iter) + { if (iter->first == k) return iter; } return end(); } - auto findFirst(auto&& f) const { - for (auto iter = val.begin(); iter != end(); ++iter) { + auto findFirst(auto&& f) const + { + for (auto iter = val.begin(); iter != end(); ++iter) + { if (f(iter->first)) return iter; } return end(); } - auto exist(const K& k) const { + auto exist(const K& k) const + { auto p = find(k); return p == end(); } - int rank(const K& k) const { + int rank(const K& k) const + { auto p = find(k); if (p == end()) return -1; else @@ -125,7 +149,8 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::DS { auto end() const { return val.begin() + _size; } - auto sort() { + auto sort() + { std::sort(val.begin(), val.end(), [](auto&& a, auto&& b) { return a.first < b.first; }); } }; @@ -134,42 +159,51 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::DS { using fake_map_default = fake_map<10, K, V>; template typename map_impl = fake_map_default> - struct StencilPad : public StringifiableObj, SerializableObj { - map_impl pad {}; + struct StencilPad : public StringifiableObj, SerializableObj + { + map_impl pad{}; Real bias = 0.; StencilPad() = default; - [[nodiscard]] std::vector serialize() const override { + + [[nodiscard]] std::vector serialize() const override + { std::vector ret; ret.resize(sizeof(int) + pad.size() * (sizeof(Idx) + sizeof(Real)) + sizeof(Real)); std::byte* ptr = ret.data(); - *(int*) ptr = pad.size(); + *(int*)ptr = pad.size(); int i = 0; - for (const auto& [k, v] : pad) { - *(Idx*) (ptr + sizeof(int) + i * (sizeof(Idx) + sizeof(Real))) = k; - *(Real*) (ptr + sizeof(int) + i * (sizeof(Idx) + sizeof(Real)) + sizeof(Idx)) = v; + for (const auto& [k, v] : pad) + { + *(Idx*)(ptr + sizeof(int) + i * (sizeof(Idx) + sizeof(Real))) = k; + *(Real*)(ptr + sizeof(int) + i * (sizeof(Idx) + sizeof(Real)) + sizeof(Idx)) = v; i++; } - *(Real*) (ptr + sizeof(int) + pad.size() * (sizeof(Idx) + sizeof(Real))) = bias; + *(Real*)(ptr + sizeof(int) + pad.size() * (sizeof(Idx) + sizeof(Real))) = bias; return ret; } - void deserialize(const std::byte* data, std::size_t size) override { + void deserialize(const std::byte* data, std::size_t) override + { const std::byte* ptr = data; - int size_ = *(int*) ptr; + int size_ = *(int*)ptr; ptr += sizeof(int); pad.clear(); - for (int i = 0; i < size_; ++i) { - Idx k = *(Idx*) (ptr + i * (sizeof(Idx) + sizeof(Real))); - Real v = *(Real*) (ptr + i * (sizeof(Idx) + sizeof(Real)) + sizeof(Idx)); + for (int i = 0; i < size_; ++i) + { + Idx k = *(Idx*)(ptr + i * (sizeof(Idx) + sizeof(Real))); + Real v = *(Real*)(ptr + i * (sizeof(Idx) + sizeof(Real)) + sizeof(Idx)); pad[k] = v; } - bias = *(Real*) (ptr + size_ * (sizeof(Idx) + sizeof(Real))); + bias = *(Real*)(ptr + size_ * (sizeof(Idx) + sizeof(Real))); } - explicit StencilPad(Real b) : bias(b) {} + explicit StencilPad(Real b) : bias(b) + { + } - [[nodiscard]] std::string toString(int n, const std::string& prefix) const override { + [[nodiscard]] std::string toString(int n, const std::string& prefix) const override + { std::string _prefix; for (auto i = 0; i < n; ++i) _prefix += prefix; std::string ret = "\n" + _prefix + "pad:\n"; @@ -182,18 +216,24 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::DS { auto operator+() const { return *this; } - auto operator-() const { + auto operator-() const + { auto ret = *this; for (auto& [k, v] : ret.pad) { v = -v; } ret.bias = -ret.bias; return ret; } - auto& operator+=(const StencilPad& other) { - for (const auto& [idx, val] : other.pad) { - if (auto iter = pad.find(idx); iter != pad.end()) { + auto& operator+=(const StencilPad& other) + { + for (const auto& [idx, val] : other.pad) + { + if (auto iter = pad.find(idx); iter != pad.end()) + { iter->second += val; - } else { + } + else + { pad[idx] = val; } } @@ -201,16 +241,22 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::DS { return *this; } - auto& operator+=(Meta::Numerical auto other) { + auto& operator+=(Meta::Numerical auto other) + { bias += other; return *this; } - auto& operator-=(const StencilPad& other) { - for (const auto& [idx, val] : other.pad) { - if (auto iter = pad.find(idx); iter != pad.end()) { + auto& operator-=(const StencilPad& other) + { + for (const auto& [idx, val] : other.pad) + { + if (auto iter = pad.find(idx); iter != pad.end()) + { iter->second -= val; - } else { + } + else + { pad[idx] = -val; } } @@ -218,69 +264,81 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::DS { return *this; } - auto& operator-=(Meta::Numerical auto other) { + auto& operator-=(Meta::Numerical auto other) + { bias -= other; return *this; } - auto& operator*=(Real r) { + auto& operator*=(Real r) + { for (auto& [idx, val] : pad) { val *= r; } bias *= r; return *this; } - auto& operator/=(Real r) { + auto& operator/=(Real r) + { for (auto& [idx, val] : pad) { val /= r; } bias /= r; return *this; } void sort() { pad.sort(); } - void reset() { + + void reset() + { pad.clear(); bias = 0.; } }; template typename map_impl> - auto operator+(const StencilPad& a, const StencilPad& b) { + auto operator+(const StencilPad& a, const StencilPad& b) + { auto ret = a; ret += b; return ret; } template typename map_impl, Meta::Numerical Num> - auto operator+(const StencilPad& a, Num b) { + auto operator+(const StencilPad& a, Num b) + { auto ret = a; ret += b; return ret; } template typename map_impl, Meta::Numerical Num> - auto operator+(Num a, const StencilPad& b) { + auto operator+(Num a, const StencilPad& b) + { auto ret = b; ret += a; return ret; } template typename map_impl> - auto operator-(const StencilPad& a, const StencilPad& b) { + auto operator-(const StencilPad& a, const StencilPad& b) + { auto ret = b * -1.0; return a + ret; } template typename map_impl, Meta::Numerical Num> - auto operator-(const StencilPad& a, Num b) { + auto operator-(const StencilPad& a, Num b) + { return a + (-b); } template typename map_impl, Meta::Numerical Num> - auto operator-(Num a, const StencilPad& b) { + auto operator-(Num a, const StencilPad& b) + { return StencilPad(a) - b; } template typename map_impl, Meta::Numerical Num> - auto operator*(const StencilPad& a, Num b) { + auto operator*(const StencilPad& a, Num b) + { auto ret = a; for (auto& [idx, val] : ret.pad) { val *= b; } ret.bias *= b; @@ -288,17 +346,20 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::DS { } template typename map_impl, Meta::Numerical Num> - auto operator*(Num b, const StencilPad& a) { + auto operator*(Num b, const StencilPad& a) + { return a * b; } template typename map_impl, Meta::Numerical Num> - auto operator/(const StencilPad& a, Num b) { + auto operator/(const StencilPad& a, Num b) + { return a * (1. / b); } template typename map_impl> - auto getOffsetStencil(const StencilPad& a, const IdxB& base) { + auto getOffsetStencil(const StencilPad& a, const IdxB& base) + { StencilPad ret; for (const auto& [idx, val] : a.pad) { ret.pad[idx - base] = val; } ret.bias = a.bias; @@ -307,10 +368,12 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::DS { template typename map_impl> auto commonStencil(const StencilPad& a, const Idx& base, - const StencilPad& offsetStencil) { + const StencilPad& offsetStencil) + { auto a_offset = getOffsetStencil(a, base); auto ret = a_offset; - for (const auto& [idx, val] : offsetStencil.pad) { + for (const auto& [idx, val] : offsetStencil.pad) + { if (auto iter = ret.pad.find(idx); iter == ret.pad.end()) { ret.pad[idx] = 0.; } } return ret; @@ -322,9 +385,11 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::DS { /// \param base /// \return template typename map_impl> - auto commonStencil(const StencilPad& a, const StencilPad& base) { + auto commonStencil(const StencilPad& a, const StencilPad& base) + { auto ret = a; - for (const auto& [idx, val] : base.pad) { + for (const auto& [idx, val] : base.pad) + { if (auto iter = ret.pad.find(idx); iter == ret.pad.end()) { ret.pad[idx] = 0.; } } return ret; @@ -336,12 +401,14 @@ OPFLOW_MODULE_EXPORT namespace OpFlow::DS { /// \param b /// \return template typename map_impl> - auto mergeStencil(const StencilPad& a, const StencilPad& b) { + auto mergeStencil(const StencilPad& a, const StencilPad& b) + { auto ret = a; - for (const auto& [idx, val] : b.pad) { + for (const auto& [idx, val] : b.pad) + { if (auto iter = ret.pad.find(idx); iter == ret.pad.end()) { ret.pad[idx] = val; } } return ret; } -}// namespace OpFlow::DS -#endif//OPFLOW_STENCILPAD_HPP +} // namespace OpFlow::DS +#endif//OPFLOW_STENCILPAD_HPP \ No newline at end of file diff --git a/test/Core/Field/CartesianFieldMPITest.cpp b/test/Core/Field/CartesianFieldMPITest.cpp index 3a301a89..99cb2f89 100644 --- a/test/Core/Field/CartesianFieldMPITest.cpp +++ b/test/Core/Field/CartesianFieldMPITest.cpp @@ -23,9 +23,11 @@ import opflow; using namespace OpFlow; class CartesianFieldMPITest - : public testing::TestWithParam, std::array>> { + : public testing::TestWithParam, std::array>> +{ protected: - void SetUp() override { + void SetUp() override + { auto info = makeParallelInfo(); setGlobalParallelInfo(info); setGlobalParallelPlan(makeParallelPlan(getGlobalParallelInfo(), ParallelIdentifier::DistributeMem)); @@ -41,7 +43,8 @@ class CartesianFieldMPITest Mesh m; }; -TEST_P(CartesianFieldMPITest, RangeCheck) { +TEST_P(CartesianFieldMPITest, RangeCheck) +{ const auto& [bcs, locs] = GetParam(); auto builder = ExprBuilder().setMesh(m); if (isLogicalBC(bcs[0])) builder.setBC(0, DimPos::start, bcs[0]); @@ -61,7 +64,8 @@ TEST_P(CartesianFieldMPITest, RangeCheck) { auto mr = strategy->splitRange(m.getRange(), getGlobalParallelPlan()); // mpi only affect localRange - for (int i = 0; i < 2; ++i) { + for (int i = 0; i < 2; ++i) + { ASSERT_EQ(u.localRange.start[i], mr.start[i]); int end; if (locs[i] == LocOnMesh::Center || bcs[i] == BCType::Periodic) end = mr.end[i]; @@ -74,7 +78,8 @@ TEST_P(CartesianFieldMPITest, RangeCheck) { } // should behave the same as no-ext version -TEST_P(CartesianFieldMPITest, WithExtRangeCheck) { +TEST_P(CartesianFieldMPITest, WithExtRangeCheck) +{ const auto& [bcs, locs] = GetParam(); auto builder = ExprBuilder().setMesh(m); if (isLogicalBC(bcs[0])) builder.setBC(0, DimPos::start, bcs[0]); @@ -94,7 +99,8 @@ TEST_P(CartesianFieldMPITest, WithExtRangeCheck) { auto mr = strategy->splitRange(m.getRange(), getGlobalParallelPlan()); // mpi only affect localRange - for (int i = 0; i < 2; ++i) { + for (int i = 0; i < 2; ++i) + { ASSERT_EQ(u.localRange.start[i], mr.start[i]); int end; if (locs[i] == LocOnMesh::Center || bcs[i] == BCType::Periodic) end = mr.end[i]; @@ -106,83 +112,99 @@ TEST_P(CartesianFieldMPITest, WithExtRangeCheck) { } } -TEST_F(CartesianFieldMPITest, PeriodicValueCheck) { +TEST_F(CartesianFieldMPITest, PeriodicValueCheck) +{ auto u = ExprBuilder() - .setMesh(m) - .setBC(0, OpFlow::DimPos::start, OpFlow::BCType::Periodic) - .setBC(0, OpFlow::DimPos::end, OpFlow::BCType::Periodic) - .setBC(1, OpFlow::DimPos::start, OpFlow::BCType::Periodic) - .setBC(1, OpFlow::DimPos::end, OpFlow::BCType::Periodic) - .setPadding(1) - .setExt(1) - .setSplitStrategy(strategy) - .setLoc({LocOnMesh::Center, LocOnMesh::Center}) - .build(); + .setMesh(m) + .setBC(0, OpFlow::DimPos::start, OpFlow::BCType::Periodic) + .setBC(0, OpFlow::DimPos::end, OpFlow::BCType::Periodic) + .setBC(1, OpFlow::DimPos::start, OpFlow::BCType::Periodic) + .setBC(1, OpFlow::DimPos::end, OpFlow::BCType::Periodic) + .setPadding(1) + .setExt(1) + .setSplitStrategy(strategy) + .setLoc({LocOnMesh::Center, LocOnMesh::Center}) + .build(); auto u_local = ExprBuilder() - .setMesh(m) - .setBC(0, OpFlow::DimPos::start, OpFlow::BCType::Periodic) - .setBC(0, OpFlow::DimPos::end, OpFlow::BCType::Periodic) - .setBC(1, OpFlow::DimPos::start, OpFlow::BCType::Periodic) - .setBC(1, OpFlow::DimPos::end, OpFlow::BCType::Periodic) - .setExt(1) - .setLoc({LocOnMesh::Center, LocOnMesh::Center}) - .build(); - - auto mapper = DS::MDRangeMapper<2>(u.assignableRange); + .setMesh(m) + .setBC(0, OpFlow::DimPos::start, OpFlow::BCType::Periodic) + .setBC(0, OpFlow::DimPos::end, OpFlow::BCType::Periodic) + .setBC(1, OpFlow::DimPos::start, OpFlow::BCType::Periodic) + .setBC(1, OpFlow::DimPos::end, OpFlow::BCType::Periodic) + .setExt(1) + .setLoc({LocOnMesh::Center, LocOnMesh::Center}) + .build(); + + auto mapper = DS::MDRangeMapper < 2 > (u.assignableRange); rangeFor_s(u.getLocalWritableRange(), [&](auto&& i) { u[i] = mapper(i); }); rangeFor_s(u_local.getLocalWritableRange(), [&](auto&& i) { u_local[i] = mapper(i); }); u.updatePadding(); u_local.updatePadding(); - rangeFor_s(u.getLocalReadableRange(), [&](auto&& i) { + rangeFor_s(u.getLocalReadableRange(), [&](auto&& i) + { if (u[i] != u_local[i]) std::cout << std::format("Not equal at {} {} != {}", i, u[i], u_local[i]); ASSERT_EQ(u[i], u_local[i]); }); } -TEST_F(CartesianFieldMPITest, Serializable_PeriodicValueCheck) { - class Int : public virtual SerializableObj { +TEST_F(CartesianFieldMPITest, Serializable_PeriodicValueCheck) +{ + class Int : public virtual SerializableObj + { public: int i = 0; Int() = default; - explicit Int(int i) : i(i) {} - [[nodiscard]] std::vector serialize() const override { + + explicit Int(int i) : i(i) + { + } + + [[nodiscard]] std::vector serialize() const override + { return {reinterpret_cast(&i), reinterpret_cast(&i + 1)}; } - void deserialize(const std::byte* data, std::size_t size) override { + + void deserialize(const std::byte* data, std::size_t) override + { std::memcpy(&i, data, sizeof(i)); } }; auto s = std::make_shared>>(); auto u = ExprBuilder>() - .setMesh(m) - .setPadding(1) - .setName("uInt") - .setLoc({LocOnMesh::Center, LocOnMesh::Center}) - .setSplitStrategy(s) - .build(); - - auto mapper = DS::MDRangeMapper<2>(u.assignableRange); - rangeFor_s(u.getLocalWritableRange(), [&](auto&& i) { u[i] = Int {mapper(i)}; }); + .setMesh(m) + .setPadding(1) + .setName("uInt") + .setLoc({LocOnMesh::Center, LocOnMesh::Center}) + .setSplitStrategy(s) + .build(); + + auto mapper = DS::MDRangeMapper < 2 > (u.assignableRange); + rangeFor_s(u.getLocalWritableRange(), [&](auto&& i) { u[i] = Int{mapper(i)}; }); u.updatePadding(); - rangeFor_s(u.getLocalReadableRange(), [&](auto&& i) { + rangeFor_s(u.getLocalReadableRange(), [&](auto&& i) + { if (u[i].i != mapper(i)) std::cout << std::format("Not equal at {} {} != {}", i, u[i].i, mapper(i)); ASSERT_EQ(u[i].i, mapper(i)); }); } INSTANTIATE_TEST_SUITE_P( - Param2D, CartesianFieldMPITest, - testing::Values(std::make_tuple(std::array {BCType::Dirc, BCType::Dirc, BCType::Dirc, BCType::Dirc}, - std::array {LocOnMesh::Center, LocOnMesh::Center}), - std::make_tuple(std::array {BCType::Neum, BCType::Neum, BCType::Neum, BCType::Neum}, - std::array {LocOnMesh ::Center, LocOnMesh::Center}), - std::make_tuple(std::array {BCType::Periodic, BCType::Periodic, BCType::Periodic, - BCType::Periodic}, - std::array {LocOnMesh ::Center, LocOnMesh::Center}), - std::make_tuple(std::array {BCType::Dirc, BCType::Dirc, BCType::Dirc, BCType::Dirc}, - std::array {LocOnMesh ::Corner, LocOnMesh::Corner}), - std::make_tuple(std::array {BCType::Neum, BCType::Neum, BCType::Neum, BCType::Neum}, - std::array {LocOnMesh ::Corner, LocOnMesh::Corner}), - std::make_tuple(std::array {BCType::Periodic, BCType::Periodic, BCType::Periodic, - BCType::Periodic}, - std::array {LocOnMesh ::Corner, LocOnMesh::Corner}))); + Param2D, CartesianFieldMPITest, + testing::Values(std::make_tuple(std::array{BCType::Dirc, BCType::Dirc, BCType::Dirc, BCType::Dirc}, + std::array{LocOnMesh::Center, LocOnMesh::Center}), + std::make_tuple(std::array{BCType::Neum, BCType::Neum, BCType::Neum, BCType::Neum}, + std::array{LocOnMesh::Center, LocOnMesh::Center}), + std::make_tuple(std::array{ + BCType::Periodic, BCType::Periodic, BCType::Periodic, + BCType::Periodic + }, + std::array{LocOnMesh::Center, LocOnMesh::Center}), + std::make_tuple(std::array{BCType::Dirc, BCType::Dirc, BCType::Dirc, BCType::Dirc}, + std::array{LocOnMesh::Corner, LocOnMesh::Corner}), + std::make_tuple(std::array{BCType::Neum, BCType::Neum, BCType::Neum, BCType::Neum}, + std::array{LocOnMesh::Corner, LocOnMesh::Corner}), + std::make_tuple(std::array{ + BCType::Periodic, BCType::Periodic, BCType::Periodic, + BCType::Periodic + }, + std::array{LocOnMesh::Corner, LocOnMesh::Corner}))); \ No newline at end of file diff --git a/test/Core/Loops/RangeForTest.cpp b/test/Core/Loops/RangeForTest.cpp index 7b06583c..7fd4161c 100644 --- a/test/Core/Loops/RangeForTest.cpp +++ b/test/Core/Loops/RangeForTest.cpp @@ -33,7 +33,8 @@ class RangedIndexTest : public Test { DS::MDIndex ret; ret.set(index.range.start); assert(linear >= 0); - for (auto i = 0; i < index.dim; ++i) { + for (std::size_t i = 0; i < index.dim; ++i) + { ret[i] += linear % ((index.range.end[i] - 1 - index.range.start[i]) / index.range.stride[i] + 1) * index.range.stride[i]; linear /= ((index.range.end[i] - 1 - index.range.start[i]) / index.range.stride[i] + 1); @@ -47,7 +48,7 @@ class RangedIndexTest : public Test { } [[nodiscard]] auto serialize(const T& idx) const { auto ret = std::format("({}", idx[0]); - for (auto i = 1; i < idx.dim; ++i) { ret += std::format(", {}", idx[i]); } + for (std::size_t i = 1; i < idx.dim; ++i) { ret += std::format(", {}", idx[i]); } ret += ")"; return ret; } @@ -58,7 +59,8 @@ class RangedIndexTest : public Test { TEST_F(RangedIndexTest, GetTotalCount) { auto total = 1; - for (auto i = 0; i < index.dim; ++i) { + for (std::size_t i = 0; i < index.dim; ++i) + { total *= (index.range.end[i] - index.range.start[i] - 1) / index.range.stride[i] + 1; } ASSERT_EQ(index.count(), total); @@ -72,7 +74,7 @@ TEST_F(RangedIndexTest, MoveToNext) { std::cout << std::format("Lin. = {:>3d}, Target = {}, Current = {}", linear, serialize(target), serialize(index)) << std::endl; - for (auto i = 0; i < index.dim; ++i) { ASSERT_EQ(target[i], index[i]); } + for (std::size_t i = 0; i < index.dim; ++i) { ASSERT_EQ(target[i], index[i]); } } } @@ -84,7 +86,7 @@ TEST_F(RangedIndexTest, GetLast) { std::cout << std::format("Lin. = {:>3d}, Target = {}, Current = {}", total - 1, serialize(target), serialize(last)) << std::endl; - for (auto i = 0; i < index.dim; ++i) { ASSERT_EQ(target[i], last[i]); } + for (std::size_t i = 0; i < index.dim; ++i) { ASSERT_EQ(target[i], last[i]); } } TEST_F(RangedIndexTest, MoveToPre) { @@ -96,20 +98,20 @@ TEST_F(RangedIndexTest, MoveToPre) { std::cout << std::format("Lin. = {:>3d}, Target = {}, Current = {}", linear, serialize(target), serialize(index)) << std::endl; - for (auto i = 0; i < index.dim; ++i) { ASSERT_EQ(target[i], index[i]); } + for (std::size_t i = 0; i < index.dim; ++i) { ASSERT_EQ(target[i], index[i]); } } } TEST_F(RangedIndexTest, OneAfterLastReturnEnd) { auto last = index.last(); ++last; - for (auto i = 0; i < index.dim; ++i) { ASSERT_EQ(last[i], index.range.end[i]); } + for (std::size_t i = 0; i < index.dim; ++i) { ASSERT_EQ(last[i], index.range.end[i]); } } TEST_F(RangedIndexTest, OneBeforeFirstReturnFirst) { auto first = index.first(); --first; - for (auto i = 0; i < index.dim; ++i) { ASSERT_EQ(first[i], index.range.start[i]); } + for (std::size_t i = 0; i < index.dim; ++i) { ASSERT_EQ(first[i], index.range.start[i]); } } class RangeForTest : public Test { From 7a24168bb2fc277eba37d9f47b6b1b7434e59967 Mon Sep 17 00:00:00 2001 From: OpFlow-Guardian Date: Mon, 2 Feb 2026 11:52:23 +0000 Subject: [PATCH 12/14] [CI] Code auto formatted --- src/Core/BC/NeumBC.hpp | 65 +- src/Core/Equation/AMGCLBackend.hpp | 48 +- src/Core/Equation/CSRMatrixGenerator.hpp | 2 +- src/Core/Equation/HYPREEqnSolveHandler.hpp | 245 ++-- src/Core/Field/MeshBased/StencilField.hpp | 570 ++++----- .../MeshBased/Structured/CartesianField.hpp | 1056 +++++++---------- src/Core/Loops/RangeFor.hpp | 60 +- .../Parallel/ParticleGuidedSplitStrategy.hpp | 140 +-- .../Solvers/Struct/StructSolverPrecond.hpp | 30 +- .../Arrays/Tensor/FixedSizeTensor.hpp | 58 +- .../LinearMapper/BlockedMDRangeMapper.hpp | 114 +- src/DataStructures/Range/Ranges.hpp | 229 ++-- src/DataStructures/StencilPad.hpp | 201 ++-- test/Core/Field/CartesianFieldMPITest.cpp | 137 +-- test/Core/Loops/RangeForTest.cpp | 6 +- 15 files changed, 1129 insertions(+), 1832 deletions(-) diff --git a/src/Core/BC/NeumBC.hpp b/src/Core/BC/NeumBC.hpp index 5ec5fa40..82402f79 100644 --- a/src/Core/BC/NeumBC.hpp +++ b/src/Core/BC/NeumBC.hpp @@ -20,11 +20,9 @@ OPFLOW_MODULE_EXPORT -namespace OpFlow -{ +namespace OpFlow { template - struct NeumBCBase : virtual public BCBase - { + struct NeumBCBase : virtual public BCBase { protected: BCType type = BCType::Neum; @@ -33,33 +31,28 @@ namespace OpFlow [[nodiscard]] BCType getBCType() const override { return type; } [[nodiscard]] virtual std::unique_ptr> - getFunctorBC(std::function::elem_type (const typename BCBase::index_type&)> f) - const = 0; + getFunctorBC(std::function::elem_type(const typename BCBase::index_type&)> f) + const = 0; }; template struct FunctorNeumBC; template - struct ConstNeumBC : virtual public NeumBCBase - { + struct ConstNeumBC : virtual public NeumBCBase { public: - explicit ConstNeumBC(auto c) : _c(c) - { - } + explicit ConstNeumBC(auto c) : _c(c) {} using NeumBCBase::operator=; typename internal::FieldExprTrait::elem_type - evalAt(const typename internal::FieldExprTrait::index_type&) const override - { + evalAt(const typename internal::FieldExprTrait::index_type&) const override { return _c; } [[nodiscard]] std::string getTypeName() const override { return "ConstNeumBC"; } - [[nodiscard]] std::string toString(int level) const override - { + [[nodiscard]] std::string toString(int level) const override { std::string ret, prefix; for (auto i = 0; i < level; ++i) prefix += "\t"; ret += prefix + "Type: ConstNeum\n"; @@ -72,46 +65,38 @@ namespace OpFlow std::unique_ptr> getCopy() const override { return std::make_unique(*this); } std::unique_ptr> - getFunctorBC(std::function::elem_type ( - const typename internal::FieldExprTrait::index_type&)> - f) const override - { + getFunctorBC(std::function::elem_type( + const typename internal::FieldExprTrait::index_type&)> + f) const override { return std::make_unique>(f); } [[nodiscard]] auto getValue() const { return _c; } protected: - void assignImpl(const BCBase& other) override - { - _c = other.evalAt(typename internal::FieldExprTrait < F > ::index_type()); + void assignImpl(const BCBase& other) override { + _c = other.evalAt(typename internal::FieldExprTrait::index_type()); } typename internal::FieldExprTrait::elem_type _c; }; template - struct FunctorNeumBC : virtual public NeumBCBase - { + struct FunctorNeumBC : virtual public NeumBCBase { public: - using Functor = std::function::elem_type( - const typename internal::MeshBasedFieldExprTrait::index_type&) - >; + using Functor = std::function::elem_type( + const typename internal::MeshBasedFieldExprTrait::index_type&)>; - explicit FunctorNeumBC(Functor f) : _f(std::move(f)) - { - } + explicit FunctorNeumBC(Functor f) : _f(std::move(f)) {} typename internal::MeshBasedFieldExprTrait::elem_type - evalAt(const typename internal::MeshBasedFieldExprTrait::index_type& index) const override - { + evalAt(const typename internal::MeshBasedFieldExprTrait::index_type& index) const override { return _f(index - this->offset); } [[nodiscard]] std::string getTypeName() const override { return "FunctorNeumBC"; } - [[nodiscard]] std::string toString(int level) const override - { + [[nodiscard]] std::string toString(int level) const override { std::string ret, prefix; for (auto i = 0; i < level; ++i) prefix += "\t"; ret += prefix + "Type: FunctorNeum"; @@ -121,22 +106,20 @@ namespace OpFlow std::unique_ptr> getCopy() const override { return std::make_unique(*this); } std::unique_ptr> - getFunctorBC(std::function::elem_type ( - const typename internal::FieldExprTrait::index_type&)> - f) const override - { + getFunctorBC(std::function::elem_type( + const typename internal::FieldExprTrait::index_type&)> + f) const override { return std::make_unique>(f); } [[nodiscard]] auto getFunctor() const { return _f; } protected: - void assignImpl(const BCBase& other) override - { + void assignImpl(const BCBase& other) override { _f = [&](auto&& i) { return other.evalAt(i); }; } Functor _f; }; -} // namespace OpFlow +}// namespace OpFlow #endif//OPFLOW_NEUMBC_HPP \ No newline at end of file diff --git a/src/Core/Equation/AMGCLBackend.hpp b/src/Core/Equation/AMGCLBackend.hpp index a09ce193..d275b00b 100644 --- a/src/Core/Equation/AMGCLBackend.hpp +++ b/src/Core/Equation/AMGCLBackend.hpp @@ -29,30 +29,24 @@ OPFLOW_MODULE_EXPORT -namespace OpFlow -{ +namespace OpFlow { template - struct AMGCLBackend - { + struct AMGCLBackend { constexpr static bool _enable_mpi = !requires { typename Solver::col_type; }; // the static solver which performs a fresh solve on each invoke static EqnSolveState solve(const DS::CSRMatrix& mat, std::vector& x, typename Solver::params p, - typename Solver::backend_params bp, bool verbose = false) - { + typename Solver::backend_params bp, bool verbose = false) { int rows = mat.row.size() - 1; std::unique_ptr solver; #if defined(OPFLOW_WITH_MPI) - if constexpr (_enable_mpi) - { + if constexpr (_enable_mpi) { amgcl::mpi::communicator world(MPI_COMM_WORLD); auto A = std::make_shared>( - world, - *amgcl::adapter::zero_copy(rows, mat.row.begin(), mat.col.begin(), mat.val.begin())); + world, + *amgcl::adapter::zero_copy(rows, mat.row.begin(), mat.col.begin(), mat.val.begin())); solver = std::make_unique(world, A, p, bp); - } - else - { + } else { auto A = amgcl::adapter::zero_copy(rows, mat.row.begin(), mat.col.begin(), mat.val.begin()); //auto A_tie = std::tie(rows, mat.row, mat.col, mat.val); solver = std::make_unique(*A, p, bp); @@ -67,39 +61,33 @@ namespace OpFlow double error; std::tie(iters, error) = (*solver)(mat.rhs, x); if (verbose) { OP_INFO("AMGCL report: iter = {}, relerr = {}", iters, error); } - return EqnSolveState{iters, error}; + return EqnSolveState {iters, error}; } // the dynamic solver which tries to reuse the built preconditioner before EqnSolveState solve_dy(const DS::CSRMatrix& mat, std::vector& x, typename Solver::params p, - typename Solver::backend_params bp, bool verbose = false) - { + typename Solver::backend_params bp, bool verbose = false) { rebuild_solver(mat, p, bp); OP_ASSERT_MSG(solver, "AMGCLBackend: solver not initialized."); auto [iters, error] = (*solver)(mat.rhs, x); if (verbose) { OP_INFO("AMGCL report: iter = {}, relerr = {}", iters, error); } solve_counter++; - return EqnSolveState{(int)iters, error}; + return EqnSolveState {(int) iters, error}; } private: void rebuild_solver(const DS::CSRMatrix& mat, typename Solver::params& p, - typename Solver::backend_params& bp) - { - if (!solver || (rebuilt_period.has_value() && solve_counter % rebuilt_period.value() == 0)) - { + typename Solver::backend_params& bp) { + if (!solver || (rebuilt_period.has_value() && solve_counter % rebuilt_period.value() == 0)) { int rows = mat.row.size() - 1; #if defined(OPFLOW_WITH_MPI) - if constexpr (_enable_mpi) - { + if constexpr (_enable_mpi) { amgcl::mpi::communicator world(MPI_COMM_WORLD); auto A = std::make_shared>( - world, *amgcl::adapter::zero_copy(rows, mat.row.begin(), mat.col.begin(), - mat.val.begin())); + world, *amgcl::adapter::zero_copy(rows, mat.row.begin(), mat.col.begin(), + mat.val.begin())); solver = std::make_unique(world, A, p, bp); - } - else - { + } else { auto A = amgcl::adapter::zero_copy(rows, mat.row.begin(), mat.col.begin(), mat.val.begin()); solver = std::make_unique(*A, p, bp); @@ -113,8 +101,8 @@ namespace OpFlow std::unique_ptr solver; unsigned long long solve_counter = 0; - std::optional rebuilt_period{}; + std::optional rebuilt_period {}; }; -} // namespace OpFlow +}// namespace OpFlow #endif//OPFLOW_AMGCLBACKEND_HPP \ No newline at end of file diff --git a/src/Core/Equation/CSRMatrixGenerator.hpp b/src/Core/Equation/CSRMatrixGenerator.hpp index 3d695f38..afaffd80 100644 --- a/src/Core/Equation/CSRMatrixGenerator.hpp +++ b/src/Core/Equation/CSRMatrixGenerator.hpp @@ -154,7 +154,7 @@ OPFLOW_MODULE_EXPORT namespace OpFlow { auto r_last = mapper(target->getGlobalWritableRange().last(), iTarget); rangeFor_s(local_range, [&](auto&& i) { - auto r = mapper(i, iTarget); // r is the rank of i in the target scope + auto r = mapper(i, iTarget);// r is the rank of i in the target scope auto currentStencil = uniEqn.evalAt(i); if (pinValue && r == r_last) { row.push_back(row.back() + 1); diff --git a/src/Core/Equation/HYPREEqnSolveHandler.hpp b/src/Core/Equation/HYPREEqnSolveHandler.hpp index f16a8365..1e008e0b 100644 --- a/src/Core/Equation/HYPREEqnSolveHandler.hpp +++ b/src/Core/Equation/HYPREEqnSolveHandler.hpp @@ -41,31 +41,26 @@ OPFLOW_MODULE_EXPORT -namespace OpFlow -{ +namespace OpFlow { template struct HYPREEqnSolveHandler; template - std::unique_ptr makeEqnSolveHandler(F&& f, T&& t, S&& s) - { + std::unique_ptr makeEqnSolveHandler(F&& f, T&& t, S&& s) { return std::make_unique, Meta::RealType>>( - OP_PERFECT_FOWD(f), OP_PERFECT_FOWD(t), OP_PERFECT_FOWD(s)); + OP_PERFECT_FOWD(f), OP_PERFECT_FOWD(t), OP_PERFECT_FOWD(s)); } template - struct HYPREEqnSolveHandler : virtual public EqnSolveHandler - { + struct HYPREEqnSolveHandler : virtual public EqnSolveHandler { HYPREEqnSolveHandler() = default; HYPREEqnSolveHandler(const F& getter, T& target, const Solver& s) - : eqn_getter{getter}, target{&target}, solver(s) - { + : eqn_getter {getter}, target {&target}, solver(s) { this->init(); } - ~HYPREEqnSolveHandler() override - { + ~HYPREEqnSolveHandler() override { HYPRE_StructMatrixDestroy(A); HYPRE_StructVectorDestroy(b); HYPRE_StructVectorDestroy(x); @@ -73,8 +68,7 @@ namespace OpFlow HYPRE_StructStencilDestroy(stencil); } - void init() override - { + void init() override { auto stField = target->getStencilField(); stField.pin(solver.params.pinValue); stencilField = std::make_unique>(std::move(stField)); @@ -87,8 +81,7 @@ namespace OpFlow solver.init(); } - void initStencil() - { + void initStencil() { HYPRE_StructGridCreate(solver.params.comm, dim, &grid); auto t = equation->lhs - equation->rhs; t.prepare(); @@ -108,20 +101,18 @@ namespace OpFlow // assume the middle stencil is complete // fixme: this is dangerous especially for MPI cases. consider a better plan - DS::MDIndex < dim > middle; + DS::MDIndex middle; for (auto i = 0; i < dim; ++i) middle[i] = (target->assignableRange.start[i] + target->assignableRange.end[i]) / 2; commStencil = getOffsetStencil(uniEqn->evalAt(middle), middle); HYPRE_StructStencilCreate(dim, commStencil.pad.size(), &stencil); auto iter = commStencil.pad.begin(); - for (auto i = 0; i < commStencil.pad.size(); ++i, ++iter) - { + for (auto i = 0; i < commStencil.pad.size(); ++i, ++iter) { HYPRE_StructStencilSetElement(stencil, i, const_cast(iter->first.get().data())); } } - void initAbx() - { + void initAbx() { HYPRE_StructMatrixCreate(solver.params.comm, grid, stencil, &A); HYPRE_StructMatrixInitialize(A); HYPRE_StructVectorCreate(solver.params.comm, grid, &b); @@ -130,21 +121,17 @@ namespace OpFlow HYPRE_StructVectorInitialize(x); } - void initx() - { - rangeFor(DS::commonRange(target->assignableRange, target->localRange), [&](auto&& k) - { + void initx() { + rangeFor(DS::commonRange(target->assignableRange, target->localRange), [&](auto&& k) { HYPRE_StructVectorSetValues(x, const_cast(k.get().data()), target->evalAt(k)); }); } - void generateAb() override - { + void generateAb() override { std::vector entries(commStencil.pad.size()); for (std::size_t i = 0; i < entries.size(); ++i) entries[i] = i; - rangeFor(DS::commonRange(target->assignableRange, target->localRange), [&](auto&& k) - { + rangeFor(DS::commonRange(target->assignableRange, target->localRange), [&](auto&& k) { auto currentStencil = getOffsetStencil(uniEqn->evalAt(k), k); auto extendedStencil = commonStencil(currentStencil, commStencil); std::vector vals; @@ -154,21 +141,17 @@ namespace OpFlow HYPRE_StructVectorSetValues(b, const_cast(k.get().data()), -extendedStencil.bias); }); - if (solver.params.pinValue) - { + if (solver.params.pinValue) { // pin the first unknown to 0 auto identical = DS::StencilPad>>(); - auto first = DS::ColoredIndex>{ - DS::MDIndex < dim > {target->assignableRange.start} - }; - if (DS::inRange(target->localRange, first)) - { + auto first = DS::ColoredIndex> { + DS::MDIndex {target->assignableRange.start}}; + if (DS::inRange(target->localRange, first)) { identical.pad[first] = 1.0; identical.bias = 0.; auto extendedStencil = commonStencil(identical, commStencil); std::vector vals; - for (const auto& [key, val] : commStencil.pad) - { + for (const auto& [key, val] : commStencil.pad) { vals.push_back(extendedStencil.pad[key]); } HYPRE_StructMatrixSetValues(A, const_cast(first.get().data()), @@ -181,26 +164,21 @@ namespace OpFlow HYPRE_StructVectorAssemble(b); } - void generateb() - { - rangeFor(DS::commonRange(target->assignableRange, target->localRange), [&](auto&& k) - { + void generateb() { + rangeFor(DS::commonRange(target->assignableRange, target->localRange), [&](auto&& k) { auto currentStencil = uniEqn->evalAt(k); HYPRE_StructVectorSetValues(b, const_cast(k.get().data()), -currentStencil.bias); }); - if (solver.params.pinValue) - { - auto first = DS::MDIndex < dim > ( - DS::commonRange(target->assignableRange, target->localRange).start); + if (solver.params.pinValue) { + auto first = DS::MDIndex( + DS::commonRange(target->assignableRange, target->localRange).start); HYPRE_StructVectorSetValues(b, const_cast(first.get().data()), 0.); } HYPRE_StructVectorAssemble(b); } - void returnValues() - { - rangeFor(DS::commonRange(target->assignableRange, target->localRange), [&](auto&& k) - { + void returnValues() { + rangeFor(DS::commonRange(target->assignableRange, target->localRange), [&](auto&& k) { Real val; HYPRE_StructVectorGetValues(x, const_cast(k.get().data()), &val); target->operator[](k) = val; @@ -208,19 +186,15 @@ namespace OpFlow target->updatePadding(); } - EqnSolveState solve() override - { - if (firstRun) - { + EqnSolveState solve() override { + if (firstRun) { generateAb(); initx(); solver.dump(A, b); solver.setup(A, b, x); solver.solve(A, b, x); firstRun = false; - } - else - { + } else { if (solver.params.staticMat) generateb(); else generateAb(); @@ -236,10 +210,8 @@ namespace OpFlow F eqn_getter; std::add_pointer_t target; using Stencil - = DS::StencilPad::index_type - > - >; - using Eqn = Meta::RealType()(std::declval < StencilField < T > & > ()))>; + = DS::StencilPad::index_type>>; + using Eqn = Meta::RealType()(std::declval&>()))>; std::unique_ptr equation; using EqExpr = Meta::RealTypelhs - equation->rhs)>; std::unique_ptr uniEqn; @@ -248,30 +220,27 @@ namespace OpFlow bool fieldsAllocated = false; bool firstRun = true; Solver solver; - HYPRE_StructStencil stencil{}; - HYPRE_StructGrid grid{}; - HYPRE_StructMatrix A{}; - HYPRE_StructVector b{}, x{}; + HYPRE_StructStencil stencil {}; + HYPRE_StructGrid grid {}; + HYPRE_StructMatrix A {}; + HYPRE_StructVector b {}, x {}; private: - constexpr static auto dim = internal::CartesianFieldExprTrait < T > ::dim; + constexpr static auto dim = internal::CartesianFieldExprTrait::dim; }; template - struct HYPREEqnSolveHandler : virtual public EqnSolveHandler - { + struct HYPREEqnSolveHandler : virtual public EqnSolveHandler { HYPREEqnSolveHandler() = default; HYPREEqnSolveHandler(const F& getter, T& target, const Solver& s) - : getter(getter), target(&target), solver(s) - { + : getter(getter), target(&target), solver(s) { this->init(); } ~HYPREEqnSolveHandler() override { deallocHYPRE(); } - void init() override - { + void init() override { stencilField = std::make_unique>(target->getStencilField()); stencilField->pin(solver.params.pinValue); equation = std::make_unique(getter(*stencilField)); @@ -280,16 +249,13 @@ namespace OpFlow solver.init(); } - void allocHYPRE() - { + void allocHYPRE() { // grid int ndim = dim, nparts = target->getLevels(), nvars = 1; int vartypes[] = {HYPRE_SSTRUCT_VARIABLE_CELL}; HYPRE_SStructGridCreate(solver.params.comm, ndim, nparts, &grid); - for (auto l = 0; l < target->localRanges.size(); ++l) - { - for (auto p = 0; p < target->localRanges[l].size(); ++p) - { + for (auto l = 0; l < target->localRanges.size(); ++l) { + for (auto p = 0; p < target->localRanges[l].size(); ++p) { auto _local_range = target->localRanges[l][p]; for (auto i = 0; i < dim; ++i) _local_range.end[i]--; HYPRE_SStructGridSetExtents(grid, l, _local_range.start.data(), _local_range.end.data()); @@ -301,7 +267,7 @@ namespace OpFlow DS::ColoredIndex> middle; for (auto i = 0; i < dim; ++i) middle[i] = (target->assignableRanges[0][0].start[i] + target->assignableRanges[0][0].end[i]) - / 2; + / 2; //commStencil = getOffsetStencil(uniEqn->evalAt(middle), middle); DS::StencilPad> _st; _st.pad[middle] = 0; @@ -313,28 +279,21 @@ namespace OpFlow HYPRE_SStructStencilCreate(ndim, commStencil.pad.size(), &stencil); auto iter = commStencil.pad.begin(); int c_var = 0; - for (auto i = 0; i < commStencil.pad.size(); ++i, ++iter) - { + for (auto i = 0; i < commStencil.pad.size(); ++i, ++iter) { HYPRE_SStructStencilSetEntry(stencil, i, const_cast(iter->first.get().data()), c_var); } HYPRE_SStructGraphCreate(solver.params.comm, grid, &graph); - for (auto l = 0; l < target->localRanges.size(); ++l) - { + for (auto l = 0; l < target->localRanges.size(); ++l) { HYPRE_SStructGraphSetStencil(graph, l, c_var, stencil); } // inter-level graph entries - for (auto l = 0; l < target->getLevels(); ++l) - { - for (auto p = 0; p < target->localRanges[l].size(); ++p) - { - rangeFor_s(target->localRanges[l][p], [&](auto&& i) - { + for (auto l = 0; l < target->getLevels(); ++l) { + for (auto p = 0; p < target->localRanges[l].size(); ++p) { + rangeFor_s(target->localRanges[l][p], [&](auto&& i) { if (stencilField->blocked(i)) return; auto st = uniEqn->evalAt(i); - for (auto& [k, v] : st.pad) - { - if (k.l != l) - { + for (auto& [k, v] : st.pad) { + if (k.l != l) { HYPRE_SStructGraphAddEntries(graph, l, i.c_arr(), c_var, k.l, k.c_arr(), c_var); std::cout << std::format("GraphAddEntry: {} -> {}\n", i, k); @@ -354,8 +313,7 @@ namespace OpFlow allocated = true; } - void deallocHYPRE() - { + void deallocHYPRE() { if (!allocated) return; HYPRE_SStructMatrixDestroy(A); HYPRE_SStructVectorDestroy(b); @@ -366,35 +324,28 @@ namespace OpFlow allocated = false; } - void generateAb() override - { - for (auto l = 0; l < target->getLevels(); ++l) - { - for (auto p = 0; p < target->localRanges[l].size(); ++p) - { - rangeFor_s(target->localRanges[l][p], [&](auto&& i) - { + void generateAb() override { + for (auto l = 0; l < target->getLevels(); ++l) { + for (auto p = 0; p < target->localRanges[l].size(); ++p) { + rangeFor_s(target->localRanges[l][p], [&](auto&& i) { if (stencilField->blocked(i)) return; // stencil part auto currentStencil = uniEqn->evalAt(i); auto offsetStencil = currentStencil; - for (auto& [k, v] : offsetStencil.pad) - { + for (auto& [k, v] : offsetStencil.pad) { if (k.l == l) { k -= i; } } std::cout << std::format("index = {}\n", i); std::cout << std::format("current stencil:{}\noffset stencil:{}\n", currentStencil, offsetStencil); auto extendedStencil = offsetStencil; - for (auto& [k, v] : commStencil.pad) - { + for (auto& [k, v] : commStencil.pad) { auto _target_k = k; _target_k.l = l; _target_k.p = p; if (auto iter = extendedStencil.pad.findFirst( - [&](auto&& _k) { return _k.l == l && _k.idx == _target_k.idx; }); - iter == extendedStencil.pad.end()) - { + [&](auto&& _k) { return _k.l == l && _k.idx == _target_k.idx; }); + iter == extendedStencil.pad.end()) { extendedStencil.pad[_target_k] = 0; } } @@ -402,22 +353,19 @@ namespace OpFlow std::vector vals; std::vector entries(commStencil.pad.size()); std::iota(entries.begin(), entries.end(), 0); - for (const auto& [key, val] : commStencil.pad) - { + for (const auto& [key, val] : commStencil.pad) { auto _k = key; _k.l = l; auto iter = extendedStencil.pad.findFirst( - [&](auto&& k) { return k.l == l && k.idx == _k.idx; }); + [&](auto&& k) { return k.l == l && k.idx == _k.idx; }); vals.push_back(iter->second); } HYPRE_SStructMatrixSetValues(A, l, i.c_arr(), 0, commStencil.pad.size(), entries.data(), vals.data()); // inter-level part int count = commStencil.pad.size(); - for (const auto& [k, v] : extendedStencil.pad) - { - if (k.l != l) - { + for (const auto& [k, v] : extendedStencil.pad) { + if (k.l != l) { int entry[] = {count++}; Real val[] = {v}; HYPRE_SStructMatrixSetValues(A, l, i.c_arr(), 0, 1, entry, val); @@ -429,16 +377,14 @@ namespace OpFlow }); } } - int (*rfactors)[HYPRE_MAXDIM]; + int(*rfactors)[HYPRE_MAXDIM]; rfactors = new int[target->getLevels()][HYPRE_MAXDIM]; for (auto l = 0; l < target->getLevels(); ++l) for (auto d = 0; d < HYPRE_MAXDIM; ++d) rfactors[l][d] = 1; - for (auto l = 1; l < target->getLevels(); ++l) - { + for (auto l = 1; l < target->getLevels(); ++l) { for (auto d = 0; d < dim; ++d) rfactors[l][d] = target->mesh.refinementRatio; } - for (auto l = target->getLevels() - 1; l > 0; --l) - { + for (auto l = target->getLevels() - 1; l > 0; --l) { HYPRE_SStructFACZeroCFSten(A, grid, l, rfactors[l]); HYPRE_SStructFACZeroFCSten(A, grid, l); HYPRE_SStructFACZeroAMRMatrixData(A, l - 1, rfactors[l]); @@ -451,25 +397,20 @@ namespace OpFlow delete[] rfactors; } - void initx() - { - for (auto l = 0; l < target->getLevels(); ++l) - { - for (auto p = 0; p < target->localRanges[l].size(); ++p) - { - rangeFor(target->localRanges[l][p], [&](auto&& i) - { + void initx() { + for (auto l = 0; l < target->getLevels(); ++l) { + for (auto p = 0; p < target->localRanges[l].size(); ++p) { + rangeFor(target->localRanges[l][p], [&](auto&& i) { auto val = target->evalAt(i); HYPRE_SStructVectorSetValues(x, l, i.c_arr(), 0, &val); }); } } - int (*rfactors)[HYPRE_MAXDIM]; + int(*rfactors)[HYPRE_MAXDIM]; rfactors = new int[target->getLevels()][HYPRE_MAXDIM]; for (auto l = 0; l < target->getLevels(); ++l) for (auto d = 0; d < HYPRE_MAXDIM; ++d) rfactors[l][d] = 1; - for (auto l = 1; l < target->getLevels(); ++l) - { + for (auto l = 1; l < target->getLevels(); ++l) { for (auto d = 0; d < dim; ++d) rfactors[l][d] = target->mesh.refinementRatio; } std::vector plevels(target->getLevels()); @@ -479,14 +420,10 @@ namespace OpFlow delete[] rfactors; } - void returnValues() - { - for (auto l = 0; l < target->getLevels(); ++l) - { - for (auto p = 0; p < target->localRanges[l].size(); ++p) - { - rangeFor(target->localRanges[l][p], [&](auto&& i) - { + void returnValues() { + for (auto l = 0; l < target->getLevels(); ++l) { + for (auto p = 0; p < target->localRanges[l].size(); ++p) { + rangeFor(target->localRanges[l][p], [&](auto&& i) { Real val; HYPRE_SStructVectorGetValues(x, l, i.c_arr(), 0, &val); target->operator[](i) = val; @@ -495,19 +432,17 @@ namespace OpFlow } } - EqnSolveState solve() override - { + EqnSolveState solve() override { allocHYPRE(); generateAb(); initx(); HYPRE_SStructFACSetMaxLevels(solver.getSolver(), target->getLevels()); std::vector plevels(target->getLevels()); - int (*rfactors)[HYPRE_MAXDIM]; + int(*rfactors)[HYPRE_MAXDIM]; std::iota(plevels.begin(), plevels.end(), 0); rfactors = new int[plevels.size()][HYPRE_MAXDIM]; for (auto i = 0; i < HYPRE_MAXDIM; ++i) rfactors[0][i] = 1; - for (auto l = 1; l < target->localRanges.size(); ++l) - { + for (auto l = 1; l < target->localRanges.size(); ++l) { for (auto i = 0; i < HYPRE_MAXDIM; ++i) rfactors[l][i] = i < dim ? target->mesh.refinementRatio : 1; } @@ -535,10 +470,8 @@ namespace OpFlow F getter; std::add_pointer_t target; using Stencil - = DS::StencilPad::index_type - > - >; - using Eqn = Meta::RealType()(std::declval < StencilField < T > & > ()))>; + = DS::StencilPad::index_type>>; + using Eqn = Meta::RealType()(std::declval&>()))>; std::unique_ptr equation; using EqExpr = Meta::RealTypelhs - equation->rhs)>; std::unique_ptr uniEqn; @@ -546,16 +479,16 @@ namespace OpFlow std::unique_ptr> stencilField; bool fieldsAllocated = false; Solver solver; - HYPRE_SStructStencil stencil{}; - HYPRE_SStructGrid grid{}; - HYPRE_SStructGraph graph{}; - HYPRE_SStructMatrix A{}; - HYPRE_SStructVector b{}, x{}; + HYPRE_SStructStencil stencil {}; + HYPRE_SStructGrid grid {}; + HYPRE_SStructGraph graph {}; + HYPRE_SStructMatrix A {}; + HYPRE_SStructVector b {}, x {}; private: bool allocated = false; - constexpr static auto dim = internal::CartAMRFieldExprTrait < T > ::dim; + constexpr static auto dim = internal::CartAMRFieldExprTrait::dim; using index_type = typename internal::CartAMRFieldExprTrait::index_type; }; -} // namespace OpFlow +}// namespace OpFlow #endif//OPFLOW_HYPREEQNSOLVEHANDLER_HPP \ No newline at end of file diff --git a/src/Core/Field/MeshBased/StencilField.hpp b/src/Core/Field/MeshBased/StencilField.hpp index 14b25d83..5c2efc9d 100644 --- a/src/Core/Field/MeshBased/StencilField.hpp +++ b/src/Core/Field/MeshBased/StencilField.hpp @@ -27,24 +27,20 @@ OPFLOW_MODULE_EXPORT -namespace OpFlow -{ +namespace OpFlow { template typename map_impl> struct StencilField - : internal::StructuredFieldExprTrait::template twin_type> - { + : internal::StructuredFieldExprTrait::template twin_type> { std::array>>, internal::ExprTrait::dim> - bc; + bc; int color = 0; StencilField() = default; StencilField(const StencilField& other) : internal::StructuredFieldExprTrait::template twin_type(other), - color(other.color), base(other.base), pinned(other.pinned) - { - for (auto i = 0; i < internal::ExprTrait::dim; ++i) - { + color(other.color), base(other.base), pinned(other.pinned) { + for (auto i = 0; i < internal::ExprTrait::dim; ++i) { bc[i].start = other.bc[i].start ? other.bc[i].start->getCopy() : nullptr; if (isLogicalBC(bc[i].start->getBCType())) dynamic_cast*>(bc[i].start.get())->rebindField(*this); @@ -56,67 +52,57 @@ namespace OpFlow StencilField(StencilField&&) noexcept = default; - explicit StencilField(const T& base, int color = 0) : color(color), base(&base) - { + explicit StencilField(const T& base, int color = 0) : color(color), base(&base) { this->name = std::format("StencilField({})", base.name); - if constexpr (StructuredFieldExprType < T >) this->loc = base.loc; + if constexpr (StructuredFieldExprType) this->loc = base.loc; this->mesh = base.mesh.getView(); this->localRange = base.localRange; this->assignableRange = base.assignableRange; this->accessibleRange = base.accessibleRange; this->logicalRange = base.logicalRange; - for (auto i = 0; i < internal::MeshBasedFieldExprTrait < T > ::dim; ++i) - { - if (base.bc[i].start && isLogicalBC(base.bc[i].start->getBCType())) - { + for (auto i = 0; i < internal::MeshBasedFieldExprTrait::dim; ++i) { + if (base.bc[i].start && isLogicalBC(base.bc[i].start->getBCType())) { // if base.bc[i].start is a logical bc, we build a new instance of the same type bc - switch (base.bc[i].start->getBCType()) - { - case BCType::Symm: - this->bc[i].start = genLogicalBC(*this, i, DimPos::start); - break; - case BCType::ASymm: - this->bc[i].start = genLogicalBC(*this, i, DimPos::start); - break; - case BCType::Periodic: - this->bc[i].start = genLogicalBC(*this, i, DimPos::start); - break; - default: - OP_CRITICAL("{} is not a logical bc type", base.bc[i].start->getTypeName()); - OP_ABORT; + switch (base.bc[i].start->getBCType()) { + case BCType::Symm: + this->bc[i].start = genLogicalBC(*this, i, DimPos::start); + break; + case BCType::ASymm: + this->bc[i].start = genLogicalBC(*this, i, DimPos::start); + break; + case BCType::Periodic: + this->bc[i].start = genLogicalBC(*this, i, DimPos::start); + break; + default: + OP_CRITICAL("{} is not a logical bc type", base.bc[i].start->getTypeName()); + OP_ABORT; } - } - else - { + } else { // other cases we build a proxy bc to convert original bc to the same bc returning stencilpads this->bc[i].start - = genProxyBC::type>( - *(base.bc[i].start)); + = genProxyBC::type>( + *(base.bc[i].start)); } - if (base.bc[i].end && isLogicalBC(base.bc[i].end->getBCType())) - { + if (base.bc[i].end && isLogicalBC(base.bc[i].end->getBCType())) { // if base.bc[i].start is a logical bc, we build a new instance of the same type bc - switch (base.bc[i].end->getBCType()) - { - case BCType::Symm: - this->bc[i].end = genLogicalBC(*this, i, DimPos::end); - break; - case BCType::ASymm: - this->bc[i].end = genLogicalBC(*this, i, DimPos::end); - break; - case BCType::Periodic: - this->bc[i].end = genLogicalBC(*this, i, DimPos::end); - break; - default: - OP_CRITICAL("{} is not a logical bc type", base.bc[i].end->getTypeName()); - OP_ABORT; + switch (base.bc[i].end->getBCType()) { + case BCType::Symm: + this->bc[i].end = genLogicalBC(*this, i, DimPos::end); + break; + case BCType::ASymm: + this->bc[i].end = genLogicalBC(*this, i, DimPos::end); + break; + case BCType::Periodic: + this->bc[i].end = genLogicalBC(*this, i, DimPos::end); + break; + default: + OP_CRITICAL("{} is not a logical bc type", base.bc[i].end->getTypeName()); + OP_ABORT; } - } - else - { + } else { this->bc[i].end - = genProxyBC::type>( - *(base.bc[i].end)); + = genProxyBC::type>( + *(base.bc[i].end)); } } } @@ -127,12 +113,9 @@ namespace OpFlow void pin(bool p) { pinned = p; } // only used for HYPRE solvers to get the exact offset stencil pad - void ignorePeriodicBC() - { - for (auto i = 0; i < dim; ++i) - { - if (base->bc[i].start->getBCType() == BCType::Periodic) - { + void ignorePeriodicBC() { + for (auto i = 0; i < dim; ++i) { + if (base->bc[i].start->getBCType() == BCType::Periodic) { this->assignableRange.start[i] = base->logicalRange.start[i]; this->accessibleRange.start[i] = base->logicalRange.start[i]; this->assignableRange.end[i] = base->logicalRange.end[i]; @@ -141,284 +124,222 @@ namespace OpFlow } } - auto evalAtImpl_final(const index_type& index) const - { + auto evalAtImpl_final(const index_type& index) const { OP_ASSERT_MSG(base, "base ptr of stencil field is nullptr"); // inner case, return a stencil pad - if (DS::inRange(this->assignableRange, index)) [[likely]] - { - auto ret = typename internal::ExprTrait::elem_type{0}; - // note: here solution is pinned at base->assignableRange.start - // rather than this->assignableRange.start; This is because - // for periodic case the assignableRange of this will be changed - // to logicalRange for HYPRE solver to get exact offset. - if (!(pinned && index == index_type(base->assignableRange.start))) - [[likely]] ret.pad[colored_index_type{index, color}] = 1.0; - return ret; - } - else if (!DS::inRange(this->logicalRange, index)) - { + if (DS::inRange(this->assignableRange, index)) [[likely]] { + auto ret = typename internal::ExprTrait::elem_type {0}; + // note: here solution is pinned at base->assignableRange.start + // rather than this->assignableRange.start; This is because + // for periodic case the assignableRange of this will be changed + // to logicalRange for HYPRE solver to get exact offset. + if (!(pinned && index == index_type(base->assignableRange.start))) + [[likely]] ret.pad[colored_index_type {index, color}] = 1.0; + return ret; + } + else if (!DS::inRange(this->logicalRange, index)) { // corner case, error & abort OP_ERROR("Index {} out of range {}", index, this->logicalRange.toString()); OP_ABORT; - } - else - { + } else { // needs boundary condition info to continue // case 1: index fall outside of boundary, fold it into accessibleRange - for (int i = 0; i < dim; ++i) - { + for (int i = 0; i < dim; ++i) { if (this->accessibleRange.start[i] <= index[i] && index[i] < this->accessibleRange.end[i]) continue; - if (this->loc[i] == LocOnMesh::Corner) - { + if (this->loc[i] == LocOnMesh::Corner) { // corner case - if (index[i] < this->accessibleRange.start[i]) - { + if (index[i] < this->accessibleRange.start[i]) { // lower case - switch (this->bc[i].start->getBCType()) - { - case BCType::Dirc: - { + switch (this->bc[i].start->getBCType()) { + case BCType::Dirc: { // mid point rule auto bc_v = this->bc[i].start->evalAt(index); auto mirror_idx = index; mirror_idx[i] = 2 * this->accessibleRange.start[i] - index[i]; return Math::Interpolator1D::intp( - base->mesh.x(i, this->accessibleRange.start[i]), bc_v, - base->mesh.x(i, mirror_idx), this->evalAtImpl_final(mirror_idx), - base->mesh.x(i, index)); - } - break; - case BCType::Neum: - { + base->mesh.x(i, this->accessibleRange.start[i]), bc_v, + base->mesh.x(i, mirror_idx), this->evalAtImpl_final(mirror_idx), + base->mesh.x(i, index)); + } break; + case BCType::Neum: { // mid-diff = bc auto bc_v = this->bc[i].start->evalAt(index); auto mirror_idx = index; mirror_idx[i] = 2 * this->accessibleRange.start[i] - index[i]; return this->evalAtImpl_final(mirror_idx) - + bc_v * (base->mesh.x(i, index) - base->mesh.x(i, mirror_idx)); - } - break; - case BCType::Symm: - { + + bc_v * (base->mesh.x(i, index) - base->mesh.x(i, mirror_idx)); + } break; + case BCType::Symm: { auto mirror_idx = index; mirror_idx[i] = 2 * this->accessibleRange.start[i] - index[i]; return this->evalAtImpl_final(mirror_idx); - } - break; - case BCType::ASymm: - { + } break; + case BCType::ASymm: { auto mirror_idx = index; mirror_idx[i] = 2 * this->accessibleRange.start[i] - index[i]; return -1. * this->evalAtImpl_final(mirror_idx); - } - break; - case BCType::Periodic: - { + } break; + case BCType::Periodic: { auto mirror_idx = index; mirror_idx[i] - += this->accessibleRange.end[i] - this->accessibleRange.start[i]; + += this->accessibleRange.end[i] - this->accessibleRange.start[i]; return this->evalAtImpl_final(mirror_idx); } - default: - OP_ERROR("Cannot handle current bc padding for stencil field: bc type {}", - this->bc[i].start->getTypeName()); - OP_ABORT; + default: + OP_ERROR("Cannot handle current bc padding for stencil field: bc type {}", + this->bc[i].start->getTypeName()); + OP_ABORT; } - } - else - { + } else { // upper case - switch (this->bc[i].end->getBCType()) - { - case BCType::Dirc: - { + switch (this->bc[i].end->getBCType()) { + case BCType::Dirc: { // mid-point rule auto bc_v = this->bc[i].end->evalAt(index); auto mirror_idx = index; mirror_idx[i] = 2 * this->accessibleRange.end[i] - 2 - index[i]; return Math::Interpolator1D::intp( - base->mesh.x(i, this->accessibleRange.end[i] - 1), bc_v, - base->mesh.x(i, mirror_idx), this->evalAtImpl_final(mirror_idx), - base->mesh.x(i, index)); - } - break; - case BCType::Neum: - { + base->mesh.x(i, this->accessibleRange.end[i] - 1), bc_v, + base->mesh.x(i, mirror_idx), this->evalAtImpl_final(mirror_idx), + base->mesh.x(i, index)); + } break; + case BCType::Neum: { // mid-diff = bc auto bc_v = this->bc[i].end->evalAt(index); auto mirror_idx = index; mirror_idx[i] = 2 * this->accessibleRange.end[i] - 2 - index[i]; return this->evalAtImpl_final(mirror_idx) - + bc_v * (base->mesh.x(i, index) - base->mesh.x(i, mirror_idx)); - } - break; - case BCType::Symm: - { + + bc_v * (base->mesh.x(i, index) - base->mesh.x(i, mirror_idx)); + } break; + case BCType::Symm: { auto mirror_idx = index; mirror_idx[i] = 2 * this->accessibleRange.end[i] - 2 - index[i]; return this->evalAtImpl_final(mirror_idx); - } - break; - case BCType::ASymm: - { + } break; + case BCType::ASymm: { auto mirror_idx = index; mirror_idx[i] = 2 * this->accessibleRange.end[i] - 2 - index[i]; return -1. * this->evalAtImpl_final(mirror_idx); - } - break; - case BCType::Periodic: - { + } break; + case BCType::Periodic: { auto mirror_idx = index; mirror_idx[i] - -= this->accessibleRange.end[i] - this->accessibleRange.start[i]; + -= this->accessibleRange.end[i] - this->accessibleRange.start[i]; return this->evalAtImpl_final(mirror_idx); - } - break; - default: - OP_ERROR("Cannot handle current bc padding for stencil field: bc type {}", - this->bc[i].end->getTypeName()); - OP_ABORT; + } break; + default: + OP_ERROR("Cannot handle current bc padding for stencil field: bc type {}", + this->bc[i].end->getTypeName()); + OP_ABORT; } } - } - else - { + } else { // center case - if (index[i] < this->accessibleRange.start[i]) - { + if (index[i] < this->accessibleRange.start[i]) { // lower case - switch (this->bc[i].start->getBCType()) - { - case BCType::Dirc: - { + switch (this->bc[i].start->getBCType()) { + case BCType::Dirc: { // mid-point rule auto bc_v = this->bc[i].start->evalAt(index); auto mirror_index = index; mirror_index[i] = 2 * this->accessibleRange.start[i] - 1 - index[i]; return Math::Interpolator1D::intp( - base->mesh.x(i, this->accessibleRange.start[i]), bc_v, - base->mesh.x(i, mirror_index[i]) - + base->mesh.dx(i, mirror_index) / 2., - this->evalAtImpl_final(mirror_index), - base->mesh.x(i, index[i]) + base->mesh.dx(i, index) / 2.); - } - break; - case BCType::Neum: - { + base->mesh.x(i, this->accessibleRange.start[i]), bc_v, + base->mesh.x(i, mirror_index[i]) + + base->mesh.dx(i, mirror_index) / 2., + this->evalAtImpl_final(mirror_index), + base->mesh.x(i, index[i]) + base->mesh.dx(i, index) / 2.); + } break; + case BCType::Neum: { // mid-diff = bc auto bc_v = this->bc[i].start->evalAt(index); auto mirror_index = index; mirror_index[i] = 2 * this->accessibleRange.start[i] - 1 - index[i]; return this->evalAtImpl_final(mirror_index) - + bc_v - * (base->mesh.x(i, index) + base->mesh.dx(i, index) / 2. - - base->mesh.x(i, mirror_index) - - base->mesh.dx(i, mirror_index) / 2.); - } - break; - case BCType::Symm: - { + + bc_v + * (base->mesh.x(i, index) + base->mesh.dx(i, index) / 2. + - base->mesh.x(i, mirror_index) + - base->mesh.dx(i, mirror_index) / 2.); + } break; + case BCType::Symm: { auto mirror_index = index; mirror_index[i] = 2 * this->accessibleRange.start[i] - 1 - index[i]; return this->evalAtImpl_final(mirror_index); - } - break; - case BCType::ASymm: - { + } break; + case BCType::ASymm: { auto mirror_index = index; mirror_index[i] = 2 * this->accessibleRange.start[i] - 1 - index[i]; return -1.0 * this->evalAtImpl_final(mirror_index); - } - break; - case BCType::Periodic: - { + } break; + case BCType::Periodic: { auto mirror_idx = index; mirror_idx[i] - += this->accessibleRange.end[i] - this->accessibleRange.start[i]; + += this->accessibleRange.end[i] - this->accessibleRange.start[i]; return this->evalAtImpl_final(mirror_idx); - } - break; - default: - OP_ERROR("Cannot handle current bc padding: bc type {}", - this->bc[i].start->getTypeName()); - OP_ABORT; + } break; + default: + OP_ERROR("Cannot handle current bc padding: bc type {}", + this->bc[i].start->getTypeName()); + OP_ABORT; } - } - else - { + } else { // upper case - switch (this->bc[i].end->getBCType()) - { - case BCType::Dirc: - { + switch (this->bc[i].end->getBCType()) { + case BCType::Dirc: { auto bc_v = this->bc[i].end->evalAt(index); auto mirror_index = index; mirror_index[i] = 2 * this->accessibleRange.end[i] - 1 - index[i]; return Math::Interpolator1D::intp( - base->mesh.x(i, this->accessibleRange.end[i]), bc_v, - base->mesh.x(i, mirror_index[i]) - + base->mesh.dx(i, mirror_index) / 2., - this->evalAtImpl_final(mirror_index), - base->mesh.x(i, index[i]) + base->mesh.dx(i, index) / 2.); - } - break; - case BCType::Neum: - { + base->mesh.x(i, this->accessibleRange.end[i]), bc_v, + base->mesh.x(i, mirror_index[i]) + + base->mesh.dx(i, mirror_index) / 2., + this->evalAtImpl_final(mirror_index), + base->mesh.x(i, index[i]) + base->mesh.dx(i, index) / 2.); + } break; + case BCType::Neum: { auto bc_v = this->bc[i].end->evalAt(index); auto mirror_index = index; mirror_index[i] = 2 * this->accessibleRange.end[i] - 1 - index[i]; return this->evalAtImpl_final(mirror_index) - + bc_v - * (base->mesh.x(i, index) + base->mesh.dx(i, index) / 2. - - base->mesh.x(i, mirror_index) - - base->mesh.dx(i, mirror_index) / 2.); - } - break; - case BCType::Symm: - { + + bc_v + * (base->mesh.x(i, index) + base->mesh.dx(i, index) / 2. + - base->mesh.x(i, mirror_index) + - base->mesh.dx(i, mirror_index) / 2.); + } break; + case BCType::Symm: { auto mirror_index = index; mirror_index[i] = 2 * this->accessibleRange.end[i] - 1 - index[i]; return this->evalAtImpl_final(mirror_index); - } - break; - case BCType::ASymm: - { + } break; + case BCType::ASymm: { auto mirror_index = index; mirror_index[i] = 2 * this->accessibleRange.end[i] - 1 - index[i]; return -1. * this->evalAtImpl_final(mirror_index); - } - break; - case BCType::Periodic: - { + } break; + case BCType::Periodic: { auto mirror_idx = index; mirror_idx[i] - -= this->accessibleRange.end[i] - this->accessibleRange.start[i]; + -= this->accessibleRange.end[i] - this->accessibleRange.start[i]; return this->evalAtImpl_final(mirror_idx); - } - break; - default: - OP_ERROR("Cannot handle current bc padding: bc type {}", - this->bc[i].end->getTypeName()); - OP_ABORT; + } break; + default: + OP_ERROR("Cannot handle current bc padding: bc type {}", + this->bc[i].end->getTypeName()); + OP_ABORT; } } } } // case 2: index fall on a Dirc bc - for (int i = 0; i < dim; ++i) - { + for (int i = 0; i < dim; ++i) { if (this->loc[i] == LocOnMesh::Corner && this->bc[i].start->getBCType() == BCType::Dirc - && index[i] == this->accessibleRange.start[i]) - { + && index[i] == this->accessibleRange.start[i]) { // fall on the left boundary return this->bc[i].start->evalAt(index); - } - else if (this->loc[i] == LocOnMesh::Corner - && this->bc[i].end->getBCType() == BCType::Dirc - && index[i] == this->accessibleRange.end[i] - 1) - { + } else if (this->loc[i] == LocOnMesh::Corner + && this->bc[i].end->getBCType() == BCType::Dirc + && index[i] == this->accessibleRange.end[i] - 1) { // fall on the right boundary return this->bc[i].end->evalAt(index); } @@ -429,14 +350,10 @@ namespace OpFlow OP_ABORT; } - void prepareImpl_final() const - { - } + void prepareImpl_final() const {} template - requires(!std::same_as) - bool containsImpl_final(const Other& o) const - { + requires(!std::same_as) bool containsImpl_final(const Other& o) const { return false; } @@ -445,31 +362,22 @@ namespace OpFlow private: const T* base; bool pinned = false; - constexpr static auto dim = internal::MeshBasedFieldExprTrait < T > ::dim; + constexpr static auto dim = internal::MeshBasedFieldExprTrait::dim; }; template typename map_impl> - struct StencilField : CartAMRFieldExpr> - { + struct StencilField : CartAMRFieldExpr> { using index_type = typename internal::ExprTrait::index_type; using colored_index_type = DS::ColoredIndex; private: // todo: why need explicit storage here? - std::vector::template other_type> - > - ::container_type - > - > - data; - std::vector::template other_type - > - ::container_type - > - > - block_mark; + std::vector::template other_type>>::container_type>> + data; + std::vector::template other_type>::container_type>> + block_mark; std::vector> offset; int color = 0; @@ -478,18 +386,13 @@ namespace OpFlow StencilField(const StencilField& other) : CartAMRFieldExpr(other), data(other.data), block_mark(other.block_mark), - offset(other.offset) - { - } + offset(other.offset) {} StencilField(StencilField&& other) noexcept : CartAMRFieldExpr(std::move(other)), data(std::move(other.data)), - block_mark(std::move(other.block_mark)), offset(std::move(other.offset)) - { - } + block_mark(std::move(other.block_mark)), offset(std::move(other.offset)) {} - explicit StencilField(const T& base, int color) : color(color) - { + explicit StencilField(const T& base, int color) : color(color) { this->name = std::format("StencilField({})", base.name); this->loc = base.loc; this->mesh = base.mesh; @@ -497,52 +400,42 @@ namespace OpFlow this->assignableRanges = base.assignableRanges; this->accessibleRanges = base.accessibleRanges; this->maxLogicalRanges = base.maxLogicalRanges; - for (auto i = 0; i < internal::SemiStructuredFieldExprTrait < T > ::dim; ++i) - { + for (auto i = 0; i < internal::SemiStructuredFieldExprTrait::dim; ++i) { this->bc[i].start - = genProxyBC::type>( - *(base.bc[i].start)); + = genProxyBC::type>( + *(base.bc[i].start)); this->bc[i].end - = genProxyBC::type>( - *(base.bc[i].end)); + = genProxyBC::type>( + *(base.bc[i].end)); } // allocate data data.resize(this->localRanges.size()); - for (auto i = 0; i < data.size(); ++i) - { + for (auto i = 0; i < data.size(); ++i) { data[i].resize(this->localRanges[i].size()); - for (auto j = 0; j < data[i].size(); ++j) - { + for (auto j = 0; j < data[i].size(); ++j) { data[i][j].reShape(this->accessibleRanges[i][j].getExtends()); } } block_mark.resize(this->localRanges.size()); - for (auto i = 0; i < block_mark.size(); ++i) - { + for (auto i = 0; i < block_mark.size(); ++i) { block_mark[i].resize(this->localRanges[i].size()); - for (auto j = 0; j < block_mark[i].size(); ++j) - { + for (auto j = 0; j < block_mark[i].size(); ++j) { block_mark[i][j].reShape(this->accessibleRanges[i][j].getExtends()); } } offset.resize(this->accessibleRanges.size()); - for (auto i = 0; i < this->accessibleRanges.size(); ++i) - { + for (auto i = 0; i < this->accessibleRanges.size(); ++i) { offset[i].resize(this->accessibleRanges[i].size()); - for (auto j = 0; j < this->accessibleRanges[i].size(); ++j) - { + for (auto j = 0; j < this->accessibleRanges[i].size(); ++j) { offset[i][j] = index_type(i, j, this->accessibleRanges[i][j].getOffset()); } } // init all stencils - for (auto l = 0; l < this->localRanges.size(); ++l) - { - for (auto p = 0; p < this->localRanges[l].size(); ++p) - { - rangeFor(this->localRanges[l][p], [&](auto&& i) - { + for (auto l = 0; l < this->localRanges.size(); ++l) { + for (auto p = 0; p < this->localRanges[l].size(); ++p) { + rangeFor(this->localRanges[l][p], [&](auto&& i) { auto& st = this->operator[](i); - st.pad[colored_index_type{i}] = 1.0; + st.pad[colored_index_type {i}] = 1.0; st.bias = 0; this->blocked(i) = false; }); @@ -555,35 +448,26 @@ namespace OpFlow void pin(bool p) { pinned = p; } - void prepareImpl_final() - { - } + void prepareImpl_final() {} - void updatePadding() - { + void updatePadding() { // step 1: fill all halo regions covered by parents - for (auto l = 1; l < this->accessibleRanges.size(); ++l) - { - for (auto p = 0; p < this->accessibleRanges[l].size(); ++p) - { + for (auto l = 1; l < this->accessibleRanges.size(); ++l) { + for (auto p = 0; p < this->accessibleRanges[l].size(); ++p) { // here to avoid the accessibleRanges[l][p] is already been trimmed by the maxLogicalRange[l] auto bc_ranges = this->localRanges[l][p] - .getInnerRange(-this->mesh.buffWidth) - .getBCRanges(this->mesh.buffWidth); - for (auto r_p : this->mesh.parents[l][p]) - { + .getInnerRange(-this->mesh.buffWidth) + .getBCRanges(this->mesh.buffWidth); + for (auto r_p : this->mesh.parents[l][p]) { // convert the parent range into this level auto p_range = this->localRanges[l - 1][r_p]; - for (auto i = 0; i < dim; ++i) - { + for (auto i = 0; i < dim; ++i) { p_range.start[i] *= this->mesh.refinementRatio; p_range.end[i] *= this->mesh.refinementRatio; } // for each potential intersections - for (auto& bc_r : bc_ranges) - { - rangeFor(DS::commonRange(bc_r, p_range), [&](auto&& i) - { + for (auto& bc_r : bc_ranges) { + rangeFor(DS::commonRange(bc_r, p_range), [&](auto&& i) { // use piecewise constant interpolation auto i_base = i.toLevel(l - 1, this->mesh.refinementRatio); i_base.p = r_p; @@ -595,21 +479,16 @@ namespace OpFlow } } // step 2: fill all halo regions covered by neighbors - for (auto l = 1; l < this->accessibleRanges.size(); ++l) - { - for (auto p = 0; p < this->accessibleRanges[l].size(); ++p) - { + for (auto l = 1; l < this->accessibleRanges.size(); ++l) { + for (auto p = 0; p < this->accessibleRanges[l].size(); ++p) { auto bc_ranges = this->localRanges[l][p] - .getInnerRange(-this->mesh.buffWidth) - .getBCRanges(this->mesh.buffWidth); - for (auto r_n : this->mesh.neighbors[l][p]) - { + .getInnerRange(-this->mesh.buffWidth) + .getBCRanges(this->mesh.buffWidth); + for (auto r_n : this->mesh.neighbors[l][p]) { // for each potential intersections - for (auto& bc_r : bc_ranges) - { + for (auto& bc_r : bc_ranges) { auto _r = DS::commonRange(bc_r, this->localRanges[l][r_n]); - rangeFor(DS::commonRange(bc_r, this->localRanges[l][r_n]), [&](auto&& i) - { + rangeFor(DS::commonRange(bc_r, this->localRanges[l][r_n]), [&](auto&& i) { // copy from other fine cells auto other_i = i; other_i.p = r_n; @@ -622,36 +501,29 @@ namespace OpFlow } } - void updateCovering() - { + void updateCovering() { auto ratio = this->mesh.refinementRatio; - for (auto l = 1; l < this->localRanges.size(); ++l) - { - for (auto p = 0; p < this->localRanges[l].size(); ++p) - { - for (auto& i_p : this->mesh.parents[l][p]) - { + for (auto l = 1; l < this->localRanges.size(); ++l) { + for (auto p = 0; p < this->localRanges[l].size(); ++p) { + for (auto& i_p : this->mesh.parents[l][p]) { auto rp = this->localRanges[l - 1][i_p]; auto rc = this->localRanges[l][p]; - for (auto i = 0; i < dim; ++i) - { + for (auto i = 0; i < dim; ++i) { rc.start[i] /= ratio; rc.end[i] /= ratio; } rc.level = l - 1; - rangeFor(DS::commonRange(rp, rc), [&](auto&& i) - { + rangeFor(DS::commonRange(rp, rc), [&](auto&& i) { auto rt = rc; - for (auto k = 0; k < dim; ++k) - { + for (auto k = 0; k < dim; ++k) { rt.start[k] = i[k] * ratio; rt.end[k] = (i[k] + 1) * ratio; } rt.level = l; this->operator[](i) = rangeReduce_s( - rt, [](auto&& a, auto&& b) { return a + b; }, - [&](auto&& k) { return this->operator[](k); }) - / Math::int_pow(ratio, dim); + rt, [](auto&& a, auto&& b) { return a + b; }, + [&](auto&& k) { return this->operator[](k); }) + / Math::int_pow(ratio, dim); this->blocked(i) = true; }); } @@ -659,14 +531,12 @@ namespace OpFlow } } - auto getView() - { + auto getView() { OP_NOT_IMPLEMENTED; return 0; } - const auto& evalAtImpl_final(const index_type& i) const - { + const auto& evalAtImpl_final(const index_type& i) const { return data[i.l][i.p][i - offset[i.l][i.p]]; } @@ -675,9 +545,7 @@ namespace OpFlow const auto& blocked(const index_type& i) const { return block_mark[i.l][i.p][i - offset[i.l][i.p]]; } template - requires(!std::same_as) - bool containsImpl_final(const Other& o) const - { + requires(!std::same_as) bool containsImpl_final(const Other& o) const { return false; } @@ -685,7 +553,7 @@ namespace OpFlow private: bool pinned = false; - constexpr static auto dim = internal::MeshBasedFieldExprTrait < T > ::dim; + constexpr static auto dim = internal::MeshBasedFieldExprTrait::dim; }; -} // namespace OpFlow +}// namespace OpFlow #endif//OPFLOW_STENCILFIELD_HPP \ No newline at end of file diff --git a/src/Core/Field/MeshBased/Structured/CartesianField.hpp b/src/Core/Field/MeshBased/Structured/CartesianField.hpp index d9286bfd..40cdd1fa 100644 --- a/src/Core/Field/MeshBased/Structured/CartesianField.hpp +++ b/src/Core/Field/MeshBased/Structured/CartesianField.hpp @@ -35,11 +35,9 @@ OPFLOW_MODULE_EXPORT -namespace OpFlow -{ +namespace OpFlow { template ::dim>> - struct CartesianField : CartesianFieldExpr> - { + struct CartesianField : CartesianFieldExpr> { using index_type = typename internal::CartesianFieldExprTrait::index_type; private: @@ -61,10 +59,8 @@ namespace OpFlow CartesianField(const CartesianField& other) : CartesianFieldExpr>(other), data(other.data), - ext_width(other.ext_width), initialized(true) - { - for (auto i = 0; i < internal::ExprTrait::dim; ++i) - { + ext_width(other.ext_width), initialized(true) { + for (auto i = 0; i < internal::ExprTrait::dim; ++i) { bc[i].start = other.bc[i].start ? other.bc[i].start->getCopy() : nullptr; if (bc[i].start && isLogicalBC(bc[i].start->getBCType())) dynamic_cast*>(bc[i].start.get())->rebindField(*this); @@ -76,27 +72,21 @@ namespace OpFlow CartesianField(CartesianField&& other) noexcept : CartesianFieldExpr>(std::move(other)), data(std::move(other.data)), - initialized(true), bc(std::move(other.bc)), ext_width(std::move(other.ext_width)) - { - } + initialized(true), bc(std::move(other.bc)), ext_width(std::move(other.ext_width)) {} - CartesianField& operator=(const CartesianField& other) - { + CartesianField& operator=(const CartesianField& other) { assignImpl_final(other); return *this; } - CartesianField& operator=(CartesianField&& other) noexcept - { + CartesianField& operator=(CartesianField&& other) noexcept { assignImpl_final(std::move(other)); return *this; } template - requires std::same_as - void - resplitWithStrategy(AbstractSplitStrategy* strategy) - { + requires std::same_as void + resplitWithStrategy(AbstractSplitStrategy* strategy) { // this method only acts when MPI is enabled #if defined(OPFLOW_WITH_MPI) && defined(OPFLOW_DISTRIBUTE_MODEL_MPI) if (!strategy) return; @@ -104,14 +94,12 @@ namespace OpFlow auto old_splitMap = this->splitMap; auto new_local_range = strategy->splitRange(this->mesh.getRange(), getGlobalParallelPlan()); auto new_splitMap = strategy->getSplitMap(this->mesh.getRange(), getGlobalParallelPlan()); - for (int i = 0; i < dim; ++i) - { + for (int i = 0; i < dim; ++i) { auto _loc = this->loc[i]; if (_loc == LocOnMesh::Corner && new_local_range.end[i] == this->mesh.getRange().end[i] - 1) new_local_range.end[i] - = std::min(new_local_range.end[i] + 1, this->accessibleRange.end[i]); - for (auto& r : new_splitMap) - { + = std::min(new_local_range.end[i] + 1, this->accessibleRange.end[i]); + for (auto& r : new_splitMap) { if (_loc == LocOnMesh::Corner && r.end[i] == this->mesh.getRange().end[i] - 1) r.end[i] = std::min(r.end[i] + 1, this->accessibleRange.end[i]); } @@ -119,30 +107,24 @@ namespace OpFlow // find each potential intersections with each rank std::vector> intersections(getWorkerCount()); - for (int i = 0; i < this->splitMap.size(); ++i) - { + for (int i = 0; i < this->splitMap.size(); ++i) { intersections[i] = DS::commonRange(old_local_range, new_splitMap[i]); } std::vector> send_buff; std::vector dest_ranks; - for (int i = 0; i < intersections.size(); ++i) - { - if (!intersections[i].empty()) - { + for (int i = 0; i < intersections.size(); ++i) { + if (!intersections[i].empty()) { dest_ranks.push_back(i); std::vector buff; buff.reserve(intersections[i].count()); rangeFor_s(intersections[i], [&](auto&& k) { buff.push_back(this->evalAt(k)); }); send_buff.push_back(std::move(buff)); - if constexpr (std::is_trivial_v&& std::is_standard_layout_v) - { + if constexpr (std::is_trivial_v && std::is_standard_layout_v) { MPI_Request request; MPI_Isend(send_buff.back().data(), send_buff.back().size() * sizeof(D), MPI_BYTE, dest_ranks.back(), getWorkerId(), MPI_COMM_WORLD, &request); - MPI_Request_free(&request); // status tested on receiver's side - } - else - { + MPI_Request_free(&request);// status tested on receiver's side + } else { OP_NOT_IMPLEMENTED; } } @@ -152,21 +134,17 @@ namespace OpFlow std::vector recv_requests; recv_buff.reserve(getWorkerCount()); recv_requests.reserve(getWorkerCount()); - for (int i = 0; i < old_splitMap.size(); ++i) - { + for (int i = 0; i < old_splitMap.size(); ++i) { intersections[i] = DS::commonRange(new_local_range, old_splitMap[i]); } std::vector src_ranks; - for (int i = 0; i < intersections.size(); ++i) - { - if (!intersections[i].empty()) - { + for (int i = 0; i < intersections.size(); ++i) { + if (!intersections[i].empty()) { src_ranks.push_back(i); recv_buff.emplace_back(); recv_buff.back().resize(intersections[i].count()); recv_requests.emplace_back(); - if constexpr (std::is_trivial_v&& std::is_standard_layout_v) - { + if constexpr (std::is_trivial_v && std::is_standard_layout_v) { MPI_Irecv(recv_buff.back().data(), intersections[i].count() * sizeof(D), MPI_BYTE, i, i, MPI_COMM_WORLD, &recv_requests.back()); } @@ -175,23 +153,19 @@ namespace OpFlow // reshape data array this->data.reShape(new_local_range.getInnerRange(-this->padding).getExtends()); this->offset = typename internal::CartesianFieldExprTrait::index_type( - new_local_range.getInnerRange(-this->padding).getOffset()); + new_local_range.getInnerRange(-this->padding).getOffset()); this->localRange = new_local_range; this->splitMap = new_splitMap; // loop over all requests int finished_count = 0; std::vector finished_bit(src_ranks.size(), false); - while (finished_count != src_ranks.size()) - { - for (int i = 0; i < finished_bit.size(); ++i) - { - if (!finished_bit[i]) - { + while (finished_count != src_ranks.size()) { + for (int i = 0; i < finished_bit.size(); ++i) { + if (!finished_bit[i]) { int flag; MPI_Test(&recv_requests[i], &flag, MPI_STATUS_IGNORE); - if (flag) - { + if (flag) { finished_bit[i] = true; finished_count++; auto iter = recv_buff[i].begin(); @@ -207,82 +181,65 @@ namespace OpFlow } template - auto& assignImpl_final(const CartesianField& other) - { - if (!initialized) - { + auto& assignImpl_final(const CartesianField& other) { + if (!initialized) { OP_ASSERT_MSG(Op == BasicArithOp::Eq, "Incremental assignment to uninitialized field is illegal"); this->initPropsFrom(other); data = other.data; ext_width = other.ext_width; initialized = true; - } - else if (this != &other) - { - internal::FieldAssigner::assign < Op > (other, *this); + } else if (this != &other) { + internal::FieldAssigner::assign(other, *this); this->updatePadding(); } return *this; } template - auto& - assignImpl_final(T&& other) - { + auto& assignImpl_final(T&& other) { // T is not const here for that we need to call other.prepare() later other.prepare(); - if (!initialized) - { + if (!initialized) { OP_ASSERT_MSG(Op == BasicArithOp::Eq, "Incremental assignment to uninitialized field is illegal"); this->initPropsFrom(other); - if constexpr (CartesianFieldType < T >) - { + if constexpr (CartesianFieldType) { data = other.data; ext_width = other.ext_width; - if constexpr (std::same_as < Meta::RealType < T >, CartesianField >) - for (int i = 0; i < dim; ++i) - { + if constexpr (std::same_as, CartesianField>) + for (int i = 0; i < dim; ++i) { this->bc[i].start = other.bc[i].start ? other.bc[i].start->getCopy() : nullptr; this->bc[i].end = other.bc[i].end ? other.bc[i].end->getCopy() : nullptr; } else - for (int i = 0; i < dim; ++i) - { + for (int i = 0; i < dim; ++i) { this->bc[i].start = other.bc[i].start - ? genProxyBC(*other.bc[i].start) - : nullptr; - this->bc[i].end = other.bc[i].end - ? genProxyBC(*other.bc[i].end) - : nullptr; + ? genProxyBC(*other.bc[i].start) + : nullptr; + this->bc[i].end = other.bc[i].end ? genProxyBC(*other.bc[i].end) + : nullptr; } - } - else - { + } else { this->data.reShape(this->localRange.getInnerRange(-this->padding).getExtends()); this->offset = typename internal::CartesianFieldExprTrait::index_type( - this->localRange.getInnerRange(-this->padding).getOffset()); + this->localRange.getInnerRange(-this->padding).getOffset()); } // invoke the assigner - internal::FieldAssigner::assign < Op > (other, *this); + internal::FieldAssigner::assign(other, *this); this->updatePadding(); initialized = true; - } - else if ((void*)this != (void*)&other) - { + } else if ((void*) this != (void*) &other) { // assign all values from T to assignable range - internal::FieldAssigner::assign < Op > (other, *this); + internal::FieldAssigner::assign(other, *this); this->updatePadding(); } return *this; } template - auto& assignImpl_final(const D& c) - { - if (!initialized) - { + auto& assignImpl_final(const D& c) { + if (!initialized) { OP_CRITICAL("CartesianField not initialized. Cannot assign constant to it."); OP_ABORT; } @@ -327,76 +284,61 @@ namespace OpFlow } auto& - initBy(const std::function::dim> &)>& f) - { - rangeFor(DS::commonRange(this->assignableRange, this->localRange), [&](auto&& i) - { + initBy(const std::function::dim>&)>& f) { + rangeFor(DS::commonRange(this->assignableRange, this->localRange), [&](auto&& i) { std::array::dim> cords; for (auto k = 0; k < internal::CartesianMeshTrait::dim; ++k) cords[k] = this->loc[k] == LocOnMesh::Corner - ? this->mesh.x(k, i) - : this->mesh.x(k, i) + .5 * this->mesh.dx(k, i); + ? this->mesh.x(k, i) + : this->mesh.x(k, i) + .5 * this->mesh.dx(k, i); this->operator[](i) = f(cords); }); this->updatePadding(); return *this; } - void prepareImpl_final() const - { - } + void prepareImpl_final() const {} - void updateNeighbors() - { - if (this->splitMap.size() == 1) - { + void updateNeighbors() { + if (this->splitMap.size() == 1) { // single node mode this->neighbors.clear(); - } - else - { + } else { #if defined(OPFLOW_WITH_MPI) && defined(OPFLOW_DISTRIBUTE_MODEL_MPI) int rank = getWorkerId(); this->neighbors.clear(); - std::array < bool, dim > is_periodic; - for (int d = 0; d < dim; ++d) - { + std::array is_periodic; + for (int d = 0; d < dim; ++d) { is_periodic[d] = this->bc[d].start && this->bc[d].start->getBCType() == BCType::Periodic; } int range_count = Math::int_pow(3, std::count(is_periodic.begin(), is_periodic.end(), true)); - for (std::size_t i = 0; i < this->splitMap.size(); ++i) - { + for (std::size_t i = 0; i < this->splitMap.size(); ++i) { auto mesh_range_extends = this->mesh.getRange().getExtends(); - for (int k = 0; k < range_count; ++k) - { + for (int k = 0; k < range_count; ++k) { auto r = this->splitMap[i]; - for (int d = 0; d < dim; ++d) - { + for (int d = 0; d < dim; ++d) { int direction - = (k % Math::int_pow(3, d + 1)) / Math::int_pow(3, d); // 0, 1(+), 2(-) - switch (direction) - { - case 2: - r.start[d] -= mesh_range_extends[d] - 1; - r.end[d] -= mesh_range_extends[d] - 1; - break; - default: - case 0: - break; - case 1: - r.start[d] += mesh_range_extends[d] - 1; - r.end[d] += mesh_range_extends[d] - 1; - break; + = (k % Math::int_pow(3, d + 1)) / Math::int_pow(3, d);// 0, 1(+), 2(-) + switch (direction) { + case 2: + r.start[d] -= mesh_range_extends[d] - 1; + r.end[d] -= mesh_range_extends[d] - 1; + break; + default: + case 0: + break; + case 1: + r.start[d] += mesh_range_extends[d] - 1; + r.end[d] += mesh_range_extends[d] - 1; + break; } } - if (!(static_cast(i) == rank && r == this->localRange)) - { + if (!(static_cast(i) == rank && r == this->localRange)) { auto send_range - = DS::commonRange(this->localRange, r.getInnerRange(-this->padding)); + = DS::commonRange(this->localRange, r.getInnerRange(-this->padding)); auto recv_range - = DS::commonRange(this->localRange.getInnerRange(-this->padding), r); - if (send_range.count() > 0) - { + = DS::commonRange(this->localRange.getInnerRange(-this->padding), r); + if (send_range.count() > 0) { this->neighbors.emplace_back(i, send_range, recv_range, k); } } @@ -408,22 +350,18 @@ namespace OpFlow } } - void updatePaddingImpl_final() - { + void updatePaddingImpl_final() { // step 0: update dirc bc for corner case - for (int i = 0; i < dim; ++i) - { + for (int i = 0; i < dim; ++i) { // lower side if (this->localRange.start[i] == this->accessibleRange.start[i] && this->bc[i].start - && this->bc[i].start->getBCType() == BCType::Dirc && this->loc[i] == LocOnMesh::Corner) - { + && this->bc[i].start->getBCType() == BCType::Dirc && this->loc[i] == LocOnMesh::Corner) { auto r = this->localRange.slice(i, this->localRange.start[i]); rangeFor(r, [&](auto&& idx) { this->operator()(idx) = this->bc[i].start->evalAt(idx); }); } // upper side if (this->localRange.end[i] == this->accessibleRange.end[i] && this->bc[i].end - && this->bc[i].end->getBCType() == BCType::Dirc && this->loc[i] == LocOnMesh::Corner) - { + && this->bc[i].end->getBCType() == BCType::Dirc && this->loc[i] == LocOnMesh::Corner) { auto r = this->localRange.slice(i, this->localRange.end[i] - 1); rangeFor(r, [&](auto&& idx) { this->operator()(idx) = this->bc[i].end->evalAt(idx); }); } @@ -431,322 +369,270 @@ namespace OpFlow // step 1: update paddings by bc extension // start/end record the start/end index of last padding operation // the latter padding op pads the outer range of the former padding zone - std::array < int, dim > start, end; - if constexpr (requires(D v) - { - { - v + v - } - -> std::same_as; - { - v - v - } - -> std::same_as; - { - v * 1.0 - } - -> std::same_as; - { - v / 1.0 - } - -> std::same_as; - }) - { - for (int i = 0; i < dim; ++i) - { + std::array start, end; + if constexpr (requires(D v) { + { v + v } + ->std::same_as; + { v - v } + ->std::same_as; + { v * 1.0 } + ->std::same_as; + { v / 1.0 } + ->std::same_as; + }) { + for (int i = 0; i < dim; ++i) { // lower side if (this->localRange.start[i] == this->accessibleRange.start[i] && this->bc[i].start - && this->bc[i].start->getBCType() != BCType::Periodic) - { + && this->bc[i].start->getBCType() != BCType::Periodic) { start[i] = this->logicalRange.start[i]; // current padding zone auto r = this->localRange; - for (int j = 0; j < i; ++j) - { + for (int j = 0; j < i; ++j) { r.start[j] = start[j]; r.end[j] = end[j]; } r.start[i] = start[i]; r.end[i] = this->localRange.start[i]; - if (this->loc[i] == LocOnMesh::Corner) - { - switch (this->bc[i].start->getBCType()) - { - case BCType::Dirc: - // mid-point rule - rangeFor(r, [&](auto&& idx) - { - auto bc_v = this->bc[i].start->evalAt(idx); - auto mirror_idx = idx; - mirror_idx[i] = 2 * this->localRange.start[i] - idx[i]; - this->operator()(idx) = Math::Interpolator1D::intp( - this->mesh.x(i, this->localRange.start[i]), bc_v, - this->mesh.x(i, mirror_idx[i]), this->evalAt(mirror_idx), - this->mesh.x(i, idx[i])); - }); - break; - case BCType::Neum: - // mid-diff = bc - rangeFor(r, [&](auto&& idx) - { - auto bc_v = this->bc[i].start->evalAt(idx); - auto mirror_idx = idx; - mirror_idx[i] = 2 * this->localRange.start[i] - idx[i]; - this->operator()(idx) = this->evalAt(mirror_idx) - + bc_v - * (this->mesh.x(i, idx) - - this->mesh.x(i, mirror_idx)); - }); - break; - case BCType::Symm: - rangeFor(r, [&](auto&& idx) - { - auto mirror_idx = idx; - mirror_idx[i] = 2 * this->localRange.start[i] - idx[i]; - this->operator()(idx) = this->evalAt(mirror_idx); - }); - break; - case BCType::ASymm: - rangeFor(r, [&](auto&& idx) - { - auto mirror_idx = idx; - mirror_idx[i] = 2 * this->localRange.start[i] - idx[i]; - this->operator()(idx) = -this->evalAt(mirror_idx); - }); - break; - default: - OP_ERROR("Cannot handle current bc padding: bc type {}", - this->bc[i].start->getTypeName()); - OP_ABORT; + if (this->loc[i] == LocOnMesh::Corner) { + switch (this->bc[i].start->getBCType()) { + case BCType::Dirc: + // mid-point rule + rangeFor(r, [&](auto&& idx) { + auto bc_v = this->bc[i].start->evalAt(idx); + auto mirror_idx = idx; + mirror_idx[i] = 2 * this->localRange.start[i] - idx[i]; + this->operator()(idx) = Math::Interpolator1D::intp( + this->mesh.x(i, this->localRange.start[i]), bc_v, + this->mesh.x(i, mirror_idx[i]), this->evalAt(mirror_idx), + this->mesh.x(i, idx[i])); + }); + break; + case BCType::Neum: + // mid-diff = bc + rangeFor(r, [&](auto&& idx) { + auto bc_v = this->bc[i].start->evalAt(idx); + auto mirror_idx = idx; + mirror_idx[i] = 2 * this->localRange.start[i] - idx[i]; + this->operator()(idx) = this->evalAt(mirror_idx) + + bc_v + * (this->mesh.x(i, idx) + - this->mesh.x(i, mirror_idx)); + }); + break; + case BCType::Symm: + rangeFor(r, [&](auto&& idx) { + auto mirror_idx = idx; + mirror_idx[i] = 2 * this->localRange.start[i] - idx[i]; + this->operator()(idx) = this->evalAt(mirror_idx); + }); + break; + case BCType::ASymm: + rangeFor(r, [&](auto&& idx) { + auto mirror_idx = idx; + mirror_idx[i] = 2 * this->localRange.start[i] - idx[i]; + this->operator()(idx) = -this->evalAt(mirror_idx); + }); + break; + default: + OP_ERROR("Cannot handle current bc padding: bc type {}", + this->bc[i].start->getTypeName()); + OP_ABORT; } - } - else - { + } else { // center case - switch (this->bc[i].start->getBCType()) - { - case BCType::Dirc: - // mid-point rule - rangeFor(r, [&](auto&& idx) - { - auto bc_v = this->bc[i].start->evalAt(idx); - auto mirror_idx = idx; - mirror_idx[i] = 2 * this->localRange.start[i] - 1 - idx[i]; - this->operator()(idx) = Math::Interpolator1D::intp( - this->mesh.x(i, this->localRange.start[i]), bc_v, - this->mesh.x(i, mirror_idx[i]) - + this->mesh.dx(i, mirror_idx) / 2., - this->evalAt(mirror_idx), - this->mesh.x(i, idx[i]) + this->mesh.dx(i, idx) / 2.); - }); - break; - case BCType::Neum: - // mid-diff = bc - rangeFor(r, [&](auto&& idx) - { - auto bc_v = this->bc[i].start->evalAt(idx); - auto mirror_idx = idx; - mirror_idx[i] = 2 * this->localRange.start[i] - 1 - idx[i]; - this->operator()(idx) - = this->evalAt(mirror_idx) - + bc_v - * (this->mesh.x(i, idx) - + this->mesh.dx(i, idx) / 2. - - this->mesh.x(i, mirror_idx) - - this->mesh.dx(i, mirror_idx) / 2.); - }); - break; - case BCType::Symm: - rangeFor(r, [&](auto&& idx) - { - auto mirror_idx = idx; - mirror_idx[i] = 2 * this->localRange.start[i] - 1 - idx[i]; - this->operator()(idx) = this->evalAt(mirror_idx); - }); - break; - case BCType::ASymm: - rangeFor(r, [&](auto&& idx) - { - auto mirror_idx = idx; - mirror_idx[i] = 2 * this->localRange.start[i] - 1 - idx[i]; - this->operator()(idx) = -this->evalAt(mirror_idx); - }); - break; - default: - OP_ERROR("Cannot handle current bc padding: bc type {}", - this->bc[i].start->getTypeName()); - OP_ABORT; + switch (this->bc[i].start->getBCType()) { + case BCType::Dirc: + // mid-point rule + rangeFor(r, [&](auto&& idx) { + auto bc_v = this->bc[i].start->evalAt(idx); + auto mirror_idx = idx; + mirror_idx[i] = 2 * this->localRange.start[i] - 1 - idx[i]; + this->operator()(idx) = Math::Interpolator1D::intp( + this->mesh.x(i, this->localRange.start[i]), bc_v, + this->mesh.x(i, mirror_idx[i]) + + this->mesh.dx(i, mirror_idx) / 2., + this->evalAt(mirror_idx), + this->mesh.x(i, idx[i]) + this->mesh.dx(i, idx) / 2.); + }); + break; + case BCType::Neum: + // mid-diff = bc + rangeFor(r, [&](auto&& idx) { + auto bc_v = this->bc[i].start->evalAt(idx); + auto mirror_idx = idx; + mirror_idx[i] = 2 * this->localRange.start[i] - 1 - idx[i]; + this->operator()(idx) + = this->evalAt(mirror_idx) + + bc_v + * (this->mesh.x(i, idx) + + this->mesh.dx(i, idx) / 2. + - this->mesh.x(i, mirror_idx) + - this->mesh.dx(i, mirror_idx) / 2.); + }); + break; + case BCType::Symm: + rangeFor(r, [&](auto&& idx) { + auto mirror_idx = idx; + mirror_idx[i] = 2 * this->localRange.start[i] - 1 - idx[i]; + this->operator()(idx) = this->evalAt(mirror_idx); + }); + break; + case BCType::ASymm: + rangeFor(r, [&](auto&& idx) { + auto mirror_idx = idx; + mirror_idx[i] = 2 * this->localRange.start[i] - 1 - idx[i]; + this->operator()(idx) = -this->evalAt(mirror_idx); + }); + break; + default: + OP_ERROR("Cannot handle current bc padding: bc type {}", + this->bc[i].start->getTypeName()); + OP_ABORT; } } - } - else - { + } else { start[i] = this->localRange.start[i]; } // upper side if (this->localRange.end[i] == this->accessibleRange.end[i] && this->bc[i].end - && this->bc[i].end->getBCType() != BCType::Periodic) - { + && this->bc[i].end->getBCType() != BCType::Periodic) { end[i] = this->logicalRange.end[i]; // current padding zone auto r = this->localRange; - for (int j = 0; j < i; ++j) - { + for (int j = 0; j < i; ++j) { r.start[j] = start[j]; r.end[j] = end[j]; } r.start[i] = this->localRange.end[i]; r.end[i] = this->logicalRange.end[i]; - if (this->loc[i] == LocOnMesh::Corner) - { - switch (this->bc[i].end->getBCType()) - { - case BCType::Dirc: - // mid-point rule - rangeFor(r, [&](auto&& idx) - { - auto bc_v = this->bc[i].end->evalAt(idx); - auto mirror_idx = idx; - mirror_idx[i] = 2 * this->localRange.end[i] - 2 - idx[i]; - this->operator()(idx) = Math::Interpolator1D::intp( - this->mesh.x(i, this->localRange.end[i] - 1), bc_v, - this->mesh.x(i, mirror_idx[i]), this->evalAt(mirror_idx), - this->mesh.x(i, idx[i])); - }); - break; - case BCType::Neum: - // mid-diff = bc - rangeFor(r, [&](auto&& idx) - { - auto bc_v = this->bc[i].end->evalAt(idx); - auto mirror_idx = idx; - mirror_idx[i] = 2 * this->localRange.end[i] - 2 - idx[i]; - this->operator()(idx) = this->evalAt(mirror_idx) - + bc_v - * (this->mesh.x(i, idx) - - this->mesh.x(i, mirror_idx)); - }); - break; - case BCType::Symm: - rangeFor(r, [&](auto&& idx) - { - auto mirror_idx = idx; - mirror_idx[i] = 2 * this->localRange.end[i] - 2 - idx[i]; - this->operator()(idx) = this->evalAt(mirror_idx); - }); - break; - case BCType::ASymm: - rangeFor(r, [&](auto&& idx) - { - auto mirror_idx = idx; - mirror_idx[i] = 2 * this->localRange.end[i] - 2 - idx[i]; - this->operator()(idx) = -this->evalAt(mirror_idx); - }); - break; - default: - OP_ERROR("Cannot handle current bc padding: bc type {}", - this->bc[i].end->getTypeName()); - OP_ABORT; + if (this->loc[i] == LocOnMesh::Corner) { + switch (this->bc[i].end->getBCType()) { + case BCType::Dirc: + // mid-point rule + rangeFor(r, [&](auto&& idx) { + auto bc_v = this->bc[i].end->evalAt(idx); + auto mirror_idx = idx; + mirror_idx[i] = 2 * this->localRange.end[i] - 2 - idx[i]; + this->operator()(idx) = Math::Interpolator1D::intp( + this->mesh.x(i, this->localRange.end[i] - 1), bc_v, + this->mesh.x(i, mirror_idx[i]), this->evalAt(mirror_idx), + this->mesh.x(i, idx[i])); + }); + break; + case BCType::Neum: + // mid-diff = bc + rangeFor(r, [&](auto&& idx) { + auto bc_v = this->bc[i].end->evalAt(idx); + auto mirror_idx = idx; + mirror_idx[i] = 2 * this->localRange.end[i] - 2 - idx[i]; + this->operator()(idx) = this->evalAt(mirror_idx) + + bc_v + * (this->mesh.x(i, idx) + - this->mesh.x(i, mirror_idx)); + }); + break; + case BCType::Symm: + rangeFor(r, [&](auto&& idx) { + auto mirror_idx = idx; + mirror_idx[i] = 2 * this->localRange.end[i] - 2 - idx[i]; + this->operator()(idx) = this->evalAt(mirror_idx); + }); + break; + case BCType::ASymm: + rangeFor(r, [&](auto&& idx) { + auto mirror_idx = idx; + mirror_idx[i] = 2 * this->localRange.end[i] - 2 - idx[i]; + this->operator()(idx) = -this->evalAt(mirror_idx); + }); + break; + default: + OP_ERROR("Cannot handle current bc padding: bc type {}", + this->bc[i].end->getTypeName()); + OP_ABORT; } - } - else - { + } else { // center case - switch (this->bc[i].end->getBCType()) - { - case BCType::Dirc: - // mid-point rule - rangeFor(r, [&](auto&& idx) - { - auto bc_v = this->bc[i].end->evalAt(idx); - auto mirror_idx = idx; - mirror_idx[i] = 2 * this->localRange.end[i] - 1 - idx[i]; - this->operator()(idx) = Math::Interpolator1D::intp( - this->mesh.x(i, this->localRange.end[i]), bc_v, - this->mesh.x(i, mirror_idx[i]) - + this->mesh.dx(i, mirror_idx) / 2., - this->evalAt(mirror_idx), - this->mesh.x(i, idx[i]) + this->mesh.dx(i, idx) / 2.); - }); - break; - case BCType::Neum: - // mid-diff = bc - rangeFor(r, [&](auto&& idx) - { - auto bc_v = this->bc[i].end->evalAt(idx); - auto mirror_idx = idx; - mirror_idx[i] = 2 * this->localRange.end[i] - 1 - idx[i]; - this->operator()(idx) - = this->evalAt(mirror_idx) - + bc_v - * (this->mesh.x(i, idx) - + this->mesh.dx(i, idx) / 2. - - this->mesh.x(i, mirror_idx) - - this->mesh.dx(i, mirror_idx) / 2.); - }); - break; - case BCType::Symm: - rangeFor(r, [&](auto&& idx) - { - auto mirror_idx = idx; - mirror_idx[i] = 2 * this->localRange.end[i] - 1 - idx[i]; - this->operator()(idx) = this->evalAt(mirror_idx); - }); - break; - case BCType::ASymm: - rangeFor(r, [&](auto&& idx) - { - auto mirror_idx = idx; - mirror_idx[i] = 2 * this->localRange.end[i] - 1 - idx[i]; - this->operator()(idx) = -this->evalAt(mirror_idx); - }); - break; - default: - OP_ERROR("Cannot handle current bc padding: bc type {}", - this->bc[i].end->getTypeName()); - OP_ABORT; + switch (this->bc[i].end->getBCType()) { + case BCType::Dirc: + // mid-point rule + rangeFor(r, [&](auto&& idx) { + auto bc_v = this->bc[i].end->evalAt(idx); + auto mirror_idx = idx; + mirror_idx[i] = 2 * this->localRange.end[i] - 1 - idx[i]; + this->operator()(idx) = Math::Interpolator1D::intp( + this->mesh.x(i, this->localRange.end[i]), bc_v, + this->mesh.x(i, mirror_idx[i]) + + this->mesh.dx(i, mirror_idx) / 2., + this->evalAt(mirror_idx), + this->mesh.x(i, idx[i]) + this->mesh.dx(i, idx) / 2.); + }); + break; + case BCType::Neum: + // mid-diff = bc + rangeFor(r, [&](auto&& idx) { + auto bc_v = this->bc[i].end->evalAt(idx); + auto mirror_idx = idx; + mirror_idx[i] = 2 * this->localRange.end[i] - 1 - idx[i]; + this->operator()(idx) + = this->evalAt(mirror_idx) + + bc_v + * (this->mesh.x(i, idx) + + this->mesh.dx(i, idx) / 2. + - this->mesh.x(i, mirror_idx) + - this->mesh.dx(i, mirror_idx) / 2.); + }); + break; + case BCType::Symm: + rangeFor(r, [&](auto&& idx) { + auto mirror_idx = idx; + mirror_idx[i] = 2 * this->localRange.end[i] - 1 - idx[i]; + this->operator()(idx) = this->evalAt(mirror_idx); + }); + break; + case BCType::ASymm: + rangeFor(r, [&](auto&& idx) { + auto mirror_idx = idx; + mirror_idx[i] = 2 * this->localRange.end[i] - 1 - idx[i]; + this->operator()(idx) = -this->evalAt(mirror_idx); + }); + break; + default: + OP_ERROR("Cannot handle current bc padding: bc type {}", + this->bc[i].end->getTypeName()); + OP_ABORT; } } - } - else - { + } else { end[i] = this->localRange.end[i]; } } } // step 2: update paddings by MPI communication - if (this->splitMap.size() == 1) - { + if (this->splitMap.size() == 1) { // no MPI or local field // update along periodic dims - for (int i = 0; i < dim; ++i) - { - if (this->bc[i].start && this->bc[i].start->getBCType() == BCType::Periodic) - { + for (int i = 0; i < dim; ++i) { + if (this->bc[i].start && this->bc[i].start->getBCType() == BCType::Periodic) { // issue an update auto rl = this->logicalRange.slice(i, this->logicalRange.start[i], this->accessibleRange.start[i]); - rangeFor(rl, [&](auto&& idx) - { + rangeFor(rl, [&](auto&& idx) { auto mirror_idx = idx; mirror_idx[i] += this->accessibleRange.end[i] - this->accessibleRange.start[i]; this->operator()(idx) = this->operator()(mirror_idx); }); auto rh = this->logicalRange.slice(i, this->accessibleRange.end[i], this->logicalRange.end[i]); - rangeFor(rh, [&](auto&& idx) - { + rangeFor(rh, [&](auto&& idx) { auto mirror_idx = idx; mirror_idx[i] -= this->accessibleRange.end[i] - this->accessibleRange.start[i]; this->operator()(idx) = this->operator()(mirror_idx); }); } } - } - else - { + } else { #if defined(OPFLOW_WITH_MPI) && defined(OPFLOW_DISTRIBUTE_MODEL_MPI) int rank = getWorkerId(); // one of the following pairs of buffer is used @@ -756,37 +642,29 @@ namespace OpFlow std::vector requests; auto mesh_range_extends = this->mesh.getRange().getExtends(); - for (const auto& [other_rank, send_range, recv_range, code] : this->neighbors) - { + for (const auto& [other_rank, send_range, recv_range, code] : this->neighbors) { // calculate the intersect range to be send - if constexpr (std::is_trivial_v&& std::is_standard_layout_v) - { + if constexpr (std::is_trivial_v && std::is_standard_layout_v) { // pack data into send buffer send_buff.emplace_back(); requests.emplace_back(); - rangeFor_s(send_range, [&](auto&& i) - { + rangeFor_s(send_range, [&](auto&& i) { OP_DEBUG("Send {} = {}", i, this->operator()(i)); send_buff.back().push_back(this->evalAt(i)); }); - } - else if constexpr (Serializable) - { + } else if constexpr (Serializable) { // pack data into send buffer send_buff_byte.emplace_back(); send_buff_offsets.emplace_back(); send_buff_offsets.back().push_back(0); requests.emplace_back(); - rangeFor_s(send_range, [&](auto&& i) - { + rangeFor_s(send_range, [&](auto&& i) { OP_DEBUG("Send {} = {}", i, this->operator()(i)); std::vector tmp = this->operator()(i).serialize(); send_buff_byte.back().insert(send_buff_byte.back().end(), tmp.begin(), tmp.end()); - send_buff_offsets.back().push_back((int)send_buff_byte.back().size()); + send_buff_offsets.back().push_back((int) send_buff_byte.back().size()); }); - } - else - { + } else { OP_ERROR("Datatype cannot be serialized."); OP_ABORT; } @@ -794,40 +672,37 @@ namespace OpFlow other_rank); auto o_recv_range = send_range; // inverse the shift to get the recv range on the receiver side - for (int d = 0; d < dim; ++d) - { + for (int d = 0; d < dim; ++d) { int direction - = (code % Math::int_pow(3, d + 1)) / Math::int_pow(3, d); // 0, 1(+), 2(-) - switch (direction) - { - case 1: - o_recv_range.start[d] -= mesh_range_extends[d] - 1; - o_recv_range.end[d] -= mesh_range_extends[d] - 1; - break; - default: - case 0: - break; - case 2: - o_recv_range.start[d] += mesh_range_extends[d] - 1; - o_recv_range.end[d] += mesh_range_extends[d] - 1; - break; + = (code % Math::int_pow(3, d + 1)) / Math::int_pow(3, d);// 0, 1(+), 2(-) + switch (direction) { + case 1: + o_recv_range.start[d] -= mesh_range_extends[d] - 1; + o_recv_range.end[d] -= mesh_range_extends[d] - 1; + break; + default: + case 0: + break; + case 2: + o_recv_range.start[d] += mesh_range_extends[d] - 1; + o_recv_range.end[d] += mesh_range_extends[d] - 1; + break; } } - if constexpr (std::is_trivial_v&& std::is_standard_layout_v) + if constexpr (std::is_trivial_v && std::is_standard_layout_v) MPI_Isend(send_buff.back().data(), send_buff.back().size() * sizeof(D) / sizeof(char), MPI_CHAR, other_rank, - std::hash>{}(o_recv_range) - % (1 << 24), + std::hash> {}(o_recv_range) + % (1 << 24), MPI_COMM_WORLD, &requests.back()); - else if constexpr (Serializable) - { + else if constexpr (Serializable) { MPI_Isend(send_buff_offsets.back().data(), send_buff_offsets.back().size(), MPI_INT, other_rank, rank, MPI_COMM_WORLD, &requests.back()); requests.emplace_back(); MPI_Isend(send_buff_byte.back().data(), send_buff_byte.back().size(), MPI_BYTE, other_rank, - std::hash>{}(o_recv_range) - % (1 << 24), + std::hash> {}(o_recv_range) + % (1 << 24), MPI_COMM_WORLD, &requests.back()); } @@ -836,24 +711,21 @@ namespace OpFlow // issue receive request OP_DEBUG("Recv range {} from rank {} to rank {}", recv_range.toString(), other_rank, rank); - if constexpr (std::is_trivial_v&& std::is_standard_layout_v) - { + if constexpr (std::is_trivial_v && std::is_standard_layout_v) { recv_buff.emplace_back(); recv_buff.back().resize(recv_range.count()); MPI_Irecv(recv_buff.back().data(), recv_buff.back().size() * sizeof(D) / sizeof(char), MPI_CHAR, other_rank, - std::hash>{}(recv_range) % (1 << 24), + std::hash> {}(recv_range) % (1 << 24), MPI_COMM_WORLD, &requests.back()); - } - else if constexpr (Serializable) - { + } else if constexpr (Serializable) { recv_buff_offsets.emplace_back(recv_range.count() + 1); MPI_Recv(recv_buff_offsets.back().data(), recv_buff_offsets.back().size(), MPI_INT, other_rank, other_rank, MPI_COMM_WORLD, MPI_STATUS_IGNORE); recv_buff_byte.emplace_back(recv_buff_offsets.back().back()); MPI_Irecv(recv_buff_byte.back().data(), recv_buff_byte.back().size(), MPI_BYTE, other_rank, - std::hash>{}(recv_range) % (1 << 24), + std::hash> {}(recv_range) % (1 << 24), MPI_COMM_WORLD, &requests.back()); } } @@ -861,38 +733,30 @@ namespace OpFlow std::vector status(requests.size()); MPI_Waitall(requests.size(), requests.data(), status.data()); // check status - for (const auto& s : status) - { + for (const auto& s : status) { if (s.MPI_ERROR != MPI_SUCCESS) OP_CRITICAL("Field {}'s updatePadding failed.", this->getName()); } // unpack receive buffer - if constexpr (std::is_trivial_v&& std::is_standard_layout_v) - { + if constexpr (std::is_trivial_v && std::is_standard_layout_v) { auto recv_iter = recv_buff.begin(); - for (const auto& [other_rank, send_range, recv_range, code] : this->neighbors) - { + for (const auto& [other_rank, send_range, recv_range, code] : this->neighbors) { auto _iter = recv_iter->begin(); OP_DEBUG("Unpacking range {}", recv_range.toString()); - rangeFor_s(recv_range, [&](auto&& i) - { + rangeFor_s(recv_range, [&](auto&& i) { OP_DEBUG("Unpack {} = {}", i, *_iter); this->operator()(i) = *_iter++; }); ++recv_iter; } - } - else if constexpr (Serializable) - { + } else if constexpr (Serializable) { auto recv_iter = recv_buff_byte.begin(); auto recv_offset_iter = recv_buff_offsets.begin(); - for (const auto& [other_rank, send_range, recv_range, code] : this->neighbors) - { + for (const auto& [other_rank, send_range, recv_range, code] : this->neighbors) { auto _iter = recv_iter->begin(); auto _offset_iter = recv_offset_iter->begin(); OP_DEBUG("Unpacking range {}", recv_range.toString()); - rangeFor_s(recv_range, [&](auto&& i) - { + rangeFor_s(recv_range, [&](auto&& i) { //OP_INFO("Unpack {} = {}", i, *(char*)&*_iter); this->operator()(i).deserialize(&(*_iter) + *_offset_iter, *(_offset_iter + 1) - *_offset_iter); @@ -908,22 +772,19 @@ namespace OpFlow } } - auto getViewImpl_final() - { + auto getViewImpl_final() { OP_NOT_IMPLEMENTED; return 0; } - const auto& evalAtImpl_final(const index_type& i) const - { + const auto& evalAtImpl_final(const index_type& i) const { OP_ASSERT_MSG(DS::inRange(this->getLocalReadableRange(), i), "Cannot eval {} at {}: out of range {}", this->getName(), i, this->getLocalReadableRange().toString()); return data[i - this->offset]; } - auto& evalAtImpl_final(const index_type& i) - { + auto& evalAtImpl_final(const index_type& i) { OP_ASSERT_MSG(DS::inRange(this->getLocalReadableRange(), i), "Cannot eval {} at {}: out of range {}", this->getName(), i, this->getLocalWritableRange().toString()); @@ -931,187 +792,159 @@ namespace OpFlow } template - requires(!std::same_as) - bool containsImpl_final(const Other& o) const - { + requires(!std::same_as) bool containsImpl_final(const Other& o) const { return false; } bool containsImpl_final(const CartesianField& other) const { return this == &other; } - }; // namespace OpFlow + };// namespace OpFlow template - struct ExprBuilder> - { + struct ExprBuilder> { using Field = CartesianField; using Mesh = M; static constexpr auto dim = internal::CartesianFieldExprTrait::dim; ExprBuilder() = default; - auto& setName(const std::string& n) - { + auto& setName(const std::string& n) { f.name = n; return *this; } - auto& setMesh(const Mesh& m) - { + auto& setMesh(const Mesh& m) { f.mesh = m; return *this; } - auto& setLoc(const std::array& loc) - { + auto& setLoc(const std::array& loc) { f.loc = loc; return *this; } - auto& setLoc(LocOnMesh loc) - { + auto& setLoc(LocOnMesh loc) { f.loc.fill(loc); return *this; } - auto& setLocOfDim(int i, LocOnMesh loc) - { + auto& setLocOfDim(int i, LocOnMesh loc) { f.loc[i] = loc; return *this; } // set a logical bc - auto& setBC(int d, DimPos pos, BCType type) - { + auto& setBC(int d, DimPos pos, BCType type) { OP_ASSERT(d < dim); OP_ASSERT(type != BCType::Dirc && type != BCType::Neum); auto& targetBC = pos == DimPos::start ? f.bc[d].start : f.bc[d].end; - switch (type) - { - case BCType::Symm: - targetBC = std::make_unique>>(f, d, pos); - break; - case BCType::ASymm: - targetBC = std::make_unique>>(f, d, pos); - break; - case BCType::Periodic: - targetBC = std::make_unique>>(f, d, pos); - break; - default: - OP_ERROR("BC Type not supported."); - OP_ABORT; + switch (type) { + case BCType::Symm: + targetBC = std::make_unique>>(f, d, pos); + break; + case BCType::ASymm: + targetBC = std::make_unique>>(f, d, pos); + break; + case BCType::Periodic: + targetBC = std::make_unique>>(f, d, pos); + break; + default: + OP_ERROR("BC Type not supported."); + OP_ABORT; } return *this; } // set a constant bc template - auto& setBC(int d, DimPos pos, BCType type, T val) - { + auto& setBC(int d, DimPos pos, BCType type, T val) { OP_ASSERT(d < dim); if (isLogicalBC(type)) return setBC(d, pos, type); auto& targetBC = pos == DimPos::start ? f.bc[d].start : f.bc[d].end; - switch (type) - { - case BCType::Dirc: - targetBC = std::make_unique>>(val); - break; - case BCType::Neum: - targetBC = std::make_unique>>(val); - break; - default: - OP_ERROR("BC Type not supported."); - OP_ABORT; + switch (type) { + case BCType::Dirc: + targetBC = std::make_unique>>(val); + break; + case BCType::Neum: + targetBC = std::make_unique>>(val); + break; + default: + OP_ERROR("BC Type not supported."); + OP_ABORT; } return *this; } // set a functor bc template - requires requires(F f) - { - { - f(std::declval>::index_type>()) - } - -> std::convertible_to>::elem_type>; - } - auto& setBC(int d, DimPos pos, BCType type, F&& functor) - { + requires requires(F f) { + { f(std::declval>::index_type>()) } + ->std::convertible_to>::elem_type>; + } + auto& setBC(int d, DimPos pos, BCType type, F&& functor) { OP_ASSERT(d < dim); auto& targetBC = pos == DimPos::start ? f.bc[d].start : f.bc[d].end; - switch (type) - { - case BCType::Dirc: - targetBC = std::make_unique>>(functor); - break; - case BCType::Neum: - targetBC = std::make_unique>>(functor); - break; - default: - OP_ERROR("BC Type not supported."); - OP_ABORT; + switch (type) { + case BCType::Dirc: + targetBC = std::make_unique>>(functor); + break; + case BCType::Neum: + targetBC = std::make_unique>>(functor); + break; + default: + OP_ERROR("BC Type not supported."); + OP_ABORT; } return *this; } // set an externally built bc - auto& setBC(int d, DimPos pos, std::unique_ptr>>&& bc) - { + auto& setBC(int d, DimPos pos, std::unique_ptr>>&& bc) { OP_ASSERT(d < dim); auto& targetBC = pos == DimPos::start ? f.bc[d].start : f.bc[d].end; targetBC = std::move(bc); return *this; } - auto& setExt(int d, DimPos pos, int width) - { - if (pos == DimPos::start) - { + auto& setExt(int d, DimPos pos, int width) { + if (pos == DimPos::start) { f.ext_width[d].start = width; - } - else - { + } else { f.ext_width[d].end = width; } return *this; } - auto& setExt(int width) - { + auto& setExt(int width) { // a uniform ext - for (auto& e : f.ext_width) - { + for (auto& e : f.ext_width) { e.start = width; e.end = width; } return *this; } - auto& setPadding(int p) - { + auto& setPadding(int p) { f.padding = p; return *this; } - auto& setSplitStrategy(std::shared_ptr>> s) - { + auto& setSplitStrategy(std::shared_ptr>> s) { strategy = s; return *this; } - auto& build() - { + auto& build() { calculateRanges(); validateRanges(); OP_ASSERT(f.localRange.check() && f.accessibleRange.check() && f.assignableRange.check()); f.data.reShape(f.localRange.getInnerRange(-f.padding).getExtends()); f.offset = typename internal::CartesianFieldExprTrait::index_type( - f.localRange.getInnerRange(-f.padding).getOffset()); + f.localRange.getInnerRange(-f.padding).getOffset()); f.updatePadding(); return f; } private: - void validateRanges() - { + void validateRanges() { // accessibleRange <= logicalRange f.accessibleRange = commonRange(f.accessibleRange, f.logicalRange); // localRange <= logicalRange @@ -1120,93 +953,80 @@ namespace OpFlow f.assignableRange = commonRange(f.assignableRange, f.accessibleRange); } - void calculateRanges() - { + void calculateRanges() { // padding take the max of {padding, ext_width} for (const auto& w : f.ext_width) f.padding = std::max({f.padding, w.start, w.end}); // init ranges to mesh range f.logicalRange = f.assignableRange = f.localRange = f.accessibleRange = f.mesh.getRange(); // trim ranges according to bcs - for (auto i = 0; i < dim; ++i) - { + for (auto i = 0; i < dim; ++i) { auto loc = f.loc[i]; // start side auto type = f.bc[i].start ? f.bc[i].start->getBCType() : BCType::Undefined; - switch (type) - { - case BCType::Dirc: - if (loc == LocOnMesh::Corner) f.assignableRange.start[i]++; - break; - case BCType::Neum: - case BCType::Undefined: - case BCType::Symm: - case BCType::ASymm: - case BCType::Periodic: - break; - default: - OP_NOT_IMPLEMENTED; + switch (type) { + case BCType::Dirc: + if (loc == LocOnMesh::Corner) f.assignableRange.start[i]++; + break; + case BCType::Neum: + case BCType::Undefined: + case BCType::Symm: + case BCType::ASymm: + case BCType::Periodic: + break; + default: + OP_NOT_IMPLEMENTED; } // end side type = f.bc[i].end ? f.bc[i].end->getBCType() : BCType::Undefined; - switch (type) - { - case BCType::Dirc: - if (loc == LocOnMesh::Corner) - { - f.assignableRange.end[i]--; - } - else if (loc == LocOnMesh::Center) - { - f.accessibleRange.end[i]--; - f.assignableRange.end[i]--; - } - break; - case BCType::Neum: - case BCType::Undefined: - case BCType::Symm: - case BCType::ASymm: - if (loc == LocOnMesh::Center) - { + switch (type) { + case BCType::Dirc: + if (loc == LocOnMesh::Corner) { + f.assignableRange.end[i]--; + } else if (loc == LocOnMesh::Center) { + f.accessibleRange.end[i]--; + f.assignableRange.end[i]--; + } + break; + case BCType::Neum: + case BCType::Undefined: + case BCType::Symm: + case BCType::ASymm: + if (loc == LocOnMesh::Center) { + f.accessibleRange.end[i]--; + f.assignableRange.end[i]--; + } + break; + case BCType::Periodic: + // same as center case f.accessibleRange.end[i]--; f.assignableRange.end[i]--; - } - break; - case BCType::Periodic: - // same as center case - f.accessibleRange.end[i]--; - f.assignableRange.end[i]--; - break; - default: - OP_NOT_IMPLEMENTED; + break; + default: + OP_NOT_IMPLEMENTED; } f.logicalRange.start[i] = f.accessibleRange.start[i] - f.ext_width[i].start; f.logicalRange.end[i] = f.accessibleRange.end[i] + f.ext_width[i].end; } // calculate localRange - if (strategy) - { + if (strategy) { // always split the mesh range to make sure associated fields shares the same split // note: the returned local range is in centered mode f.localRange = strategy->splitRange(f.mesh.getRange(), getGlobalParallelPlan()); f.splitMap = strategy->getSplitMap(f.mesh.getRange(), getGlobalParallelPlan()); // adjust the local range according to the location & bc - for (auto i = 0; i < dim; ++i) - { + for (auto i = 0; i < dim; ++i) { auto loc = f.loc[i]; // we only need to consider the end side for whether taken the right boundary into account // only +1 if the block is at the right end // periodic bc can be trimmed by the min operation if (loc == LocOnMesh::Corner && f.localRange.end[i] == f.mesh.getRange().end[i] - 1) f.localRange.end[i] = std::min(f.localRange.end[i] + 1, f.accessibleRange.end[i]); - for (auto& range : f.splitMap) - { + for (auto& range : f.splitMap) { if (loc == LocOnMesh::Corner && range.end[i] == f.mesh.getRange().end[i] - 1) range.end[i] = std::min(range.end[i] + 1, f.accessibleRange.end[i]); } } - } - else - { + } else { f.localRange = f.accessibleRange; f.splitMap.clear(); f.splitMap.push_back(f.localRange); @@ -1217,15 +1037,13 @@ namespace OpFlow CartesianField f; std::shared_ptr>> strategy; }; -} // namespace OpFlow +}// namespace OpFlow -namespace std -{ +namespace std { template - void swap(OpFlow::CartesianField& a, OpFlow::CartesianField& b) - { + void swap(OpFlow::CartesianField& a, OpFlow::CartesianField& b) { std::swap(a.data, b.data); } -} // namespace std +}// namespace std #endif//OPFLOW_CARTESIANFIELD_HPP \ No newline at end of file diff --git a/src/Core/Loops/RangeFor.hpp b/src/Core/Loops/RangeFor.hpp index 80a14931..a72b34e7 100644 --- a/src/Core/Loops/RangeFor.hpp +++ b/src/Core/Loops/RangeFor.hpp @@ -31,8 +31,7 @@ OPFLOW_MODULE_EXPORT -namespace OpFlow -{ +namespace OpFlow { /// \brief Serial version of range for /// \tparam dim Range dim /// \tparam F Functor type @@ -40,27 +39,23 @@ namespace OpFlow /// \param func Applied functor /// \return The input functor template - F rangeFor_s(const R& range, F&& func) - { + F rangeFor_s(const R& range, F&& func) { typename R::index_type i(range); auto total_count = range.count(); - for (auto count = 0; count < total_count; ++count, ++i) - { + for (auto count = 0; count < total_count; ++count, ++i) { func(static_cast(i)); } return std::forward(func); } template - auto rangeReduce_s(const R& range, ReOp&& op, F&& func) - { + auto rangeReduce_s(const R& range, ReOp&& op, F&& func) { //OP_INFO("Called on {}, size = {}", range.toString(), range.count()); typename R::index_type idx(range); auto result = func(static_cast(idx)); ++idx; auto total_count = range.count(); - for (auto count = 1; count < total_count; ++count, ++idx) - { + for (auto count = 1; count < total_count; ++count, ++idx) { result = op(result, func(static_cast(idx))); } return result; @@ -73,22 +68,17 @@ namespace OpFlow /// \param func Applied functor /// \return The input functor template - F rangeFor(const R& range, F&& func) - { + F rangeFor(const R& range, F&& func) { [[maybe_unused]] constexpr static auto dim = R::dim; [[maybe_unused]] auto total_count = range.count(); auto line_size = range.end[0] - range.start[0]; if (line_size <= 0) return std::forward(func); - if (range.stride[0] == 1) - { + if (range.stride[0] == 1) { tbb::task_arena arena(getGlobalParallelPlan().shared_memory_workers_count); - arena.execute([&]() - { + arena.execute([&]() { tbb::parallel_for(range, [&](const R& r) { rangeFor_s(r, OP_PERFECT_FOWD(func)); }); }); - } - else - { + } else { OP_NOT_IMPLEMENTED; std::abort(); } @@ -96,43 +86,36 @@ namespace OpFlow } template - auto rangeReduce(const R& range, ReOp&& op, F&& func) - { + auto rangeReduce(const R& range, ReOp&& op, F&& func) { using resultType = Meta::RealType()))>; auto line_size = range.end[0] - range.start[0]; if (line_size <= 0) return resultType(); - struct Reducer - { + struct Reducer { const ReOp& _op; const F& _func; - resultType result{}; + resultType result {}; void operator()(const R& _range) { result = _op(result, rangeReduce_s(_range, _op, _func)); } Reducer(Reducer& _reducer, tbb::detail::split) - : _op(_reducer._op), _func(_reducer._func), result() - { + : _op(_reducer._op), _func(_reducer._func), result() { if constexpr (Meta::Numerical) result = 0; } void join(const Reducer& _reducer) { result = _op(result, _reducer.result); } - Reducer(const ReOp& _op, const F& _func) : _op(_op), _func(_func), result() - { + Reducer(const ReOp& _op, const F& _func) : _op(_op), _func(_func), result() { // make sure for numerical type the reduction base is 0 if constexpr (Meta::Numerical) result = 0; // otherwise, we assume the default ctor of resultType provides an adequate base } - } reducer{op, func}; + } reducer {op, func}; - if (range.stride[0] == 1) - { + if (range.stride[0] == 1) { tbb::task_arena arena(getGlobalParallelPlan().shared_memory_workers_count); arena.execute([&]() { tbb::parallel_reduce(range, reducer); }); return reducer.result; - } - else - { + } else { OP_NOT_IMPLEMENTED; std::abort(); } @@ -140,18 +123,17 @@ namespace OpFlow #ifdef OPFLOW_WITH_MPI template - auto globalReduce(const R& range, ReOp&& op, F&& func) - { + auto globalReduce(const R& range, ReOp&& op, F&& func) { auto local_result = rangeReduce(range, op, func); std::vector results(getWorkerCount()); results[getWorkerId()] = local_result; static_assert(std::is_standard_layout_v && std::is_trivial_v, + local_result)> && std::is_trivial_v, "local_result must be pod type"); MPI_Allgather(MPI_IN_PLACE, sizeof(decltype(local_result)), MPI_BYTE, results.data(), sizeof(decltype(local_result)), MPI_BYTE, MPI_COMM_WORLD); - return std::reduce(results.begin(), results.end(), decltype(local_result){}, op); + return std::reduce(results.begin(), results.end(), decltype(local_result) {}, op); } #endif -} // namespace OpFlow +}// namespace OpFlow #endif//OPFLOW_RANGEFOR_HPP \ No newline at end of file diff --git a/src/Core/Parallel/ParticleGuidedSplitStrategy.hpp b/src/Core/Parallel/ParticleGuidedSplitStrategy.hpp index 90f4ea11..0ae1a859 100644 --- a/src/Core/Parallel/ParticleGuidedSplitStrategy.hpp +++ b/src/Core/Parallel/ParticleGuidedSplitStrategy.hpp @@ -29,19 +29,16 @@ OPFLOW_MODULE_EXPORT -namespace OpFlow -{ +namespace OpFlow { template - struct Particle - { + struct Particle { std::array x; }; template - struct ParticleGuidedSplitStrategy : AbstractSplitStrategy - { + struct ParticleGuidedSplitStrategy : AbstractSplitStrategy { public: - static constexpr int dim = internal::ExprTrait < F > ::dim; + static constexpr int dim = internal::ExprTrait::dim; ParticleGuidedSplitStrategy() = default; @@ -49,25 +46,20 @@ namespace OpFlow int max_levels, const typename internal::ExprTrait::mesh_type& ref_mesh) : particles(parts), part_load_factor(part_load), mesh_load_factor(mesh_laod), - max_levels(max_levels), ref_mesh(ref_mesh) - { - } + max_levels(max_levels), ref_mesh(ref_mesh) {} [[nodiscard]] std::string strategyName() const override { return "Particle guided split"; } typename internal::ExprTrait::range_type splitRange(const typename internal::ExprTrait::range_type& range, - const ParallelPlan& plan) override - { + const ParallelPlan& plan) override { check_state(plan); return split_impl(range, plan); } - std::vector::range_type - > + std::vector::range_type> getSplitMap(const typename internal::ExprTrait::range_type& range, - const ParallelPlan& plan) override - { + const ParallelPlan& plan) override { check_state(plan); return splitMap_impl(range, plan); } @@ -92,35 +84,28 @@ namespace OpFlow double part_load_factor = 0, mesh_load_factor = 1; int max_levels = 0; - struct Node - { + struct Node { std::unique_ptr lc, rc; Node* parent = nullptr; DS::Range range; std::vector> particles; std::vector particle_weight; - int split_axis = -1; // -1 for leaf node + int split_axis = -1;// -1 for leaf node Node() = default; - void traverse(auto&& func) const - { - if (!is_leaf()) - { + void traverse(auto&& func) const { + if (!is_leaf()) { lc->traverse(OP_PERFECT_FOWD(func)); rc->traverse(OP_PERFECT_FOWD(func)); - } - else - { + } else { func(*this); } } - void print_tree(std::string prefix) const - { + void print_tree(std::string prefix) const { OP_INFO("{} range = {}, axis = {}", prefix, range.toString(), split_axis); - if (!is_leaf()) - { + if (!is_leaf()) { prefix += "--"; OP_INFO("{} lc:", prefix); lc->print_tree(prefix); @@ -129,8 +114,7 @@ namespace OpFlow } } - void splitAt(int d, int pos, const typename internal::ExprTrait::mesh_type& mesh) - { + void splitAt(int d, int pos, const typename internal::ExprTrait::mesh_type& mesh) { auto new_lc = std::make_unique(); auto new_rc = std::make_unique(); new_lc->range = range; @@ -143,15 +127,11 @@ namespace OpFlow new_lc->parent = this; new_rc->parent = this; split_axis = d; - for (std::size_t i = 0; i < particles.size(); ++i) - { - if (particles[i].x[d] < mesh.x(d, pos + range.start[d])) - { + for (std::size_t i = 0; i < particles.size(); ++i) { + if (particles[i].x[d] < mesh.x(d, pos + range.start[d])) { new_lc->particles.push_back(particles[i]); new_lc->particle_weight.push_back(particle_weight[i]); - } - else - { + } else { new_rc->particles.push_back(particles[i]); new_rc->particle_weight.push_back(particle_weight[i]); } @@ -161,8 +141,7 @@ namespace OpFlow } void splitAtLoadMid(int d, double pload, double mload, - const typename internal::ExprTrait::mesh_type& mesh) - { + const typename internal::ExprTrait::mesh_type& mesh) { auto offset = get_load_mid(d, pload, mload, mesh); splitAt(d, offset, mesh); } @@ -173,8 +152,7 @@ namespace OpFlow bool is_leaf() const { return !lc && !rc; } int get_load_mid(int d, double pload, double mload, - const typename internal::ExprTrait::mesh_type& mesh) - { + const typename internal::ExprTrait::mesh_type& mesh) { auto load = get_load_along_dim(d, pload, mload, mesh); auto total_load = get_total_load(pload, mload); auto mid_iter = std::find_if_not(load.begin(), load.end(), @@ -182,16 +160,14 @@ namespace OpFlow return mid_iter - load.begin(); } - double get_total_load(double pload, double mload) const - { + double get_total_load(double pload, double mload) const { double weighted_particle_size - = std::accumulate(particle_weight.begin(), particle_weight.end(), 0); + = std::accumulate(particle_weight.begin(), particle_weight.end(), 0); return weighted_particle_size * pload + range.count() * mload; } std::vector get_load_along_dim(int d, double pload, double mload, - const typename internal::ExprTrait::mesh_type& mesh) - { + const typename internal::ExprTrait::mesh_type& mesh) { auto per_slice_load = get_per_slice_load_along_dim(d, pload, mload, mesh); std::vector ret(per_slice_load.size()); std::exclusive_scan(per_slice_load.begin(), per_slice_load.end(), ret.begin(), 0); @@ -200,54 +176,43 @@ namespace OpFlow std::vector get_per_slice_load_along_dim(int d, double pload, double mload, - const typename internal::ExprTrait::mesh_type& mesh) - { + const typename internal::ExprTrait::mesh_type& mesh) { std::vector ret(range.end[d] - range.start[d], 0); - if (!is_leaf()) - { - if (d == split_axis) - { + if (!is_leaf()) { + if (d == split_axis) { // merge results from children auto left = lc->get_per_slice_load_along_dim(d, pload, mload, mesh); auto right = rc->get_per_slice_load_along_dim(d, pload, mload, mesh); std::copy(ret.begin(), ret.begin() + left.size(), left.begin()); std::copy(ret.begin() + left.size(), ret.end(), right.begin()); return ret; - } - else - { + } else { // merge results from children by add auto left = lc->get_per_slice_load_along_dim(d, pload, mload, mesh); auto right = rc->get_per_slice_load_along_dim(d, pload, mload, mesh); for (std::size_t i = 0; i < ret.size(); ++i) ret[i] = left[i] + right[i]; return ret; } - } - else - { + } else { // do the real work // sort particles along axis d std::vector, double>> buffer; - for (std::size_t i = 0; i < particles.size(); ++i) - { + for (std::size_t i = 0; i < particles.size(); ++i) { buffer.emplace_back(particles[i], particle_weight[i]); } std::sort(buffer.begin(), buffer.end(), [d](auto&& a, auto&& b) { return a.first.x[d] < b.first.x[d]; }); - for (std::size_t i = 0; i < particles.size(); ++i) - { + for (std::size_t i = 0; i < particles.size(); ++i) { particles[i] = buffer[i].first; particle_weight[i] = buffer[i].second; } buffer.clear(); // add particle work load first auto part_iter = particles.begin(); - for (std::size_t i = 0; i < ret.size(); ++i) - { + for (std::size_t i = 0; i < ret.size(); ++i) { double xleft = mesh.x(d, i), xright = mesh.x(d, i + 1); while (part_iter != particles.end() && xleft <= part_iter->x[d] - && part_iter->x[d] < xright) - { + && part_iter->x[d] < xright) { ret[i] += particle_weight[part_iter - particles.begin()] * pload; part_iter++; } @@ -262,14 +227,12 @@ namespace OpFlow std::unique_ptr kdtree = nullptr; - void check_state(const ParallelPlan& plan) const - { + void check_state(const ParallelPlan& plan) const { OP_ASSERT_MSG(1 << max_levels == plan.distributed_workers_count, "ParticleGuidedSplitStrategy: total number of ranks must be power of 2"); } - void gather_all_particles() - { + void gather_all_particles() { #if defined(OPFLOW_WITH_MPI) // gather counts std::vector counts(getWorkerCount(), 0); @@ -281,8 +244,7 @@ namespace OpFlow MPI_Allgather(&local_particle_weight, 1, MPI_DOUBLE, weights_buffer.data(), 1, MPI_DOUBLE, MPI_COMM_WORLD); global_weights.reserve(total_part_size); - for (std::size_t i = 0; i < counts.size(); ++i) - { + for (std::size_t i = 0; i < counts.size(); ++i) { for (int j = 0; j < counts[i]; ++j) global_weights.push_back(weights_buffer[i]); } particle_weight = std::move(global_weights); @@ -302,8 +264,7 @@ namespace OpFlow } // build a kd-tree of max_levels according to given particles and background mesh - auto gen_split_tree(const DS::Range& range, const ParallelPlan&) - { + auto gen_split_tree(const DS::Range& range, const ParallelPlan&) { gather_all_particles(); Node root; root.range = range; @@ -311,12 +272,10 @@ namespace OpFlow root.particle_weight = particle_weight; std::deque build_queue; build_queue.push_back(&root); - for (int i = 0; i < max_levels; ++i) - { + for (int i = 0; i < max_levels; ++i) { auto iter = build_queue.begin(); auto end = build_queue.end(); - while (iter != end) - { + while (iter != end) { auto ptr = *iter; ptr->splitAtLoadMid(i % dim, part_load_factor, mesh_load_factor, ref_mesh); build_queue.pop_front(); @@ -328,23 +287,20 @@ namespace OpFlow return std::make_unique(std::move(root)); } - auto split_impl(const DS::Range& range, const ParallelPlan& plan) - { + auto split_impl(const DS::Range& range, const ParallelPlan& plan) { // assume the input range is nodal range, convert to central range auto _range = range; for (std::size_t i = 0; i < dim; ++i) _range.end[i]--; if (plan.singleNodeMode() || max_levels == 0) return _range; - else - { + else { if (!kdtree) kdtree = gen_split_tree(_range, plan); auto* ptr = kdtree.get(); // root is a full binary tree auto mask = OpFlow::getWorkerCount(); auto rank = OpFlow::getWorkerId(); - OP_ASSERT_MSG(std::exp2((int)std::log2(mask)) == mask, + OP_ASSERT_MSG(std::exp2((int) std::log2(mask)) == mask, "total worker count must be power of 2"); - while (mask >>= 1) - { + while (mask >>= 1) { if (mask & rank) ptr = ptr->rc.get(); else ptr = ptr->lc.get(); @@ -353,14 +309,12 @@ namespace OpFlow } } - auto splitMap_impl(const DS::Range& range, const ParallelPlan& plan) - { + auto splitMap_impl(const DS::Range& range, const ParallelPlan& plan) { // assume the input range is nodal range, convert to central range auto _range = range; for (std::size_t i = 0; i < dim; ++i) _range.end[i]--; - if (plan.singleNodeMode()) return std::vector>{_range}; - else - { + if (plan.singleNodeMode()) return std::vector> {_range}; + else { if (!kdtree) kdtree = gen_split_tree(_range, plan); #if defined(OPFLOW_WITH_MPI) || defined(OPFLOW_TEST_ENVIRONMENT) std::vector> ret; @@ -373,6 +327,6 @@ namespace OpFlow } } }; -} // namespace OpFlow +}// namespace OpFlow #endif//OPFLOW_PARTICLEGUIDEDSPLITSTRATEGY_HPP \ No newline at end of file diff --git a/src/Core/Solvers/Struct/StructSolverPrecond.hpp b/src/Core/Solvers/Struct/StructSolverPrecond.hpp index 2f9bad6d..ca767684 100644 --- a/src/Core/Solvers/Struct/StructSolverPrecond.hpp +++ b/src/Core/Solvers/Struct/StructSolverPrecond.hpp @@ -17,11 +17,9 @@ OPFLOW_MODULE_EXPORT -namespace OpFlow -{ +namespace OpFlow { template - struct PrecondStructSolver - { + struct PrecondStructSolver { constexpr auto static type = Type; constexpr auto static precondType = PrecondType; using Param = StructSolverParams; @@ -32,19 +30,15 @@ namespace OpFlow PrecondStructSolver() = default; PrecondStructSolver(const Param& p, const PrecondParam& pp) - : params(p), precondParam(pp), solver(p), precond(pp) - { - } + : params(p), precondParam(pp), solver(p), precond(pp) {} - void init() - { + void init() { solver.init(); precond.init(); solver.setPrecond(precond.getSolveFunc(), precond.getSetUpFunc(), precond.getSolver()); } - void reinit() - { + void reinit() { solver.reinit(); precond.reinit(); solver.setPrecond(precond.getSolveFunc(), precond.getSetUpFunc(), precond.getSolver()); @@ -55,20 +49,16 @@ namespace OpFlow auto getSolveFunc() const { return solver.getSolveFunc(); } auto getSetUpFunc() const { return solver.getSetUpFunc(); } - auto solve(HYPRE_StructMatrix& A, HYPRE_StructVector& b, HYPRE_StructVector& x) - { + auto solve(HYPRE_StructMatrix& A, HYPRE_StructVector& b, HYPRE_StructVector& x) { return solver.solve(A, b, x); } - auto setup(HYPRE_StructMatrix& A, HYPRE_StructVector& b, HYPRE_StructVector& x) - { + auto setup(HYPRE_StructMatrix& A, HYPRE_StructVector& b, HYPRE_StructVector& x) { return solver.setup(A, b, x); } - void dump(HYPRE_StructMatrix& A, HYPRE_StructVector& b) - { - if (params.dumpPath) - { + void dump(HYPRE_StructMatrix& A, HYPRE_StructVector& b) { + if (params.dumpPath) { HYPRE_StructMatrixPrint((params.dumpPath.value() + "_A.mat").c_str(), A, 0); HYPRE_StructVectorPrint((params.dumpPath.value() + "_b.vec").c_str(), b, 0); } @@ -82,5 +72,5 @@ namespace OpFlow StructSolver solver; StructSolver precond; }; -} // namespace OpFlow +}// namespace OpFlow #endif//OPFLOW_STRUCTSOLVERPRECOND_HPP \ No newline at end of file diff --git a/src/DataStructures/Arrays/Tensor/FixedSizeTensor.hpp b/src/DataStructures/Arrays/Tensor/FixedSizeTensor.hpp index a3d1b4d6..76e63526 100644 --- a/src/DataStructures/Arrays/Tensor/FixedSizeTensor.hpp +++ b/src/DataStructures/Arrays/Tensor/FixedSizeTensor.hpp @@ -22,73 +22,54 @@ OPFLOW_MODULE_EXPORT -namespace OpFlow::DS -{ - namespace internal - { +namespace OpFlow::DS { + namespace internal { template - constexpr int accumulate_product(std::array arr) - { + constexpr int accumulate_product(std::array arr) { if constexpr (N == 0) return 0; - else - { + else { int ret = arr[0]; for (std::size_t i = 1; i < N; ++i) ret *= arr[i]; return ret; } } - } // namespace internal + }// namespace internal template - requires(std::integral && ...) - struct FixedSizeTensor; + requires(std::integral&&...) struct FixedSizeTensor; - namespace internal - { + namespace internal { template - requires(std::integral && ...) - struct TensorTrait> - { + requires(std::integral&&...) struct TensorTrait> { using scalar_type = T; static constexpr auto dim = sizeof...(n); }; template - struct is_fixed_size_tensor : std::false_type - { - }; + struct is_fixed_size_tensor : std::false_type {}; template - requires(std::integral && ...) - struct is_fixed_size_tensor> - : std::true_type - { - }; - } // namespace internal + requires(std::integral&&...) struct is_fixed_size_tensor> + : std::true_type {}; + }// namespace internal template concept FixedSizeTensorType = internal::is_fixed_size_tensor>::value; template - requires(std::integral && ...) - struct FixedSizeTensor : Tensor> - { + requires(std::integral&&...) struct FixedSizeTensor : Tensor> { constexpr static auto N = sizeof...(n); constexpr FixedSizeTensor() = default; constexpr explicit FixedSizeTensor(T val) { _val.fill(val); } - constexpr explicit FixedSizeTensor(auto... vals) : _val{vals...} - { - } + constexpr explicit FixedSizeTensor(auto... vals) : _val {vals...} {} - constexpr const auto& operator[](const MDIndex& idx) const - { + constexpr const auto& operator[](const MDIndex& idx) const { int _pos = idx[N - 1]; for (int i = N - 2; i >= 0; --i) { _pos = _pos * _sizes[i] + idx[i]; } return _val[_pos]; } - constexpr auto& operator[](const MDIndex& idx) - { + constexpr auto& operator[](const MDIndex& idx) { int _pos = idx[N - 1]; for (int i = N - 2; i >= 0; --i) { _pos = _pos * _sizes[i] + idx[i]; } return _val[_pos]; @@ -105,8 +86,7 @@ namespace OpFlow::DS constexpr static auto total_size() { return _total_size; } constexpr static auto size_of(int d) { return _sizes[d]; } - constexpr static auto max_half_width() - { + constexpr static auto max_half_width() { if constexpr (N == 0) return 0; auto max_dim = _sizes[0]; for (int i = 1; i < N; ++i) max_dim = std::max(max_dim, _sizes[i]); @@ -115,9 +95,9 @@ namespace OpFlow::DS constexpr void fill(T val) { _val.fill(val); } - static constexpr std::array _sizes{n...}; + static constexpr std::array _sizes {n...}; static constexpr int _total_size = internal::accumulate_product(_sizes); std::array _val; }; -} // namespace OpFlow::DS +}// namespace OpFlow::DS #endif//OPFLOW_FIXEDSIZETENSOR_HPP \ No newline at end of file diff --git a/src/DataStructures/Index/LinearMapper/BlockedMDRangeMapper.hpp b/src/DataStructures/Index/LinearMapper/BlockedMDRangeMapper.hpp index 9ea73c60..e39d2887 100644 --- a/src/DataStructures/Index/LinearMapper/BlockedMDRangeMapper.hpp +++ b/src/DataStructures/Index/LinearMapper/BlockedMDRangeMapper.hpp @@ -22,8 +22,7 @@ OPFLOW_MODULE_EXPORT -namespace OpFlow::DS -{ +namespace OpFlow::DS { /** * \brief Axis aligned split multi-dimensional range mapper * \note We assume here the input _ranges are generated by splitting a range by several orthogonal planes. @@ -31,13 +30,11 @@ namespace OpFlow::DS * @tparam d Dimension */ template - struct BlockedMDRangeMapper - { + struct BlockedMDRangeMapper { BlockedMDRangeMapper() = default; // local ctor - explicit BlockedMDRangeMapper(const std::vector>& ranges) : _ranges(ranges) - { + explicit BlockedMDRangeMapper(const std::vector>& ranges) : _ranges(ranges) { gatherSplits(); sortRanges(); calculateOffsets(); @@ -45,28 +42,23 @@ namespace OpFlow::DS } // MPI collective ctor - explicit BlockedMDRangeMapper(const Range& range) - { + explicit BlockedMDRangeMapper(const Range& range) { #ifdef OPFLOW_WITH_MPI - if (getWorkerCount() > 1) - { + if (getWorkerCount() > 1) { _ranges.resize(getWorkerCount()); _ranges[getWorkerId()] = range; std::vector> _starts(_ranges.size()), _ends(_ranges.size()), - _strides(_ranges.size()); + _strides(_ranges.size()); _starts[getWorkerId()] = range.start; _ends[getWorkerId()] = range.end; _strides[getWorkerId()] = range.stride; MPI_Allgather(MPI_IN_PLACE, d, MPI_INT, _starts.data(), d, MPI_INT, MPI_COMM_WORLD); MPI_Allgather(MPI_IN_PLACE, d, MPI_INT, _ends.data(), d, MPI_INT, MPI_COMM_WORLD); MPI_Allgather(MPI_IN_PLACE, d, MPI_INT, _strides.data(), d, MPI_INT, MPI_COMM_WORLD); - for (std::size_t i = 0; i < _ranges.size(); ++i) - { - _ranges[i] = Range < d > (_starts[i], _ends[i], _strides[i]); + for (std::size_t i = 0; i < _ranges.size(); ++i) { + _ranges[i] = Range(_starts[i], _ends[i], _strides[i]); } - } - else - { + } else { _ranges.resize(1); _ranges[0] = range; } @@ -79,16 +71,11 @@ namespace OpFlow::DS calculateMultiplier(); } - std::array getBlockIndex(const MDIndex& idx) const - { - if (!checkIndexInBlock(idx, getBlockRank(last_block))) - { - for (std::size_t i = 0; i < d; ++i) - { - for (std::size_t j = 0; j < _split[i].size() - 1; ++j) - { - if (_split[i][j] <= idx[i] && idx[i] < _split[i][j + 1]) - { + std::array getBlockIndex(const MDIndex& idx) const { + if (!checkIndexInBlock(idx, getBlockRank(last_block))) { + for (std::size_t i = 0; i < d; ++i) { + for (std::size_t j = 0; j < _split[i].size() - 1; ++j) { + if (_split[i][j] <= idx[i] && idx[i] < _split[i][j + 1]) { last_block[i] = j; break; } @@ -98,23 +85,19 @@ namespace OpFlow::DS return last_block; } - bool checkIndexInBlock(const MDIndex& idx, const int block_rank) const - { + bool checkIndexInBlock(const MDIndex& idx, const int block_rank) const { return inRange(_ranges[block_rank], idx); } - int getBlockRank(const std::array& block_idx) const - { + int getBlockRank(const std::array& block_idx) const { // we assume the _ranges are listed by column-major sequence int block_rank = block_idx[d - 1]; - for (int i = d - 2; i >= 0; --i) - { + for (int i = d - 2; i >= 0; --i) { block_rank *= _split[i].size() - 1; block_rank += block_idx[i]; } - OP_ASSERT_MSG(static_cast(block_rank) < _ranges.size(), "Block rank {} out of range {}", - block_rank, - _ranges.size()); + OP_ASSERT_MSG(static_cast(block_rank) < _ranges.size(), + "Block rank {} out of range {}", block_rank, _ranges.size()); return block_rank; } @@ -122,10 +105,8 @@ namespace OpFlow::DS int getBlockSize(int block_rank) const { return _ranges[block_rank].count(); } - int getLocalRank(const MDIndex& idx) const - { - if (!checkIndexInBlock(idx, last_block_rank)) - { + int getLocalRank(const MDIndex& idx) const { + if (!checkIndexInBlock(idx, last_block_rank)) { last_block = getBlockIndex(idx); last_block_rank = getBlockRank(last_block); } @@ -141,10 +122,8 @@ namespace OpFlow::DS return ret; } - int operator()(const MDIndex& idx) const - { - if (!checkIndexInBlock(idx, last_block_rank)) - { + int operator()(const MDIndex& idx) const { + if (!checkIndexInBlock(idx, last_block_rank)) { last_block = getBlockIndex(idx); last_block_rank = getBlockRank(last_block); } @@ -162,28 +141,20 @@ namespace OpFlow::DS [[nodiscard]] int count() const { return _offset.back(); } [[nodiscard]] int block_count() const { return _ranges.size(); } - int operator()(const ColoredIndex>& idx) const - { + int operator()(const ColoredIndex>& idx) const { // todo: color is ignored here. check this out - return this->operator()(MDIndex < d > - { - idx - } - ) - ; + return this->operator()(MDIndex {idx}); } // todo: workaround same as MDIndexMapper int operator()(const MDIndex& idx, int) const { return operator()(idx); } private: - void gatherSplits() - { + void gatherSplits() { // IMPORTANT ASSUMPTION: // We assume here the input _ranges are generated by splitting a range by several orthogonal planes std::vector>> segments(d); - for (std::size_t i = 0; i < d; ++i) - { + for (std::size_t i = 0; i < d; ++i) { for (const auto& _r : _ranges) { segments[i].emplace_back(_r.start[i], _r.end[i]); } std::sort(segments[i].begin(), segments[i].end()); auto end = std::unique(segments[i].begin(), segments[i].end()); @@ -193,40 +164,31 @@ namespace OpFlow::DS } } - void sortRanges() - { + void sortRanges() { // sort the ranges according to column-major rank - std::sort(_ranges.begin(), _ranges.end(), [&](const Range& a, const Range& b) - { + std::sort(_ranges.begin(), _ranges.end(), [&](const Range& a, const Range& b) { // this happens when the left-most block is empty because all nodes covered by the boundary // e.g., x-face field on a 4x4 mesh with 3 MPI procs and Dirichlet boundary condition - if (a.empty() && !b.empty()) - { + if (a.empty() && !b.empty()) { return true; - } - else + } else return getBlockRank(getBlockIndex(a.first())) < getBlockRank(getBlockIndex(b.first())); }); } - void calculateOffsets() - { + void calculateOffsets() { _offset.resize(_ranges.size() + 1); _offset[0] = 0; - for (std::size_t i = 1; i < _offset.size(); ++i) - { + for (std::size_t i = 1; i < _offset.size(); ++i) { _offset[i] = _offset[i - 1] + _ranges[i - 1].count(); } } - void calculateMultiplier() - { + void calculateMultiplier() { _fac.resize(_ranges.size()); - for (std::size_t i = 0; i < _fac.size(); ++i) - { + for (std::size_t i = 0; i < _fac.size(); ++i) { _fac[i][0] = 1; - for (std::size_t j = 1; j < d; ++j) - { + for (std::size_t j = 1; j < d; ++j) { _fac[i][j] = (_ranges[i].end[j - 1] - _ranges[i].start[j - 1]) * _fac[i][j - 1]; } } @@ -238,9 +200,9 @@ namespace OpFlow::DS std::vector> _ranges; // used to accelerate repeating query inside the same block - mutable std::array last_block{0}; + mutable std::array last_block {0}; mutable int last_block_rank = 0; }; -} // namespace OpFlow::DS +}// namespace OpFlow::DS #endif//OPFLOW_BLOCKEDMDRANGEMAPPER_HPP \ No newline at end of file diff --git a/src/DataStructures/Range/Ranges.hpp b/src/DataStructures/Range/Ranges.hpp index 11ce0e37..3cf807c6 100644 --- a/src/DataStructures/Range/Ranges.hpp +++ b/src/DataStructures/Range/Ranges.hpp @@ -28,25 +28,22 @@ OPFLOW_MODULE_EXPORT -namespace OpFlow::DS -{ +namespace OpFlow::DS { template struct RangedIndex; template - struct Range - { + struct Range { constexpr static int dim = d; using index_type = RangedIndex; using base_index_type = MDIndex; - std::array start, end, stride; // stride here means the step in each dim. + std::array start, end, stride;// stride here means the step in each dim. // Not the same as StrideIndex. private: mutable std::array pace; public: - constexpr static auto EmptyRange() - { + constexpr static auto EmptyRange() { Range ret; ret.start.fill(0); ret.end.fill(0); @@ -57,54 +54,45 @@ namespace OpFlow::DS constexpr Range() { stride.fill(1); } - constexpr explicit Range(const std::array& end) noexcept : end(end), pace(end) - { + constexpr explicit Range(const std::array& end) noexcept : end(end), pace(end) { start.fill(0); stride.fill(1); } constexpr Range(const std::array& start, const std::array& end) noexcept - : start(start), end(end) - { + : start(start), end(end) { stride.fill(1); reValidPace(); } constexpr Range(const std::array& start, const std::array& end, const std::array& stride) noexcept - : start(start), end(end), stride(stride) - { + : start(start), end(end), stride(stride) { reValidPace(); } - constexpr void reValidPace() const - { + constexpr void reValidPace() const { for (std::size_t i = 0; i < dim; ++i) pace[i] = (end[i] - start[i]) / stride[i]; } - constexpr auto operator==(const Range& other) const - { + constexpr auto operator==(const Range& other) const { return start == other.start && end == other.end && stride == other.stride; } - constexpr auto check() const - { + constexpr auto check() const { bool ret = true; ret &= (d == start.size()) && (d == end.size()) && (d == stride.size()); - for (std::size_t i = 0; i < d; ++i) - { + for (std::size_t i = 0; i < d; ++i) { ret &= (end[i] >= start[i]); ret &= (stride[i] >= 1); } return ret; } - constexpr auto count() const - { + constexpr auto count() const { // make sure the pace is valid reValidPace(); - for (std::size_t i = 0; i < d; ++i) - { + for (std::size_t i = 0; i < d; ++i) { if (pace[i] <= 0) return 0; } auto ret = 1; @@ -112,11 +100,9 @@ namespace OpFlow::DS return ret; } - constexpr auto covers(const Range& other) const - { + constexpr auto covers(const Range& other) const { auto ret = true; - for (std::size_t i = 0; i < d; ++i) - { + for (std::size_t i = 0; i < d; ++i) { ret &= start[i] <= other.start[i] && end[i] >= other.end[i]; } return ret; @@ -127,8 +113,7 @@ namespace OpFlow::DS /// \brief Get the sliced range (1 layer thick) along dim \p k at position \p pos /// \param k normal dimension of the slice /// \param pos position of the slice - constexpr auto slice(std::size_t k, int pos) const - { + constexpr auto slice(std::size_t k, int pos) const { assert(k < d); Range ret = *this; ret.start[k] = pos; @@ -142,8 +127,7 @@ namespace OpFlow::DS /// \param pos_start Position of the start /// \param pos_end Position of the end /// \return The sliced range - constexpr auto slice(std::size_t k, int pos_start, int pos_end) const - { + constexpr auto slice(std::size_t k, int pos_start, int pos_end) const { assert(k < d); Range ret = *this; ret.start[k] = pos_start; @@ -152,34 +136,29 @@ namespace OpFlow::DS return ret; } - auto toString() const - { + auto toString() const { std::string ret; ret = std::format("{{{} - {} by {}}}", Utils::Serializer::serialize(start), Utils::Serializer::serialize(end), Utils::Serializer::serialize(stride)); return ret; } - constexpr auto getExtends() const - { + constexpr auto getExtends() const { reValidPace(); - std::array < int, d > ret; + std::array ret; for (std::size_t i = 0; i < d; ++i) { ret[i] = pace[i]; } return ret; } - constexpr auto getOffset() const - { - std::array < int, d > ret; + constexpr auto getOffset() const { + std::array ret; for (std::size_t i = 0; i < d; ++i) ret[i] = start[i]; return ret; } - auto getBCRanges(int width) const - { + auto getBCRanges(int width) const { std::vector ret; - for (std::size_t i = 0; i < d; ++i) - { + for (std::size_t i = 0; i < d; ++i) { ret.push_back(*this); ret.back().end[i] = ret.back().start[i] + width; ret.back().pace[i] = width; @@ -190,11 +169,9 @@ namespace OpFlow::DS return ret; } - auto getInnerRange(int width) const - { + auto getInnerRange(int width) const { auto ret = *this; - for (std::size_t i = 0; i < dim; ++i) - { + for (std::size_t i = 0; i < dim; ++i) { ret.start[i] += width; ret.end[i] -= width; ret.pace[i] -= 2 * width; @@ -204,28 +181,24 @@ namespace OpFlow::DS void setEmpty() { *this = EmptyRange(); } - auto first() const { return base_index_type{start}; } + auto first() const { return base_index_type {start}; } - auto last() const - { - auto ret = base_index_type{end}; + auto last() const { + auto ret = base_index_type {end}; for (int i = 0; i < d; ++i) ret[i]--; return ret; } bool empty() const { return count() <= 0; } - bool is_divisible() const - { - for (int i = 0; i < dim; ++i) - { + bool is_divisible() const { + for (int i = 0; i < dim; ++i) { if (end[i] - start[i] > 1) return true; } return false; } - Range(Range& r, [[maybe_unused]] tbb::detail::split split) : Range(r) - { + Range(Range& r, [[maybe_unused]] tbb::detail::split split) : Range(r) { this->reValidPace(); int max_iter = std::max_element(pace.begin(), pace.end()) - pace.begin(); this->end[max_iter] = this->start[max_iter] + this->pace[max_iter] / 2; @@ -234,13 +207,12 @@ namespace OpFlow::DS r.pace[max_iter] = r.end[max_iter] - r.start[max_iter]; } - Range(Range& r, tbb::detail::proportional_split proportion) : Range(r) - { + Range(Range& r, tbb::detail::proportional_split proportion) : Range(r) { this->reValidPace(); int max_iter = std::max_element(pace.begin(), pace.end()) - pace.begin(); int right_part = int(float(r.end[max_iter] - r.start[max_iter]) * float(proportion.right()) - / float(proportion.left() + proportion.right()) - + 0.5f); + / float(proportion.left() + proportion.right()) + + 0.5f); r.end[max_iter] -= right_part; this->start[max_iter] = r.end[max_iter]; this->pace[max_iter] = this->end[max_iter] - this->start[max_iter]; @@ -249,61 +221,44 @@ namespace OpFlow::DS static constexpr bool is_splittable_in_proportion = true; - auto center() const - { - auto ret = base_index_type{start}; + auto center() const { + auto ret = base_index_type {start}; for (std::size_t i = 0; i < d; ++i) ret[i] = (ret[i] + end[i]) / 2; return ret; } }; template - concept isRange = requires - { - T::dim; - } - && std::is_same_v, Range>; + concept isRange = requires { + T::dim; + } + &&std::is_same_v, Range>; template - constexpr auto commonRange(const Range& a, const Range& b) - { - std::array < int, dim1 > start, end; - if constexpr (dim1 != dim2) - { - static_assert(dim1 == 0 || dim2 == 0, - OP_ERRMSG_DIM_MISMATCH - ) - ; - if constexpr (dim1 == 0) - { + constexpr auto commonRange(const Range& a, const Range& b) { + std::array start, end; + if constexpr (dim1 != dim2) { + static_assert(dim1 == 0 || dim2 == 0, OP_ERRMSG_DIM_MISMATCH); + if constexpr (dim1 == 0) { return b; - } - else - { + } else { return a; } - } - else - { - static_assert(dim1 == dim2, - OP_ERRMSG_DIM_MISMATCH - ) - ; + } else { + static_assert(dim1 == dim2, OP_ERRMSG_DIM_MISMATCH); constexpr auto dim = dim1; start.fill(std::numeric_limits::min()); end.fill(std::numeric_limits::max()); - for (std::size_t i = 0; i < dim; ++i) - { + for (std::size_t i = 0; i < dim; ++i) { start[i] = std::max(a.start[i], b.start[i]); end[i] = std::min(a.end[i], b.end[i]); } - return Range{start, end}; + return Range {start, end}; } } template - constexpr auto commonRanges(const std::vector>& a, const std::vector>& b) - { + constexpr auto commonRanges(const std::vector>& a, const std::vector>& b) { std::vector> ret; OP_ASSERT(a.size() == b.size()); ret.reserve(a.size()); @@ -312,42 +267,29 @@ namespace OpFlow::DS } template - constexpr auto minCoverRange(const Range& a, const Range& b) - { - if constexpr (dim1 != dim2) - { - static_assert(dim1 == 0 || dim2 == 0, - OP_ERRMSG_DIM_MISMATCH - ) - ; + constexpr auto minCoverRange(const Range& a, const Range& b) { + if constexpr (dim1 != dim2) { + static_assert(dim1 == 0 || dim2 == 0, OP_ERRMSG_DIM_MISMATCH); if constexpr (dim1 == 0) return b; else return a; - } - else - { - static_assert(dim1 == dim2, - OP_ERRMSG_DIM_MISMATCH - ) - ; + } else { + static_assert(dim1 == dim2, OP_ERRMSG_DIM_MISMATCH); constexpr auto dim = dim1; Range ret; - for (std::size_t i = 0; i < dim; ++i) - { + for (std::size_t i = 0; i < dim; ++i) { ret.start[i] = std::min(a.start[i], b.start[i]); ret.end[i] = std::max(a.end[i], b.end[i]); OP_ASSERT(a.stride[i] == b.stride[i]); } - return Range{ret.start, ret.end}; + return Range {ret.start, ret.end}; } } template - constexpr auto minCoverRange(const std::vector>& r) - { + constexpr auto minCoverRange(const std::vector>& r) { if constexpr (dim == 0) return r[0]; - else - { + else { Range ret = r[0]; for (auto i = 1; i < r.size(); ++i) { ret = minCoverRange(ret, r[i]); } return ret; @@ -355,43 +297,30 @@ namespace OpFlow::DS } template - constexpr auto maxCommonRange(const Range& a, const Range& b) - { - if constexpr (dim1 != dim2) - { - static_assert(dim1 == 0 || dim2 == 0, - OP_ERRMSG_DIM_MISMATCH - ) - ; + constexpr auto maxCommonRange(const Range& a, const Range& b) { + if constexpr (dim1 != dim2) { + static_assert(dim1 == 0 || dim2 == 0, OP_ERRMSG_DIM_MISMATCH); if constexpr (dim1 == 0) return b; else return a; - } - else - { - static_assert(dim1 == dim2, - OP_ERRMSG_DIM_MISMATCH - ) - ; + } else { + static_assert(dim1 == dim2, OP_ERRMSG_DIM_MISMATCH); constexpr auto dim = dim1; Range ret; - for (std::size_t i = 0; i < dim; ++i) - { + for (std::size_t i = 0; i < dim; ++i) { ret.start[i] = std::max(a.start[i], b.start[i]); ret.end[i] = std::min(a.end[i], b.end[i]); OP_ASSERT(a.stride[i] == b.stride[i]); - if (ret.end[i] < ret.start[i]) return Range{}; + if (ret.end[i] < ret.start[i]) return Range {}; } - return Range{ret.start, ret.end}; + return Range {ret.start, ret.end}; } } template - constexpr auto maxCommonRange(const std::vector>& r) - { + constexpr auto maxCommonRange(const std::vector>& r) { if constexpr (dim == 0) return r[0]; - else - { + else { Range ret = r[0]; for (auto i = 1; i < r.size(); ++i) { ret = maxCommonRange(ret, r[i]); } return ret; @@ -399,23 +328,19 @@ namespace OpFlow::DS } template - constexpr auto inRange(const Range& r, const T& t) - { + constexpr auto inRange(const Range& r, const T& t) { auto ret = true; for (std::size_t i = 0; i < dim; ++i) { ret &= (r.start[i] <= t[i] && t[i] < r.end[i]); } return ret; } -} // namespace OpFlow::DS +}// namespace OpFlow::DS template -struct std::hash> -{ +struct std::hash> { public: - std::size_t operator()(const OpFlow::DS::Range& r) const noexcept - { - std::array < int, 3 * dim > arr; - for (std::size_t i = 0; i < dim; ++i) - { + std::size_t operator()(const OpFlow::DS::Range& r) const noexcept { + std::array arr; + for (std::size_t i = 0; i < dim; ++i) { arr[i] = r.start[i]; arr[i + dim] = r.end[i]; arr[i + 2 * dim] = r.stride[i]; diff --git a/src/DataStructures/StencilPad.hpp b/src/DataStructures/StencilPad.hpp index 6037742f..dcd2a8eb 100644 --- a/src/DataStructures/StencilPad.hpp +++ b/src/DataStructures/StencilPad.hpp @@ -24,11 +24,9 @@ OPFLOW_MODULE_EXPORT -namespace OpFlow::DS -{ +namespace OpFlow::DS { template - struct fake_map - { + struct fake_map { private: std::array, max_size> val; @@ -37,62 +35,50 @@ namespace OpFlow::DS public: fake_map() = default; - bool operator==(const fake_map& other) const - { + bool operator==(const fake_map& other) const { bool ret = _size == other._size; if (!ret) return false; - for (auto i = 0; i < _size; ++i) - { + for (auto i = 0; i < _size; ++i) { auto iter = other.find(val[i].first); ret &= iter != other.end() && val[i].second == iter->second; } return ret; } - auto& at(const K& key) - { + auto& at(const K& key) { auto iter = find(key); if (iter != end()) return iter->second; - else - { + else { OP_CRITICAL("fake map error: Key {} out of range", key.toString()); OP_ABORT; } } - const auto& at(const K& key) const - { + const auto& at(const K& key) const { auto iter = find(key); if (iter != end()) return iter->second; - else - { + else { OP_CRITICAL("fake map error: Key {} out of range", key.toString()); OP_ABORT; } } - auto& operator[](const K& key) - { + auto& operator[](const K& key) { auto pos = -1; - for (auto i = 0; i < _size; ++i) - { - if (key == val[i].first) - { + for (auto i = 0; i < _size; ++i) { + if (key == val[i].first) { pos = i; break; } } - if (pos == -1) - { + if (pos == -1) { #ifndef NDEBUG OP_ASSERT_MSG(static_cast(_size) < max_size, "fake map error: Map is full"); #endif val[_size].first = key; _size++; return val[_size - 1].second; - } - else - { + } else { return val[pos].second; } } @@ -100,41 +86,33 @@ namespace OpFlow::DS auto size() const { return _size; } void clear() { _size = 0; } - auto find(const K& k) - { - for (auto iter = val.begin(); iter != end(); ++iter) - { + auto find(const K& k) { + for (auto iter = val.begin(); iter != end(); ++iter) { if (iter->first == k) return iter; } return end(); } - auto find(const K& k) const - { - for (auto iter = val.begin(); iter != end(); ++iter) - { + auto find(const K& k) const { + for (auto iter = val.begin(); iter != end(); ++iter) { if (iter->first == k) return iter; } return end(); } - auto findFirst(auto&& f) const - { - for (auto iter = val.begin(); iter != end(); ++iter) - { + auto findFirst(auto&& f) const { + for (auto iter = val.begin(); iter != end(); ++iter) { if (f(iter->first)) return iter; } return end(); } - auto exist(const K& k) const - { + auto exist(const K& k) const { auto p = find(k); return p == end(); } - int rank(const K& k) const - { + int rank(const K& k) const { auto p = find(k); if (p == end()) return -1; else @@ -149,8 +127,7 @@ namespace OpFlow::DS auto end() const { return val.begin() + _size; } - auto sort() - { + auto sort() { std::sort(val.begin(), val.end(), [](auto&& a, auto&& b) { return a.first < b.first; }); } }; @@ -159,51 +136,43 @@ namespace OpFlow::DS using fake_map_default = fake_map<10, K, V>; template typename map_impl = fake_map_default> - struct StencilPad : public StringifiableObj, SerializableObj - { - map_impl pad{}; + struct StencilPad : public StringifiableObj, SerializableObj { + map_impl pad {}; Real bias = 0.; StencilPad() = default; - [[nodiscard]] std::vector serialize() const override - { + [[nodiscard]] std::vector serialize() const override { std::vector ret; ret.resize(sizeof(int) + pad.size() * (sizeof(Idx) + sizeof(Real)) + sizeof(Real)); std::byte* ptr = ret.data(); - *(int*)ptr = pad.size(); + *(int*) ptr = pad.size(); int i = 0; - for (const auto& [k, v] : pad) - { - *(Idx*)(ptr + sizeof(int) + i * (sizeof(Idx) + sizeof(Real))) = k; - *(Real*)(ptr + sizeof(int) + i * (sizeof(Idx) + sizeof(Real)) + sizeof(Idx)) = v; + for (const auto& [k, v] : pad) { + *(Idx*) (ptr + sizeof(int) + i * (sizeof(Idx) + sizeof(Real))) = k; + *(Real*) (ptr + sizeof(int) + i * (sizeof(Idx) + sizeof(Real)) + sizeof(Idx)) = v; i++; } - *(Real*)(ptr + sizeof(int) + pad.size() * (sizeof(Idx) + sizeof(Real))) = bias; + *(Real*) (ptr + sizeof(int) + pad.size() * (sizeof(Idx) + sizeof(Real))) = bias; return ret; } - void deserialize(const std::byte* data, std::size_t) override - { + void deserialize(const std::byte* data, std::size_t) override { const std::byte* ptr = data; - int size_ = *(int*)ptr; + int size_ = *(int*) ptr; ptr += sizeof(int); pad.clear(); - for (int i = 0; i < size_; ++i) - { - Idx k = *(Idx*)(ptr + i * (sizeof(Idx) + sizeof(Real))); - Real v = *(Real*)(ptr + i * (sizeof(Idx) + sizeof(Real)) + sizeof(Idx)); + for (int i = 0; i < size_; ++i) { + Idx k = *(Idx*) (ptr + i * (sizeof(Idx) + sizeof(Real))); + Real v = *(Real*) (ptr + i * (sizeof(Idx) + sizeof(Real)) + sizeof(Idx)); pad[k] = v; } - bias = *(Real*)(ptr + size_ * (sizeof(Idx) + sizeof(Real))); + bias = *(Real*) (ptr + size_ * (sizeof(Idx) + sizeof(Real))); } - explicit StencilPad(Real b) : bias(b) - { - } + explicit StencilPad(Real b) : bias(b) {} - [[nodiscard]] std::string toString(int n, const std::string& prefix) const override - { + [[nodiscard]] std::string toString(int n, const std::string& prefix) const override { std::string _prefix; for (auto i = 0; i < n; ++i) _prefix += prefix; std::string ret = "\n" + _prefix + "pad:\n"; @@ -216,24 +185,18 @@ namespace OpFlow::DS auto operator+() const { return *this; } - auto operator-() const - { + auto operator-() const { auto ret = *this; for (auto& [k, v] : ret.pad) { v = -v; } ret.bias = -ret.bias; return ret; } - auto& operator+=(const StencilPad& other) - { - for (const auto& [idx, val] : other.pad) - { - if (auto iter = pad.find(idx); iter != pad.end()) - { + auto& operator+=(const StencilPad& other) { + for (const auto& [idx, val] : other.pad) { + if (auto iter = pad.find(idx); iter != pad.end()) { iter->second += val; - } - else - { + } else { pad[idx] = val; } } @@ -241,22 +204,16 @@ namespace OpFlow::DS return *this; } - auto& operator+=(Meta::Numerical auto other) - { + auto& operator+=(Meta::Numerical auto other) { bias += other; return *this; } - auto& operator-=(const StencilPad& other) - { - for (const auto& [idx, val] : other.pad) - { - if (auto iter = pad.find(idx); iter != pad.end()) - { + auto& operator-=(const StencilPad& other) { + for (const auto& [idx, val] : other.pad) { + if (auto iter = pad.find(idx); iter != pad.end()) { iter->second -= val; - } - else - { + } else { pad[idx] = -val; } } @@ -264,21 +221,18 @@ namespace OpFlow::DS return *this; } - auto& operator-=(Meta::Numerical auto other) - { + auto& operator-=(Meta::Numerical auto other) { bias -= other; return *this; } - auto& operator*=(Real r) - { + auto& operator*=(Real r) { for (auto& [idx, val] : pad) { val *= r; } bias *= r; return *this; } - auto& operator/=(Real r) - { + auto& operator/=(Real r) { for (auto& [idx, val] : pad) { val /= r; } bias /= r; return *this; @@ -286,59 +240,51 @@ namespace OpFlow::DS void sort() { pad.sort(); } - void reset() - { + void reset() { pad.clear(); bias = 0.; } }; template typename map_impl> - auto operator+(const StencilPad& a, const StencilPad& b) - { + auto operator+(const StencilPad& a, const StencilPad& b) { auto ret = a; ret += b; return ret; } template typename map_impl, Meta::Numerical Num> - auto operator+(const StencilPad& a, Num b) - { + auto operator+(const StencilPad& a, Num b) { auto ret = a; ret += b; return ret; } template typename map_impl, Meta::Numerical Num> - auto operator+(Num a, const StencilPad& b) - { + auto operator+(Num a, const StencilPad& b) { auto ret = b; ret += a; return ret; } template typename map_impl> - auto operator-(const StencilPad& a, const StencilPad& b) - { + auto operator-(const StencilPad& a, const StencilPad& b) { auto ret = b * -1.0; return a + ret; } template typename map_impl, Meta::Numerical Num> - auto operator-(const StencilPad& a, Num b) - { + auto operator-(const StencilPad& a, Num b) { return a + (-b); } template typename map_impl, Meta::Numerical Num> - auto operator-(Num a, const StencilPad& b) - { + auto operator-(Num a, const StencilPad& b) { return StencilPad(a) - b; } template typename map_impl, Meta::Numerical Num> - auto operator*(const StencilPad& a, Num b) - { + auto operator*(const StencilPad& a, Num b) { auto ret = a; for (auto& [idx, val] : ret.pad) { val *= b; } ret.bias *= b; @@ -346,20 +292,17 @@ namespace OpFlow::DS } template typename map_impl, Meta::Numerical Num> - auto operator*(Num b, const StencilPad& a) - { + auto operator*(Num b, const StencilPad& a) { return a * b; } template typename map_impl, Meta::Numerical Num> - auto operator/(const StencilPad& a, Num b) - { + auto operator/(const StencilPad& a, Num b) { return a * (1. / b); } template typename map_impl> - auto getOffsetStencil(const StencilPad& a, const IdxB& base) - { + auto getOffsetStencil(const StencilPad& a, const IdxB& base) { StencilPad ret; for (const auto& [idx, val] : a.pad) { ret.pad[idx - base] = val; } ret.bias = a.bias; @@ -368,12 +311,10 @@ namespace OpFlow::DS template typename map_impl> auto commonStencil(const StencilPad& a, const Idx& base, - const StencilPad& offsetStencil) - { + const StencilPad& offsetStencil) { auto a_offset = getOffsetStencil(a, base); auto ret = a_offset; - for (const auto& [idx, val] : offsetStencil.pad) - { + for (const auto& [idx, val] : offsetStencil.pad) { if (auto iter = ret.pad.find(idx); iter == ret.pad.end()) { ret.pad[idx] = 0.; } } return ret; @@ -385,11 +326,9 @@ namespace OpFlow::DS /// \param base /// \return template typename map_impl> - auto commonStencil(const StencilPad& a, const StencilPad& base) - { + auto commonStencil(const StencilPad& a, const StencilPad& base) { auto ret = a; - for (const auto& [idx, val] : base.pad) - { + for (const auto& [idx, val] : base.pad) { if (auto iter = ret.pad.find(idx); iter == ret.pad.end()) { ret.pad[idx] = 0.; } } return ret; @@ -401,14 +340,12 @@ namespace OpFlow::DS /// \param b /// \return template typename map_impl> - auto mergeStencil(const StencilPad& a, const StencilPad& b) - { + auto mergeStencil(const StencilPad& a, const StencilPad& b) { auto ret = a; - for (const auto& [idx, val] : b.pad) - { + for (const auto& [idx, val] : b.pad) { if (auto iter = ret.pad.find(idx); iter == ret.pad.end()) { ret.pad[idx] = val; } } return ret; } -} // namespace OpFlow::DS +}// namespace OpFlow::DS #endif//OPFLOW_STENCILPAD_HPP \ No newline at end of file diff --git a/test/Core/Field/CartesianFieldMPITest.cpp b/test/Core/Field/CartesianFieldMPITest.cpp index 99cb2f89..7ff148a9 100644 --- a/test/Core/Field/CartesianFieldMPITest.cpp +++ b/test/Core/Field/CartesianFieldMPITest.cpp @@ -23,11 +23,9 @@ import opflow; using namespace OpFlow; class CartesianFieldMPITest - : public testing::TestWithParam, std::array>> -{ + : public testing::TestWithParam, std::array>> { protected: - void SetUp() override - { + void SetUp() override { auto info = makeParallelInfo(); setGlobalParallelInfo(info); setGlobalParallelPlan(makeParallelPlan(getGlobalParallelInfo(), ParallelIdentifier::DistributeMem)); @@ -43,8 +41,7 @@ class CartesianFieldMPITest Mesh m; }; -TEST_P(CartesianFieldMPITest, RangeCheck) -{ +TEST_P(CartesianFieldMPITest, RangeCheck) { const auto& [bcs, locs] = GetParam(); auto builder = ExprBuilder().setMesh(m); if (isLogicalBC(bcs[0])) builder.setBC(0, DimPos::start, bcs[0]); @@ -64,8 +61,7 @@ TEST_P(CartesianFieldMPITest, RangeCheck) auto mr = strategy->splitRange(m.getRange(), getGlobalParallelPlan()); // mpi only affect localRange - for (int i = 0; i < 2; ++i) - { + for (int i = 0; i < 2; ++i) { ASSERT_EQ(u.localRange.start[i], mr.start[i]); int end; if (locs[i] == LocOnMesh::Center || bcs[i] == BCType::Periodic) end = mr.end[i]; @@ -78,8 +74,7 @@ TEST_P(CartesianFieldMPITest, RangeCheck) } // should behave the same as no-ext version -TEST_P(CartesianFieldMPITest, WithExtRangeCheck) -{ +TEST_P(CartesianFieldMPITest, WithExtRangeCheck) { const auto& [bcs, locs] = GetParam(); auto builder = ExprBuilder().setMesh(m); if (isLogicalBC(bcs[0])) builder.setBC(0, DimPos::start, bcs[0]); @@ -99,8 +94,7 @@ TEST_P(CartesianFieldMPITest, WithExtRangeCheck) auto mr = strategy->splitRange(m.getRange(), getGlobalParallelPlan()); // mpi only affect localRange - for (int i = 0; i < 2; ++i) - { + for (int i = 0; i < 2; ++i) { ASSERT_EQ(u.localRange.start[i], mr.start[i]); int end; if (locs[i] == LocOnMesh::Center || bcs[i] == BCType::Periodic) end = mr.end[i]; @@ -112,99 +106,84 @@ TEST_P(CartesianFieldMPITest, WithExtRangeCheck) } } -TEST_F(CartesianFieldMPITest, PeriodicValueCheck) -{ +TEST_F(CartesianFieldMPITest, PeriodicValueCheck) { auto u = ExprBuilder() - .setMesh(m) - .setBC(0, OpFlow::DimPos::start, OpFlow::BCType::Periodic) - .setBC(0, OpFlow::DimPos::end, OpFlow::BCType::Periodic) - .setBC(1, OpFlow::DimPos::start, OpFlow::BCType::Periodic) - .setBC(1, OpFlow::DimPos::end, OpFlow::BCType::Periodic) - .setPadding(1) - .setExt(1) - .setSplitStrategy(strategy) - .setLoc({LocOnMesh::Center, LocOnMesh::Center}) - .build(); + .setMesh(m) + .setBC(0, OpFlow::DimPos::start, OpFlow::BCType::Periodic) + .setBC(0, OpFlow::DimPos::end, OpFlow::BCType::Periodic) + .setBC(1, OpFlow::DimPos::start, OpFlow::BCType::Periodic) + .setBC(1, OpFlow::DimPos::end, OpFlow::BCType::Periodic) + .setPadding(1) + .setExt(1) + .setSplitStrategy(strategy) + .setLoc({LocOnMesh::Center, LocOnMesh::Center}) + .build(); auto u_local = ExprBuilder() - .setMesh(m) - .setBC(0, OpFlow::DimPos::start, OpFlow::BCType::Periodic) - .setBC(0, OpFlow::DimPos::end, OpFlow::BCType::Periodic) - .setBC(1, OpFlow::DimPos::start, OpFlow::BCType::Periodic) - .setBC(1, OpFlow::DimPos::end, OpFlow::BCType::Periodic) - .setExt(1) - .setLoc({LocOnMesh::Center, LocOnMesh::Center}) - .build(); - - auto mapper = DS::MDRangeMapper < 2 > (u.assignableRange); + .setMesh(m) + .setBC(0, OpFlow::DimPos::start, OpFlow::BCType::Periodic) + .setBC(0, OpFlow::DimPos::end, OpFlow::BCType::Periodic) + .setBC(1, OpFlow::DimPos::start, OpFlow::BCType::Periodic) + .setBC(1, OpFlow::DimPos::end, OpFlow::BCType::Periodic) + .setExt(1) + .setLoc({LocOnMesh::Center, LocOnMesh::Center}) + .build(); + + auto mapper = DS::MDRangeMapper<2>(u.assignableRange); rangeFor_s(u.getLocalWritableRange(), [&](auto&& i) { u[i] = mapper(i); }); rangeFor_s(u_local.getLocalWritableRange(), [&](auto&& i) { u_local[i] = mapper(i); }); u.updatePadding(); u_local.updatePadding(); - rangeFor_s(u.getLocalReadableRange(), [&](auto&& i) - { + rangeFor_s(u.getLocalReadableRange(), [&](auto&& i) { if (u[i] != u_local[i]) std::cout << std::format("Not equal at {} {} != {}", i, u[i], u_local[i]); ASSERT_EQ(u[i], u_local[i]); }); } -TEST_F(CartesianFieldMPITest, Serializable_PeriodicValueCheck) -{ - class Int : public virtual SerializableObj - { +TEST_F(CartesianFieldMPITest, Serializable_PeriodicValueCheck) { + class Int : public virtual SerializableObj { public: int i = 0; Int() = default; - explicit Int(int i) : i(i) - { - } + explicit Int(int i) : i(i) {} - [[nodiscard]] std::vector serialize() const override - { + [[nodiscard]] std::vector serialize() const override { return {reinterpret_cast(&i), reinterpret_cast(&i + 1)}; } - void deserialize(const std::byte* data, std::size_t) override - { - std::memcpy(&i, data, sizeof(i)); - } + void deserialize(const std::byte* data, std::size_t) override { std::memcpy(&i, data, sizeof(i)); } }; auto s = std::make_shared>>(); auto u = ExprBuilder>() - .setMesh(m) - .setPadding(1) - .setName("uInt") - .setLoc({LocOnMesh::Center, LocOnMesh::Center}) - .setSplitStrategy(s) - .build(); - - auto mapper = DS::MDRangeMapper < 2 > (u.assignableRange); - rangeFor_s(u.getLocalWritableRange(), [&](auto&& i) { u[i] = Int{mapper(i)}; }); + .setMesh(m) + .setPadding(1) + .setName("uInt") + .setLoc({LocOnMesh::Center, LocOnMesh::Center}) + .setSplitStrategy(s) + .build(); + + auto mapper = DS::MDRangeMapper<2>(u.assignableRange); + rangeFor_s(u.getLocalWritableRange(), [&](auto&& i) { u[i] = Int {mapper(i)}; }); u.updatePadding(); - rangeFor_s(u.getLocalReadableRange(), [&](auto&& i) - { + rangeFor_s(u.getLocalReadableRange(), [&](auto&& i) { if (u[i].i != mapper(i)) std::cout << std::format("Not equal at {} {} != {}", i, u[i].i, mapper(i)); ASSERT_EQ(u[i].i, mapper(i)); }); } INSTANTIATE_TEST_SUITE_P( - Param2D, CartesianFieldMPITest, - testing::Values(std::make_tuple(std::array{BCType::Dirc, BCType::Dirc, BCType::Dirc, BCType::Dirc}, - std::array{LocOnMesh::Center, LocOnMesh::Center}), - std::make_tuple(std::array{BCType::Neum, BCType::Neum, BCType::Neum, BCType::Neum}, - std::array{LocOnMesh::Center, LocOnMesh::Center}), - std::make_tuple(std::array{ - BCType::Periodic, BCType::Periodic, BCType::Periodic, - BCType::Periodic - }, - std::array{LocOnMesh::Center, LocOnMesh::Center}), - std::make_tuple(std::array{BCType::Dirc, BCType::Dirc, BCType::Dirc, BCType::Dirc}, - std::array{LocOnMesh::Corner, LocOnMesh::Corner}), - std::make_tuple(std::array{BCType::Neum, BCType::Neum, BCType::Neum, BCType::Neum}, - std::array{LocOnMesh::Corner, LocOnMesh::Corner}), - std::make_tuple(std::array{ - BCType::Periodic, BCType::Periodic, BCType::Periodic, - BCType::Periodic - }, - std::array{LocOnMesh::Corner, LocOnMesh::Corner}))); \ No newline at end of file + Param2D, CartesianFieldMPITest, + testing::Values(std::make_tuple(std::array {BCType::Dirc, BCType::Dirc, BCType::Dirc, BCType::Dirc}, + std::array {LocOnMesh::Center, LocOnMesh::Center}), + std::make_tuple(std::array {BCType::Neum, BCType::Neum, BCType::Neum, BCType::Neum}, + std::array {LocOnMesh::Center, LocOnMesh::Center}), + std::make_tuple(std::array {BCType::Periodic, BCType::Periodic, BCType::Periodic, + BCType::Periodic}, + std::array {LocOnMesh::Center, LocOnMesh::Center}), + std::make_tuple(std::array {BCType::Dirc, BCType::Dirc, BCType::Dirc, BCType::Dirc}, + std::array {LocOnMesh::Corner, LocOnMesh::Corner}), + std::make_tuple(std::array {BCType::Neum, BCType::Neum, BCType::Neum, BCType::Neum}, + std::array {LocOnMesh::Corner, LocOnMesh::Corner}), + std::make_tuple(std::array {BCType::Periodic, BCType::Periodic, BCType::Periodic, + BCType::Periodic}, + std::array {LocOnMesh::Corner, LocOnMesh::Corner}))); \ No newline at end of file diff --git a/test/Core/Loops/RangeForTest.cpp b/test/Core/Loops/RangeForTest.cpp index 7fd4161c..7fb798c4 100644 --- a/test/Core/Loops/RangeForTest.cpp +++ b/test/Core/Loops/RangeForTest.cpp @@ -33,8 +33,7 @@ class RangedIndexTest : public Test { DS::MDIndex ret; ret.set(index.range.start); assert(linear >= 0); - for (std::size_t i = 0; i < index.dim; ++i) - { + for (std::size_t i = 0; i < index.dim; ++i) { ret[i] += linear % ((index.range.end[i] - 1 - index.range.start[i]) / index.range.stride[i] + 1) * index.range.stride[i]; linear /= ((index.range.end[i] - 1 - index.range.start[i]) / index.range.stride[i] + 1); @@ -59,8 +58,7 @@ class RangedIndexTest : public Test { TEST_F(RangedIndexTest, GetTotalCount) { auto total = 1; - for (std::size_t i = 0; i < index.dim; ++i) - { + for (std::size_t i = 0; i < index.dim; ++i) { total *= (index.range.end[i] - index.range.start[i] - 1) / index.range.stride[i] + 1; } ASSERT_EQ(index.count(), total); From 23db8d202d88d70d3cec11982e57de9e7b195773 Mon Sep 17 00:00:00 2001 From: Luohao Wang Date: Tue, 3 Feb 2026 07:38:01 +0800 Subject: [PATCH 13/14] Fix warnings --- examples/AMR/Poisson.cpp | 5 +- examples/LevelSet/LevelSet.cpp | 2 +- examples/LevelSet/UniLS.cpp | 2 +- examples/LidDriven/LidDriven2D.cpp | 12 +- examples/LidDriven/LidDriven3D.cpp | 13 +- .../include/spdlog/fmt/bundled/format.h | 7093 +++++++++-------- src/Core/Equation/AMGCLEqnSolveHandler.hpp | 10 +- src/Core/Equation/HYPREEqnSolveHandler.hpp | 58 +- src/Core/Equation/UnifiedSolve.hpp | 1 - .../MeshBased/SemiStructured/CartAMRField.hpp | 58 +- .../SemiStructuredFieldExpr.hpp | 10 +- src/Core/Field/MeshBased/StencilField.hpp | 71 +- .../MeshBased/Structured/CartesianField.hpp | 32 +- src/Core/Interfaces/Stringifiable.hpp | 6 +- src/Core/Loops/FieldAssigner.hpp | 2 +- src/Core/Macros.hpp | 36 +- src/Core/Mesh/MeshBase.hpp | 2 +- .../Mesh/SemiStructured/CartesianAMRMesh.hpp | 82 +- .../SemiStructured/CartesianAMRMeshBase.hpp | 2 +- .../SemiStructured/CartesianAMRMeshView.hpp | 6 +- .../Mesh/Structured/CartesianMeshView.hpp | 5 +- src/Core/Operator/BinOpDefMacros.hpp.in | 8 +- src/Core/Operator/Convolution/Convolution.hpp | 27 +- .../FDMOperators/D1WENO53Downwind.hpp | 6 +- .../Operator/FDMOperators/D1WENO53Upwind.hpp | 6 +- src/Core/Operator/PerElemOpAdaptor.hpp | 2 +- src/Core/Parallel/ManualSplitStrategy.hpp | 6 +- .../Parallel/ParticleGuidedSplitStrategy.hpp | 2 +- src/Core/Solvers/Struct/StructSolver.hpp | 2 + src/DataStructures/Geometry/BasicElements.hpp | 17 +- src/DataStructures/Index/ColoredIndex.hpp | 39 +- src/DataStructures/Index/LevelMDIndex.hpp | 13 +- src/DataStructures/Index/LevelRangedIndex.hpp | 4 +- .../LinearMapper/ColoredMDRangeMapper.hpp | 4 +- src/DataStructures/Index/MDIndex.hpp | 9 +- src/DataStructures/Index/RangedIndex.hpp | 4 +- src/DataStructures/Range/LevelRanges.hpp | 38 +- src/DataStructures/Range/Ranges.hpp | 7 +- src/Math/Function/Numeric.hpp | 8 +- src/Utils/ConstexprString.hpp | 5 +- src/Utils/Writers/HDF5Stream.hpp | 6 +- src/Utils/Writers/IOGroup.hpp | 5 +- src/Utils/Writers/TecplotBinaryStream.hpp | 41 +- src/Utils/Writers/TecplotSZPLTStream.hpp | 64 +- src/Utils/Writers/VTKAMRStream.hpp | 2 +- test/Core/Equation/CSRMatrixGeneratorTest.cpp | 28 +- 46 files changed, 4112 insertions(+), 3749 deletions(-) diff --git a/examples/AMR/Poisson.cpp b/examples/AMR/Poisson.cpp index bd57e401..83ee6e4e 100644 --- a/examples/AMR/Poisson.cpp +++ b/examples/AMR/Poisson.cpp @@ -11,8 +11,9 @@ void Poisson() { using Mesh = CartesianAMRMesh>; using Field = CartAMRField; - int n = 9, maxlevel = 2, ratio = 2, buffWidth = 1; - auto h = 2. / (n - 1); + int n = 9; + [[maybe_unused]] int maxlevel = 2, ratio = 2, buffWidth = 1; + [[maybe_unused]] auto h = 2. / (n - 1); /* auto m = MeshBuilder() .setBaseMesh(MeshBuilder>>() diff --git a/examples/LevelSet/LevelSet.cpp b/examples/LevelSet/LevelSet.cpp index a7d4b161..38f106fc 100644 --- a/examples/LevelSet/LevelSet.cpp +++ b/examples/LevelSet/LevelSet.cpp @@ -13,7 +13,7 @@ #include "AMRLS.hpp" #include "UniLS.hpp" -int main(int argc, char* argv[]) { +int main(int /* argc */, char* /* argv */[]) { //ls(); amrls_3d(); //ls_3d(); diff --git a/examples/LevelSet/UniLS.cpp b/examples/LevelSet/UniLS.cpp index d61609c5..92caebc0 100644 --- a/examples/LevelSet/UniLS.cpp +++ b/examples/LevelSet/UniLS.cpp @@ -79,7 +79,7 @@ void ls() { uf << Utils::TimeStamp(0) << u; vf << Utils::TimeStamp(0) << v; - int buffWidth = 5; + [[maybe_unused]] int buffWidth = 5; constexpr auto h = 1. / (n - 1); auto _eps = 1e-6; auto _1 = [&](auto&& _p, auto&& _pp) { diff --git a/examples/LidDriven/LidDriven2D.cpp b/examples/LidDriven/LidDriven2D.cpp index 61563eca..0781099f 100644 --- a/examples/LidDriven/LidDriven2D.cpp +++ b/examples/LidDriven/LidDriven2D.cpp @@ -44,8 +44,16 @@ int main(int argc, char* argv[]) { const Real dt = 0.5e-2, nu = 1.0e-2; StructSolverParams params; params.tol = 1e-10; params.maxIter = 100; StructSolverParams poisson_params = params; - StructSolverParams p_params {.useZeroGuess = true, .relaxType = 1, .rapType = 0, - .numPreRelax = 1, .numPostRelax = 1, .skipRelax = 0}; p_params.tol = 1e-10; + StructSolverParams p_params; + p_params.useZeroGuess = true; + p_params.relaxType = 1; + p_params.rapType = 0; + p_params.numPreRelax = 1; + p_params.numPostRelax = 1; + p_params.skipRelax = 0; + p_params.tol = 1e-10; + p_params.printLevel = 0; + p_params.logging = false; auto solver = PrecondStructSolver(params, p_params); auto u_handler = makeEqnSolveHandler( [&](auto&& e) { diff --git a/examples/LidDriven/LidDriven3D.cpp b/examples/LidDriven/LidDriven3D.cpp index 58a13d09..d344707f 100644 --- a/examples/LidDriven/LidDriven3D.cpp +++ b/examples/LidDriven/LidDriven3D.cpp @@ -94,12 +94,13 @@ int main(int argc, char* argv[]) { params.tol = 1e-6; params.maxIter = 100; StructSolverParams poisson_params; - StructSolverParams p_params {.useZeroGuess = true, - .relaxType = 1, - .rapType = 0, - .numPreRelax = 1, - .numPostRelax = 1, - .skipRelax = 0}; + StructSolverParams p_params; + p_params.useZeroGuess = true; + p_params.relaxType = 1; + p_params.rapType = 0; + p_params.numPreRelax = 1; + p_params.numPostRelax = 1; + p_params.skipRelax = 0; p_params.tol = 1e-10; auto solver = PrecondStructSolver(params, p_params); auto u_handler = makeEqnSolveHandler( diff --git a/external/spdlog/include/spdlog/fmt/bundled/format.h b/external/spdlog/include/spdlog/fmt/bundled/format.h index 7c607dbd..2ee5466d 100755 --- a/external/spdlog/include/spdlog/fmt/bundled/format.h +++ b/external/spdlog/include/spdlog/fmt/bundled/format.h @@ -33,100 +33,103 @@ #ifndef FMT_FORMAT_H_ #define FMT_FORMAT_H_ -#include // std::signbit -#include // uint32_t -#include // std::memcpy -#include // std::numeric_limits -#include // std::uninitialized_copy -#include // std::runtime_error -#include // std::system_error +#include // std::signbit +#include // uint32_t +#include // std::memcpy +#include // std::numeric_limits +#include // std::uninitialized_copy +#include // std::runtime_error +#include // std::system_error #ifdef __cpp_lib_bit_cast -# include // std::bitcast +# include // std::bitcast #endif #include "core.h" #if FMT_GCC_VERSION -# define FMT_GCC_VISIBILITY_HIDDEN __attribute__((visibility("hidden"))) +# define FMT_GCC_VISIBILITY_HIDDEN __attribute__((visibility("hidden"))) #else -# define FMT_GCC_VISIBILITY_HIDDEN +# define FMT_GCC_VISIBILITY_HIDDEN #endif #ifdef __NVCC__ -# define FMT_CUDA_VERSION (__CUDACC_VER_MAJOR__ * 100 + __CUDACC_VER_MINOR__) +# define FMT_CUDA_VERSION (__CUDACC_VER_MAJOR__ * 100 + __CUDACC_VER_MINOR__) #else -# define FMT_CUDA_VERSION 0 +# define FMT_CUDA_VERSION 0 #endif #ifdef __has_builtin -# define FMT_HAS_BUILTIN(x) __has_builtin(x) +# define FMT_HAS_BUILTIN(x) __has_builtin(x) #else -# define FMT_HAS_BUILTIN(x) 0 +# define FMT_HAS_BUILTIN(x) 0 #endif #if FMT_GCC_VERSION || FMT_CLANG_VERSION -# define FMT_NOINLINE __attribute__((noinline)) +# define FMT_NOINLINE __attribute__((noinline)) #else -# define FMT_NOINLINE +# define FMT_NOINLINE #endif #if FMT_MSC_VERSION -# define FMT_MSC_DEFAULT = default +# define FMT_MSC_DEFAULT = default #else -# define FMT_MSC_DEFAULT +# define FMT_MSC_DEFAULT #endif #ifndef FMT_THROW -# if FMT_EXCEPTIONS -# if FMT_MSC_VERSION || defined(__NVCC__) +# if FMT_EXCEPTIONS +# if FMT_MSC_VERSION || defined(__NVCC__) FMT_BEGIN_NAMESPACE namespace detail { -template inline void do_throw(const Exception& x) { - // Silence unreachable code warnings in MSVC and NVCC because these - // are nearly impossible to fix in a generic code. - volatile bool b = true; - if (b) throw x; -} -} // namespace detail +template +inline void do_throw(const Exception &x) +{ + // Silence unreachable code warnings in MSVC and NVCC because these + // are nearly impossible to fix in a generic code. + volatile bool b = true; + if (b) + throw x; +} +} // namespace detail FMT_END_NAMESPACE -# define FMT_THROW(x) detail::do_throw(x) +# define FMT_THROW(x) detail::do_throw(x) +# else +# define FMT_THROW(x) throw x +# endif # else -# define FMT_THROW(x) throw x +# define FMT_THROW(x) \ + do \ + { \ + FMT_ASSERT(false, (x).what()); \ + } while (false) # endif -# else -# define FMT_THROW(x) \ - do { \ - FMT_ASSERT(false, (x).what()); \ - } while (false) -# endif #endif #if FMT_EXCEPTIONS -# define FMT_TRY try -# define FMT_CATCH(x) catch (x) +# define FMT_TRY try +# define FMT_CATCH(x) catch (x) #else -# define FMT_TRY if (true) -# define FMT_CATCH(x) if (false) +# define FMT_TRY if (true) +# define FMT_CATCH(x) if (false) #endif #ifndef FMT_MAYBE_UNUSED -# if FMT_HAS_CPP17_ATTRIBUTE(maybe_unused) -# define FMT_MAYBE_UNUSED [[maybe_unused]] -# else -# define FMT_MAYBE_UNUSED -# endif +# if FMT_HAS_CPP17_ATTRIBUTE(maybe_unused) +# define FMT_MAYBE_UNUSED [[maybe_unused]] +# else +# define FMT_MAYBE_UNUSED +# endif #endif #ifndef FMT_USE_USER_DEFINED_LITERALS // EDG based compilers (Intel, NVIDIA, Elbrus, etc), GCC and MSVC support UDLs. -# if (FMT_HAS_FEATURE(cxx_user_literals) || FMT_GCC_VERSION >= 407 || \ - FMT_MSC_VERSION >= 1900) && \ - (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= /* UDL feature */ 480) -# define FMT_USE_USER_DEFINED_LITERALS 1 -# else -# define FMT_USE_USER_DEFINED_LITERALS 0 -# endif +# if (FMT_HAS_FEATURE(cxx_user_literals) || FMT_GCC_VERSION >= 407 || FMT_MSC_VERSION >= 1900) && \ + (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= /* UDL feature */ 480) +# define FMT_USE_USER_DEFINED_LITERALS 1 +# else +# define FMT_USE_USER_DEFINED_LITERALS 0 +# endif #endif // Defining FMT_REDUCE_INT_INSTANTIATIONS to 1, will reduce the number of @@ -134,294 +137,312 @@ FMT_END_NAMESPACE // largest integer type. This results in a reduction in binary size but will // cause a decrease in integer formatting performance. #if !defined(FMT_REDUCE_INT_INSTANTIATIONS) -# define FMT_REDUCE_INT_INSTANTIATIONS 0 +# define FMT_REDUCE_INT_INSTANTIATIONS 0 #endif // __builtin_clz is broken in clang with Microsoft CodeGen: // https://github.com/fmtlib/fmt/issues/519. #if !FMT_MSC_VERSION -# if FMT_HAS_BUILTIN(__builtin_clz) || FMT_GCC_VERSION || FMT_ICC_VERSION -# define FMT_BUILTIN_CLZ(n) __builtin_clz(n) -# endif -# if FMT_HAS_BUILTIN(__builtin_clzll) || FMT_GCC_VERSION || FMT_ICC_VERSION -# define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n) -# endif +# if FMT_HAS_BUILTIN(__builtin_clz) || FMT_GCC_VERSION || FMT_ICC_VERSION +# define FMT_BUILTIN_CLZ(n) __builtin_clz(n) +# endif +# if FMT_HAS_BUILTIN(__builtin_clzll) || FMT_GCC_VERSION || FMT_ICC_VERSION +# define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n) +# endif #endif // __builtin_ctz is broken in Intel Compiler Classic on Windows: // https://github.com/fmtlib/fmt/issues/2510. #ifndef __ICL -# if FMT_HAS_BUILTIN(__builtin_ctz) || FMT_GCC_VERSION || FMT_ICC_VERSION || \ - defined(__NVCOMPILER) -# define FMT_BUILTIN_CTZ(n) __builtin_ctz(n) -# endif -# if FMT_HAS_BUILTIN(__builtin_ctzll) || FMT_GCC_VERSION || \ - FMT_ICC_VERSION || defined(__NVCOMPILER) -# define FMT_BUILTIN_CTZLL(n) __builtin_ctzll(n) -# endif +# if FMT_HAS_BUILTIN(__builtin_ctz) || FMT_GCC_VERSION || FMT_ICC_VERSION || defined(__NVCOMPILER) +# define FMT_BUILTIN_CTZ(n) __builtin_ctz(n) +# endif +# if FMT_HAS_BUILTIN(__builtin_ctzll) || FMT_GCC_VERSION || FMT_ICC_VERSION || defined(__NVCOMPILER) +# define FMT_BUILTIN_CTZLL(n) __builtin_ctzll(n) +# endif #endif #if FMT_MSC_VERSION -# include // _BitScanReverse[64], _BitScanForward[64], _umul128 +# include // _BitScanReverse[64], _BitScanForward[64], _umul128 #endif // Some compilers masquerade as both MSVC and GCC-likes or otherwise support // __builtin_clz and __builtin_clzll, so only define FMT_BUILTIN_CLZ using the // MSVC intrinsics if the clz and clzll builtins are not available. -#if FMT_MSC_VERSION && !defined(FMT_BUILTIN_CLZLL) && \ - !defined(FMT_BUILTIN_CTZLL) +#if FMT_MSC_VERSION && !defined(FMT_BUILTIN_CLZLL) && !defined(FMT_BUILTIN_CTZLL) FMT_BEGIN_NAMESPACE namespace detail { // Avoid Clang with Microsoft CodeGen's -Wunknown-pragmas warning. -# if !defined(__clang__) -# pragma intrinsic(_BitScanForward) -# pragma intrinsic(_BitScanReverse) -# if defined(_WIN64) -# pragma intrinsic(_BitScanForward64) -# pragma intrinsic(_BitScanReverse64) +# if !defined(__clang__) +# pragma intrinsic(_BitScanForward) +# pragma intrinsic(_BitScanReverse) +# if defined(_WIN64) +# pragma intrinsic(_BitScanForward64) +# pragma intrinsic(_BitScanReverse64) +# endif # endif -# endif - -inline auto clz(uint32_t x) -> int { - unsigned long r = 0; - _BitScanReverse(&r, x); - FMT_ASSERT(x != 0, ""); - // Static analysis complains about using uninitialized data - // "r", but the only way that can happen is if "x" is 0, - // which the callers guarantee to not happen. - FMT_MSC_WARNING(suppress : 6102) - return 31 ^ static_cast(r); -} -# define FMT_BUILTIN_CLZ(n) detail::clz(n) - -inline auto clzll(uint64_t x) -> int { - unsigned long r = 0; -# ifdef _WIN64 - _BitScanReverse64(&r, x); -# else - // Scan the high 32 bits. - if (_BitScanReverse(&r, static_cast(x >> 32))) return 63 ^ (r + 32); - // Scan the low 32 bits. - _BitScanReverse(&r, static_cast(x)); -# endif - FMT_ASSERT(x != 0, ""); - FMT_MSC_WARNING(suppress : 6102) // Suppress a bogus static analysis warning. - return 63 ^ static_cast(r); -} -# define FMT_BUILTIN_CLZLL(n) detail::clzll(n) - -inline auto ctz(uint32_t x) -> int { - unsigned long r = 0; - _BitScanForward(&r, x); - FMT_ASSERT(x != 0, ""); - FMT_MSC_WARNING(suppress : 6102) // Suppress a bogus static analysis warning. - return static_cast(r); -} -# define FMT_BUILTIN_CTZ(n) detail::ctz(n) - -inline auto ctzll(uint64_t x) -> int { - unsigned long r = 0; - FMT_ASSERT(x != 0, ""); - FMT_MSC_WARNING(suppress : 6102) // Suppress a bogus static analysis warning. -# ifdef _WIN64 - _BitScanForward64(&r, x); -# else - // Scan the low 32 bits. - if (_BitScanForward(&r, static_cast(x))) return static_cast(r); - // Scan the high 32 bits. - _BitScanForward(&r, static_cast(x >> 32)); - r += 32; -# endif - return static_cast(r); + +inline auto clz(uint32_t x) -> int +{ + unsigned long r = 0; + _BitScanReverse(&r, x); + FMT_ASSERT(x != 0, ""); + // Static analysis complains about using uninitialized data + // "r", but the only way that can happen is if "x" is 0, + // which the callers guarantee to not happen. + FMT_MSC_WARNING(suppress : 6102) + return 31 ^ static_cast(r); +} +# define FMT_BUILTIN_CLZ(n) detail::clz(n) + +inline auto clzll(uint64_t x) -> int +{ + unsigned long r = 0; +# ifdef _WIN64 + _BitScanReverse64(&r, x); +# else + // Scan the high 32 bits. + if (_BitScanReverse(&r, static_cast(x >> 32))) + return 63 ^ (r + 32); + // Scan the low 32 bits. + _BitScanReverse(&r, static_cast(x)); +# endif + FMT_ASSERT(x != 0, ""); + FMT_MSC_WARNING(suppress : 6102) // Suppress a bogus static analysis warning. + return 63 ^ static_cast(r); +} +# define FMT_BUILTIN_CLZLL(n) detail::clzll(n) + +inline auto ctz(uint32_t x) -> int +{ + unsigned long r = 0; + _BitScanForward(&r, x); + FMT_ASSERT(x != 0, ""); + FMT_MSC_WARNING(suppress : 6102) // Suppress a bogus static analysis warning. + return static_cast(r); +} +# define FMT_BUILTIN_CTZ(n) detail::ctz(n) + +inline auto ctzll(uint64_t x) -> int +{ + unsigned long r = 0; + FMT_ASSERT(x != 0, ""); + FMT_MSC_WARNING(suppress : 6102) // Suppress a bogus static analysis warning. +# ifdef _WIN64 + _BitScanForward64(&r, x); +# else + // Scan the low 32 bits. + if (_BitScanForward(&r, static_cast(x))) + return static_cast(r); + // Scan the high 32 bits. + _BitScanForward(&r, static_cast(x >> 32)); + r += 32; +# endif + return static_cast(r); } -# define FMT_BUILTIN_CTZLL(n) detail::ctzll(n) -} // namespace detail +# define FMT_BUILTIN_CTZLL(n) detail::ctzll(n) +} // namespace detail FMT_END_NAMESPACE #endif FMT_BEGIN_NAMESPACE namespace detail { -FMT_CONSTEXPR inline void abort_fuzzing_if(bool condition) { - ignore_unused(condition); +FMT_CONSTEXPR inline void abort_fuzzing_if(bool condition) +{ + ignore_unused(condition); #ifdef FMT_FUZZ - if (condition) throw std::runtime_error("fuzzing limit reached"); + if (condition) + throw std::runtime_error("fuzzing limit reached"); #endif } -template struct string_literal { - static constexpr CharT value[sizeof...(C)] = {C...}; - constexpr operator basic_string_view() const { - return {value, sizeof...(C)}; - } +template +struct string_literal +{ + static constexpr CharT value[sizeof...(C)] = {C...}; + constexpr operator basic_string_view() const + { return {value, sizeof...(C)}; } }; #if FMT_CPLUSPLUS < 201703L -template +template constexpr CharT string_literal::value[sizeof...(C)]; #endif -template class formatbuf : public Streambuf { - private: - using char_type = typename Streambuf::char_type; - using streamsize = decltype(std::declval().sputn(nullptr, 0)); - using int_type = typename Streambuf::int_type; - using traits_type = typename Streambuf::traits_type; - - buffer& buffer_; - - public: - explicit formatbuf(buffer& buf) : buffer_(buf) {} - - protected: - // The put area is always empty. This makes the implementation simpler and has - // the advantage that the streambuf and the buffer are always in sync and - // sputc never writes into uninitialized memory. A disadvantage is that each - // call to sputc always results in a (virtual) call to overflow. There is no - // disadvantage here for sputn since this always results in a call to xsputn. - - auto overflow(int_type ch) -> int_type override { - if (!traits_type::eq_int_type(ch, traits_type::eof())) - buffer_.push_back(static_cast(ch)); - return ch; - } - - auto xsputn(const char_type* s, streamsize count) -> streamsize override { - buffer_.append(s, s + count); - return count; - } +template +class formatbuf : public Streambuf +{ +private: + using char_type = typename Streambuf::char_type; + using streamsize = decltype(std::declval().sputn(nullptr, 0)); + using int_type = typename Streambuf::int_type; + using traits_type = typename Streambuf::traits_type; + + buffer &buffer_; + +public: + explicit formatbuf(buffer &buf) + : buffer_(buf) + {} + +protected: + // The put area is always empty. This makes the implementation simpler and has + // the advantage that the streambuf and the buffer are always in sync and + // sputc never writes into uninitialized memory. A disadvantage is that each + // call to sputc always results in a (virtual) call to overflow. There is no + // disadvantage here for sputn since this always results in a call to xsputn. + + auto overflow(int_type ch) -> int_type override + { + if (!traits_type::eq_int_type(ch, traits_type::eof())) + buffer_.push_back(static_cast(ch)); + return ch; + } + + auto xsputn(const char_type *s, streamsize count) -> streamsize override + { + buffer_.append(s, s + count); + return count; + } }; // Implementation of std::bit_cast for pre-C++20. -template -FMT_CONSTEXPR20 auto bit_cast(const From& from) -> To { +template +FMT_CONSTEXPR20 auto bit_cast(const From &from) -> To +{ #ifdef __cpp_lib_bit_cast - if (is_constant_evaluated()) return std::bit_cast(from); + if (is_constant_evaluated()) + return std::bit_cast(from); #endif - auto to = To(); - // The cast suppresses a bogus -Wclass-memaccess on GCC. - std::memcpy(static_cast(&to), &from, sizeof(to)); - return to; + auto to = To(); + // The cast suppresses a bogus -Wclass-memaccess on GCC. + std::memcpy(static_cast(&to), &from, sizeof(to)); + return to; } -inline auto is_big_endian() -> bool { +inline auto is_big_endian() -> bool +{ #ifdef _WIN32 - return false; + return false; #elif defined(__BIG_ENDIAN__) - return true; + return true; #elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) - return __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__; + return __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__; #else - struct bytes { - char data[sizeof(int)]; - }; - return bit_cast(1).data[0] == 0; + struct bytes + { + char data[sizeof(int)]; + }; + return bit_cast(1).data[0] == 0; #endif } -class uint128_fallback { - private: - uint64_t lo_, hi_; - - friend uint128_fallback umul128(uint64_t x, uint64_t y) noexcept; - - public: - constexpr uint128_fallback(uint64_t hi, uint64_t lo) : lo_(lo), hi_(hi) {} - constexpr uint128_fallback(uint64_t value = 0) : lo_(value), hi_(0) {} - - constexpr uint64_t high() const noexcept { return hi_; } - constexpr uint64_t low() const noexcept { return lo_; } - - template ::value)> - constexpr explicit operator T() const { - return static_cast(lo_); - } - - friend constexpr auto operator==(const uint128_fallback& lhs, - const uint128_fallback& rhs) -> bool { - return lhs.hi_ == rhs.hi_ && lhs.lo_ == rhs.lo_; - } - friend constexpr auto operator!=(const uint128_fallback& lhs, - const uint128_fallback& rhs) -> bool { - return !(lhs == rhs); - } - friend constexpr auto operator>(const uint128_fallback& lhs, - const uint128_fallback& rhs) -> bool { - return lhs.hi_ != rhs.hi_ ? lhs.hi_ > rhs.hi_ : lhs.lo_ > rhs.lo_; - } - friend constexpr auto operator|(const uint128_fallback& lhs, - const uint128_fallback& rhs) - -> uint128_fallback { - return {lhs.hi_ | rhs.hi_, lhs.lo_ | rhs.lo_}; - } - friend constexpr auto operator&(const uint128_fallback& lhs, - const uint128_fallback& rhs) - -> uint128_fallback { - return {lhs.hi_ & rhs.hi_, lhs.lo_ & rhs.lo_}; - } - friend auto operator+(const uint128_fallback& lhs, - const uint128_fallback& rhs) -> uint128_fallback { - auto result = uint128_fallback(lhs); - result += rhs; - return result; - } - friend auto operator*(const uint128_fallback& lhs, uint32_t rhs) - -> uint128_fallback { - FMT_ASSERT(lhs.hi_ == 0, ""); - uint64_t hi = (lhs.lo_ >> 32) * rhs; - uint64_t lo = (lhs.lo_ & ~uint32_t()) * rhs; - uint64_t new_lo = (hi << 32) + lo; - return {(hi >> 32) + (new_lo < lo ? 1 : 0), new_lo}; - } - friend auto operator-(const uint128_fallback& lhs, uint64_t rhs) - -> uint128_fallback { - return {lhs.hi_ - (lhs.lo_ < rhs ? 1 : 0), lhs.lo_ - rhs}; - } - FMT_CONSTEXPR auto operator>>(int shift) const -> uint128_fallback { - if (shift == 64) return {0, hi_}; - if (shift > 64) return uint128_fallback(0, hi_) >> (shift - 64); - return {hi_ >> shift, (hi_ << (64 - shift)) | (lo_ >> shift)}; - } - FMT_CONSTEXPR auto operator<<(int shift) const -> uint128_fallback { - if (shift == 64) return {lo_, 0}; - if (shift > 64) return uint128_fallback(lo_, 0) << (shift - 64); - return {hi_ << shift | (lo_ >> (64 - shift)), (lo_ << shift)}; - } - FMT_CONSTEXPR auto operator>>=(int shift) -> uint128_fallback& { - return *this = *this >> shift; - } - FMT_CONSTEXPR void operator+=(uint128_fallback n) { - uint64_t new_lo = lo_ + n.lo_; - uint64_t new_hi = hi_ + n.hi_ + (new_lo < lo_ ? 1 : 0); - FMT_ASSERT(new_hi >= hi_, ""); - lo_ = new_lo; - hi_ = new_hi; - } - - FMT_CONSTEXPR20 uint128_fallback& operator+=(uint64_t n) noexcept { - if (is_constant_evaluated()) { - lo_ += n; - hi_ += (lo_ < n ? 1 : 0); - return *this; +class uint128_fallback +{ +private: + uint64_t lo_, hi_; + + friend uint128_fallback umul128(uint64_t x, uint64_t y) noexcept; + +public: + constexpr uint128_fallback(uint64_t hi, uint64_t lo) + : lo_(lo) + , hi_(hi) + {} + constexpr uint128_fallback(uint64_t value = 0) + : lo_(value) + , hi_(0) + {} + + constexpr uint64_t high() const noexcept + { return hi_; } + constexpr uint64_t low() const noexcept + { return lo_; } + + template::value)> + constexpr explicit operator T() const + { return static_cast(lo_); } + + friend constexpr auto operator==(const uint128_fallback &lhs, const uint128_fallback &rhs) -> bool + { return lhs.hi_ == rhs.hi_ && lhs.lo_ == rhs.lo_; } + friend constexpr auto operator!=(const uint128_fallback &lhs, const uint128_fallback &rhs) -> bool + { return !(lhs == rhs); } + friend constexpr auto operator>(const uint128_fallback &lhs, const uint128_fallback &rhs) -> bool + { return lhs.hi_ != rhs.hi_ ? lhs.hi_ > rhs.hi_ : lhs.lo_ > rhs.lo_; } + friend constexpr auto operator|(const uint128_fallback &lhs, const uint128_fallback &rhs) -> uint128_fallback + { return {lhs.hi_ | rhs.hi_, lhs.lo_ | rhs.lo_}; } + friend constexpr auto operator&(const uint128_fallback &lhs, const uint128_fallback &rhs) -> uint128_fallback + { return {lhs.hi_ & rhs.hi_, lhs.lo_ & rhs.lo_}; } + friend auto operator+(const uint128_fallback &lhs, const uint128_fallback &rhs) -> uint128_fallback + { + auto result = uint128_fallback(lhs); + result += rhs; + return result; + } + friend auto operator*(const uint128_fallback &lhs, uint32_t rhs) -> uint128_fallback + { + FMT_ASSERT(lhs.hi_ == 0, ""); + uint64_t hi = (lhs.lo_ >> 32) * rhs; + uint64_t lo = (lhs.lo_ & ~uint32_t()) * rhs; + uint64_t new_lo = (hi << 32) + lo; + return {(hi >> 32) + (new_lo < lo ? 1 : 0), new_lo}; + } + friend auto operator-(const uint128_fallback &lhs, uint64_t rhs) -> uint128_fallback + { return {lhs.hi_ - (lhs.lo_ < rhs ? 1 : 0), lhs.lo_ - rhs}; } + FMT_CONSTEXPR auto operator>>(int shift) const -> uint128_fallback + { + if (shift == 64) + return {0, hi_}; + if (shift > 64) + return uint128_fallback(0, hi_) >> (shift - 64); + return {hi_ >> shift, (hi_ << (64 - shift)) | (lo_ >> shift)}; + } + FMT_CONSTEXPR auto operator<<(int shift) const -> uint128_fallback + { + if (shift == 64) + return {lo_, 0}; + if (shift > 64) + return uint128_fallback(lo_, 0) << (shift - 64); + return {hi_ << shift | (lo_ >> (64 - shift)), (lo_ << shift)}; } + FMT_CONSTEXPR auto operator>>=(int shift) -> uint128_fallback & + { return *this = *this >> shift; } + FMT_CONSTEXPR void operator+=(uint128_fallback n) + { + uint64_t new_lo = lo_ + n.lo_; + uint64_t new_hi = hi_ + n.hi_ + (new_lo < lo_ ? 1 : 0); + FMT_ASSERT(new_hi >= hi_, ""); + lo_ = new_lo; + hi_ = new_hi; + } + + FMT_CONSTEXPR20 uint128_fallback &operator+=(uint64_t n) noexcept + { + if (is_constant_evaluated()) + { + lo_ += n; + hi_ += (lo_ < n ? 1 : 0); + return *this; + } #if FMT_HAS_BUILTIN(__builtin_addcll) && !defined(__ibmxl__) - unsigned long long carry; - lo_ = __builtin_addcll(lo_, n, 0, &carry); - hi_ += carry; + unsigned long long carry; + lo_ = __builtin_addcll(lo_, n, 0, &carry); + hi_ += carry; #elif FMT_HAS_BUILTIN(__builtin_ia32_addcarryx_u64) && !defined(__ibmxl__) - unsigned long long result; - auto carry = __builtin_ia32_addcarryx_u64(0, lo_, n, &result); - lo_ = result; - hi_ += carry; + unsigned long long result; + auto carry = __builtin_ia32_addcarryx_u64(0, lo_, n, &result); + lo_ = result; + hi_ += carry; #elif defined(_MSC_VER) && defined(_M_X64) - auto carry = _addcarry_u64(0, lo_, n, &lo_); - _addcarry_u64(carry, hi_, 0, &hi_); + auto carry = _addcarry_u64(0, lo_, n, &lo_); + _addcarry_u64(carry, hi_, 0, &hi_); #else - lo_ += n; - hi_ += (lo_ < n ? 1 : 0); + lo_ += n; + hi_ += (lo_ < n ? 1 : 0); #endif - return *this; - } + return *this; + } }; using uint128_t = conditional_t; @@ -434,154 +455,164 @@ using uintptr_t = uint128_t; // Returns the largest possible value for type T. Same as // std::numeric_limits::max() but shorter and not affected by the max macro. -template constexpr auto max_value() -> T { - return (std::numeric_limits::max)(); -} -template constexpr auto num_bits() -> int { - return std::numeric_limits::digits; -} +template +constexpr auto max_value() -> T +{ return (std::numeric_limits::max)(); } +template +constexpr auto num_bits() -> int +{ return std::numeric_limits::digits; } // std::numeric_limits::digits may return 0 for 128-bit ints. -template <> constexpr auto num_bits() -> int { return 128; } -template <> constexpr auto num_bits() -> int { return 128; } +template<> +constexpr auto num_bits() -> int +{ return 128; } +template<> +constexpr auto num_bits() -> int +{ return 128; } // A heterogeneous bit_cast used for converting 96-bit long double to uint128_t // and 128-bit pointers to uint128_fallback. -template sizeof(From))> -inline auto bit_cast(const From& from) -> To { - constexpr auto size = static_cast(sizeof(From) / sizeof(unsigned)); - struct data_t { - unsigned value[static_cast(size)]; - } data = bit_cast(from); - auto result = To(); - if (const_check(is_big_endian())) { - for (int i = 0; i < size; ++i) - result = (result << num_bits()) | data.value[i]; - } else { - for (int i = size - 1; i >= 0; --i) - result = (result << num_bits()) | data.value[i]; - } - return result; +template sizeof(From))> +inline auto bit_cast(const From &from) -> To +{ + constexpr auto size = static_cast(sizeof(From) / sizeof(unsigned)); + struct data_t + { + unsigned value[static_cast(size)]; + } data = bit_cast(from); + auto result = To(); + if (const_check(is_big_endian())) + { + for (int i = 0; i < size; ++i) + result = (result << num_bits()) | data.value[i]; + } + else + { + for (int i = size - 1; i >= 0; --i) + result = (result << num_bits()) | data.value[i]; + } + return result; } -FMT_INLINE void assume(bool condition) { - (void)condition; +FMT_INLINE void assume(bool condition) +{ + (void)condition; #if FMT_HAS_BUILTIN(__builtin_assume) && !FMT_ICC_VERSION - __builtin_assume(condition); + __builtin_assume(condition); #endif } // An approximation of iterator_t for pre-C++20 systems. -template -using iterator_t = decltype(std::begin(std::declval())); -template using sentinel_t = decltype(std::end(std::declval())); +template +using iterator_t = decltype(std::begin(std::declval())); +template +using sentinel_t = decltype(std::end(std::declval())); // A workaround for std::string not having mutable data() until C++17. -template -inline auto get_data(std::basic_string& s) -> Char* { - return &s[0]; -} -template -inline auto get_data(Container& c) -> typename Container::value_type* { - return c.data(); -} +template +inline auto get_data(std::basic_string &s) -> Char * +{ return &s[0]; } +template +inline auto get_data(Container &c) -> typename Container::value_type * +{ return c.data(); } #if defined(_SECURE_SCL) && _SECURE_SCL // Make a checked iterator to avoid MSVC warnings. -template using checked_ptr = stdext::checked_array_iterator; -template -constexpr auto make_checked(T* p, size_t size) -> checked_ptr { - return {p, size}; -} +template +using checked_ptr = stdext::checked_array_iterator; +template +constexpr auto make_checked(T *p, size_t size) -> checked_ptr +{ return {p, size}; } #else -template using checked_ptr = T*; -template constexpr auto make_checked(T* p, size_t) -> T* { - return p; -} +template +using checked_ptr = T *; +template +constexpr auto make_checked(T *p, size_t) -> T * +{ return p; } #endif // Attempts to reserve space for n extra characters in the output range. // Returns a pointer to the reserved range or a reference to it. -template ::value)> +template::value)> #if FMT_CLANG_VERSION >= 307 && !FMT_ICC_VERSION __attribute__((no_sanitize("undefined"))) #endif -inline auto -reserve(std::back_insert_iterator it, size_t n) - -> checked_ptr { - Container& c = get_container(it); - size_t size = c.size(); - c.resize(size + n); - return make_checked(get_data(c) + size, n); -} - -template -inline auto reserve(buffer_appender it, size_t n) -> buffer_appender { - buffer& buf = get_container(it); - buf.try_reserve(buf.size() + n); - return it; +inline auto reserve(std::back_insert_iterator it, size_t n) -> checked_ptr +{ + Container &c = get_container(it); + size_t size = c.size(); + c.resize(size + n); + return make_checked(get_data(c) + size, n); +} + +template +inline auto reserve(buffer_appender it, size_t n) -> buffer_appender +{ + buffer &buf = get_container(it); + buf.try_reserve(buf.size() + n); + return it; } -template -constexpr auto reserve(Iterator& it, size_t) -> Iterator& { - return it; -} +template +constexpr auto reserve(Iterator &it, size_t) -> Iterator & +{ return it; } -template -using reserve_iterator = - remove_reference_t(), 0))>; +template +using reserve_iterator = remove_reference_t(), 0))>; -template -constexpr auto to_pointer(OutputIt, size_t) -> T* { - return nullptr; -} -template auto to_pointer(buffer_appender it, size_t n) -> T* { - buffer& buf = get_container(it); - auto size = buf.size(); - if (buf.capacity() < size + n) return nullptr; - buf.try_resize(size + n); - return buf.data() + size; +template +constexpr auto to_pointer(OutputIt, size_t) -> T * +{ return nullptr; } +template +auto to_pointer(buffer_appender it, size_t n) -> T * +{ + buffer &buf = get_container(it); + auto size = buf.size(); + if (buf.capacity() < size + n) + return nullptr; + buf.try_resize(size + n); + return buf.data() + size; } -template ::value)> -inline auto base_iterator(std::back_insert_iterator& it, - checked_ptr) - -> std::back_insert_iterator { - return it; -} +template::value)> +inline auto base_iterator(std::back_insert_iterator &it, checked_ptr) + -> std::back_insert_iterator +{ return it; } -template -constexpr auto base_iterator(Iterator, Iterator it) -> Iterator { - return it; -} +template +constexpr auto base_iterator(Iterator, Iterator it) -> Iterator +{ return it; } // is spectacularly slow to compile in C++20 so use a simple fill_n // instead (#1998). -template -FMT_CONSTEXPR auto fill_n(OutputIt out, Size count, const T& value) - -> OutputIt { - for (Size i = 0; i < count; ++i) *out++ = value; - return out; +template +FMT_CONSTEXPR auto fill_n(OutputIt out, Size count, const T &value) -> OutputIt +{ + for (Size i = 0; i < count; ++i) + *out++ = value; + return out; } -template -FMT_CONSTEXPR20 auto fill_n(T* out, Size count, char value) -> T* { - if (is_constant_evaluated()) { - return fill_n(out, count, value); - } - std::memset(out, value, to_unsigned(count)); - return out + count; +template +FMT_CONSTEXPR20 auto fill_n(T *out, Size count, char value) -> T * +{ + if (is_constant_evaluated()) + { + return fill_n(out, count, value); + } + std::memset(out, value, to_unsigned(count)); + return out + count; } #ifdef __cpp_char8_t using char8_type = char8_t; #else -enum char8_type : unsigned char {}; +enum char8_type : unsigned char +{ +}; #endif -template -FMT_CONSTEXPR FMT_NOINLINE auto copy_str_noinline(InputIt begin, InputIt end, - OutputIt out) -> OutputIt { - return copy_str(begin, end, out); -} +template +FMT_CONSTEXPR FMT_NOINLINE auto copy_str_noinline(InputIt begin, InputIt end, OutputIt out) -> OutputIt +{ return copy_str(begin, end, out); } // A public domain branchless UTF-8 decoder by Christopher Wellons: // https://github.com/skeeto/branchless-utf8 @@ -600,198 +631,212 @@ FMT_CONSTEXPR FMT_NOINLINE auto copy_str_noinline(InputIt begin, InputIt end, * occurs, this pointer will be a guess that depends on the particular * error, but it will always advance at least one byte. */ -FMT_CONSTEXPR inline auto utf8_decode(const char* s, uint32_t* c, int* e) - -> const char* { - constexpr const int masks[] = {0x00, 0x7f, 0x1f, 0x0f, 0x07}; - constexpr const uint32_t mins[] = {4194304, 0, 128, 2048, 65536}; - constexpr const int shiftc[] = {0, 18, 12, 6, 0}; - constexpr const int shifte[] = {0, 6, 4, 2, 0}; - - int len = code_point_length_impl(*s); - // Compute the pointer to the next character early so that the next - // iteration can start working on the next character. Neither Clang - // nor GCC figure out this reordering on their own. - const char* next = s + len + !len; - - using uchar = unsigned char; - - // Assume a four-byte character and load four bytes. Unused bits are - // shifted out. - *c = uint32_t(uchar(s[0]) & masks[len]) << 18; - *c |= uint32_t(uchar(s[1]) & 0x3f) << 12; - *c |= uint32_t(uchar(s[2]) & 0x3f) << 6; - *c |= uint32_t(uchar(s[3]) & 0x3f) << 0; - *c >>= shiftc[len]; - - // Accumulate the various error conditions. - *e = (*c < mins[len]) << 6; // non-canonical encoding - *e |= ((*c >> 11) == 0x1b) << 7; // surrogate half? - *e |= (*c > 0x10FFFF) << 8; // out of range? - *e |= (uchar(s[1]) & 0xc0) >> 2; - *e |= (uchar(s[2]) & 0xc0) >> 4; - *e |= uchar(s[3]) >> 6; - *e ^= 0x2a; // top two bits of each tail byte correct? - *e >>= shifte[len]; - - return next; +FMT_CONSTEXPR inline auto utf8_decode(const char *s, uint32_t *c, int *e) -> const char * +{ + constexpr const int masks[] = {0x00, 0x7f, 0x1f, 0x0f, 0x07}; + constexpr const uint32_t mins[] = {4194304, 0, 128, 2048, 65536}; + constexpr const int shiftc[] = {0, 18, 12, 6, 0}; + constexpr const int shifte[] = {0, 6, 4, 2, 0}; + + int len = code_point_length_impl(*s); + // Compute the pointer to the next character early so that the next + // iteration can start working on the next character. Neither Clang + // nor GCC figure out this reordering on their own. + const char *next = s + len + !len; + + using uchar = unsigned char; + + // Assume a four-byte character and load four bytes. Unused bits are + // shifted out. + *c = uint32_t(uchar(s[0]) & masks[len]) << 18; + *c |= uint32_t(uchar(s[1]) & 0x3f) << 12; + *c |= uint32_t(uchar(s[2]) & 0x3f) << 6; + *c |= uint32_t(uchar(s[3]) & 0x3f) << 0; + *c >>= shiftc[len]; + + // Accumulate the various error conditions. + *e = (*c < mins[len]) << 6; // non-canonical encoding + *e |= ((*c >> 11) == 0x1b) << 7; // surrogate half? + *e |= (*c > 0x10FFFF) << 8; // out of range? + *e |= (uchar(s[1]) & 0xc0) >> 2; + *e |= (uchar(s[2]) & 0xc0) >> 4; + *e |= uchar(s[3]) >> 6; + *e ^= 0x2a; // top two bits of each tail byte correct? + *e >>= shifte[len]; + + return next; } constexpr uint32_t invalid_code_point = ~uint32_t(); // Invokes f(cp, sv) for every code point cp in s with sv being the string view // corresponding to the code point. cp is invalid_code_point on error. -template -FMT_CONSTEXPR void for_each_codepoint(string_view s, F f) { - auto decode = [f](const char* buf_ptr, const char* ptr) { - auto cp = uint32_t(); - auto error = 0; - auto end = utf8_decode(buf_ptr, &cp, &error); - bool result = f(error ? invalid_code_point : cp, - string_view(ptr, error ? 1 : to_unsigned(end - buf_ptr))); - return result ? (error ? buf_ptr + 1 : end) : nullptr; - }; - auto p = s.data(); - const size_t block_size = 4; // utf8_decode always reads blocks of 4 chars. - if (s.size() >= block_size) { - for (auto end = p + s.size() - block_size + 1; p < end;) { - p = decode(p, p); - if (!p) return; - } - } - if (auto num_chars_left = s.data() + s.size() - p) { - char buf[2 * block_size - 1] = {}; - copy_str(p, p + num_chars_left, buf); - const char* buf_ptr = buf; - do { - auto end = decode(buf_ptr, p); - if (!end) return; - p += end - buf_ptr; - buf_ptr = end; - } while (buf_ptr - buf < num_chars_left); - } +template +FMT_CONSTEXPR void for_each_codepoint(string_view s, F f) +{ + auto decode = [f](const char *buf_ptr, const char *ptr) { + auto cp = uint32_t(); + auto error = 0; + auto end = utf8_decode(buf_ptr, &cp, &error); + bool result = f(error ? invalid_code_point : cp, string_view(ptr, error ? 1 : to_unsigned(end - buf_ptr))); + return result ? (error ? buf_ptr + 1 : end) : nullptr; + }; + auto p = s.data(); + const size_t block_size = 4; // utf8_decode always reads blocks of 4 chars. + if (s.size() >= block_size) + { + for (auto end = p + s.size() - block_size + 1; p < end;) + { + p = decode(p, p); + if (!p) + return; + } + } + if (auto num_chars_left = s.data() + s.size() - p) + { + char buf[2 * block_size - 1] = {}; + copy_str(p, p + num_chars_left, buf); + const char *buf_ptr = buf; + do + { + auto end = decode(buf_ptr, p); + if (!end) + return; + p += end - buf_ptr; + buf_ptr = end; + } while (buf_ptr - buf < num_chars_left); + } } -template -inline auto compute_width(basic_string_view s) -> size_t { - return s.size(); -} +template +inline auto compute_width(basic_string_view s) -> size_t +{ return s.size(); } // Computes approximate display width of a UTF-8 string. -FMT_CONSTEXPR inline size_t compute_width(string_view s) { - size_t num_code_points = 0; - // It is not a lambda for compatibility with C++14. - struct count_code_points { - size_t* count; - FMT_CONSTEXPR auto operator()(uint32_t cp, string_view) const -> bool { - *count += detail::to_unsigned( - 1 + - (cp >= 0x1100 && - (cp <= 0x115f || // Hangul Jamo init. consonants - cp == 0x2329 || // LEFT-POINTING ANGLE BRACKET - cp == 0x232a || // RIGHT-POINTING ANGLE BRACKET - // CJK ... Yi except IDEOGRAPHIC HALF FILL SPACE: - (cp >= 0x2e80 && cp <= 0xa4cf && cp != 0x303f) || - (cp >= 0xac00 && cp <= 0xd7a3) || // Hangul Syllables - (cp >= 0xf900 && cp <= 0xfaff) || // CJK Compatibility Ideographs - (cp >= 0xfe10 && cp <= 0xfe19) || // Vertical Forms - (cp >= 0xfe30 && cp <= 0xfe6f) || // CJK Compatibility Forms - (cp >= 0xff00 && cp <= 0xff60) || // Fullwidth Forms - (cp >= 0xffe0 && cp <= 0xffe6) || // Fullwidth Forms - (cp >= 0x20000 && cp <= 0x2fffd) || // CJK - (cp >= 0x30000 && cp <= 0x3fffd) || - // Miscellaneous Symbols and Pictographs + Emoticons: - (cp >= 0x1f300 && cp <= 0x1f64f) || - // Supplemental Symbols and Pictographs: - (cp >= 0x1f900 && cp <= 0x1f9ff)))); - return true; - } - }; - for_each_codepoint(s, count_code_points{&num_code_points}); - return num_code_points; +FMT_CONSTEXPR inline size_t compute_width(string_view s) +{ + size_t num_code_points = 0; + // It is not a lambda for compatibility with C++14. + struct count_code_points + { + size_t *count; + FMT_CONSTEXPR auto operator()(uint32_t cp, string_view) const -> bool + { + *count += detail::to_unsigned(1 + (cp >= 0x1100 && (cp <= 0x115f || // Hangul Jamo init. consonants + cp == 0x2329 || // LEFT-POINTING ANGLE BRACKET + cp == 0x232a || // RIGHT-POINTING ANGLE BRACKET + // CJK ... Yi except IDEOGRAPHIC HALF FILL SPACE: + (cp >= 0x2e80 && cp <= 0xa4cf && cp != 0x303f) || + (cp >= 0xac00 && cp <= 0xd7a3) || // Hangul Syllables + (cp >= 0xf900 && cp <= 0xfaff) || // CJK Compatibility Ideographs + (cp >= 0xfe10 && cp <= 0xfe19) || // Vertical Forms + (cp >= 0xfe30 && cp <= 0xfe6f) || // CJK Compatibility Forms + (cp >= 0xff00 && cp <= 0xff60) || // Fullwidth Forms + (cp >= 0xffe0 && cp <= 0xffe6) || // Fullwidth Forms + (cp >= 0x20000 && cp <= 0x2fffd) || // CJK + (cp >= 0x30000 && cp <= 0x3fffd) || + // Miscellaneous Symbols and Pictographs + Emoticons: + (cp >= 0x1f300 && cp <= 0x1f64f) || + // Supplemental Symbols and Pictographs: + (cp >= 0x1f900 && cp <= 0x1f9ff)))); + return true; + } + }; + for_each_codepoint(s, count_code_points{&num_code_points}); + return num_code_points; } -inline auto compute_width(basic_string_view s) -> size_t { - return compute_width( - string_view(reinterpret_cast(s.data()), s.size())); -} +inline auto compute_width(basic_string_view s) -> size_t +{ return compute_width(string_view(reinterpret_cast(s.data()), s.size())); } -template -inline auto code_point_index(basic_string_view s, size_t n) -> size_t { - size_t size = s.size(); - return n < size ? n : size; +template +inline auto code_point_index(basic_string_view s, size_t n) -> size_t +{ + size_t size = s.size(); + return n < size ? n : size; } // Calculates the index of the nth code point in a UTF-8 string. -inline auto code_point_index(string_view s, size_t n) -> size_t { - const char* data = s.data(); - size_t num_code_points = 0; - for (size_t i = 0, size = s.size(); i != size; ++i) { - if ((data[i] & 0xc0) != 0x80 && ++num_code_points > n) return i; - } - return s.size(); +inline auto code_point_index(string_view s, size_t n) -> size_t +{ + const char *data = s.data(); + size_t num_code_points = 0; + for (size_t i = 0, size = s.size(); i != size; ++i) + { + if ((data[i] & 0xc0) != 0x80 && ++num_code_points > n) + return i; + } + return s.size(); } -inline auto code_point_index(basic_string_view s, size_t n) - -> size_t { - return code_point_index( - string_view(reinterpret_cast(s.data()), s.size()), n); -} +inline auto code_point_index(basic_string_view s, size_t n) -> size_t +{ return code_point_index(string_view(reinterpret_cast(s.data()), s.size()), n); } #ifndef FMT_USE_FLOAT128 -# ifdef __SIZEOF_FLOAT128__ -# define FMT_USE_FLOAT128 1 -# else -# define FMT_USE_FLOAT128 0 -# endif +# ifdef __SIZEOF_FLOAT128__ +# define FMT_USE_FLOAT128 1 +# else +# define FMT_USE_FLOAT128 0 +# endif #endif #if FMT_USE_FLOAT128 using float128 = __float128; #else using float128 = void; #endif -template using is_float128 = std::is_same; +template +using is_float128 = std::is_same; -template -using is_floating_point = - bool_constant::value || is_float128::value>; +template +using is_floating_point = bool_constant::value || is_float128::value>; -template ::value> -struct is_fast_float : bool_constant::is_iec559 && - sizeof(T) <= sizeof(double)> {}; -template struct is_fast_float : std::false_type {}; +template::value> +struct is_fast_float : bool_constant::is_iec559 && sizeof(T) <= sizeof(double)> +{}; +template +struct is_fast_float : std::false_type +{}; -template +template using is_double_double = bool_constant::digits == 106>; #ifndef FMT_USE_FULL_CACHE_DRAGONBOX -# define FMT_USE_FULL_CACHE_DRAGONBOX 0 +# define FMT_USE_FULL_CACHE_DRAGONBOX 0 #endif -template -template -void buffer::append(const U* begin, const U* end) { - while (begin != end) { - auto count = to_unsigned(end - begin); - try_reserve(size_ + count); - auto free_cap = capacity_ - size_; - if (free_cap < count) count = free_cap; - std::uninitialized_copy_n(begin, count, make_checked(ptr_ + size_, count)); - size_ += count; - begin += count; - } +template +template +void buffer::append(const U *begin, const U *end) +{ + while (begin != end) + { + auto count = to_unsigned(end - begin); + try_reserve(size_ + count); + auto free_cap = capacity_ - size_; + if (free_cap < count) + count = free_cap; + std::uninitialized_copy_n(begin, count, make_checked(ptr_ + size_, count)); + size_ += count; + begin += count; + } } -template -struct is_locale : std::false_type {}; -template -struct is_locale> : std::true_type {}; -} // namespace detail +template +struct is_locale : std::false_type +{}; +template +struct is_locale> : std::true_type +{}; +} // namespace detail FMT_MODULE_EXPORT_BEGIN // The number of characters to store in the basic_memory_buffer object itself // to avoid dynamic memory allocation. -enum { inline_buffer_size = 500 }; +enum +{ + inline_buffer_size = 500 +}; /** \rst @@ -814,950 +859,1072 @@ enum { inline_buffer_size = 500 }; The output can be converted to an ``std::string`` with ``to_string(out)``. \endrst */ -template > -class basic_memory_buffer final : public detail::buffer { - private: - T store_[SIZE]; - - // Don't inherit from Allocator avoid generating type_info for it. - Allocator alloc_; - - // Deallocate memory allocated by the buffer. - FMT_CONSTEXPR20 void deallocate() { - T* data = this->data(); - if (data != store_) alloc_.deallocate(data, this->capacity()); - } - - protected: - FMT_CONSTEXPR20 void grow(size_t size) override; - - public: - using value_type = T; - using const_reference = const T&; - - FMT_CONSTEXPR20 explicit basic_memory_buffer( - const Allocator& alloc = Allocator()) - : alloc_(alloc) { - this->set(store_, SIZE); - if (detail::is_constant_evaluated()) detail::fill_n(store_, SIZE, T()); - } - FMT_CONSTEXPR20 ~basic_memory_buffer() { deallocate(); } - - private: - // Move data from other to this buffer. - FMT_CONSTEXPR20 void move(basic_memory_buffer& other) { - alloc_ = std::move(other.alloc_); - T* data = other.data(); - size_t size = other.size(), capacity = other.capacity(); - if (data == other.store_) { - this->set(store_, capacity); - detail::copy_str(other.store_, other.store_ + size, - detail::make_checked(store_, capacity)); - } else { - this->set(data, capacity); - // Set pointer to the inline array so that delete is not called - // when deallocating. - other.set(other.store_, 0); - other.clear(); - } - this->resize(size); - } - - public: - /** - \rst - Constructs a :class:`fmt::basic_memory_buffer` object moving the content - of the other object to it. - \endrst - */ - FMT_CONSTEXPR20 basic_memory_buffer(basic_memory_buffer&& other) noexcept { - move(other); - } - - /** - \rst - Moves the content of the other ``basic_memory_buffer`` object to this one. - \endrst - */ - auto operator=(basic_memory_buffer&& other) noexcept -> basic_memory_buffer& { - FMT_ASSERT(this != &other, ""); - deallocate(); - move(other); - return *this; - } - - // Returns a copy of the allocator associated with this buffer. - auto get_allocator() const -> Allocator { return alloc_; } - - /** - Resizes the buffer to contain *count* elements. If T is a POD type new - elements may not be initialized. - */ - FMT_CONSTEXPR20 void resize(size_t count) { this->try_resize(count); } - - /** Increases the buffer capacity to *new_capacity*. */ - void reserve(size_t new_capacity) { this->try_reserve(new_capacity); } - - // Directly append data into the buffer - using detail::buffer::append; - template - void append(const ContiguousRange& range) { - append(range.data(), range.data() + range.size()); - } +template> +class basic_memory_buffer final : public detail::buffer +{ +private: + T store_[SIZE]; + + // Don't inherit from Allocator avoid generating type_info for it. + Allocator alloc_; + + // Deallocate memory allocated by the buffer. + FMT_CONSTEXPR20 void deallocate() + { + T *data = this->data(); + if (data != store_) + alloc_.deallocate(data, this->capacity()); + } + +protected: + FMT_CONSTEXPR20 void grow(size_t size) override; + +public: + using value_type = T; + using const_reference = const T &; + + FMT_CONSTEXPR20 explicit basic_memory_buffer(const Allocator &alloc = Allocator()) + : alloc_(alloc) + { + this->set(store_, SIZE); + if (detail::is_constant_evaluated()) + detail::fill_n(store_, SIZE, T()); + } + FMT_CONSTEXPR20 ~basic_memory_buffer() + { deallocate(); } + +private: + // Move data from other to this buffer. + FMT_CONSTEXPR20 void move(basic_memory_buffer &other) + { + alloc_ = std::move(other.alloc_); + T *data = other.data(); + size_t size = other.size(), capacity = other.capacity(); + if (data == other.store_) + { + this->set(store_, capacity); + detail::copy_str(other.store_, other.store_ + size, detail::make_checked(store_, capacity)); + } + else + { + this->set(data, capacity); + // Set pointer to the inline array so that delete is not called + // when deallocating. + other.set(other.store_, 0); + other.clear(); + } + this->resize(size); + } + +public: + /** + \rst + Constructs a :class:`fmt::basic_memory_buffer` object moving the content + of the other object to it. + \endrst + */ + FMT_CONSTEXPR20 basic_memory_buffer(basic_memory_buffer &&other) noexcept + { move(other); } + + /** + \rst + Moves the content of the other ``basic_memory_buffer`` object to this one. + \endrst + */ + auto operator=(basic_memory_buffer &&other) noexcept -> basic_memory_buffer & + { + FMT_ASSERT(this != &other, ""); + deallocate(); + move(other); + return *this; + } + + // Returns a copy of the allocator associated with this buffer. + auto get_allocator() const -> Allocator + { return alloc_; } + + /** + Resizes the buffer to contain *count* elements. If T is a POD type new + elements may not be initialized. + */ + FMT_CONSTEXPR20 void resize(size_t count) + { this->try_resize(count); } + + /** Increases the buffer capacity to *new_capacity*. */ + void reserve(size_t new_capacity) + { this->try_reserve(new_capacity); } + + // Directly append data into the buffer + using detail::buffer::append; + template + void append(const ContiguousRange &range) + { append(range.data(), range.data() + range.size()); } }; -template -FMT_CONSTEXPR20 void basic_memory_buffer::grow( - size_t size) { - detail::abort_fuzzing_if(size > 5000); - const size_t max_size = std::allocator_traits::max_size(alloc_); - size_t old_capacity = this->capacity(); - size_t new_capacity = old_capacity + old_capacity / 2; - if (size > new_capacity) - new_capacity = size; - else if (new_capacity > max_size) - new_capacity = size > max_size ? size : max_size; - T* old_data = this->data(); - T* new_data = - std::allocator_traits::allocate(alloc_, new_capacity); - // The following code doesn't throw, so the raw pointer above doesn't leak. - std::uninitialized_copy(old_data, old_data + this->size(), - detail::make_checked(new_data, new_capacity)); - this->set(new_data, new_capacity); - // deallocate must not throw according to the standard, but even if it does, - // the buffer already uses the new storage and will deallocate it in - // destructor. - if (old_data != store_) alloc_.deallocate(old_data, old_capacity); +template +FMT_CONSTEXPR20 void basic_memory_buffer::grow(size_t size) +{ + detail::abort_fuzzing_if(size > 5000); + const size_t max_size = std::allocator_traits::max_size(alloc_); + size_t old_capacity = this->capacity(); + size_t new_capacity = old_capacity + old_capacity / 2; + if (size > new_capacity) + new_capacity = size; + else if (new_capacity > max_size) + new_capacity = size > max_size ? size : max_size; + T *old_data = this->data(); + T *new_data = std::allocator_traits::allocate(alloc_, new_capacity); + // The following code doesn't throw, so the raw pointer above doesn't leak. + std::uninitialized_copy(old_data, old_data + this->size(), detail::make_checked(new_data, new_capacity)); + this->set(new_data, new_capacity); + // deallocate must not throw according to the standard, but even if it does, + // the buffer already uses the new storage and will deallocate it in + // destructor. + if (old_data != store_) + alloc_.deallocate(old_data, old_capacity); } using memory_buffer = basic_memory_buffer; -template -struct is_contiguous> : std::true_type { -}; +template +struct is_contiguous> : std::true_type +{}; namespace detail { #ifdef _WIN32 -FMT_API bool write_console(std::FILE* f, string_view text); +FMT_API bool write_console(std::FILE *f, string_view text); #endif -FMT_API void print(std::FILE*, string_view); -} // namespace detail +FMT_API void print(std::FILE *, string_view); +} // namespace detail /** A formatting error such as invalid format string. */ FMT_CLASS_API -class FMT_API format_error : public std::runtime_error { - public: - explicit format_error(const char* message) : std::runtime_error(message) {} - explicit format_error(const std::string& message) - : std::runtime_error(message) {} - format_error(const format_error&) = default; - format_error& operator=(const format_error&) = default; - format_error(format_error&&) = default; - format_error& operator=(format_error&&) = default; - ~format_error() noexcept override FMT_MSC_DEFAULT; +class FMT_API format_error : public std::runtime_error +{ +public: + explicit format_error(const char *message) + : std::runtime_error(message) + {} + explicit format_error(const std::string &message) + : std::runtime_error(message) + {} + format_error(const format_error &) = default; + format_error &operator=(const format_error &) = default; + format_error(format_error &&) = default; + format_error &operator=(format_error &&) = default; + ~format_error() noexcept override FMT_MSC_DEFAULT; }; namespace detail_exported { #if FMT_USE_NONTYPE_TEMPLATE_ARGS -template struct fixed_string { - constexpr fixed_string(const Char (&str)[N]) { - detail::copy_str(static_cast(str), - str + N, data); - } - Char data[N] = {}; +template +struct fixed_string +{ + constexpr fixed_string(const Char (&str)[N]) + { detail::copy_str(static_cast(str), str + N, data); } + Char data[N] = {}; }; #endif // Converts a compile-time string to basic_string_view. -template -constexpr auto compile_string_to_view(const Char (&s)[N]) - -> basic_string_view { - // Remove trailing NUL character if needed. Won't be present if this is used - // with a raw character array (i.e. not defined as a string). - return {s, N - (std::char_traits::to_int_type(s[N - 1]) == 0 ? 1 : 0)}; -} -template -constexpr auto compile_string_to_view(detail::std_string_view s) - -> basic_string_view { - return {s.data(), s.size()}; -} -} // namespace detail_exported +template +constexpr auto compile_string_to_view(const Char (&s)[N]) -> basic_string_view +{ + // Remove trailing NUL character if needed. Won't be present if this is used + // with a raw character array (i.e. not defined as a string). + return {s, N - (std::char_traits::to_int_type(s[N - 1]) == 0 ? 1 : 0)}; +} +template +constexpr auto compile_string_to_view(detail::std_string_view s) -> basic_string_view +{ return {s.data(), s.size()}; } +} // namespace detail_exported FMT_BEGIN_DETAIL_NAMESPACE -template struct is_integral : std::is_integral {}; -template <> struct is_integral : std::true_type {}; -template <> struct is_integral : std::true_type {}; +template +struct is_integral : std::is_integral +{}; +template<> +struct is_integral : std::true_type +{}; +template<> +struct is_integral : std::true_type +{}; -template -using is_signed = - std::integral_constant::is_signed || - std::is_same::value>; +template +using is_signed = std::integral_constant::is_signed || std::is_same::value>; // Returns true if value is negative, false otherwise. // Same as `value < 0` but doesn't produce warnings if T is an unsigned type. -template ::value)> -constexpr auto is_negative(T value) -> bool { - return value < 0; -} -template ::value)> -constexpr auto is_negative(T) -> bool { - return false; -} - -template -FMT_CONSTEXPR auto is_supported_floating_point(T) -> bool { - if (std::is_same()) return FMT_USE_FLOAT; - if (std::is_same()) return FMT_USE_DOUBLE; - if (std::is_same()) return FMT_USE_LONG_DOUBLE; - return true; +template::value)> +constexpr auto is_negative(T value) -> bool +{ return value < 0; } +template::value)> +constexpr auto is_negative(T) -> bool +{ return false; } + +template +FMT_CONSTEXPR auto is_supported_floating_point(T) -> bool +{ + if (std::is_same()) + return FMT_USE_FLOAT; + if (std::is_same()) + return FMT_USE_DOUBLE; + if (std::is_same()) + return FMT_USE_LONG_DOUBLE; + return true; } // Smallest of uint32_t, uint64_t, uint128_t that is large enough to // represent all values of an integral type T. -template +template using uint32_or_64_or_128_t = - conditional_t() <= 32 && !FMT_REDUCE_INT_INSTANTIATIONS, - uint32_t, - conditional_t() <= 64, uint64_t, uint128_t>>; -template + conditional_t() <= 32 && !FMT_REDUCE_INT_INSTANTIATIONS, uint32_t, conditional_t() <= 64, uint64_t, uint128_t>>; +template using uint64_or_128_t = conditional_t() <= 64, uint64_t, uint128_t>; -#define FMT_POWERS_OF_10(factor) \ - factor * 10, (factor)*100, (factor)*1000, (factor)*10000, (factor)*100000, \ - (factor)*1000000, (factor)*10000000, (factor)*100000000, \ - (factor)*1000000000 +#define FMT_POWERS_OF_10(factor) \ + factor * 10, (factor) * 100, (factor) * 1000, (factor) * 10000, (factor) * 100000, (factor) * 1000000, (factor) * 10000000, \ + (factor) * 100000000, (factor) * 1000000000 // Converts value in the range [0, 100) to a string. -constexpr const char* digits2(size_t value) { - // GCC generates slightly better code when value is pointer-size. - return &"0001020304050607080910111213141516171819" - "2021222324252627282930313233343536373839" - "4041424344454647484950515253545556575859" - "6061626364656667686970717273747576777879" - "8081828384858687888990919293949596979899"[value * 2]; +constexpr const char *digits2(size_t value) +{ + // GCC generates slightly better code when value is pointer-size. + return &"0001020304050607080910111213141516171819" + "2021222324252627282930313233343536373839" + "4041424344454647484950515253545556575859" + "6061626364656667686970717273747576777879" + "8081828384858687888990919293949596979899"[value * 2]; } // Sign is a template parameter to workaround a bug in gcc 4.8. -template constexpr Char sign(Sign s) { +template +constexpr Char sign(Sign s) +{ #if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 604 - static_assert(std::is_same::value, ""); + static_assert(std::is_same::value, ""); #endif - return static_cast("\0-+ "[s]); -} - -template FMT_CONSTEXPR auto count_digits_fallback(T n) -> int { - int count = 1; - for (;;) { - // Integer division is slow so do it for a group of four digits instead - // of for every digit. The idea comes from the talk by Alexandrescu - // "Three Optimization Tips for C++". See speed-test for a comparison. - if (n < 10) return count; - if (n < 100) return count + 1; - if (n < 1000) return count + 2; - if (n < 10000) return count + 3; - n /= 10000u; - count += 4; - } + return static_cast("\0-+ "[s]); +} + +template +FMT_CONSTEXPR auto count_digits_fallback(T n) -> int +{ + int count = 1; + for (;;) + { + // Integer division is slow so do it for a group of four digits instead + // of for every digit. The idea comes from the talk by Alexandrescu + // "Three Optimization Tips for C++". See speed-test for a comparison. + if (n < 10) + return count; + if (n < 100) + return count + 1; + if (n < 1000) + return count + 2; + if (n < 10000) + return count + 3; + n /= 10000u; + count += 4; + } } #if FMT_USE_INT128 -FMT_CONSTEXPR inline auto count_digits(uint128_opt n) -> int { - return count_digits_fallback(n); -} +FMT_CONSTEXPR inline auto count_digits(uint128_opt n) -> int +{ return count_digits_fallback(n); } #endif #ifdef FMT_BUILTIN_CLZLL // It is a separate function rather than a part of count_digits to workaround // the lack of static constexpr in constexpr functions. -inline auto do_count_digits(uint64_t n) -> int { - // This has comparable performance to the version by Kendall Willets - // (https://github.com/fmtlib/format-benchmark/blob/master/digits10) - // but uses smaller tables. - // Maps bsr(n) to ceil(log10(pow(2, bsr(n) + 1) - 1)). - static constexpr uint8_t bsr2log10[] = { - 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, - 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, - 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 15, 15, - 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 19, 20}; - auto t = bsr2log10[FMT_BUILTIN_CLZLL(n | 1) ^ 63]; - static constexpr const uint64_t zero_or_powers_of_10[] = { - 0, 0, FMT_POWERS_OF_10(1U), FMT_POWERS_OF_10(1000000000ULL), - 10000000000000000000ULL}; - return t - (n < zero_or_powers_of_10[t]); +inline auto do_count_digits(uint64_t n) -> int +{ + // This has comparable performance to the version by Kendall Willets + // (https://github.com/fmtlib/format-benchmark/blob/master/digits10) + // but uses smaller tables. + // Maps bsr(n) to ceil(log10(pow(2, bsr(n) + 1) - 1)). + static constexpr uint8_t bsr2log10[] = {1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, + 10, 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 19, 20}; + auto t = bsr2log10[FMT_BUILTIN_CLZLL(n | 1) ^ 63]; + static constexpr const uint64_t zero_or_powers_of_10[] = { + 0, 0, FMT_POWERS_OF_10(1U), FMT_POWERS_OF_10(1000000000ULL), 10000000000000000000ULL}; + return t - (n < zero_or_powers_of_10[t]); } #endif // Returns the number of decimal digits in n. Leading zeros are not counted // except for n == 0 in which case count_digits returns 1. -FMT_CONSTEXPR20 inline auto count_digits(uint64_t n) -> int { +FMT_CONSTEXPR20 inline auto count_digits(uint64_t n) -> int +{ #ifdef FMT_BUILTIN_CLZLL - if (!is_constant_evaluated()) { - return do_count_digits(n); - } + if (!is_constant_evaluated()) + { + return do_count_digits(n); + } #endif - return count_digits_fallback(n); + return count_digits_fallback(n); } // Counts the number of digits in n. BITS = log2(radix). -template -FMT_CONSTEXPR auto count_digits(UInt n) -> int { +template +FMT_CONSTEXPR auto count_digits(UInt n) -> int +{ #ifdef FMT_BUILTIN_CLZ - if (!is_constant_evaluated() && num_bits() == 32) - return (FMT_BUILTIN_CLZ(static_cast(n) | 1) ^ 31) / BITS + 1; + if (!is_constant_evaluated() && num_bits() == 32) + return (FMT_BUILTIN_CLZ(static_cast(n) | 1) ^ 31) / BITS + 1; #endif - // Lambda avoids unreachable code warnings from NVHPC. - return [](UInt m) { - int num_digits = 0; - do { - ++num_digits; - } while ((m >>= BITS) != 0); - return num_digits; - }(n); + // Lambda avoids unreachable code warnings from NVHPC. + return [](UInt m) { + int num_digits = 0; + do + { + ++num_digits; + } while ((m >>= BITS) != 0); + return num_digits; + }(n); } #ifdef FMT_BUILTIN_CLZ // It is a separate function rather than a part of count_digits to workaround // the lack of static constexpr in constexpr functions. -FMT_INLINE auto do_count_digits(uint32_t n) -> int { +FMT_INLINE auto do_count_digits(uint32_t n) -> int +{ // An optimization by Kendall Willets from https://bit.ly/3uOIQrB. // This increments the upper 32 bits (log10(T) - 1) when >= T is added. -# define FMT_INC(T) (((sizeof(# T) - 1ull) << 32) - T) - static constexpr uint64_t table[] = { - FMT_INC(0), FMT_INC(0), FMT_INC(0), // 8 - FMT_INC(10), FMT_INC(10), FMT_INC(10), // 64 - FMT_INC(100), FMT_INC(100), FMT_INC(100), // 512 - FMT_INC(1000), FMT_INC(1000), FMT_INC(1000), // 4096 - FMT_INC(10000), FMT_INC(10000), FMT_INC(10000), // 32k - FMT_INC(100000), FMT_INC(100000), FMT_INC(100000), // 256k - FMT_INC(1000000), FMT_INC(1000000), FMT_INC(1000000), // 2048k - FMT_INC(10000000), FMT_INC(10000000), FMT_INC(10000000), // 16M - FMT_INC(100000000), FMT_INC(100000000), FMT_INC(100000000), // 128M - FMT_INC(1000000000), FMT_INC(1000000000), FMT_INC(1000000000), // 1024M - FMT_INC(1000000000), FMT_INC(1000000000) // 4B - }; - auto inc = table[FMT_BUILTIN_CLZ(n | 1) ^ 31]; - return static_cast((n + inc) >> 32); +# define FMT_INC(T) (((sizeof(#T) - 1ull) << 32) - T) + static constexpr uint64_t table[] = { + FMT_INC(0), FMT_INC(0), FMT_INC(0), // 8 + FMT_INC(10), FMT_INC(10), FMT_INC(10), // 64 + FMT_INC(100), FMT_INC(100), FMT_INC(100), // 512 + FMT_INC(1000), FMT_INC(1000), FMT_INC(1000), // 4096 + FMT_INC(10000), FMT_INC(10000), FMT_INC(10000), // 32k + FMT_INC(100000), FMT_INC(100000), FMT_INC(100000), // 256k + FMT_INC(1000000), FMT_INC(1000000), FMT_INC(1000000), // 2048k + FMT_INC(10000000), FMT_INC(10000000), FMT_INC(10000000), // 16M + FMT_INC(100000000), FMT_INC(100000000), FMT_INC(100000000), // 128M + FMT_INC(1000000000), FMT_INC(1000000000), FMT_INC(1000000000), // 1024M + FMT_INC(1000000000), FMT_INC(1000000000) // 4B + }; + auto inc = table[FMT_BUILTIN_CLZ(n | 1) ^ 31]; + return static_cast((n + inc) >> 32); } #endif // Optional version of count_digits for better performance on 32-bit platforms. -FMT_CONSTEXPR20 inline auto count_digits(uint32_t n) -> int { +FMT_CONSTEXPR20 inline auto count_digits(uint32_t n) -> int +{ #ifdef FMT_BUILTIN_CLZ - if (!is_constant_evaluated()) { - return do_count_digits(n); - } + if (!is_constant_evaluated()) + { + return do_count_digits(n); + } #endif - return count_digits_fallback(n); -} - -template constexpr auto digits10() noexcept -> int { - return std::numeric_limits::digits10; -} -template <> constexpr auto digits10() noexcept -> int { return 38; } -template <> constexpr auto digits10() noexcept -> int { return 38; } - -template struct thousands_sep_result { - std::string grouping; - Char thousands_sep; + return count_digits_fallback(n); +} + +template +constexpr auto digits10() noexcept -> int +{ return std::numeric_limits::digits10; } +template<> +constexpr auto digits10() noexcept -> int +{ return 38; } +template<> +constexpr auto digits10() noexcept -> int +{ return 38; } + +template +struct thousands_sep_result +{ + std::string grouping; + Char thousands_sep; }; -template +template FMT_API auto thousands_sep_impl(locale_ref loc) -> thousands_sep_result; -template -inline auto thousands_sep(locale_ref loc) -> thousands_sep_result { - auto result = thousands_sep_impl(loc); - return {result.grouping, Char(result.thousands_sep)}; -} -template <> -inline auto thousands_sep(locale_ref loc) -> thousands_sep_result { - return thousands_sep_impl(loc); +template +inline auto thousands_sep(locale_ref loc) -> thousands_sep_result +{ + auto result = thousands_sep_impl(loc); + return {result.grouping, Char(result.thousands_sep)}; } +template<> +inline auto thousands_sep(locale_ref loc) -> thousands_sep_result +{ return thousands_sep_impl(loc); } -template +template FMT_API auto decimal_point_impl(locale_ref loc) -> Char; -template inline auto decimal_point(locale_ref loc) -> Char { - return Char(decimal_point_impl(loc)); -} -template <> inline auto decimal_point(locale_ref loc) -> wchar_t { - return decimal_point_impl(loc); -} +template +inline auto decimal_point(locale_ref loc) -> Char +{ return Char(decimal_point_impl(loc)); } +template<> +inline auto decimal_point(locale_ref loc) -> wchar_t +{ return decimal_point_impl(loc); } // Compares two characters for equality. -template auto equal2(const Char* lhs, const char* rhs) -> bool { - return lhs[0] == Char(rhs[0]) && lhs[1] == Char(rhs[1]); -} -inline auto equal2(const char* lhs, const char* rhs) -> bool { - return memcmp(lhs, rhs, 2) == 0; -} +template +auto equal2(const Char *lhs, const char *rhs) -> bool +{ return lhs[0] == Char(rhs[0]) && lhs[1] == Char(rhs[1]); } +inline auto equal2(const char *lhs, const char *rhs) -> bool +{ return memcmp(lhs, rhs, 2) == 0; } // Copies two characters from src to dst. -template -FMT_CONSTEXPR20 FMT_INLINE void copy2(Char* dst, const char* src) { - if (!is_constant_evaluated() && sizeof(Char) == sizeof(char)) { - memcpy(dst, src, 2); - return; - } - *dst++ = static_cast(*src++); - *dst = static_cast(*src); +template +FMT_CONSTEXPR20 FMT_INLINE void copy2(Char *dst, const char *src) +{ + if (!is_constant_evaluated() && sizeof(Char) == sizeof(char)) + { + memcpy(dst, src, 2); + return; + } + *dst++ = static_cast(*src++); + *dst = static_cast(*src); } -template struct format_decimal_result { - Iterator begin; - Iterator end; +template +struct format_decimal_result +{ + Iterator begin; + Iterator end; }; // Formats a decimal unsigned integer value writing into out pointing to a // buffer of specified size. The caller must ensure that the buffer is large // enough. -template -FMT_CONSTEXPR20 auto format_decimal(Char* out, UInt value, int size) - -> format_decimal_result { - FMT_ASSERT(size >= count_digits(value), "invalid digit count"); - out += size; - Char* end = out; - while (value >= 100) { - // Integer division is slow so do it for a group of two digits instead - // of for every digit. The idea comes from the talk by Alexandrescu - // "Three Optimization Tips for C++". See speed-test for a comparison. +template +FMT_CONSTEXPR20 auto format_decimal(Char *out, UInt value, int size) -> format_decimal_result +{ + FMT_ASSERT(size >= count_digits(value), "invalid digit count"); + out += size; + Char *end = out; + while (value >= 100) + { + // Integer division is slow so do it for a group of two digits instead + // of for every digit. The idea comes from the talk by Alexandrescu + // "Three Optimization Tips for C++". See speed-test for a comparison. + out -= 2; + copy2(out, digits2(static_cast(value % 100))); + value /= 100; + } + if (value < 10) + { + *--out = static_cast('0' + value); + return {out, end}; + } out -= 2; - copy2(out, digits2(static_cast(value % 100))); - value /= 100; - } - if (value < 10) { - *--out = static_cast('0' + value); + copy2(out, digits2(static_cast(value))); return {out, end}; - } - out -= 2; - copy2(out, digits2(static_cast(value))); - return {out, end}; -} - -template >::value)> -FMT_CONSTEXPR inline auto format_decimal(Iterator out, UInt value, int size) - -> format_decimal_result { - // Buffer is large enough to hold all digits (digits10 + 1). - Char buffer[digits10() + 1]; - auto end = format_decimal(buffer, value, size).end; - return {out, detail::copy_str_noinline(buffer, end, out)}; -} - -template -FMT_CONSTEXPR auto format_uint(Char* buffer, UInt value, int num_digits, - bool upper = false) -> Char* { - buffer += num_digits; - Char* end = buffer; - do { - const char* digits = upper ? "0123456789ABCDEF" : "0123456789abcdef"; - unsigned digit = static_cast(value & ((1 << BASE_BITS) - 1)); - *--buffer = static_cast(BASE_BITS < 4 ? static_cast('0' + digit) - : digits[digit]); - } while ((value >>= BASE_BITS) != 0); - return end; } -template -inline auto format_uint(It out, UInt value, int num_digits, bool upper = false) - -> It { - if (auto ptr = to_pointer(out, to_unsigned(num_digits))) { - format_uint(ptr, value, num_digits, upper); - return out; - } - // Buffer should be large enough to hold all digits (digits / BASE_BITS + 1). - char buffer[num_bits() / BASE_BITS + 1]; - format_uint(buffer, value, num_digits, upper); - return detail::copy_str_noinline(buffer, buffer + num_digits, out); +template>::value)> +FMT_CONSTEXPR inline auto format_decimal(Iterator out, UInt value, int size) -> format_decimal_result +{ + // Buffer is large enough to hold all digits (digits10 + 1). + Char buffer[digits10() + 1]; + auto end = format_decimal(buffer, value, size).end; + return {out, detail::copy_str_noinline(buffer, end, out)}; +} + +template +FMT_CONSTEXPR auto format_uint(Char *buffer, UInt value, int num_digits, bool upper = false) -> Char * +{ + buffer += num_digits; + Char *end = buffer; + do + { + const char *digits = upper ? "0123456789ABCDEF" : "0123456789abcdef"; + unsigned digit = static_cast(value & ((1 << BASE_BITS) - 1)); + *--buffer = static_cast(BASE_BITS < 4 ? static_cast('0' + digit) : digits[digit]); + } while ((value >>= BASE_BITS) != 0); + return end; +} + +template +inline auto format_uint(It out, UInt value, int num_digits, bool upper = false) -> It +{ + if (auto ptr = to_pointer(out, to_unsigned(num_digits))) + { + format_uint(ptr, value, num_digits, upper); + return out; + } + // Buffer should be large enough to hold all digits (digits / BASE_BITS + 1). + char buffer[num_bits() / BASE_BITS + 1]; + format_uint(buffer, value, num_digits, upper); + return detail::copy_str_noinline(buffer, buffer + num_digits, out); } // A converter from UTF-8 to UTF-16. -class utf8_to_utf16 { - private: - basic_memory_buffer buffer_; - - public: - FMT_API explicit utf8_to_utf16(string_view s); - operator basic_string_view() const { return {&buffer_[0], size()}; } - auto size() const -> size_t { return buffer_.size() - 1; } - auto c_str() const -> const wchar_t* { return &buffer_[0]; } - auto str() const -> std::wstring { return {&buffer_[0], size()}; } +class utf8_to_utf16 +{ +private: + basic_memory_buffer buffer_; + +public: + FMT_API explicit utf8_to_utf16(string_view s); + operator basic_string_view() const + { return {&buffer_[0], size()}; } + auto size() const -> size_t + { return buffer_.size() - 1; } + auto c_str() const -> const wchar_t * + { return &buffer_[0]; } + auto str() const -> std::wstring + { return {&buffer_[0], size()}; } }; namespace dragonbox { // Type-specific information that Dragonbox uses. -template struct float_info; - -template <> struct float_info { - using carrier_uint = uint32_t; - static const int exponent_bits = 8; - static const int kappa = 1; - static const int big_divisor = 100; - static const int small_divisor = 10; - static const int min_k = -31; - static const int max_k = 46; - static const int shorter_interval_tie_lower_threshold = -35; - static const int shorter_interval_tie_upper_threshold = -35; +template +struct float_info; + +template<> +struct float_info +{ + using carrier_uint = uint32_t; + static const int exponent_bits = 8; + static const int kappa = 1; + static const int big_divisor = 100; + static const int small_divisor = 10; + static const int min_k = -31; + static const int max_k = 46; + static const int shorter_interval_tie_lower_threshold = -35; + static const int shorter_interval_tie_upper_threshold = -35; }; -template <> struct float_info { - using carrier_uint = uint64_t; - static const int exponent_bits = 11; - static const int kappa = 2; - static const int big_divisor = 1000; - static const int small_divisor = 100; - static const int min_k = -292; - static const int max_k = 326; - static const int shorter_interval_tie_lower_threshold = -77; - static const int shorter_interval_tie_upper_threshold = -77; +template<> +struct float_info +{ + using carrier_uint = uint64_t; + static const int exponent_bits = 11; + static const int kappa = 2; + static const int big_divisor = 1000; + static const int small_divisor = 100; + static const int min_k = -292; + static const int max_k = 326; + static const int shorter_interval_tie_lower_threshold = -77; + static const int shorter_interval_tie_upper_threshold = -77; }; // An 80- or 128-bit floating point number. -template -struct float_info::digits == 64 || - std::numeric_limits::digits == 113 || - is_float128::value>> { - using carrier_uint = detail::uint128_t; - static const int exponent_bits = 15; +template +struct float_info::digits == 64 || std::numeric_limits::digits == 113 || is_float128::value>> +{ + using carrier_uint = detail::uint128_t; + static const int exponent_bits = 15; }; // A double-double floating point number. -template -struct float_info::value>> { - using carrier_uint = detail::uint128_t; +template +struct float_info::value>> +{ + using carrier_uint = detail::uint128_t; }; -template struct decimal_fp { - using significand_type = typename float_info::carrier_uint; - significand_type significand; - int exponent; +template +struct decimal_fp +{ + using significand_type = typename float_info::carrier_uint; + significand_type significand; + int exponent; }; -template FMT_API auto to_decimal(T x) noexcept -> decimal_fp; -} // namespace dragonbox +template +FMT_API auto to_decimal(T x) noexcept -> decimal_fp; +} // namespace dragonbox // Returns true iff Float has the implicit bit which is not stored. -template constexpr bool has_implicit_bit() { - // An 80-bit FP number has a 64-bit significand an no implicit bit. - return std::numeric_limits::digits != 64; +template +constexpr bool has_implicit_bit() +{ + // An 80-bit FP number has a 64-bit significand an no implicit bit. + return std::numeric_limits::digits != 64; } // Returns the number of significand bits stored in Float. The implicit bit is // not counted since it is not stored. -template constexpr int num_significand_bits() { - // std::numeric_limits may not support __float128. - return is_float128() ? 112 - : (std::numeric_limits::digits - - (has_implicit_bit() ? 1 : 0)); +template +constexpr int num_significand_bits() +{ + // std::numeric_limits may not support __float128. + return is_float128() ? 112 : (std::numeric_limits::digits - (has_implicit_bit() ? 1 : 0)); } -template -constexpr auto exponent_mask() -> - typename dragonbox::float_info::carrier_uint { - using uint = typename dragonbox::float_info::carrier_uint; - return ((uint(1) << dragonbox::float_info::exponent_bits) - 1) - << num_significand_bits(); +template +constexpr auto exponent_mask() -> typename dragonbox::float_info::carrier_uint +{ + using uint = typename dragonbox::float_info::carrier_uint; + return ((uint(1) << dragonbox::float_info::exponent_bits) - 1) << num_significand_bits(); } -template constexpr auto exponent_bias() -> int { - // std::numeric_limits may not support __float128. - return is_float128() ? 16383 - : std::numeric_limits::max_exponent - 1; +template +constexpr auto exponent_bias() -> int +{ + // std::numeric_limits may not support __float128. + return is_float128() ? 16383 : std::numeric_limits::max_exponent - 1; } // Writes the exponent exp in the form "[+-]d{2,3}" to buffer. -template -FMT_CONSTEXPR auto write_exponent(int exp, It it) -> It { - FMT_ASSERT(-10000 < exp && exp < 10000, "exponent out of range"); - if (exp < 0) { - *it++ = static_cast('-'); - exp = -exp; - } else { - *it++ = static_cast('+'); - } - if (exp >= 100) { - const char* top = digits2(to_unsigned(exp / 100)); - if (exp >= 1000) *it++ = static_cast(top[0]); - *it++ = static_cast(top[1]); - exp %= 100; - } - const char* d = digits2(to_unsigned(exp)); - *it++ = static_cast(d[0]); - *it++ = static_cast(d[1]); - return it; +template +FMT_CONSTEXPR auto write_exponent(int exp, It it) -> It +{ + FMT_ASSERT(-10000 < exp && exp < 10000, "exponent out of range"); + if (exp < 0) + { + *it++ = static_cast('-'); + exp = -exp; + } + else + { + *it++ = static_cast('+'); + } + if (exp >= 100) + { + const char *top = digits2(to_unsigned(exp / 100)); + if (exp >= 1000) + *it++ = static_cast(top[0]); + *it++ = static_cast(top[1]); + exp %= 100; + } + const char *d = digits2(to_unsigned(exp)); + *it++ = static_cast(d[0]); + *it++ = static_cast(d[1]); + return it; } // A floating-point number f * pow(2, e) where F is an unsigned type. -template struct basic_fp { - F f; - int e; - - static constexpr const int num_significand_bits = - static_cast(sizeof(F) * num_bits()); - - constexpr basic_fp() : f(0), e(0) {} - constexpr basic_fp(uint64_t f_val, int e_val) : f(f_val), e(e_val) {} - - // Constructs fp from an IEEE754 floating-point number. - template FMT_CONSTEXPR basic_fp(Float n) { assign(n); } - - // Assigns n to this and return true iff predecessor is closer than successor. - template ::value)> - FMT_CONSTEXPR auto assign(Float n) -> bool { - static_assert(std::numeric_limits::digits <= 113, "unsupported FP"); - // Assume Float is in the format [sign][exponent][significand]. - using carrier_uint = typename dragonbox::float_info::carrier_uint; - const auto num_float_significand_bits = - detail::num_significand_bits(); - const auto implicit_bit = carrier_uint(1) << num_float_significand_bits; - const auto significand_mask = implicit_bit - 1; - auto u = bit_cast(n); - f = static_cast(u & significand_mask); - auto biased_e = static_cast((u & exponent_mask()) >> - num_float_significand_bits); - // The predecessor is closer if n is a normalized power of 2 (f == 0) - // other than the smallest normalized number (biased_e > 1). - auto is_predecessor_closer = f == 0 && biased_e > 1; - if (biased_e == 0) - biased_e = 1; // Subnormals use biased exponent 1 (min exponent). - else if (has_implicit_bit()) - f += static_cast(implicit_bit); - e = biased_e - exponent_bias() - num_float_significand_bits; - if (!has_implicit_bit()) ++e; - return is_predecessor_closer; - } - - template ::value)> - FMT_CONSTEXPR auto assign(Float n) -> bool { - static_assert(std::numeric_limits::is_iec559, "unsupported FP"); - return assign(static_cast(n)); - } +template +struct basic_fp +{ + F f; + int e; + + static constexpr const int num_significand_bits = static_cast(sizeof(F) * num_bits()); + + constexpr basic_fp() + : f(0) + , e(0) + {} + constexpr basic_fp(uint64_t f_val, int e_val) + : f(f_val) + , e(e_val) + {} + + // Constructs fp from an IEEE754 floating-point number. + template + FMT_CONSTEXPR basic_fp(Float n) + { assign(n); } + + // Assigns n to this and return true iff predecessor is closer than successor. + template::value)> + FMT_CONSTEXPR auto assign(Float n) -> bool + { + static_assert(std::numeric_limits::digits <= 113, "unsupported FP"); + // Assume Float is in the format [sign][exponent][significand]. + using carrier_uint = typename dragonbox::float_info::carrier_uint; + const auto num_float_significand_bits = detail::num_significand_bits(); + const auto implicit_bit = carrier_uint(1) << num_float_significand_bits; + const auto significand_mask = implicit_bit - 1; + auto u = bit_cast(n); + f = static_cast(u & significand_mask); + auto biased_e = static_cast((u & exponent_mask()) >> num_float_significand_bits); + // The predecessor is closer if n is a normalized power of 2 (f == 0) + // other than the smallest normalized number (biased_e > 1). + auto is_predecessor_closer = f == 0 && biased_e > 1; + if (biased_e == 0) + biased_e = 1; // Subnormals use biased exponent 1 (min exponent). + else if (has_implicit_bit()) + f += static_cast(implicit_bit); + e = biased_e - exponent_bias() - num_float_significand_bits; + if (!has_implicit_bit()) + ++e; + return is_predecessor_closer; + } + + template::value)> + FMT_CONSTEXPR auto assign(Float n) -> bool + { + static_assert(std::numeric_limits::is_iec559, "unsupported FP"); + return assign(static_cast(n)); + } }; using fp = basic_fp; // Normalizes the value converted from double and multiplied by (1 << SHIFT). -template -FMT_CONSTEXPR basic_fp normalize(basic_fp value) { - // Handle subnormals. - const auto implicit_bit = F(1) << num_significand_bits(); - const auto shifted_implicit_bit = implicit_bit << SHIFT; - while ((value.f & shifted_implicit_bit) == 0) { - value.f <<= 1; - --value.e; - } - // Subtract 1 to account for hidden bit. - const auto offset = basic_fp::num_significand_bits - - num_significand_bits() - SHIFT - 1; - value.f <<= offset; - value.e -= offset; - return value; +template +FMT_CONSTEXPR basic_fp normalize(basic_fp value) +{ + // Handle subnormals. + const auto implicit_bit = F(1) << num_significand_bits(); + const auto shifted_implicit_bit = implicit_bit << SHIFT; + while ((value.f & shifted_implicit_bit) == 0) + { + value.f <<= 1; + --value.e; + } + // Subtract 1 to account for hidden bit. + const auto offset = basic_fp::num_significand_bits - num_significand_bits() - SHIFT - 1; + value.f <<= offset; + value.e -= offset; + return value; } // Computes lhs * rhs / pow(2, 64) rounded to nearest with half-up tie breaking. -FMT_CONSTEXPR inline uint64_t multiply(uint64_t lhs, uint64_t rhs) { +FMT_CONSTEXPR inline uint64_t multiply(uint64_t lhs, uint64_t rhs) +{ #if FMT_USE_INT128 - auto product = static_cast<__uint128_t>(lhs) * rhs; - auto f = static_cast(product >> 64); - return (static_cast(product) & (1ULL << 63)) != 0 ? f + 1 : f; + auto product = static_cast<__uint128_t>(lhs) * rhs; + auto f = static_cast(product >> 64); + return (static_cast(product) & (1ULL << 63)) != 0 ? f + 1 : f; #else - // Multiply 32-bit parts of significands. - uint64_t mask = (1ULL << 32) - 1; - uint64_t a = lhs >> 32, b = lhs & mask; - uint64_t c = rhs >> 32, d = rhs & mask; - uint64_t ac = a * c, bc = b * c, ad = a * d, bd = b * d; - // Compute mid 64-bit of result and round. - uint64_t mid = (bd >> 32) + (ad & mask) + (bc & mask) + (1U << 31); - return ac + (ad >> 32) + (bc >> 32) + (mid >> 32); + // Multiply 32-bit parts of significands. + uint64_t mask = (1ULL << 32) - 1; + uint64_t a = lhs >> 32, b = lhs & mask; + uint64_t c = rhs >> 32, d = rhs & mask; + uint64_t ac = a * c, bc = b * c, ad = a * d, bd = b * d; + // Compute mid 64-bit of result and round. + uint64_t mid = (bd >> 32) + (ad & mask) + (bc & mask) + (1U << 31); + return ac + (ad >> 32) + (bc >> 32) + (mid >> 32); #endif } -FMT_CONSTEXPR inline fp operator*(fp x, fp y) { - return {multiply(x.f, y.f), x.e + y.e + 64}; -} - -template struct basic_data { - // Normalized 64-bit significands of pow(10, k), for k = -348, -340, ..., 340. - // These are generated by support/compute-powers.py. - static constexpr uint64_t pow10_significands[87] = { - 0xfa8fd5a0081c0288, 0xbaaee17fa23ebf76, 0x8b16fb203055ac76, - 0xcf42894a5dce35ea, 0x9a6bb0aa55653b2d, 0xe61acf033d1a45df, - 0xab70fe17c79ac6ca, 0xff77b1fcbebcdc4f, 0xbe5691ef416bd60c, - 0x8dd01fad907ffc3c, 0xd3515c2831559a83, 0x9d71ac8fada6c9b5, - 0xea9c227723ee8bcb, 0xaecc49914078536d, 0x823c12795db6ce57, - 0xc21094364dfb5637, 0x9096ea6f3848984f, 0xd77485cb25823ac7, - 0xa086cfcd97bf97f4, 0xef340a98172aace5, 0xb23867fb2a35b28e, - 0x84c8d4dfd2c63f3b, 0xc5dd44271ad3cdba, 0x936b9fcebb25c996, - 0xdbac6c247d62a584, 0xa3ab66580d5fdaf6, 0xf3e2f893dec3f126, - 0xb5b5ada8aaff80b8, 0x87625f056c7c4a8b, 0xc9bcff6034c13053, - 0x964e858c91ba2655, 0xdff9772470297ebd, 0xa6dfbd9fb8e5b88f, - 0xf8a95fcf88747d94, 0xb94470938fa89bcf, 0x8a08f0f8bf0f156b, - 0xcdb02555653131b6, 0x993fe2c6d07b7fac, 0xe45c10c42a2b3b06, - 0xaa242499697392d3, 0xfd87b5f28300ca0e, 0xbce5086492111aeb, - 0x8cbccc096f5088cc, 0xd1b71758e219652c, 0x9c40000000000000, - 0xe8d4a51000000000, 0xad78ebc5ac620000, 0x813f3978f8940984, - 0xc097ce7bc90715b3, 0x8f7e32ce7bea5c70, 0xd5d238a4abe98068, - 0x9f4f2726179a2245, 0xed63a231d4c4fb27, 0xb0de65388cc8ada8, - 0x83c7088e1aab65db, 0xc45d1df942711d9a, 0x924d692ca61be758, - 0xda01ee641a708dea, 0xa26da3999aef774a, 0xf209787bb47d6b85, - 0xb454e4a179dd1877, 0x865b86925b9bc5c2, 0xc83553c5c8965d3d, - 0x952ab45cfa97a0b3, 0xde469fbd99a05fe3, 0xa59bc234db398c25, - 0xf6c69a72a3989f5c, 0xb7dcbf5354e9bece, 0x88fcf317f22241e2, - 0xcc20ce9bd35c78a5, 0x98165af37b2153df, 0xe2a0b5dc971f303a, - 0xa8d9d1535ce3b396, 0xfb9b7cd9a4a7443c, 0xbb764c4ca7a44410, - 0x8bab8eefb6409c1a, 0xd01fef10a657842c, 0x9b10a4e5e9913129, - 0xe7109bfba19c0c9d, 0xac2820d9623bf429, 0x80444b5e7aa7cf85, - 0xbf21e44003acdd2d, 0x8e679c2f5e44ff8f, 0xd433179d9c8cb841, - 0x9e19db92b4e31ba9, 0xeb96bf6ebadf77d9, 0xaf87023b9bf0ee6b, - }; +FMT_CONSTEXPR inline fp operator*(fp x, fp y) +{ return {multiply(x.f, y.f), x.e + y.e + 64}; } + +template +struct basic_data +{ + // Normalized 64-bit significands of pow(10, k), for k = -348, -340, ..., 340. + // These are generated by support/compute-powers.py. + static constexpr uint64_t pow10_significands[87] = { + 0xfa8fd5a0081c0288, + 0xbaaee17fa23ebf76, + 0x8b16fb203055ac76, + 0xcf42894a5dce35ea, + 0x9a6bb0aa55653b2d, + 0xe61acf033d1a45df, + 0xab70fe17c79ac6ca, + 0xff77b1fcbebcdc4f, + 0xbe5691ef416bd60c, + 0x8dd01fad907ffc3c, + 0xd3515c2831559a83, + 0x9d71ac8fada6c9b5, + 0xea9c227723ee8bcb, + 0xaecc49914078536d, + 0x823c12795db6ce57, + 0xc21094364dfb5637, + 0x9096ea6f3848984f, + 0xd77485cb25823ac7, + 0xa086cfcd97bf97f4, + 0xef340a98172aace5, + 0xb23867fb2a35b28e, + 0x84c8d4dfd2c63f3b, + 0xc5dd44271ad3cdba, + 0x936b9fcebb25c996, + 0xdbac6c247d62a584, + 0xa3ab66580d5fdaf6, + 0xf3e2f893dec3f126, + 0xb5b5ada8aaff80b8, + 0x87625f056c7c4a8b, + 0xc9bcff6034c13053, + 0x964e858c91ba2655, + 0xdff9772470297ebd, + 0xa6dfbd9fb8e5b88f, + 0xf8a95fcf88747d94, + 0xb94470938fa89bcf, + 0x8a08f0f8bf0f156b, + 0xcdb02555653131b6, + 0x993fe2c6d07b7fac, + 0xe45c10c42a2b3b06, + 0xaa242499697392d3, + 0xfd87b5f28300ca0e, + 0xbce5086492111aeb, + 0x8cbccc096f5088cc, + 0xd1b71758e219652c, + 0x9c40000000000000, + 0xe8d4a51000000000, + 0xad78ebc5ac620000, + 0x813f3978f8940984, + 0xc097ce7bc90715b3, + 0x8f7e32ce7bea5c70, + 0xd5d238a4abe98068, + 0x9f4f2726179a2245, + 0xed63a231d4c4fb27, + 0xb0de65388cc8ada8, + 0x83c7088e1aab65db, + 0xc45d1df942711d9a, + 0x924d692ca61be758, + 0xda01ee641a708dea, + 0xa26da3999aef774a, + 0xf209787bb47d6b85, + 0xb454e4a179dd1877, + 0x865b86925b9bc5c2, + 0xc83553c5c8965d3d, + 0x952ab45cfa97a0b3, + 0xde469fbd99a05fe3, + 0xa59bc234db398c25, + 0xf6c69a72a3989f5c, + 0xb7dcbf5354e9bece, + 0x88fcf317f22241e2, + 0xcc20ce9bd35c78a5, + 0x98165af37b2153df, + 0xe2a0b5dc971f303a, + 0xa8d9d1535ce3b396, + 0xfb9b7cd9a4a7443c, + 0xbb764c4ca7a44410, + 0x8bab8eefb6409c1a, + 0xd01fef10a657842c, + 0x9b10a4e5e9913129, + 0xe7109bfba19c0c9d, + 0xac2820d9623bf429, + 0x80444b5e7aa7cf85, + 0xbf21e44003acdd2d, + 0x8e679c2f5e44ff8f, + 0xd433179d9c8cb841, + 0x9e19db92b4e31ba9, + 0xeb96bf6ebadf77d9, + 0xaf87023b9bf0ee6b, + }; #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wnarrowing" +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wnarrowing" #endif - // Binary exponents of pow(10, k), for k = -348, -340, ..., 340, corresponding - // to significands above. - static constexpr int16_t pow10_exponents[87] = { - -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, -954, - -927, -901, -874, -847, -821, -794, -768, -741, -715, -688, -661, - -635, -608, -582, -555, -529, -502, -475, -449, -422, -396, -369, - -343, -316, -289, -263, -236, -210, -183, -157, -130, -103, -77, - -50, -24, 3, 30, 56, 83, 109, 136, 162, 189, 216, - 242, 269, 295, 322, 348, 375, 402, 428, 455, 481, 508, - 534, 561, 588, 614, 641, 667, 694, 720, 747, 774, 800, - 827, 853, 880, 907, 933, 960, 986, 1013, 1039, 1066}; + // Binary exponents of pow(10, k), for k = -348, -340, ..., 340, corresponding + // to significands above. + static constexpr int16_t pow10_exponents[87] = {-1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, -954, -927, -901, + -874, -847, -821, -794, -768, -741, -715, -688, -661, -635, -608, -582, -555, -529, -502, -475, -449, -422, -396, -369, -343, -316, + -289, -263, -236, -210, -183, -157, -130, -103, -77, -50, -24, 3, 30, 56, 83, 109, 136, 162, 189, 216, 242, 269, 295, 322, 348, 375, + 402, 428, 455, 481, 508, 534, 561, 588, 614, 641, 667, 694, 720, 747, 774, 800, 827, 853, 880, 907, 933, 960, 986, 1013, 1039, + 1066}; #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 -# pragma GCC diagnostic pop +# pragma GCC diagnostic pop #endif - static constexpr uint64_t power_of_10_64[20] = { - 1, FMT_POWERS_OF_10(1ULL), FMT_POWERS_OF_10(1000000000ULL), - 10000000000000000000ULL}; + static constexpr uint64_t power_of_10_64[20] = {1, FMT_POWERS_OF_10(1ULL), FMT_POWERS_OF_10(1000000000ULL), 10000000000000000000ULL}; }; #if FMT_CPLUSPLUS < 201703L -template constexpr uint64_t basic_data::pow10_significands[]; -template constexpr int16_t basic_data::pow10_exponents[]; -template constexpr uint64_t basic_data::power_of_10_64[]; +template +constexpr uint64_t basic_data::pow10_significands[]; +template +constexpr int16_t basic_data::pow10_exponents[]; +template +constexpr uint64_t basic_data::power_of_10_64[]; #endif // This is a struct rather than an alias to avoid shadowing warnings in gcc. -struct data : basic_data<> {}; +struct data : basic_data<> +{}; // Returns a cached power of 10 `c_k = c_k.f * pow(2, c_k.e)` such that its // (binary) exponent satisfies `min_exponent <= c_k.e <= min_exponent + 28`. -FMT_CONSTEXPR inline fp get_cached_power(int min_exponent, - int& pow10_exponent) { - const int shift = 32; - // log10(2) = 0x0.4d104d427de7fbcc... - const int64_t significand = 0x4d104d427de7fbcc; - int index = static_cast( - ((min_exponent + fp::num_significand_bits - 1) * (significand >> shift) + - ((int64_t(1) << shift) - 1)) // ceil - >> 32 // arithmetic shift - ); - // Decimal exponent of the first (smallest) cached power of 10. - const int first_dec_exp = -348; - // Difference between 2 consecutive decimal exponents in cached powers of 10. - const int dec_exp_step = 8; - index = (index - first_dec_exp - 1) / dec_exp_step + 1; - pow10_exponent = first_dec_exp + index * dec_exp_step; - // Using *(x + index) instead of x[index] avoids an issue with some compilers - // using the EDG frontend (e.g. nvhpc/22.3 in C++17 mode). - return {*(data::pow10_significands + index), - *(data::pow10_exponents + index)}; +FMT_CONSTEXPR inline fp get_cached_power(int min_exponent, int &pow10_exponent) +{ + const int shift = 32; + // log10(2) = 0x0.4d104d427de7fbcc... + const int64_t significand = 0x4d104d427de7fbcc; + int index = + static_cast(((min_exponent + fp::num_significand_bits - 1) * (significand >> shift) + ((int64_t(1) << shift) - 1)) // ceil + >> 32 // arithmetic shift + ); + // Decimal exponent of the first (smallest) cached power of 10. + const int first_dec_exp = -348; + // Difference between 2 consecutive decimal exponents in cached powers of 10. + const int dec_exp_step = 8; + index = (index - first_dec_exp - 1) / dec_exp_step + 1; + pow10_exponent = first_dec_exp + index * dec_exp_step; + // Using *(x + index) instead of x[index] avoids an issue with some compilers + // using the EDG frontend (e.g. nvhpc/22.3 in C++17 mode). + return {*(data::pow10_significands + index), *(data::pow10_exponents + index)}; } #ifndef _MSC_VER -# define FMT_SNPRINTF snprintf +# define FMT_SNPRINTF snprintf #else -FMT_API auto fmt_snprintf(char* buf, size_t size, const char* fmt, ...) -> int; -# define FMT_SNPRINTF fmt_snprintf -#endif // _MSC_VER +FMT_API auto fmt_snprintf(char *buf, size_t size, const char *fmt, ...) -> int; +# define FMT_SNPRINTF fmt_snprintf +#endif // _MSC_VER // Formats a floating-point number with snprintf using the hexfloat format. -template -auto snprintf_float(T value, int precision, float_specs specs, - buffer& buf) -> int { - // Buffer capacity must be non-zero, otherwise MSVC's vsnprintf_s will fail. - FMT_ASSERT(buf.capacity() > buf.size(), "empty buffer"); - FMT_ASSERT(specs.format == float_format::hex, ""); - static_assert(!std::is_same::value, ""); - - // Build the format string. - char format[7]; // The longest format is "%#.*Le". - char* format_ptr = format; - *format_ptr++ = '%'; - if (specs.showpoint) *format_ptr++ = '#'; - if (precision >= 0) { - *format_ptr++ = '.'; - *format_ptr++ = '*'; - } - if (std::is_same()) *format_ptr++ = 'L'; - *format_ptr++ = specs.upper ? 'A' : 'a'; - *format_ptr = '\0'; - - // Format using snprintf. - auto offset = buf.size(); - for (;;) { - auto begin = buf.data() + offset; - auto capacity = buf.capacity() - offset; - abort_fuzzing_if(precision > 100000); - // Suppress the warning about a nonliteral format string. - // Cannot use auto because of a bug in MinGW (#1532). - int (*snprintf_ptr)(char*, size_t, const char*, ...) = FMT_SNPRINTF; - int result = precision >= 0 - ? snprintf_ptr(begin, capacity, format, precision, value) - : snprintf_ptr(begin, capacity, format, value); - if (result < 0) { - // The buffer will grow exponentially. - buf.try_reserve(buf.capacity() + 1); - continue; - } - auto size = to_unsigned(result); - // Size equal to capacity means that the last character was truncated. - if (size < capacity) { - buf.try_resize(size + offset); - return 0; - } - buf.try_reserve(size + offset + 1); // Add 1 for the terminating '\0'. - } +template +auto snprintf_float(T value, int precision, float_specs specs, buffer &buf) -> int +{ + // Buffer capacity must be non-zero, otherwise MSVC's vsnprintf_s will fail. + FMT_ASSERT(buf.capacity() > buf.size(), "empty buffer"); + FMT_ASSERT(specs.format == float_format::hex, ""); + static_assert(!std::is_same::value, ""); + + // Build the format string. + char format[7]; // The longest format is "%#.*Le". + char *format_ptr = format; + *format_ptr++ = '%'; + if (specs.showpoint) + *format_ptr++ = '#'; + if (precision >= 0) + { + *format_ptr++ = '.'; + *format_ptr++ = '*'; + } + if (std::is_same()) + *format_ptr++ = 'L'; + *format_ptr++ = specs.upper ? 'A' : 'a'; + *format_ptr = '\0'; + + // Format using snprintf. + auto offset = buf.size(); + for (;;) + { + auto begin = buf.data() + offset; + auto capacity = buf.capacity() - offset; + abort_fuzzing_if(precision > 100000); + // Suppress the warning about a nonliteral format string. + // Cannot use auto because of a bug in MinGW (#1532). + int (*snprintf_ptr)(char *, size_t, const char *, ...) = FMT_SNPRINTF; + int result = + precision >= 0 ? snprintf_ptr(begin, capacity, format, precision, value) : snprintf_ptr(begin, capacity, format, value); + if (result < 0) + { + // The buffer will grow exponentially. + buf.try_reserve(buf.capacity() + 1); + continue; + } + auto size = to_unsigned(result); + // Size equal to capacity means that the last character was truncated. + if (size < capacity) + { + buf.try_resize(size + offset); + return 0; + } + buf.try_reserve(size + offset + 1); // Add 1 for the terminating '\0'. + } } -template -using convert_float_result = - conditional_t::value || sizeof(T) == sizeof(double), - double, T>; +template +using convert_float_result = conditional_t::value || sizeof(T) == sizeof(double), double, T>; -template -constexpr auto convert_float(T value) -> convert_float_result { - return static_cast>(value); -} +template +constexpr auto convert_float(T value) -> convert_float_result +{ return static_cast>(value); } -template -FMT_NOINLINE FMT_CONSTEXPR auto fill(OutputIt it, size_t n, - const fill_t& fill) -> OutputIt { - auto fill_size = fill.size(); - if (fill_size == 1) return detail::fill_n(it, n, fill[0]); - auto data = fill.data(); - for (size_t i = 0; i < n; ++i) - it = copy_str(data, data + fill_size, it); - return it; +template +FMT_NOINLINE FMT_CONSTEXPR auto fill(OutputIt it, size_t n, const fill_t &fill) -> OutputIt +{ + auto fill_size = fill.size(); + if (fill_size == 1) + return detail::fill_n(it, n, fill[0]); + auto data = fill.data(); + for (size_t i = 0; i < n; ++i) + it = copy_str(data, data + fill_size, it); + return it; } // Writes the output of f, padded according to format specifications in specs. // size: output size in code units. // width: output display width in (terminal) column positions. -template -FMT_CONSTEXPR auto write_padded(OutputIt out, - const basic_format_specs& specs, - size_t size, size_t width, F&& f) -> OutputIt { - static_assert(align == align::left || align == align::right, ""); - unsigned spec_width = to_unsigned(specs.width); - size_t padding = spec_width > width ? spec_width - width : 0; - // Shifts are encoded as string literals because static constexpr is not - // supported in constexpr functions. - auto* shifts = align == align::left ? "\x1f\x1f\x00\x01" : "\x00\x1f\x00\x01"; - size_t left_padding = padding >> shifts[specs.align]; - size_t right_padding = padding - left_padding; - auto it = reserve(out, size + padding * specs.fill.size()); - if (left_padding != 0) it = fill(it, left_padding, specs.fill); - it = f(it); - if (right_padding != 0) it = fill(it, right_padding, specs.fill); - return base_iterator(out, it); -} - -template -constexpr auto write_padded(OutputIt out, const basic_format_specs& specs, - size_t size, F&& f) -> OutputIt { - return write_padded(out, specs, size, size, f); -} - -template -FMT_CONSTEXPR auto write_bytes(OutputIt out, string_view bytes, - const basic_format_specs& specs) - -> OutputIt { - return write_padded( - out, specs, bytes.size(), [bytes](reserve_iterator it) { - const char* data = bytes.data(); +template +FMT_CONSTEXPR auto write_padded(OutputIt out, const basic_format_specs &specs, size_t size, size_t width, F &&f) -> OutputIt +{ + static_assert(align == align::left || align == align::right, ""); + unsigned spec_width = to_unsigned(specs.width); + size_t padding = spec_width > width ? spec_width - width : 0; + // Shifts are encoded as string literals because static constexpr is not + // supported in constexpr functions. + auto *shifts = align == align::left ? "\x1f\x1f\x00\x01" : "\x00\x1f\x00\x01"; + size_t left_padding = padding >> shifts[specs.align]; + size_t right_padding = padding - left_padding; + auto it = reserve(out, size + padding * specs.fill.size()); + if (left_padding != 0) + it = fill(it, left_padding, specs.fill); + it = f(it); + if (right_padding != 0) + it = fill(it, right_padding, specs.fill); + return base_iterator(out, it); +} + +template +constexpr auto write_padded(OutputIt out, const basic_format_specs &specs, size_t size, F &&f) -> OutputIt +{ return write_padded(out, specs, size, size, f); } + +template +FMT_CONSTEXPR auto write_bytes(OutputIt out, string_view bytes, const basic_format_specs &specs) -> OutputIt +{ + return write_padded(out, specs, bytes.size(), [bytes](reserve_iterator it) { + const char *data = bytes.data(); return copy_str(data, data + bytes.size(), it); - }); + }); } -template -auto write_ptr(OutputIt out, UIntPtr value, - const basic_format_specs* specs) -> OutputIt { - int num_digits = count_digits<4>(value); - auto size = to_unsigned(num_digits) + size_t(2); - auto write = [=](reserve_iterator it) { - *it++ = static_cast('0'); - *it++ = static_cast('x'); - return format_uint<4, Char>(it, value, num_digits); - }; - return specs ? write_padded(out, *specs, size, write) - : base_iterator(out, write(reserve(out, size))); +template +auto write_ptr(OutputIt out, UIntPtr value, const basic_format_specs *specs) -> OutputIt +{ + int num_digits = count_digits<4>(value); + auto size = to_unsigned(num_digits) + size_t(2); + auto write = [=](reserve_iterator it) { + *it++ = static_cast('0'); + *it++ = static_cast('x'); + return format_uint<4, Char>(it, value, num_digits); + }; + return specs ? write_padded(out, *specs, size, write) : base_iterator(out, write(reserve(out, size))); } // Returns true iff the code point cp is printable. FMT_API auto is_printable(uint32_t cp) -> bool; -inline auto needs_escape(uint32_t cp) -> bool { - return cp < 0x20 || cp == 0x7f || cp == '"' || cp == '\\' || - !is_printable(cp); -} +inline auto needs_escape(uint32_t cp) -> bool +{ return cp < 0x20 || cp == 0x7f || cp == '"' || cp == '\\' || !is_printable(cp); } -template struct find_escape_result { - const Char* begin; - const Char* end; - uint32_t cp; +template +struct find_escape_result +{ + const Char *begin; + const Char *end; + uint32_t cp; }; -template -using make_unsigned_char = - typename conditional_t::value, - std::make_unsigned, - type_identity>::type; - -template -auto find_escape(const Char* begin, const Char* end) - -> find_escape_result { - for (; begin != end; ++begin) { - uint32_t cp = static_cast>(*begin); - if (const_check(sizeof(Char) == 1) && cp >= 0x80) continue; - if (needs_escape(cp)) return {begin, begin + 1, cp}; - } - return {begin, nullptr, 0}; -} - -inline auto find_escape(const char* begin, const char* end) - -> find_escape_result { - if (!is_utf8()) return find_escape(begin, end); - auto result = find_escape_result{end, nullptr, 0}; - for_each_codepoint(string_view(begin, to_unsigned(end - begin)), - [&](uint32_t cp, string_view sv) { - if (needs_escape(cp)) { - result = {sv.begin(), sv.end(), cp}; - return false; - } - return true; - }); - return result; +template +using make_unsigned_char = typename conditional_t::value, std::make_unsigned, type_identity>::type; + +template +auto find_escape(const Char *begin, const Char *end) -> find_escape_result +{ + for (; begin != end; ++begin) + { + uint32_t cp = static_cast>(*begin); + if (const_check(sizeof(Char) == 1) && cp >= 0x80) + continue; + if (needs_escape(cp)) + return {begin, begin + 1, cp}; + } + return {begin, nullptr, 0}; +} + +inline auto find_escape(const char *begin, const char *end) -> find_escape_result +{ + if (!is_utf8()) + return find_escape(begin, end); + auto result = find_escape_result{end, nullptr, 0}; + for_each_codepoint(string_view(begin, to_unsigned(end - begin)), [&](uint32_t cp, string_view sv) { + if (needs_escape(cp)) + { + result = {sv.begin(), sv.end(), cp}; + return false; + } + return true; + }); + return result; } -#define FMT_STRING_IMPL(s, base, explicit) \ - [] { \ - /* Use the hidden visibility as a workaround for a GCC bug (#1973). */ \ - /* Use a macro-like name to avoid shadowing warnings. */ \ - struct FMT_GCC_VISIBILITY_HIDDEN FMT_COMPILE_STRING : base { \ - using char_type FMT_MAYBE_UNUSED = fmt::remove_cvref_t; \ - FMT_MAYBE_UNUSED FMT_CONSTEXPR explicit \ - operator fmt::basic_string_view() const { \ - return fmt::detail_exported::compile_string_to_view(s); \ - } \ - }; \ - return FMT_COMPILE_STRING(); \ - }() +#define FMT_STRING_IMPL(s, base, explicit) \ + [] { \ + /* Use the hidden visibility as a workaround for a GCC bug (#1973). */ \ + /* Use a macro-like name to avoid shadowing warnings. */ \ + struct FMT_GCC_VISIBILITY_HIDDEN FMT_COMPILE_STRING : base \ + { \ + using char_type FMT_MAYBE_UNUSED = fmt::remove_cvref_t; \ + FMT_MAYBE_UNUSED FMT_CONSTEXPR explicit operator fmt::basic_string_view() const \ + { return fmt::detail_exported::compile_string_to_view(s); } \ + }; \ + return FMT_COMPILE_STRING(); \ + }() /** \rst @@ -1771,1835 +1938,1981 @@ inline auto find_escape(const char* begin, const char* end) */ #define FMT_STRING(s) FMT_STRING_IMPL(s, fmt::detail::compile_string, ) -template -auto write_codepoint(OutputIt out, char prefix, uint32_t cp) -> OutputIt { - *out++ = static_cast('\\'); - *out++ = static_cast(prefix); - Char buf[width]; - fill_n(buf, width, static_cast('0')); - format_uint<4>(buf, cp, width); - return copy_str(buf, buf + width, out); -} - -template -auto write_escaped_cp(OutputIt out, const find_escape_result& escape) - -> OutputIt { - auto c = static_cast(escape.cp); - switch (escape.cp) { - case '\n': - *out++ = static_cast('\\'); - c = static_cast('n'); - break; - case '\r': - *out++ = static_cast('\\'); - c = static_cast('r'); - break; - case '\t': - *out++ = static_cast('\\'); - c = static_cast('t'); - break; - case '"': - FMT_FALLTHROUGH; - case '\'': - FMT_FALLTHROUGH; - case '\\': +template +auto write_codepoint(OutputIt out, char prefix, uint32_t cp) -> OutputIt +{ *out++ = static_cast('\\'); - break; - default: - if (is_utf8()) { - if (escape.cp < 0x100) { - return write_codepoint<2, Char>(out, 'x', escape.cp); - } - if (escape.cp < 0x10000) { - return write_codepoint<4, Char>(out, 'u', escape.cp); - } - if (escape.cp < 0x110000) { - return write_codepoint<8, Char>(out, 'U', escape.cp); - } - } - for (Char escape_char : basic_string_view( - escape.begin, to_unsigned(escape.end - escape.begin))) { - out = write_codepoint<2, Char>(out, 'x', - static_cast(escape_char) & 0xFF); + *out++ = static_cast(prefix); + Char buf[width]; + fill_n(buf, width, static_cast('0')); + format_uint<4>(buf, cp, width); + return copy_str(buf, buf + width, out); +} + +template +auto write_escaped_cp(OutputIt out, const find_escape_result &escape) -> OutputIt +{ + auto c = static_cast(escape.cp); + switch (escape.cp) + { + case '\n': + *out++ = static_cast('\\'); + c = static_cast('n'); + break; + case '\r': + *out++ = static_cast('\\'); + c = static_cast('r'); + break; + case '\t': + *out++ = static_cast('\\'); + c = static_cast('t'); + break; + case '"': + FMT_FALLTHROUGH; + case '\'': + FMT_FALLTHROUGH; + case '\\': + *out++ = static_cast('\\'); + break; + default: + if (is_utf8()) + { + if (escape.cp < 0x100) + { + return write_codepoint<2, Char>(out, 'x', escape.cp); + } + if (escape.cp < 0x10000) + { + return write_codepoint<4, Char>(out, 'u', escape.cp); + } + if (escape.cp < 0x110000) + { + return write_codepoint<8, Char>(out, 'U', escape.cp); + } + } + for (Char escape_char : basic_string_view(escape.begin, to_unsigned(escape.end - escape.begin))) + { + out = write_codepoint<2, Char>(out, 'x', static_cast(escape_char) & 0xFF); + } + return out; } + *out++ = c; return out; - } - *out++ = c; - return out; } -template -auto write_escaped_string(OutputIt out, basic_string_view str) - -> OutputIt { - *out++ = static_cast('"'); - auto begin = str.begin(), end = str.end(); - do { - auto escape = find_escape(begin, end); - out = copy_str(begin, escape.begin, out); - begin = escape.end; - if (!begin) break; - out = write_escaped_cp(out, escape); - } while (begin != end); - *out++ = static_cast('"'); - return out; +template +auto write_escaped_string(OutputIt out, basic_string_view str) -> OutputIt +{ + *out++ = static_cast('"'); + auto begin = str.begin(), end = str.end(); + do + { + auto escape = find_escape(begin, end); + out = copy_str(begin, escape.begin, out); + begin = escape.end; + if (!begin) + break; + out = write_escaped_cp(out, escape); + } while (begin != end); + *out++ = static_cast('"'); + return out; } -template -auto write_escaped_char(OutputIt out, Char v) -> OutputIt { - *out++ = static_cast('\''); - if ((needs_escape(static_cast(v)) && v != static_cast('"')) || - v == static_cast('\'')) { - out = write_escaped_cp( - out, find_escape_result{&v, &v + 1, static_cast(v)}); - } else { - *out++ = v; - } - *out++ = static_cast('\''); - return out; +template +auto write_escaped_char(OutputIt out, Char v) -> OutputIt +{ + *out++ = static_cast('\''); + if ((needs_escape(static_cast(v)) && v != static_cast('"')) || v == static_cast('\'')) + { + out = write_escaped_cp(out, find_escape_result{&v, &v + 1, static_cast(v)}); + } + else + { + *out++ = v; + } + *out++ = static_cast('\''); + return out; } -template -FMT_CONSTEXPR auto write_char(OutputIt out, Char value, - const basic_format_specs& specs) - -> OutputIt { - bool is_debug = specs.type == presentation_type::debug; - return write_padded(out, specs, 1, [=](reserve_iterator it) { - if (is_debug) return write_escaped_char(it, value); - *it++ = value; - return it; - }); -} -template -FMT_CONSTEXPR auto write(OutputIt out, Char value, - const basic_format_specs& specs, - locale_ref loc = {}) -> OutputIt { - return check_char_specs(specs) - ? write_char(out, value, specs) - : write(out, static_cast(value), specs, loc); +template +FMT_CONSTEXPR auto write_char(OutputIt out, Char value, const basic_format_specs &specs) -> OutputIt +{ + bool is_debug = specs.type == presentation_type::debug; + return write_padded(out, specs, 1, [=](reserve_iterator it) { + if (is_debug) + return write_escaped_char(it, value); + *it++ = value; + return it; + }); } +template +FMT_CONSTEXPR auto write(OutputIt out, Char value, const basic_format_specs &specs, locale_ref loc = {}) -> OutputIt +{ return check_char_specs(specs) ? write_char(out, value, specs) : write(out, static_cast(value), specs, loc); } // Data for write_int that doesn't depend on output iterator type. It is used to // avoid template code bloat. -template struct write_int_data { - size_t size; - size_t padding; - - FMT_CONSTEXPR write_int_data(int num_digits, unsigned prefix, - const basic_format_specs& specs) - : size((prefix >> 24) + to_unsigned(num_digits)), padding(0) { - if (specs.align == align::numeric) { - auto width = to_unsigned(specs.width); - if (width > size) { - padding = width - size; - size = width; - } - } else if (specs.precision > num_digits) { - size = (prefix >> 24) + to_unsigned(specs.precision); - padding = to_unsigned(specs.precision - num_digits); - } - } +template +struct write_int_data +{ + size_t size; + size_t padding; + + FMT_CONSTEXPR write_int_data(int num_digits, unsigned prefix, const basic_format_specs &specs) + : size((prefix >> 24) + to_unsigned(num_digits)) + , padding(0) + { + if (specs.align == align::numeric) + { + auto width = to_unsigned(specs.width); + if (width > size) + { + padding = width - size; + size = width; + } + } + else if (specs.precision > num_digits) + { + size = (prefix >> 24) + to_unsigned(specs.precision); + padding = to_unsigned(specs.precision - num_digits); + } + } }; // Writes an integer in the format // // where are written by write_digits(it). // prefix contains chars in three lower bytes and the size in the fourth byte. -template -FMT_CONSTEXPR FMT_INLINE auto write_int(OutputIt out, int num_digits, - unsigned prefix, - const basic_format_specs& specs, - W write_digits) -> OutputIt { - // Slightly faster check for specs.width == 0 && specs.precision == -1. - if ((specs.width | (specs.precision + 1)) == 0) { - auto it = reserve(out, to_unsigned(num_digits) + (prefix >> 24)); - if (prefix != 0) { - for (unsigned p = prefix & 0xffffff; p != 0; p >>= 8) - *it++ = static_cast(p & 0xff); - } - return base_iterator(out, write_digits(it)); - } - auto data = write_int_data(num_digits, prefix, specs); - return write_padded( - out, specs, data.size, [=](reserve_iterator it) { +template +FMT_CONSTEXPR FMT_INLINE auto write_int( + OutputIt out, int num_digits, unsigned prefix, const basic_format_specs &specs, W write_digits) -> OutputIt +{ + // Slightly faster check for specs.width == 0 && specs.precision == -1. + if ((specs.width | (specs.precision + 1)) == 0) + { + auto it = reserve(out, to_unsigned(num_digits) + (prefix >> 24)); + if (prefix != 0) + { + for (unsigned p = prefix & 0xffffff; p != 0; p >>= 8) + *it++ = static_cast(p & 0xff); + } + return base_iterator(out, write_digits(it)); + } + auto data = write_int_data(num_digits, prefix, specs); + return write_padded(out, specs, data.size, [=](reserve_iterator it) { for (unsigned p = prefix & 0xffffff; p != 0; p >>= 8) - *it++ = static_cast(p & 0xff); + *it++ = static_cast(p & 0xff); it = detail::fill_n(it, data.padding, static_cast('0')); return write_digits(it); - }); + }); } -template class digit_grouping { - private: - thousands_sep_result sep_; - - struct next_state { - std::string::const_iterator group; - int pos; - }; - next_state initial_state() const { return {sep_.grouping.begin(), 0}; } - - // Returns the next digit group separator position. - int next(next_state& state) const { - if (!sep_.thousands_sep) return max_value(); - if (state.group == sep_.grouping.end()) - return state.pos += sep_.grouping.back(); - if (*state.group <= 0 || *state.group == max_value()) - return max_value(); - state.pos += *state.group++; - return state.pos; - } - - public: - explicit digit_grouping(locale_ref loc, bool localized = true) { - if (localized) - sep_ = thousands_sep(loc); - else - sep_.thousands_sep = Char(); - } - explicit digit_grouping(thousands_sep_result sep) : sep_(sep) {} - - Char separator() const { return sep_.thousands_sep; } - - int count_separators(int num_digits) const { - int count = 0; - auto state = initial_state(); - while (num_digits > next(state)) ++count; - return count; - } - - // Applies grouping to digits and write the output to out. - template - Out apply(Out out, basic_string_view digits) const { - auto num_digits = static_cast(digits.size()); - auto separators = basic_memory_buffer(); - separators.push_back(0); - auto state = initial_state(); - while (int i = next(state)) { - if (i >= num_digits) break; - separators.push_back(i); - } - for (int i = 0, sep_index = static_cast(separators.size() - 1); - i < num_digits; ++i) { - if (num_digits - i == separators[sep_index]) { - *out++ = separator(); - --sep_index; - } - *out++ = static_cast(digits[to_unsigned(i)]); +template +class digit_grouping +{ +private: + thousands_sep_result sep_; + + struct next_state + { + std::string::const_iterator group; + int pos; + }; + next_state initial_state() const + { return {sep_.grouping.begin(), 0}; } + + // Returns the next digit group separator position. + int next(next_state &state) const + { + if (!sep_.thousands_sep) + return max_value(); + if (state.group == sep_.grouping.end()) + return state.pos += sep_.grouping.back(); + if (*state.group <= 0 || *state.group == max_value()) + return max_value(); + state.pos += *state.group++; + return state.pos; + } + +public: + explicit digit_grouping(locale_ref loc, bool localized = true) + { + if (localized) + sep_ = thousands_sep(loc); + else + sep_.thousands_sep = Char(); + } + explicit digit_grouping(thousands_sep_result sep) + : sep_(sep) + {} + + Char separator() const + { return sep_.thousands_sep; } + + int count_separators(int num_digits) const + { + int count = 0; + auto state = initial_state(); + while (num_digits > next(state)) + ++count; + return count; + } + + // Applies grouping to digits and write the output to out. + template + Out apply(Out out, basic_string_view digits) const + { + auto num_digits = static_cast(digits.size()); + auto separators = basic_memory_buffer(); + separators.push_back(0); + auto state = initial_state(); + while (int i = next(state)) + { + if (i >= num_digits) + break; + separators.push_back(i); + } + for (int i = 0, sep_index = static_cast(separators.size() - 1); i < num_digits; ++i) + { + if (num_digits - i == separators[sep_index]) + { + *out++ = separator(); + --sep_index; + } + *out++ = static_cast(digits[to_unsigned(i)]); + } + return out; } - return out; - } }; -template -auto write_int_localized(OutputIt out, UInt value, unsigned prefix, - const basic_format_specs& specs, - const digit_grouping& grouping) -> OutputIt { - static_assert(std::is_same, UInt>::value, ""); - int num_digits = count_digits(value); - char digits[40]; - format_decimal(digits, value, num_digits); - unsigned size = to_unsigned((prefix != 0 ? 1 : 0) + num_digits + - grouping.count_separators(num_digits)); - return write_padded( - out, specs, size, size, [&](reserve_iterator it) { - if (prefix != 0) { - char sign = static_cast(prefix); - *it++ = static_cast(sign); +template +auto write_int_localized( + OutputIt out, UInt value, unsigned prefix, const basic_format_specs &specs, const digit_grouping &grouping) -> OutputIt +{ + static_assert(std::is_same, UInt>::value, ""); + int num_digits = count_digits(value); + char digits[40]; + format_decimal(digits, value, num_digits); + unsigned size = to_unsigned((prefix != 0 ? 1 : 0) + num_digits + grouping.count_separators(num_digits)); + return write_padded(out, specs, size, size, [&](reserve_iterator it) { + if (prefix != 0) + { + char sign = static_cast(prefix); + *it++ = static_cast(sign); } return grouping.apply(it, string_view(digits, to_unsigned(num_digits))); - }); + }); } -template -auto write_int_localized(OutputIt& out, UInt value, unsigned prefix, - const basic_format_specs& specs, locale_ref loc) - -> bool { - auto grouping = digit_grouping(loc); - out = write_int_localized(out, value, prefix, specs, grouping); - return true; +template +auto write_int_localized(OutputIt &out, UInt value, unsigned prefix, const basic_format_specs &specs, locale_ref loc) -> bool +{ + auto grouping = digit_grouping(loc); + out = write_int_localized(out, value, prefix, specs, grouping); + return true; } -FMT_CONSTEXPR inline void prefix_append(unsigned& prefix, unsigned value) { - prefix |= prefix != 0 ? value << 8 : value; - prefix += (1u + (value > 0xff ? 1 : 0)) << 24; +FMT_CONSTEXPR inline void prefix_append(unsigned &prefix, unsigned value) +{ + prefix |= prefix != 0 ? value << 8 : value; + prefix += (1u + (value > 0xff ? 1 : 0)) << 24; } -template struct write_int_arg { - UInt abs_value; - unsigned prefix; +template +struct write_int_arg +{ + UInt abs_value; + unsigned prefix; }; -template -FMT_CONSTEXPR auto make_write_int_arg(T value, sign_t sign) - -> write_int_arg> { - auto prefix = 0u; - auto abs_value = static_cast>(value); - if (is_negative(value)) { - prefix = 0x01000000 | '-'; - abs_value = 0 - abs_value; - } else { - constexpr const unsigned prefixes[4] = {0, 0, 0x1000000u | '+', - 0x1000000u | ' '}; - prefix = prefixes[sign]; - } - return {abs_value, prefix}; -} - -template -FMT_CONSTEXPR FMT_INLINE auto write_int(OutputIt out, write_int_arg arg, - const basic_format_specs& specs, - locale_ref loc) -> OutputIt { - static_assert(std::is_same>::value, ""); - auto abs_value = arg.abs_value; - auto prefix = arg.prefix; - switch (specs.type) { - case presentation_type::none: - case presentation_type::dec: { - if (specs.localized && - write_int_localized(out, static_cast>(abs_value), - prefix, specs, loc)) { - return out; - } - auto num_digits = count_digits(abs_value); - return write_int( - out, num_digits, prefix, specs, [=](reserve_iterator it) { - return format_decimal(it, abs_value, num_digits).end; - }); - } - case presentation_type::hex_lower: - case presentation_type::hex_upper: { - bool upper = specs.type == presentation_type::hex_upper; - if (specs.alt) - prefix_append(prefix, unsigned(upper ? 'X' : 'x') << 8 | '0'); - int num_digits = count_digits<4>(abs_value); - return write_int( - out, num_digits, prefix, specs, [=](reserve_iterator it) { - return format_uint<4, Char>(it, abs_value, num_digits, upper); - }); - } - case presentation_type::bin_lower: - case presentation_type::bin_upper: { - bool upper = specs.type == presentation_type::bin_upper; - if (specs.alt) - prefix_append(prefix, unsigned(upper ? 'B' : 'b') << 8 | '0'); - int num_digits = count_digits<1>(abs_value); - return write_int(out, num_digits, prefix, specs, - [=](reserve_iterator it) { - return format_uint<1, Char>(it, abs_value, num_digits); - }); - } - case presentation_type::oct: { - int num_digits = count_digits<3>(abs_value); - // Octal prefix '0' is counted as a digit, so only add it if precision - // is not greater than the number of digits. - if (specs.alt && specs.precision <= num_digits && abs_value != 0) - prefix_append(prefix, '0'); - return write_int(out, num_digits, prefix, specs, - [=](reserve_iterator it) { - return format_uint<3, Char>(it, abs_value, num_digits); - }); - } - case presentation_type::chr: - return write_char(out, static_cast(abs_value), specs); - default: - throw_format_error("invalid type specifier"); - } - return out; +template +FMT_CONSTEXPR auto make_write_int_arg(T value, sign_t sign) -> write_int_arg> +{ + auto prefix = 0u; + auto abs_value = static_cast>(value); + if (is_negative(value)) + { + prefix = 0x01000000 | '-'; + abs_value = 0 - abs_value; + } + else + { + constexpr const unsigned prefixes[4] = {0, 0, 0x1000000u | '+', 0x1000000u | ' '}; + prefix = prefixes[sign]; + } + return {abs_value, prefix}; +} + +template +FMT_CONSTEXPR FMT_INLINE auto write_int(OutputIt out, write_int_arg arg, const basic_format_specs &specs, locale_ref loc) + -> OutputIt +{ + static_assert(std::is_same>::value, ""); + auto abs_value = arg.abs_value; + auto prefix = arg.prefix; + switch (specs.type) + { + case presentation_type::none: + case presentation_type::dec: { + if (specs.localized && write_int_localized(out, static_cast>(abs_value), prefix, specs, loc)) + { + return out; + } + auto num_digits = count_digits(abs_value); + return write_int(out, num_digits, prefix, specs, + [=](reserve_iterator it) { return format_decimal(it, abs_value, num_digits).end; }); + } + case presentation_type::hex_lower: + case presentation_type::hex_upper: { + bool upper = specs.type == presentation_type::hex_upper; + if (specs.alt) + prefix_append(prefix, unsigned(upper ? 'X' : 'x') << 8 | '0'); + int num_digits = count_digits<4>(abs_value); + return write_int(out, num_digits, prefix, specs, + [=](reserve_iterator it) { return format_uint<4, Char>(it, abs_value, num_digits, upper); }); + } + case presentation_type::bin_lower: + case presentation_type::bin_upper: { + bool upper = specs.type == presentation_type::bin_upper; + if (specs.alt) + prefix_append(prefix, unsigned(upper ? 'B' : 'b') << 8 | '0'); + int num_digits = count_digits<1>(abs_value); + return write_int( + out, num_digits, prefix, specs, [=](reserve_iterator it) { return format_uint<1, Char>(it, abs_value, num_digits); }); + } + case presentation_type::oct: { + int num_digits = count_digits<3>(abs_value); + // Octal prefix '0' is counted as a digit, so only add it if precision + // is not greater than the number of digits. + if (specs.alt && specs.precision <= num_digits && abs_value != 0) + prefix_append(prefix, '0'); + return write_int( + out, num_digits, prefix, specs, [=](reserve_iterator it) { return format_uint<3, Char>(it, abs_value, num_digits); }); + } + case presentation_type::chr: + return write_char(out, static_cast(abs_value), specs); + default: + throw_format_error("invalid type specifier"); + } + return out; } -template +template FMT_CONSTEXPR FMT_NOINLINE auto write_int_noinline( - OutputIt out, write_int_arg arg, const basic_format_specs& specs, - locale_ref loc) -> OutputIt { - return write_int(out, arg, specs, loc); -} -template ::value && - !std::is_same::value && - std::is_same>::value)> -FMT_CONSTEXPR FMT_INLINE auto write(OutputIt out, T value, - const basic_format_specs& specs, - locale_ref loc) -> OutputIt { - return write_int_noinline(out, make_write_int_arg(value, specs.sign), specs, - loc); -} + OutputIt out, write_int_arg arg, const basic_format_specs &specs, locale_ref loc) -> OutputIt +{ return write_int(out, arg, specs, loc); } +template::value && !std::is_same::value && std::is_same>::value)> +FMT_CONSTEXPR FMT_INLINE auto write(OutputIt out, T value, const basic_format_specs &specs, locale_ref loc) -> OutputIt +{ return write_int_noinline(out, make_write_int_arg(value, specs.sign), specs, loc); } // An inlined version of write used in format string compilation. -template ::value && - !std::is_same::value && - !std::is_same>::value)> -FMT_CONSTEXPR FMT_INLINE auto write(OutputIt out, T value, - const basic_format_specs& specs, - locale_ref loc) -> OutputIt { - return write_int(out, make_write_int_arg(value, specs.sign), specs, loc); -} +template::value && !std::is_same::value && !std::is_same>::value)> +FMT_CONSTEXPR FMT_INLINE auto write(OutputIt out, T value, const basic_format_specs &specs, locale_ref loc) -> OutputIt +{ return write_int(out, make_write_int_arg(value, specs.sign), specs, loc); } // An output iterator that counts the number of objects written to it and // discards them. -class counting_iterator { - private: - size_t count_; - - public: - using iterator_category = std::output_iterator_tag; - using difference_type = std::ptrdiff_t; - using pointer = void; - using reference = void; - FMT_UNCHECKED_ITERATOR(counting_iterator); - - struct value_type { - template FMT_CONSTEXPR void operator=(const T&) {} - }; - - FMT_CONSTEXPR counting_iterator() : count_(0) {} - - FMT_CONSTEXPR size_t count() const { return count_; } - - FMT_CONSTEXPR counting_iterator& operator++() { - ++count_; - return *this; - } - FMT_CONSTEXPR counting_iterator operator++(int) { - auto it = *this; - ++*this; - return it; - } +class counting_iterator +{ +private: + size_t count_; + +public: + using iterator_category = std::output_iterator_tag; + using difference_type = std::ptrdiff_t; + using pointer = void; + using reference = void; + FMT_UNCHECKED_ITERATOR(counting_iterator); + + struct value_type + { + template + FMT_CONSTEXPR void operator=(const T &) + {} + }; - FMT_CONSTEXPR friend counting_iterator operator+(counting_iterator it, - difference_type n) { - it.count_ += static_cast(n); - return it; - } + FMT_CONSTEXPR counting_iterator() + : count_(0) + {} - FMT_CONSTEXPR value_type operator*() const { return {}; } -}; + FMT_CONSTEXPR size_t count() const + { return count_; } -template -FMT_CONSTEXPR auto write(OutputIt out, basic_string_view s, - const basic_format_specs& specs) -> OutputIt { - auto data = s.data(); - auto size = s.size(); - if (specs.precision >= 0 && to_unsigned(specs.precision) < size) - size = code_point_index(s, to_unsigned(specs.precision)); - bool is_debug = specs.type == presentation_type::debug; - size_t width = 0; - if (specs.width != 0) { - if (is_debug) - width = write_escaped_string(counting_iterator{}, s).count(); - else - width = compute_width(basic_string_view(data, size)); - } - return write_padded(out, specs, size, width, - [=](reserve_iterator it) { - if (is_debug) return write_escaped_string(it, s); - return copy_str(data, data + size, it); - }); -} -template -FMT_CONSTEXPR auto write(OutputIt out, - basic_string_view> s, - const basic_format_specs& specs, locale_ref) - -> OutputIt { - check_string_type_spec(specs.type); - return write(out, s, specs); -} -template -FMT_CONSTEXPR auto write(OutputIt out, const Char* s, - const basic_format_specs& specs, locale_ref) - -> OutputIt { - return check_cstring_type_spec(specs.type) - ? write(out, basic_string_view(s), specs, {}) - : write_ptr(out, bit_cast(s), &specs); -} - -template ::value && - !std::is_same::value && - !std::is_same::value)> -FMT_CONSTEXPR auto write(OutputIt out, T value) -> OutputIt { - auto abs_value = static_cast>(value); - bool negative = is_negative(value); - // Don't do -abs_value since it trips unsigned-integer-overflow sanitizer. - if (negative) abs_value = ~abs_value + 1; - int num_digits = count_digits(abs_value); - auto size = (negative ? 1 : 0) + static_cast(num_digits); - auto it = reserve(out, size); - if (auto ptr = to_pointer(it, size)) { - if (negative) *ptr++ = static_cast('-'); - format_decimal(ptr, abs_value, num_digits); - return out; - } - if (negative) *it++ = static_cast('-'); - it = format_decimal(it, abs_value, num_digits).end; - return base_iterator(out, it); -} + FMT_CONSTEXPR counting_iterator &operator++() + { + ++count_; + return *this; + } + FMT_CONSTEXPR counting_iterator operator++(int) + { + auto it = *this; + ++*this; + return it; + } -template -FMT_CONSTEXPR20 auto write_nonfinite(OutputIt out, bool isnan, - basic_format_specs specs, - const float_specs& fspecs) -> OutputIt { - auto str = - isnan ? (fspecs.upper ? "NAN" : "nan") : (fspecs.upper ? "INF" : "inf"); - constexpr size_t str_size = 3; - auto sign = fspecs.sign; - auto size = str_size + (sign ? 1 : 0); - // Replace '0'-padding with space for non-finite values. - const bool is_zero_fill = - specs.fill.size() == 1 && *specs.fill.data() == static_cast('0'); - if (is_zero_fill) specs.fill[0] = static_cast(' '); - return write_padded(out, specs, size, [=](reserve_iterator it) { - if (sign) *it++ = detail::sign(sign); - return copy_str(str, str + str_size, it); - }); -} + FMT_CONSTEXPR friend counting_iterator operator+(counting_iterator it, difference_type n) + { + it.count_ += static_cast(n); + return it; + } -// A decimal floating-point number significand * pow(10, exp). -struct big_decimal_fp { - const char* significand; - int significand_size; - int exponent; + FMT_CONSTEXPR value_type operator*() const + { return {}; } }; -constexpr auto get_significand_size(const big_decimal_fp& f) -> int { - return f.significand_size; -} -template -inline auto get_significand_size(const dragonbox::decimal_fp& f) -> int { - return count_digits(f.significand); -} - -template -constexpr auto write_significand(OutputIt out, const char* significand, - int significand_size) -> OutputIt { - return copy_str(significand, significand + significand_size, out); -} -template -inline auto write_significand(OutputIt out, UInt significand, - int significand_size) -> OutputIt { - return format_decimal(out, significand, significand_size).end; -} -template -FMT_CONSTEXPR20 auto write_significand(OutputIt out, T significand, - int significand_size, int exponent, - const Grouping& grouping) -> OutputIt { - if (!grouping.separator()) { - out = write_significand(out, significand, significand_size); - return detail::fill_n(out, exponent, static_cast('0')); - } - auto buffer = memory_buffer(); - write_significand(appender(buffer), significand, significand_size); - detail::fill_n(appender(buffer), exponent, '0'); - return grouping.apply(out, string_view(buffer.data(), buffer.size())); -} - -template ::value)> -inline auto write_significand(Char* out, UInt significand, int significand_size, - int integral_size, Char decimal_point) -> Char* { - if (!decimal_point) - return format_decimal(out, significand, significand_size).end; - out += significand_size + 1; - Char* end = out; - int floating_size = significand_size - integral_size; - for (int i = floating_size / 2; i > 0; --i) { - out -= 2; - copy2(out, digits2(static_cast(significand % 100))); - significand /= 100; - } - if (floating_size % 2 != 0) { - *--out = static_cast('0' + significand % 10); - significand /= 10; - } - *--out = decimal_point; - format_decimal(out - integral_size, significand, integral_size); - return end; -} - -template >::value)> -inline auto write_significand(OutputIt out, UInt significand, - int significand_size, int integral_size, - Char decimal_point) -> OutputIt { - // Buffer is large enough to hold digits (digits10 + 1) and a decimal point. - Char buffer[digits10() + 2]; - auto end = write_significand(buffer, significand, significand_size, - integral_size, decimal_point); - return detail::copy_str_noinline(buffer, end, out); +template +FMT_CONSTEXPR auto write(OutputIt out, basic_string_view s, const basic_format_specs &specs) -> OutputIt +{ + auto data = s.data(); + auto size = s.size(); + if (specs.precision >= 0 && to_unsigned(specs.precision) < size) + size = code_point_index(s, to_unsigned(specs.precision)); + bool is_debug = specs.type == presentation_type::debug; + size_t width = 0; + if (specs.width != 0) + { + if (is_debug) + width = write_escaped_string(counting_iterator{}, s).count(); + else + width = compute_width(basic_string_view(data, size)); + } + return write_padded(out, specs, size, width, [=](reserve_iterator it) { + if (is_debug) + return write_escaped_string(it, s); + return copy_str(data, data + size, it); + }); } - -template -FMT_CONSTEXPR auto write_significand(OutputIt out, const char* significand, - int significand_size, int integral_size, - Char decimal_point) -> OutputIt { - out = detail::copy_str_noinline(significand, - significand + integral_size, out); - if (!decimal_point) return out; - *out++ = decimal_point; - return detail::copy_str_noinline(significand + integral_size, - significand + significand_size, out); +template +FMT_CONSTEXPR auto write(OutputIt out, basic_string_view> s, const basic_format_specs &specs, locale_ref) + -> OutputIt +{ + check_string_type_spec(specs.type); + return write(out, s, specs); +} +template +FMT_CONSTEXPR auto write(OutputIt out, const Char *s, const basic_format_specs &specs, locale_ref) -> OutputIt +{ + return check_cstring_type_spec(specs.type) ? write(out, basic_string_view(s), specs, {}) + : write_ptr(out, bit_cast(s), &specs); +} + +template::value && !std::is_same::value && !std::is_same::value)> +FMT_CONSTEXPR auto write(OutputIt out, T value) -> OutputIt +{ + auto abs_value = static_cast>(value); + bool negative = is_negative(value); + // Don't do -abs_value since it trips unsigned-integer-overflow sanitizer. + if (negative) + abs_value = ~abs_value + 1; + int num_digits = count_digits(abs_value); + auto size = (negative ? 1 : 0) + static_cast(num_digits); + auto it = reserve(out, size); + if (auto ptr = to_pointer(it, size)) + { + if (negative) + *ptr++ = static_cast('-'); + format_decimal(ptr, abs_value, num_digits); + return out; + } + if (negative) + *it++ = static_cast('-'); + it = format_decimal(it, abs_value, num_digits).end; + return base_iterator(out, it); +} + +template +FMT_CONSTEXPR20 auto write_nonfinite(OutputIt out, bool isnan, basic_format_specs specs, const float_specs &fspecs) -> OutputIt +{ + auto str = isnan ? (fspecs.upper ? "NAN" : "nan") : (fspecs.upper ? "INF" : "inf"); + constexpr size_t str_size = 3; + auto sign = fspecs.sign; + auto size = str_size + (sign ? 1 : 0); + // Replace '0'-padding with space for non-finite values. + const bool is_zero_fill = specs.fill.size() == 1 && *specs.fill.data() == static_cast('0'); + if (is_zero_fill) + specs.fill[0] = static_cast(' '); + return write_padded(out, specs, size, [=](reserve_iterator it) { + if (sign) + *it++ = detail::sign(sign); + return copy_str(str, str + str_size, it); + }); } -template -FMT_CONSTEXPR20 auto write_significand(OutputIt out, T significand, - int significand_size, int integral_size, - Char decimal_point, - const Grouping& grouping) -> OutputIt { - if (!grouping.separator()) { - return write_significand(out, significand, significand_size, integral_size, - decimal_point); - } - auto buffer = basic_memory_buffer(); - write_significand(buffer_appender(buffer), significand, - significand_size, integral_size, decimal_point); - grouping.apply( - out, basic_string_view(buffer.data(), to_unsigned(integral_size))); - return detail::copy_str_noinline(buffer.data() + integral_size, - buffer.end(), out); -} +// A decimal floating-point number significand * pow(10, exp). +struct big_decimal_fp +{ + const char *significand; + int significand_size; + int exponent; +}; -template > -FMT_CONSTEXPR20 auto do_write_float(OutputIt out, const DecimalFP& f, - const basic_format_specs& specs, - float_specs fspecs, locale_ref loc) - -> OutputIt { - auto significand = f.significand; - int significand_size = get_significand_size(f); - const Char zero = static_cast('0'); - auto sign = fspecs.sign; - size_t size = to_unsigned(significand_size) + (sign ? 1 : 0); - using iterator = reserve_iterator; - - Char decimal_point = - fspecs.locale ? detail::decimal_point(loc) : static_cast('.'); - - int output_exp = f.exponent + significand_size - 1; - auto use_exp_format = [=]() { - if (fspecs.format == float_format::exp) return true; - if (fspecs.format != float_format::general) return false; - // Use the fixed notation if the exponent is in [exp_lower, exp_upper), - // e.g. 0.0001 instead of 1e-04. Otherwise use the exponent notation. - const int exp_lower = -4, exp_upper = 16; - return output_exp < exp_lower || - output_exp >= (fspecs.precision > 0 ? fspecs.precision : exp_upper); - }; - if (use_exp_format()) { - int num_zeros = 0; - if (fspecs.showpoint) { - num_zeros = fspecs.precision - significand_size; - if (num_zeros < 0) num_zeros = 0; - size += to_unsigned(num_zeros); - } else if (significand_size == 1) { - decimal_point = Char(); - } - auto abs_output_exp = output_exp >= 0 ? output_exp : -output_exp; - int exp_digits = 2; - if (abs_output_exp >= 100) exp_digits = abs_output_exp >= 1000 ? 4 : 3; - - size += to_unsigned((decimal_point ? 1 : 0) + 2 + exp_digits); - char exp_char = fspecs.upper ? 'E' : 'e'; - auto write = [=](iterator it) { - if (sign) *it++ = detail::sign(sign); - // Insert a decimal point after the first digit and add an exponent. - it = write_significand(it, significand, significand_size, 1, - decimal_point); - if (num_zeros > 0) it = detail::fill_n(it, num_zeros, zero); - *it++ = static_cast(exp_char); - return write_exponent(output_exp, it); +constexpr auto get_significand_size(const big_decimal_fp &f) -> int +{ return f.significand_size; } +template +inline auto get_significand_size(const dragonbox::decimal_fp &f) -> int +{ return count_digits(f.significand); } + +template +constexpr auto write_significand(OutputIt out, const char *significand, int significand_size) -> OutputIt +{ return copy_str(significand, significand + significand_size, out); } +template +inline auto write_significand(OutputIt out, UInt significand, int significand_size) -> OutputIt +{ return format_decimal(out, significand, significand_size).end; } +template +FMT_CONSTEXPR20 auto write_significand(OutputIt out, T significand, int significand_size, int exponent, const Grouping &grouping) + -> OutputIt +{ + if (!grouping.separator()) + { + out = write_significand(out, significand, significand_size); + return detail::fill_n(out, exponent, static_cast('0')); + } + auto buffer = memory_buffer(); + write_significand(appender(buffer), significand, significand_size); + detail::fill_n(appender(buffer), exponent, '0'); + return grouping.apply(out, string_view(buffer.data(), buffer.size())); +} + +template::value)> +inline auto write_significand(Char *out, UInt significand, int significand_size, int integral_size, Char decimal_point) -> Char * +{ + if (!decimal_point) + return format_decimal(out, significand, significand_size).end; + out += significand_size + 1; + Char *end = out; + int floating_size = significand_size - integral_size; + for (int i = floating_size / 2; i > 0; --i) + { + out -= 2; + copy2(out, digits2(static_cast(significand % 100))); + significand /= 100; + } + if (floating_size % 2 != 0) + { + *--out = static_cast('0' + significand % 10); + significand /= 10; + } + *--out = decimal_point; + format_decimal(out - integral_size, significand, integral_size); + return end; +} + +template>::value)> +inline auto write_significand(OutputIt out, UInt significand, int significand_size, int integral_size, Char decimal_point) -> OutputIt +{ + // Buffer is large enough to hold digits (digits10 + 1) and a decimal point. + Char buffer[digits10() + 2]; + auto end = write_significand(buffer, significand, significand_size, integral_size, decimal_point); + return detail::copy_str_noinline(buffer, end, out); +} + +template +FMT_CONSTEXPR auto write_significand(OutputIt out, const char *significand, int significand_size, int integral_size, Char decimal_point) + -> OutputIt +{ + out = detail::copy_str_noinline(significand, significand + integral_size, out); + if (!decimal_point) + return out; + *out++ = decimal_point; + return detail::copy_str_noinline(significand + integral_size, significand + significand_size, out); +} + +template +FMT_CONSTEXPR20 auto write_significand( + OutputIt out, T significand, int significand_size, int integral_size, Char decimal_point, const Grouping &grouping) -> OutputIt +{ + if (!grouping.separator()) + { + return write_significand(out, significand, significand_size, integral_size, decimal_point); + } + auto buffer = basic_memory_buffer(); + write_significand(buffer_appender(buffer), significand, significand_size, integral_size, decimal_point); + grouping.apply(out, basic_string_view(buffer.data(), to_unsigned(integral_size))); + return detail::copy_str_noinline(buffer.data() + integral_size, buffer.end(), out); +} + +template> +FMT_CONSTEXPR20 auto do_write_float( + OutputIt out, const DecimalFP &f, const basic_format_specs &specs, float_specs fspecs, locale_ref loc) -> OutputIt +{ + auto significand = f.significand; + int significand_size = get_significand_size(f); + const Char zero = static_cast('0'); + auto sign = fspecs.sign; + size_t size = to_unsigned(significand_size) + (sign ? 1 : 0); + using iterator = reserve_iterator; + + Char decimal_point = fspecs.locale ? detail::decimal_point(loc) : static_cast('.'); + + int output_exp = f.exponent + significand_size - 1; + auto use_exp_format = [=]() { + if (fspecs.format == float_format::exp) + return true; + if (fspecs.format != float_format::general) + return false; + // Use the fixed notation if the exponent is in [exp_lower, exp_upper), + // e.g. 0.0001 instead of 1e-04. Otherwise use the exponent notation. + const int exp_lower = -4, exp_upper = 16; + return output_exp < exp_lower || output_exp >= (fspecs.precision > 0 ? fspecs.precision : exp_upper); }; - return specs.width > 0 ? write_padded(out, specs, size, write) - : base_iterator(out, write(reserve(out, size))); - } - - int exp = f.exponent + significand_size; - if (f.exponent >= 0) { - // 1234e5 -> 123400000[.0+] - size += to_unsigned(f.exponent); - int num_zeros = fspecs.precision - exp; - abort_fuzzing_if(num_zeros > 5000); - if (fspecs.showpoint) { - ++size; - if (num_zeros <= 0 && fspecs.format != float_format::fixed) num_zeros = 1; - if (num_zeros > 0) size += to_unsigned(num_zeros); - } - auto grouping = Grouping(loc, fspecs.locale); - size += to_unsigned(grouping.count_separators(exp)); - return write_padded(out, specs, size, [&](iterator it) { - if (sign) *it++ = detail::sign(sign); - it = write_significand(it, significand, significand_size, - f.exponent, grouping); - if (!fspecs.showpoint) return it; - *it++ = decimal_point; - return num_zeros > 0 ? detail::fill_n(it, num_zeros, zero) : it; - }); - } else if (exp > 0) { - // 1234e-2 -> 12.34[0+] - int num_zeros = fspecs.showpoint ? fspecs.precision - significand_size : 0; - size += 1 + to_unsigned(num_zeros > 0 ? num_zeros : 0); - auto grouping = Grouping(loc, fspecs.locale); - size += to_unsigned(grouping.count_separators(significand_size)); + if (use_exp_format()) + { + int num_zeros = 0; + if (fspecs.showpoint) + { + num_zeros = fspecs.precision - significand_size; + if (num_zeros < 0) + num_zeros = 0; + size += to_unsigned(num_zeros); + } + else if (significand_size == 1) + { + decimal_point = Char(); + } + auto abs_output_exp = output_exp >= 0 ? output_exp : -output_exp; + int exp_digits = 2; + if (abs_output_exp >= 100) + exp_digits = abs_output_exp >= 1000 ? 4 : 3; + + size += to_unsigned((decimal_point ? 1 : 0) + 2 + exp_digits); + char exp_char = fspecs.upper ? 'E' : 'e'; + auto write = [=](iterator it) { + if (sign) + *it++ = detail::sign(sign); + // Insert a decimal point after the first digit and add an exponent. + it = write_significand(it, significand, significand_size, 1, decimal_point); + if (num_zeros > 0) + it = detail::fill_n(it, num_zeros, zero); + *it++ = static_cast(exp_char); + return write_exponent(output_exp, it); + }; + return specs.width > 0 ? write_padded(out, specs, size, write) : base_iterator(out, write(reserve(out, size))); + } + + int exp = f.exponent + significand_size; + if (f.exponent >= 0) + { + // 1234e5 -> 123400000[.0+] + size += to_unsigned(f.exponent); + int num_zeros = fspecs.precision - exp; + abort_fuzzing_if(num_zeros > 5000); + if (fspecs.showpoint) + { + ++size; + if (num_zeros <= 0 && fspecs.format != float_format::fixed) + num_zeros = 1; + if (num_zeros > 0) + size += to_unsigned(num_zeros); + } + auto grouping = Grouping(loc, fspecs.locale); + size += to_unsigned(grouping.count_separators(exp)); + return write_padded(out, specs, size, [&](iterator it) { + if (sign) + *it++ = detail::sign(sign); + it = write_significand(it, significand, significand_size, f.exponent, grouping); + if (!fspecs.showpoint) + return it; + *it++ = decimal_point; + return num_zeros > 0 ? detail::fill_n(it, num_zeros, zero) : it; + }); + } + else if (exp > 0) + { + // 1234e-2 -> 12.34[0+] + int num_zeros = fspecs.showpoint ? fspecs.precision - significand_size : 0; + size += 1 + to_unsigned(num_zeros > 0 ? num_zeros : 0); + auto grouping = Grouping(loc, fspecs.locale); + size += to_unsigned(grouping.count_separators(significand_size)); + return write_padded(out, specs, size, [&](iterator it) { + if (sign) + *it++ = detail::sign(sign); + it = write_significand(it, significand, significand_size, exp, decimal_point, grouping); + return num_zeros > 0 ? detail::fill_n(it, num_zeros, zero) : it; + }); + } + // 1234e-6 -> 0.001234 + int num_zeros = -exp; + if (significand_size == 0 && fspecs.precision >= 0 && fspecs.precision < num_zeros) + { + num_zeros = fspecs.precision; + } + bool pointy = num_zeros != 0 || significand_size != 0 || fspecs.showpoint; + size += 1 + (pointy ? 1 : 0) + to_unsigned(num_zeros); return write_padded(out, specs, size, [&](iterator it) { - if (sign) *it++ = detail::sign(sign); - it = write_significand(it, significand, significand_size, exp, - decimal_point, grouping); - return num_zeros > 0 ? detail::fill_n(it, num_zeros, zero) : it; + if (sign) + *it++ = detail::sign(sign); + *it++ = zero; + if (!pointy) + return it; + *it++ = decimal_point; + it = detail::fill_n(it, num_zeros, zero); + return write_significand(it, significand, significand_size); }); - } - // 1234e-6 -> 0.001234 - int num_zeros = -exp; - if (significand_size == 0 && fspecs.precision >= 0 && - fspecs.precision < num_zeros) { - num_zeros = fspecs.precision; - } - bool pointy = num_zeros != 0 || significand_size != 0 || fspecs.showpoint; - size += 1 + (pointy ? 1 : 0) + to_unsigned(num_zeros); - return write_padded(out, specs, size, [&](iterator it) { - if (sign) *it++ = detail::sign(sign); - *it++ = zero; - if (!pointy) return it; - *it++ = decimal_point; - it = detail::fill_n(it, num_zeros, zero); - return write_significand(it, significand, significand_size); - }); } -template class fallback_digit_grouping { - public: - constexpr fallback_digit_grouping(locale_ref, bool) {} +template +class fallback_digit_grouping +{ +public: + constexpr fallback_digit_grouping(locale_ref, bool) {} - constexpr Char separator() const { return Char(); } + constexpr Char separator() const + { return Char(); } - constexpr int count_separators(int) const { return 0; } + constexpr int count_separators(int) const + { return 0; } - template - constexpr Out apply(Out out, basic_string_view) const { - return out; - } + template + constexpr Out apply(Out out, basic_string_view) const + { return out; } }; -template -FMT_CONSTEXPR20 auto write_float(OutputIt out, const DecimalFP& f, - const basic_format_specs& specs, - float_specs fspecs, locale_ref loc) - -> OutputIt { - if (is_constant_evaluated()) { - return do_write_float>(out, f, specs, fspecs, - loc); - } else { - return do_write_float(out, f, specs, fspecs, loc); - } +template +FMT_CONSTEXPR20 auto write_float( + OutputIt out, const DecimalFP &f, const basic_format_specs &specs, float_specs fspecs, locale_ref loc) -> OutputIt +{ + if (is_constant_evaluated()) + { + return do_write_float>(out, f, specs, fspecs, loc); + } + else + { + return do_write_float(out, f, specs, fspecs, loc); + } } -template constexpr bool isnan(T value) { - return !(value >= value); // std::isnan doesn't support __float128. +template +constexpr bool isnan(T value) +{ + return !(value >= value); // std::isnan doesn't support __float128. } -template -struct has_isfinite : std::false_type {}; +template +struct has_isfinite : std::false_type +{}; -template -struct has_isfinite> - : std::true_type {}; +template +struct has_isfinite> : std::true_type +{}; -template ::value&& - has_isfinite::value)> -FMT_CONSTEXPR20 bool isfinite(T value) { - constexpr T inf = T(std::numeric_limits::infinity()); - if (is_constant_evaluated()) - return !detail::isnan(value) && value != inf && value != -inf; - return std::isfinite(value); +template::value &&has_isfinite::value)> +FMT_CONSTEXPR20 bool isfinite(T value) +{ + constexpr T inf = T(std::numeric_limits::infinity()); + if (is_constant_evaluated()) + return !detail::isnan(value) && value != inf && value != -inf; + return std::isfinite(value); } -template ::value)> -FMT_CONSTEXPR bool isfinite(T value) { - T inf = T(std::numeric_limits::infinity()); - // std::isfinite doesn't support __float128. - return !detail::isnan(value) && value != inf && value != -inf; +template::value)> +FMT_CONSTEXPR bool isfinite(T value) +{ + T inf = T(std::numeric_limits::infinity()); + // std::isfinite doesn't support __float128. + return !detail::isnan(value) && value != inf && value != -inf; } -template ::value)> -FMT_INLINE FMT_CONSTEXPR bool signbit(T value) { - if (is_constant_evaluated()) { +template::value)> +FMT_INLINE FMT_CONSTEXPR bool signbit(T value) +{ + if (is_constant_evaluated()) + { #ifdef __cpp_if_constexpr - if constexpr (std::numeric_limits::is_iec559) { - auto bits = detail::bit_cast(static_cast(value)); - return (bits >> (num_bits() - 1)) != 0; - } + if constexpr (std::numeric_limits::is_iec559) + { + auto bits = detail::bit_cast(static_cast(value)); + return (bits >> (num_bits() - 1)) != 0; + } #endif - } - return std::signbit(static_cast(value)); + } + return std::signbit(static_cast(value)); } -enum class round_direction { unknown, up, down }; +enum class round_direction +{ + unknown, + up, + down +}; // Given the divisor (normally a power of 10), the remainder = v % divisor for // some number v and the error, returns whether v should be rounded up, down, or // whether the rounding direction can't be determined due to error. // error should be less than divisor / 2. -FMT_CONSTEXPR inline round_direction get_round_direction(uint64_t divisor, - uint64_t remainder, - uint64_t error) { - FMT_ASSERT(remainder < divisor, ""); // divisor - remainder won't overflow. - FMT_ASSERT(error < divisor, ""); // divisor - error won't overflow. - FMT_ASSERT(error < divisor - error, ""); // error * 2 won't overflow. - // Round down if (remainder + error) * 2 <= divisor. - if (remainder <= divisor - remainder && error * 2 <= divisor - remainder * 2) - return round_direction::down; - // Round up if (remainder - error) * 2 >= divisor. - if (remainder >= error && - remainder - error >= divisor - (remainder - error)) { - return round_direction::up; - } - return round_direction::unknown; +FMT_CONSTEXPR inline round_direction get_round_direction(uint64_t divisor, uint64_t remainder, uint64_t error) +{ + FMT_ASSERT(remainder < divisor, ""); // divisor - remainder won't overflow. + FMT_ASSERT(error < divisor, ""); // divisor - error won't overflow. + FMT_ASSERT(error < divisor - error, ""); // error * 2 won't overflow. + // Round down if (remainder + error) * 2 <= divisor. + if (remainder <= divisor - remainder && error * 2 <= divisor - remainder * 2) + return round_direction::down; + // Round up if (remainder - error) * 2 >= divisor. + if (remainder >= error && remainder - error >= divisor - (remainder - error)) + { + return round_direction::up; + } + return round_direction::unknown; } namespace digits { -enum result { - more, // Generate more digits. - done, // Done generating digits. - error // Digit generation cancelled due to an error. +enum result +{ + more, // Generate more digits. + done, // Done generating digits. + error // Digit generation cancelled due to an error. }; } -struct gen_digits_handler { - char* buf; - int size; - int precision; - int exp10; - bool fixed; - - FMT_CONSTEXPR digits::result on_digit(char digit, uint64_t divisor, - uint64_t remainder, uint64_t error, - bool integral) { - FMT_ASSERT(remainder < divisor, ""); - buf[size++] = digit; - if (!integral && error >= remainder) return digits::error; - if (size < precision) return digits::more; - if (!integral) { - // Check if error * 2 < divisor with overflow prevention. - // The check is not needed for the integral part because error = 1 - // and divisor > (1 << 32) there. - if (error >= divisor || error >= divisor - error) return digits::error; - } else { - FMT_ASSERT(error == 1 && divisor > 2, ""); - } - auto dir = get_round_direction(divisor, remainder, error); - if (dir != round_direction::up) - return dir == round_direction::down ? digits::done : digits::error; - ++buf[size - 1]; - for (int i = size - 1; i > 0 && buf[i] > '9'; --i) { - buf[i] = '0'; - ++buf[i - 1]; - } - if (buf[0] > '9') { - buf[0] = '1'; - if (fixed) - buf[size++] = '0'; - else - ++exp10; - } - return digits::done; - } +struct gen_digits_handler +{ + char *buf; + int size; + int precision; + int exp10; + bool fixed; + + FMT_CONSTEXPR digits::result on_digit(char digit, uint64_t divisor, uint64_t remainder, uint64_t error, bool integral) + { + FMT_ASSERT(remainder < divisor, ""); + buf[size++] = digit; + if (!integral && error >= remainder) + return digits::error; + if (size < precision) + return digits::more; + if (!integral) + { + // Check if error * 2 < divisor with overflow prevention. + // The check is not needed for the integral part because error = 1 + // and divisor > (1 << 32) there. + if (error >= divisor || error >= divisor - error) + return digits::error; + } + else + { + FMT_ASSERT(error == 1 && divisor > 2, ""); + } + auto dir = get_round_direction(divisor, remainder, error); + if (dir != round_direction::up) + return dir == round_direction::down ? digits::done : digits::error; + ++buf[size - 1]; + for (int i = size - 1; i > 0 && buf[i] > '9'; --i) + { + buf[i] = '0'; + ++buf[i - 1]; + } + if (buf[0] > '9') + { + buf[0] = '1'; + if (fixed) + buf[size++] = '0'; + else + ++exp10; + } + return digits::done; + } }; -inline FMT_CONSTEXPR20 void adjust_precision(int& precision, int exp10) { - // Adjust fixed precision by exponent because it is relative to decimal - // point. - if (exp10 > 0 && precision > max_value() - exp10) - FMT_THROW(format_error("number is too big")); - precision += exp10; +inline FMT_CONSTEXPR20 void adjust_precision(int &precision, int exp10) +{ + // Adjust fixed precision by exponent because it is relative to decimal + // point. + if (exp10 > 0 && precision > max_value() - exp10) + FMT_THROW(format_error("number is too big")); + precision += exp10; } // Generates output using the Grisu digit-gen algorithm. // error: the size of the region (lower, upper) outside of which numbers // definitely do not round to value (Delta in Grisu3). -FMT_INLINE FMT_CONSTEXPR20 auto grisu_gen_digits(fp value, uint64_t error, - int& exp, - gen_digits_handler& handler) - -> digits::result { - const fp one(1ULL << -value.e, value.e); - // The integral part of scaled value (p1 in Grisu) = value / one. It cannot be - // zero because it contains a product of two 64-bit numbers with MSB set (due - // to normalization) - 1, shifted right by at most 60 bits. - auto integral = static_cast(value.f >> -one.e); - FMT_ASSERT(integral != 0, ""); - FMT_ASSERT(integral == value.f >> -one.e, ""); - // The fractional part of scaled value (p2 in Grisu) c = value % one. - uint64_t fractional = value.f & (one.f - 1); - exp = count_digits(integral); // kappa in Grisu. - // Non-fixed formats require at least one digit and no precision adjustment. - if (handler.fixed) { - adjust_precision(handler.precision, exp + handler.exp10); - // Check if precision is satisfied just by leading zeros, e.g. - // format("{:.2f}", 0.001) gives "0.00" without generating any digits. - if (handler.precision <= 0) { - if (handler.precision < 0) return digits::done; - // Divide by 10 to prevent overflow. - uint64_t divisor = data::power_of_10_64[exp - 1] << -one.e; - auto dir = get_round_direction(divisor, value.f / 10, error * 10); - if (dir == round_direction::unknown) return digits::error; - handler.buf[handler.size++] = dir == round_direction::up ? '1' : '0'; - return digits::done; - } - } - // Generate digits for the integral part. This can produce up to 10 digits. - do { - uint32_t digit = 0; - auto divmod_integral = [&](uint32_t divisor) { - digit = integral / divisor; - integral %= divisor; - }; - // This optimization by Milo Yip reduces the number of integer divisions by - // one per iteration. - switch (exp) { - case 10: - divmod_integral(1000000000); - break; - case 9: - divmod_integral(100000000); - break; - case 8: - divmod_integral(10000000); - break; - case 7: - divmod_integral(1000000); - break; - case 6: - divmod_integral(100000); - break; - case 5: - divmod_integral(10000); - break; - case 4: - divmod_integral(1000); - break; - case 3: - divmod_integral(100); - break; - case 2: - divmod_integral(10); - break; - case 1: - digit = integral; - integral = 0; - break; - default: - FMT_ASSERT(false, "invalid number of digits"); - } - --exp; - auto remainder = (static_cast(integral) << -one.e) + fractional; - auto result = handler.on_digit(static_cast('0' + digit), - data::power_of_10_64[exp] << -one.e, - remainder, error, true); - if (result != digits::more) return result; - } while (exp > 0); - // Generate digits for the fractional part. - for (;;) { - fractional *= 10; - error *= 10; - char digit = static_cast('0' + (fractional >> -one.e)); - fractional &= one.f - 1; - --exp; - auto result = handler.on_digit(digit, one.f, fractional, error, false); - if (result != digits::more) return result; - } +FMT_INLINE FMT_CONSTEXPR20 auto grisu_gen_digits(fp value, uint64_t error, int &exp, gen_digits_handler &handler) -> digits::result +{ + const fp one(1ULL << -value.e, value.e); + // The integral part of scaled value (p1 in Grisu) = value / one. It cannot be + // zero because it contains a product of two 64-bit numbers with MSB set (due + // to normalization) - 1, shifted right by at most 60 bits. + auto integral = static_cast(value.f >> -one.e); + FMT_ASSERT(integral != 0, ""); + FMT_ASSERT(integral == value.f >> -one.e, ""); + // The fractional part of scaled value (p2 in Grisu) c = value % one. + uint64_t fractional = value.f & (one.f - 1); + exp = count_digits(integral); // kappa in Grisu. + // Non-fixed formats require at least one digit and no precision adjustment. + if (handler.fixed) + { + adjust_precision(handler.precision, exp + handler.exp10); + // Check if precision is satisfied just by leading zeros, e.g. + // format("{:.2f}", 0.001) gives "0.00" without generating any digits. + if (handler.precision <= 0) + { + if (handler.precision < 0) + return digits::done; + // Divide by 10 to prevent overflow. + uint64_t divisor = data::power_of_10_64[exp - 1] << -one.e; + auto dir = get_round_direction(divisor, value.f / 10, error * 10); + if (dir == round_direction::unknown) + return digits::error; + handler.buf[handler.size++] = dir == round_direction::up ? '1' : '0'; + return digits::done; + } + } + // Generate digits for the integral part. This can produce up to 10 digits. + do + { + uint32_t digit = 0; + auto divmod_integral = [&](uint32_t divisor) { + digit = integral / divisor; + integral %= divisor; + }; + // This optimization by Milo Yip reduces the number of integer divisions by + // one per iteration. + switch (exp) + { + case 10: + divmod_integral(1000000000); + break; + case 9: + divmod_integral(100000000); + break; + case 8: + divmod_integral(10000000); + break; + case 7: + divmod_integral(1000000); + break; + case 6: + divmod_integral(100000); + break; + case 5: + divmod_integral(10000); + break; + case 4: + divmod_integral(1000); + break; + case 3: + divmod_integral(100); + break; + case 2: + divmod_integral(10); + break; + case 1: + digit = integral; + integral = 0; + break; + default: + FMT_ASSERT(false, "invalid number of digits"); + } + --exp; + auto remainder = (static_cast(integral) << -one.e) + fractional; + auto result = handler.on_digit(static_cast('0' + digit), data::power_of_10_64[exp] << -one.e, remainder, error, true); + if (result != digits::more) + return result; + } while (exp > 0); + // Generate digits for the fractional part. + for (;;) + { + fractional *= 10; + error *= 10; + char digit = static_cast('0' + (fractional >> -one.e)); + fractional &= one.f - 1; + --exp; + auto result = handler.on_digit(digit, one.f, fractional, error, false); + if (result != digits::more) + return result; + } } -class bigint { - private: - // A bigint is stored as an array of bigits (big digits), with bigit at index - // 0 being the least significant one. - using bigit = uint32_t; - using double_bigit = uint64_t; - enum { bigits_capacity = 32 }; - basic_memory_buffer bigits_; - int exp_; - - FMT_CONSTEXPR20 bigit operator[](int index) const { - return bigits_[to_unsigned(index)]; - } - FMT_CONSTEXPR20 bigit& operator[](int index) { - return bigits_[to_unsigned(index)]; - } - - static constexpr const int bigit_bits = num_bits(); - - friend struct formatter; - - FMT_CONSTEXPR20 void subtract_bigits(int index, bigit other, bigit& borrow) { - auto result = static_cast((*this)[index]) - other - borrow; - (*this)[index] = static_cast(result); - borrow = static_cast(result >> (bigit_bits * 2 - 1)); - } - - FMT_CONSTEXPR20 void remove_leading_zeros() { - int num_bigits = static_cast(bigits_.size()) - 1; - while (num_bigits > 0 && (*this)[num_bigits] == 0) --num_bigits; - bigits_.resize(to_unsigned(num_bigits + 1)); - } - - // Computes *this -= other assuming aligned bigints and *this >= other. - FMT_CONSTEXPR20 void subtract_aligned(const bigint& other) { - FMT_ASSERT(other.exp_ >= exp_, "unaligned bigints"); - FMT_ASSERT(compare(*this, other) >= 0, ""); - bigit borrow = 0; - int i = other.exp_ - exp_; - for (size_t j = 0, n = other.bigits_.size(); j != n; ++i, ++j) - subtract_bigits(i, other.bigits_[j], borrow); - while (borrow > 0) subtract_bigits(i, 0, borrow); - remove_leading_zeros(); - } - - FMT_CONSTEXPR20 void multiply(uint32_t value) { - const double_bigit wide_value = value; - bigit carry = 0; - for (size_t i = 0, n = bigits_.size(); i < n; ++i) { - double_bigit result = bigits_[i] * wide_value + carry; - bigits_[i] = static_cast(result); - carry = static_cast(result >> bigit_bits); - } - if (carry != 0) bigits_.push_back(carry); - } - - template ::value || - std::is_same::value)> - FMT_CONSTEXPR20 void multiply(UInt value) { - using half_uint = - conditional_t::value, uint64_t, uint32_t>; - const int shift = num_bits() - bigit_bits; - const UInt lower = static_cast(value); - const UInt upper = value >> num_bits(); - UInt carry = 0; - for (size_t i = 0, n = bigits_.size(); i < n; ++i) { - UInt result = lower * bigits_[i] + static_cast(carry); - carry = (upper * bigits_[i] << shift) + (result >> bigit_bits) + - (carry >> bigit_bits); - bigits_[i] = static_cast(result); - } - while (carry != 0) { - bigits_.push_back(static_cast(carry)); - carry >>= bigit_bits; - } - } - - template ::value || - std::is_same::value)> - FMT_CONSTEXPR20 void assign(UInt n) { - size_t num_bigits = 0; - do { - bigits_[num_bigits++] = static_cast(n); - n >>= bigit_bits; - } while (n != 0); - bigits_.resize(num_bigits); - exp_ = 0; - } - - public: - FMT_CONSTEXPR20 bigint() : exp_(0) {} - explicit bigint(uint64_t n) { assign(n); } - - bigint(const bigint&) = delete; - void operator=(const bigint&) = delete; - - FMT_CONSTEXPR20 void assign(const bigint& other) { - auto size = other.bigits_.size(); - bigits_.resize(size); - auto data = other.bigits_.data(); - std::copy(data, data + size, make_checked(bigits_.data(), size)); - exp_ = other.exp_; - } - - template FMT_CONSTEXPR20 void operator=(Int n) { - FMT_ASSERT(n > 0, ""); - assign(uint64_or_128_t(n)); - } - - FMT_CONSTEXPR20 int num_bigits() const { - return static_cast(bigits_.size()) + exp_; - } - - FMT_NOINLINE FMT_CONSTEXPR20 bigint& operator<<=(int shift) { - FMT_ASSERT(shift >= 0, ""); - exp_ += shift / bigit_bits; - shift %= bigit_bits; - if (shift == 0) return *this; - bigit carry = 0; - for (size_t i = 0, n = bigits_.size(); i < n; ++i) { - bigit c = bigits_[i] >> (bigit_bits - shift); - bigits_[i] = (bigits_[i] << shift) + carry; - carry = c; - } - if (carry != 0) bigits_.push_back(carry); - return *this; - } - - template FMT_CONSTEXPR20 bigint& operator*=(Int value) { - FMT_ASSERT(value > 0, ""); - multiply(uint32_or_64_or_128_t(value)); - return *this; - } - - friend FMT_CONSTEXPR20 int compare(const bigint& lhs, const bigint& rhs) { - int num_lhs_bigits = lhs.num_bigits(), num_rhs_bigits = rhs.num_bigits(); - if (num_lhs_bigits != num_rhs_bigits) - return num_lhs_bigits > num_rhs_bigits ? 1 : -1; - int i = static_cast(lhs.bigits_.size()) - 1; - int j = static_cast(rhs.bigits_.size()) - 1; - int end = i - j; - if (end < 0) end = 0; - for (; i >= end; --i, --j) { - bigit lhs_bigit = lhs[i], rhs_bigit = rhs[j]; - if (lhs_bigit != rhs_bigit) return lhs_bigit > rhs_bigit ? 1 : -1; - } - if (i != j) return i > j ? 1 : -1; - return 0; - } - - // Returns compare(lhs1 + lhs2, rhs). - friend FMT_CONSTEXPR20 int add_compare(const bigint& lhs1, const bigint& lhs2, - const bigint& rhs) { - auto minimum = [](int a, int b) { return a < b ? a : b; }; - auto maximum = [](int a, int b) { return a > b ? a : b; }; - int max_lhs_bigits = maximum(lhs1.num_bigits(), lhs2.num_bigits()); - int num_rhs_bigits = rhs.num_bigits(); - if (max_lhs_bigits + 1 < num_rhs_bigits) return -1; - if (max_lhs_bigits > num_rhs_bigits) return 1; - auto get_bigit = [](const bigint& n, int i) -> bigit { - return i >= n.exp_ && i < n.num_bigits() ? n[i - n.exp_] : 0; +class bigint +{ +private: + // A bigint is stored as an array of bigits (big digits), with bigit at index + // 0 being the least significant one. + using bigit = uint32_t; + using double_bigit = uint64_t; + enum + { + bigits_capacity = 32 }; - double_bigit borrow = 0; - int min_exp = minimum(minimum(lhs1.exp_, lhs2.exp_), rhs.exp_); - for (int i = num_rhs_bigits - 1; i >= min_exp; --i) { - double_bigit sum = - static_cast(get_bigit(lhs1, i)) + get_bigit(lhs2, i); - bigit rhs_bigit = get_bigit(rhs, i); - if (sum > rhs_bigit + borrow) return 1; - borrow = rhs_bigit + borrow - sum; - if (borrow > 1) return -1; - borrow <<= bigit_bits; - } - return borrow != 0 ? -1 : 0; - } - - // Assigns pow(10, exp) to this bigint. - FMT_CONSTEXPR20 void assign_pow10(int exp) { - FMT_ASSERT(exp >= 0, ""); - if (exp == 0) return *this = 1; - // Find the top bit. - int bitmask = 1; - while (exp >= bitmask) bitmask <<= 1; - bitmask >>= 1; - // pow(10, exp) = pow(5, exp) * pow(2, exp). First compute pow(5, exp) by - // repeated squaring and multiplication. - *this = 5; - bitmask >>= 1; - while (bitmask != 0) { - square(); - if ((exp & bitmask) != 0) *this *= 5; - bitmask >>= 1; - } - *this <<= exp; // Multiply by pow(2, exp) by shifting. - } - - FMT_CONSTEXPR20 void square() { - int num_bigits = static_cast(bigits_.size()); - int num_result_bigits = 2 * num_bigits; - basic_memory_buffer n(std::move(bigits_)); - bigits_.resize(to_unsigned(num_result_bigits)); - auto sum = uint128_t(); - for (int bigit_index = 0; bigit_index < num_bigits; ++bigit_index) { - // Compute bigit at position bigit_index of the result by adding - // cross-product terms n[i] * n[j] such that i + j == bigit_index. - for (int i = 0, j = bigit_index; j >= 0; ++i, --j) { - // Most terms are multiplied twice which can be optimized in the future. - sum += static_cast(n[i]) * n[j]; - } - (*this)[bigit_index] = static_cast(sum); - sum >>= num_bits(); // Compute the carry. - } - // Do the same for the top half. - for (int bigit_index = num_bigits; bigit_index < num_result_bigits; - ++bigit_index) { - for (int j = num_bigits - 1, i = bigit_index - j; i < num_bigits;) - sum += static_cast(n[i++]) * n[j--]; - (*this)[bigit_index] = static_cast(sum); - sum >>= num_bits(); - } - remove_leading_zeros(); - exp_ *= 2; - } - - // If this bigint has a bigger exponent than other, adds trailing zero to make - // exponents equal. This simplifies some operations such as subtraction. - FMT_CONSTEXPR20 void align(const bigint& other) { - int exp_difference = exp_ - other.exp_; - if (exp_difference <= 0) return; - int num_bigits = static_cast(bigits_.size()); - bigits_.resize(to_unsigned(num_bigits + exp_difference)); - for (int i = num_bigits - 1, j = i + exp_difference; i >= 0; --i, --j) - bigits_[j] = bigits_[i]; - std::uninitialized_fill_n(bigits_.data(), exp_difference, 0); - exp_ -= exp_difference; - } - - // Divides this bignum by divisor, assigning the remainder to this and - // returning the quotient. - FMT_CONSTEXPR20 int divmod_assign(const bigint& divisor) { - FMT_ASSERT(this != &divisor, ""); - if (compare(*this, divisor) < 0) return 0; - FMT_ASSERT(divisor.bigits_[divisor.bigits_.size() - 1u] != 0, ""); - align(divisor); - int quotient = 0; - do { - subtract_aligned(divisor); - ++quotient; - } while (compare(*this, divisor) >= 0); - return quotient; - } + basic_memory_buffer bigits_; + int exp_; + + FMT_CONSTEXPR20 bigit operator[](int index) const + { return bigits_[to_unsigned(index)]; } + FMT_CONSTEXPR20 bigit &operator[](int index) + { return bigits_[to_unsigned(index)]; } + + static constexpr const int bigit_bits = num_bits(); + + friend struct formatter; + + FMT_CONSTEXPR20 void subtract_bigits(int index, bigit other, bigit &borrow) + { + auto result = static_cast((*this)[index]) - other - borrow; + (*this)[index] = static_cast(result); + borrow = static_cast(result >> (bigit_bits * 2 - 1)); + } + + FMT_CONSTEXPR20 void remove_leading_zeros() + { + int num_bigits = static_cast(bigits_.size()) - 1; + while (num_bigits > 0 && (*this)[num_bigits] == 0) + --num_bigits; + bigits_.resize(to_unsigned(num_bigits + 1)); + } + + // Computes *this -= other assuming aligned bigints and *this >= other. + FMT_CONSTEXPR20 void subtract_aligned(const bigint &other) + { + FMT_ASSERT(other.exp_ >= exp_, "unaligned bigints"); + FMT_ASSERT(compare(*this, other) >= 0, ""); + bigit borrow = 0; + int i = other.exp_ - exp_; + for (size_t j = 0, n = other.bigits_.size(); j != n; ++i, ++j) + subtract_bigits(i, other.bigits_[j], borrow); + while (borrow > 0) + subtract_bigits(i, 0, borrow); + remove_leading_zeros(); + } + + FMT_CONSTEXPR20 void multiply(uint32_t value) + { + const double_bigit wide_value = value; + bigit carry = 0; + for (size_t i = 0, n = bigits_.size(); i < n; ++i) + { + double_bigit result = bigits_[i] * wide_value + carry; + bigits_[i] = static_cast(result); + carry = static_cast(result >> bigit_bits); + } + if (carry != 0) + bigits_.push_back(carry); + } + + template::value || std::is_same::value)> + FMT_CONSTEXPR20 void multiply(UInt value) + { + using half_uint = conditional_t::value, uint64_t, uint32_t>; + const int shift = num_bits() - bigit_bits; + const UInt lower = static_cast(value); + const UInt upper = value >> num_bits(); + UInt carry = 0; + for (size_t i = 0, n = bigits_.size(); i < n; ++i) + { + UInt result = lower * bigits_[i] + static_cast(carry); + carry = (upper * bigits_[i] << shift) + (result >> bigit_bits) + (carry >> bigit_bits); + bigits_[i] = static_cast(result); + } + while (carry != 0) + { + bigits_.push_back(static_cast(carry)); + carry >>= bigit_bits; + } + } + + template::value || std::is_same::value)> + FMT_CONSTEXPR20 void assign(UInt n) + { + size_t num_bigits = 0; + do + { + bigits_[num_bigits++] = static_cast(n); + n >>= bigit_bits; + } while (n != 0); + bigits_.resize(num_bigits); + exp_ = 0; + } + +public: + FMT_CONSTEXPR20 bigint() + : exp_(0) + {} + explicit bigint(uint64_t n) + { assign(n); } + + bigint(const bigint &) = delete; + void operator=(const bigint &) = delete; + + FMT_CONSTEXPR20 void assign(const bigint &other) + { + auto size = other.bigits_.size(); + bigits_.resize(size); + auto data = other.bigits_.data(); + std::copy(data, data + size, make_checked(bigits_.data(), size)); + exp_ = other.exp_; + } + + template + FMT_CONSTEXPR20 void operator=(Int n) + { + FMT_ASSERT(n > 0, ""); + assign(uint64_or_128_t(n)); + } + + FMT_CONSTEXPR20 int num_bigits() const + { return static_cast(bigits_.size()) + exp_; } + + FMT_NOINLINE FMT_CONSTEXPR20 bigint &operator<<=(int shift) + { + FMT_ASSERT(shift >= 0, ""); + exp_ += shift / bigit_bits; + shift %= bigit_bits; + if (shift == 0) + return *this; + bigit carry = 0; + for (size_t i = 0, n = bigits_.size(); i < n; ++i) + { + bigit c = bigits_[i] >> (bigit_bits - shift); + bigits_[i] = (bigits_[i] << shift) + carry; + carry = c; + } + if (carry != 0) + bigits_.push_back(carry); + return *this; + } + + template + FMT_CONSTEXPR20 bigint &operator*=(Int value) + { + FMT_ASSERT(value > 0, ""); + multiply(uint32_or_64_or_128_t(value)); + return *this; + } + + friend FMT_CONSTEXPR20 int compare(const bigint &lhs, const bigint &rhs) + { + int num_lhs_bigits = lhs.num_bigits(), num_rhs_bigits = rhs.num_bigits(); + if (num_lhs_bigits != num_rhs_bigits) + return num_lhs_bigits > num_rhs_bigits ? 1 : -1; + int i = static_cast(lhs.bigits_.size()) - 1; + int j = static_cast(rhs.bigits_.size()) - 1; + int end = i - j; + if (end < 0) + end = 0; + for (; i >= end; --i, --j) + { + bigit lhs_bigit = lhs[i], rhs_bigit = rhs[j]; + if (lhs_bigit != rhs_bigit) + return lhs_bigit > rhs_bigit ? 1 : -1; + } + if (i != j) + return i > j ? 1 : -1; + return 0; + } + + // Returns compare(lhs1 + lhs2, rhs). + friend FMT_CONSTEXPR20 int add_compare(const bigint &lhs1, const bigint &lhs2, const bigint &rhs) + { + auto minimum = [](int a, int b) { return a < b ? a : b; }; + auto maximum = [](int a, int b) { return a > b ? a : b; }; + int max_lhs_bigits = maximum(lhs1.num_bigits(), lhs2.num_bigits()); + int num_rhs_bigits = rhs.num_bigits(); + if (max_lhs_bigits + 1 < num_rhs_bigits) + return -1; + if (max_lhs_bigits > num_rhs_bigits) + return 1; + auto get_bigit = [](const bigint &n, int i) -> bigit { return i >= n.exp_ && i < n.num_bigits() ? n[i - n.exp_] : 0; }; + double_bigit borrow = 0; + int min_exp = minimum(minimum(lhs1.exp_, lhs2.exp_), rhs.exp_); + for (int i = num_rhs_bigits - 1; i >= min_exp; --i) + { + double_bigit sum = static_cast(get_bigit(lhs1, i)) + get_bigit(lhs2, i); + bigit rhs_bigit = get_bigit(rhs, i); + if (sum > rhs_bigit + borrow) + return 1; + borrow = rhs_bigit + borrow - sum; + if (borrow > 1) + return -1; + borrow <<= bigit_bits; + } + return borrow != 0 ? -1 : 0; + } + + // Assigns pow(10, exp) to this bigint. + FMT_CONSTEXPR20 void assign_pow10(int exp) + { + FMT_ASSERT(exp >= 0, ""); + if (exp == 0) + return *this = 1; + // Find the top bit. + int bitmask = 1; + while (exp >= bitmask) + bitmask <<= 1; + bitmask >>= 1; + // pow(10, exp) = pow(5, exp) * pow(2, exp). First compute pow(5, exp) by + // repeated squaring and multiplication. + *this = 5; + bitmask >>= 1; + while (bitmask != 0) + { + square(); + if ((exp & bitmask) != 0) + *this *= 5; + bitmask >>= 1; + } + *this <<= exp; // Multiply by pow(2, exp) by shifting. + } + + FMT_CONSTEXPR20 void square() + { + int num_bigits = static_cast(bigits_.size()); + int num_result_bigits = 2 * num_bigits; + basic_memory_buffer n(std::move(bigits_)); + bigits_.resize(to_unsigned(num_result_bigits)); + auto sum = uint128_t(); + for (int bigit_index = 0; bigit_index < num_bigits; ++bigit_index) + { + // Compute bigit at position bigit_index of the result by adding + // cross-product terms n[i] * n[j] such that i + j == bigit_index. + for (int i = 0, j = bigit_index; j >= 0; ++i, --j) + { + // Most terms are multiplied twice which can be optimized in the future. + sum += static_cast(n[i]) * n[j]; + } + (*this)[bigit_index] = static_cast(sum); + sum >>= num_bits(); // Compute the carry. + } + // Do the same for the top half. + for (int bigit_index = num_bigits; bigit_index < num_result_bigits; ++bigit_index) + { + for (int j = num_bigits - 1, i = bigit_index - j; i < num_bigits;) + sum += static_cast(n[i++]) * n[j--]; + (*this)[bigit_index] = static_cast(sum); + sum >>= num_bits(); + } + remove_leading_zeros(); + exp_ *= 2; + } + + // If this bigint has a bigger exponent than other, adds trailing zero to make + // exponents equal. This simplifies some operations such as subtraction. + FMT_CONSTEXPR20 void align(const bigint &other) + { + int exp_difference = exp_ - other.exp_; + if (exp_difference <= 0) + return; + int num_bigits = static_cast(bigits_.size()); + bigits_.resize(to_unsigned(num_bigits + exp_difference)); + for (int i = num_bigits - 1, j = i + exp_difference; i >= 0; --i, --j) + bigits_[j] = bigits_[i]; + std::uninitialized_fill_n(bigits_.data(), exp_difference, 0); + exp_ -= exp_difference; + } + + // Divides this bignum by divisor, assigning the remainder to this and + // returning the quotient. + FMT_CONSTEXPR20 int divmod_assign(const bigint &divisor) + { + FMT_ASSERT(this != &divisor, ""); + if (compare(*this, divisor) < 0) + return 0; + FMT_ASSERT(divisor.bigits_[divisor.bigits_.size() - 1u] != 0, ""); + align(divisor); + int quotient = 0; + do + { + subtract_aligned(divisor); + ++quotient; + } while (compare(*this, divisor) >= 0); + return quotient; + } }; // format_dragon flags. -enum dragon { - predecessor_closer = 1, - fixup = 2, // Run fixup to correct exp10 which can be off by one. - fixed = 4, +enum dragon +{ + predecessor_closer = 1, + fixup = 2, // Run fixup to correct exp10 which can be off by one. + fixed = 4, }; // Formats a floating-point number using a variation of the Fixed-Precision // Positive Floating-Point Printout ((FPP)^2) algorithm by Steele & White: // https://fmt.dev/papers/p372-steele.pdf. -FMT_CONSTEXPR20 inline void format_dragon(basic_fp value, - unsigned flags, int num_digits, - buffer& buf, int& exp10) { - bigint numerator; // 2 * R in (FPP)^2. - bigint denominator; // 2 * S in (FPP)^2. - // lower and upper are differences between value and corresponding boundaries. - bigint lower; // (M^- in (FPP)^2). - bigint upper_store; // upper's value if different from lower. - bigint* upper = nullptr; // (M^+ in (FPP)^2). - // Shift numerator and denominator by an extra bit or two (if lower boundary - // is closer) to make lower and upper integers. This eliminates multiplication - // by 2 during later computations. - bool is_predecessor_closer = (flags & dragon::predecessor_closer) != 0; - int shift = is_predecessor_closer ? 2 : 1; - if (value.e >= 0) { - numerator = value.f; - numerator <<= value.e + shift; - lower = 1; - lower <<= value.e; - if (is_predecessor_closer) { - upper_store = 1; - upper_store <<= value.e + 1; - upper = &upper_store; - } - denominator.assign_pow10(exp10); - denominator <<= shift; - } else if (exp10 < 0) { - numerator.assign_pow10(-exp10); - lower.assign(numerator); - if (is_predecessor_closer) { - upper_store.assign(numerator); - upper_store <<= 1; - upper = &upper_store; - } - numerator *= value.f; - numerator <<= shift; - denominator = 1; - denominator <<= shift - value.e; - } else { - numerator = value.f; - numerator <<= shift; - denominator.assign_pow10(exp10); - denominator <<= shift - value.e; - lower = 1; - if (is_predecessor_closer) { - upper_store = 1ULL << 1; - upper = &upper_store; - } - } - int even = static_cast((value.f & 1) == 0); - if (!upper) upper = &lower; - if ((flags & dragon::fixup) != 0) { - if (add_compare(numerator, *upper, denominator) + even <= 0) { - --exp10; - numerator *= 10; - if (num_digits < 0) { - lower *= 10; - if (upper != &lower) *upper *= 10; - } - } - if ((flags & dragon::fixed) != 0) adjust_precision(num_digits, exp10 + 1); - } - // Invariant: value == (numerator / denominator) * pow(10, exp10). - if (num_digits < 0) { - // Generate the shortest representation. - num_digits = 0; - char* data = buf.data(); - for (;;) { - int digit = numerator.divmod_assign(denominator); - bool low = compare(numerator, lower) - even < 0; // numerator <[=] lower. - // numerator + upper >[=] pow10: - bool high = add_compare(numerator, *upper, denominator) + even > 0; - data[num_digits++] = static_cast('0' + digit); - if (low || high) { - if (!low) { - ++data[num_digits - 1]; - } else if (high) { - int result = add_compare(numerator, numerator, denominator); - // Round half to even. - if (result > 0 || (result == 0 && (digit % 2) != 0)) - ++data[num_digits - 1]; +FMT_CONSTEXPR20 inline void format_dragon(basic_fp value, unsigned flags, int num_digits, buffer &buf, int &exp10) +{ + bigint numerator; // 2 * R in (FPP)^2. + bigint denominator; // 2 * S in (FPP)^2. + // lower and upper are differences between value and corresponding boundaries. + bigint lower; // (M^- in (FPP)^2). + bigint upper_store; // upper's value if different from lower. + bigint *upper = nullptr; // (M^+ in (FPP)^2). + // Shift numerator and denominator by an extra bit or two (if lower boundary + // is closer) to make lower and upper integers. This eliminates multiplication + // by 2 during later computations. + bool is_predecessor_closer = (flags & dragon::predecessor_closer) != 0; + int shift = is_predecessor_closer ? 2 : 1; + if (value.e >= 0) + { + numerator = value.f; + numerator <<= value.e + shift; + lower = 1; + lower <<= value.e; + if (is_predecessor_closer) + { + upper_store = 1; + upper_store <<= value.e + 1; + upper = &upper_store; + } + denominator.assign_pow10(exp10); + denominator <<= shift; + } + else if (exp10 < 0) + { + numerator.assign_pow10(-exp10); + lower.assign(numerator); + if (is_predecessor_closer) + { + upper_store.assign(numerator); + upper_store <<= 1; + upper = &upper_store; + } + numerator *= value.f; + numerator <<= shift; + denominator = 1; + denominator <<= shift - value.e; + } + else + { + numerator = value.f; + numerator <<= shift; + denominator.assign_pow10(exp10); + denominator <<= shift - value.e; + lower = 1; + if (is_predecessor_closer) + { + upper_store = 1ULL << 1; + upper = &upper_store; + } + } + int even = static_cast((value.f & 1) == 0); + if (!upper) + upper = &lower; + if ((flags & dragon::fixup) != 0) + { + if (add_compare(numerator, *upper, denominator) + even <= 0) + { + --exp10; + numerator *= 10; + if (num_digits < 0) + { + lower *= 10; + if (upper != &lower) + *upper *= 10; + } + } + if ((flags & dragon::fixed) != 0) + adjust_precision(num_digits, exp10 + 1); + } + // Invariant: value == (numerator / denominator) * pow(10, exp10). + if (num_digits < 0) + { + // Generate the shortest representation. + num_digits = 0; + char *data = buf.data(); + for (;;) + { + int digit = numerator.divmod_assign(denominator); + bool low = compare(numerator, lower) - even < 0; // numerator <[=] lower. + // numerator + upper >[=] pow10: + bool high = add_compare(numerator, *upper, denominator) + even > 0; + data[num_digits++] = static_cast('0' + digit); + if (low || high) + { + if (!low) + { + ++data[num_digits - 1]; + } + else if (high) + { + int result = add_compare(numerator, numerator, denominator); + // Round half to even. + if (result > 0 || (result == 0 && (digit % 2) != 0)) + ++data[num_digits - 1]; + } + buf.try_resize(to_unsigned(num_digits)); + exp10 -= num_digits - 1; + return; + } + numerator *= 10; + lower *= 10; + if (upper != &lower) + *upper *= 10; } - buf.try_resize(to_unsigned(num_digits)); - exp10 -= num_digits - 1; + } + // Generate the given number of digits. + exp10 -= num_digits - 1; + if (num_digits == 0) + { + denominator *= 10; + auto digit = add_compare(numerator, numerator, denominator) > 0 ? '1' : '0'; + buf.push_back(digit); return; - } - numerator *= 10; - lower *= 10; - if (upper != &lower) *upper *= 10; - } - } - // Generate the given number of digits. - exp10 -= num_digits - 1; - if (num_digits == 0) { - denominator *= 10; - auto digit = add_compare(numerator, numerator, denominator) > 0 ? '1' : '0'; - buf.push_back(digit); - return; - } - buf.try_resize(to_unsigned(num_digits)); - for (int i = 0; i < num_digits - 1; ++i) { + } + buf.try_resize(to_unsigned(num_digits)); + for (int i = 0; i < num_digits - 1; ++i) + { + int digit = numerator.divmod_assign(denominator); + buf[i] = static_cast('0' + digit); + numerator *= 10; + } int digit = numerator.divmod_assign(denominator); - buf[i] = static_cast('0' + digit); - numerator *= 10; - } - int digit = numerator.divmod_assign(denominator); - auto result = add_compare(numerator, numerator, denominator); - if (result > 0 || (result == 0 && (digit % 2) != 0)) { - if (digit == 9) { - const auto overflow = '0' + 10; - buf[num_digits - 1] = overflow; - // Propagate the carry. - for (int i = num_digits - 1; i > 0 && buf[i] == overflow; --i) { - buf[i] = '0'; - ++buf[i - 1]; - } - if (buf[0] == overflow) { - buf[0] = '1'; - ++exp10; - } - return; - } - ++digit; - } - buf[num_digits - 1] = static_cast('0' + digit); -} - -template -FMT_CONSTEXPR20 auto format_float(Float value, int precision, float_specs specs, - buffer& buf) -> int { - // float is passed as double to reduce the number of instantiations. - static_assert(!std::is_same::value, ""); - FMT_ASSERT(value >= 0, "value is negative"); - auto converted_value = convert_float(value); - - const bool fixed = specs.format == float_format::fixed; - if (value <= 0) { // <= instead of == to silence a warning. - if (precision <= 0 || !fixed) { - buf.push_back('0'); - return 0; - } - buf.try_resize(to_unsigned(precision)); - fill_n(buf.data(), precision, '0'); - return -precision; - } - - int exp = 0; - bool use_dragon = true; - unsigned dragon_flags = 0; - if (!is_fast_float()) { - const auto inv_log2_10 = 0.3010299956639812; // 1 / log2(10) - using info = dragonbox::float_info; - const auto f = basic_fp(converted_value); - // Compute exp, an approximate power of 10, such that - // 10^(exp - 1) <= value < 10^exp or 10^exp <= value < 10^(exp + 1). - // This is based on log10(value) == log2(value) / log2(10) and approximation - // of log2(value) by e + num_fraction_bits idea from double-conversion. - exp = static_cast( - std::ceil((f.e + count_digits<1>(f.f) - 1) * inv_log2_10 - 1e-10)); - dragon_flags = dragon::fixup; - } else if (!is_constant_evaluated() && precision < 0) { - // Use Dragonbox for the shortest format. - if (specs.binary32) { - auto dec = dragonbox::to_decimal(static_cast(value)); - write(buffer_appender(buf), dec.significand); - return dec.exponent; - } - auto dec = dragonbox::to_decimal(static_cast(value)); - write(buffer_appender(buf), dec.significand); - return dec.exponent; - } else { - // Use Grisu + Dragon4 for the given precision: - // https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf. - const int min_exp = -60; // alpha in Grisu. - int cached_exp10 = 0; // K in Grisu. - fp normalized = normalize(fp(converted_value)); - const auto cached_pow = get_cached_power( - min_exp - (normalized.e + fp::num_significand_bits), cached_exp10); - normalized = normalized * cached_pow; - gen_digits_handler handler{buf.data(), 0, precision, -cached_exp10, fixed}; - if (grisu_gen_digits(normalized, 1, exp, handler) != digits::error && - !is_constant_evaluated()) { - exp += handler.exp10; - buf.try_resize(to_unsigned(handler.size)); - use_dragon = false; - } else { - exp += handler.size - cached_exp10 - 1; - precision = handler.precision; - } - } - if (use_dragon) { - auto f = basic_fp(); - bool is_predecessor_closer = specs.binary32 - ? f.assign(static_cast(value)) - : f.assign(converted_value); - if (is_predecessor_closer) dragon_flags |= dragon::predecessor_closer; - if (fixed) dragon_flags |= dragon::fixed; - // Limit precision to the maximum possible number of significant digits in - // an IEEE754 double because we don't need to generate zeros. - const int max_double_digits = 767; - if (precision > max_double_digits) precision = max_double_digits; - format_dragon(f, dragon_flags, precision, buf, exp); - } - if (!fixed && !specs.showpoint) { - // Remove trailing zeros. - auto num_digits = buf.size(); - while (num_digits > 0 && buf[num_digits - 1] == '0') { - --num_digits; - ++exp; - } - buf.try_resize(num_digits); - } - return exp; -} + auto result = add_compare(numerator, numerator, denominator); + if (result > 0 || (result == 0 && (digit % 2) != 0)) + { + if (digit == 9) + { + const auto overflow = '0' + 10; + buf[num_digits - 1] = overflow; + // Propagate the carry. + for (int i = num_digits - 1; i > 0 && buf[i] == overflow; --i) + { + buf[i] = '0'; + ++buf[i - 1]; + } + if (buf[0] == overflow) + { + buf[0] = '1'; + ++exp10; + } + return; + } + ++digit; + } + buf[num_digits - 1] = static_cast('0' + digit); +} + +template +FMT_CONSTEXPR20 auto format_float(Float value, int precision, float_specs specs, buffer &buf) -> int +{ + // float is passed as double to reduce the number of instantiations. + static_assert(!std::is_same::value, ""); + FMT_ASSERT(value >= 0, "value is negative"); + auto converted_value = convert_float(value); + + const bool fixed = specs.format == float_format::fixed; + if (value <= 0) + { // <= instead of == to silence a warning. + if (precision <= 0 || !fixed) + { + buf.push_back('0'); + return 0; + } + buf.try_resize(to_unsigned(precision)); + fill_n(buf.data(), precision, '0'); + return -precision; + } -template ::value)> -FMT_CONSTEXPR20 auto write(OutputIt out, T value, - basic_format_specs specs, locale_ref loc = {}) - -> OutputIt { - if (const_check(!is_supported_floating_point(value))) return out; - float_specs fspecs = parse_float_type_spec(specs); - fspecs.sign = specs.sign; - if (detail::signbit(value)) { // value < 0 is false for NaN so use signbit. - fspecs.sign = sign::minus; - value = -value; - } else if (fspecs.sign == sign::minus) { - fspecs.sign = sign::none; - } - - if (!detail::isfinite(value)) - return write_nonfinite(out, detail::isnan(value), specs, fspecs); - - if (specs.align == align::numeric && fspecs.sign) { - auto it = reserve(out, 1); - *it++ = detail::sign(fspecs.sign); - out = base_iterator(out, it); - fspecs.sign = sign::none; - if (specs.width != 0) --specs.width; - } - - memory_buffer buffer; - if (fspecs.format == float_format::hex) { - if (fspecs.sign) buffer.push_back(detail::sign(fspecs.sign)); - snprintf_float(convert_float(value), specs.precision, fspecs, buffer); - return write_bytes(out, {buffer.data(), buffer.size()}, - specs); - } - int precision = specs.precision >= 0 || specs.type == presentation_type::none - ? specs.precision - : 6; - if (fspecs.format == float_format::exp) { - if (precision == max_value()) - throw_format_error("number is too big"); + int exp = 0; + bool use_dragon = true; + unsigned dragon_flags = 0; + if (!is_fast_float()) + { + const auto inv_log2_10 = 0.3010299956639812; // 1 / log2(10) + using info = dragonbox::float_info; + const auto f = basic_fp(converted_value); + // Compute exp, an approximate power of 10, such that + // 10^(exp - 1) <= value < 10^exp or 10^exp <= value < 10^(exp + 1). + // This is based on log10(value) == log2(value) / log2(10) and approximation + // of log2(value) by e + num_fraction_bits idea from double-conversion. + exp = static_cast(std::ceil((f.e + count_digits<1>(f.f) - 1) * inv_log2_10 - 1e-10)); + dragon_flags = dragon::fixup; + } + else if (!is_constant_evaluated() && precision < 0) + { + // Use Dragonbox for the shortest format. + if (specs.binary32) + { + auto dec = dragonbox::to_decimal(static_cast(value)); + write(buffer_appender(buf), dec.significand); + return dec.exponent; + } + auto dec = dragonbox::to_decimal(static_cast(value)); + write(buffer_appender(buf), dec.significand); + return dec.exponent; + } else - ++precision; - } else if (fspecs.format != float_format::fixed && precision == 0) { - precision = 1; - } - if (const_check(std::is_same())) fspecs.binary32 = true; - int exp = format_float(convert_float(value), precision, fspecs, buffer); - fspecs.precision = precision; - auto f = big_decimal_fp{buffer.data(), static_cast(buffer.size()), exp}; - return write_float(out, f, specs, fspecs, loc); -} + { + // Use Grisu + Dragon4 for the given precision: + // https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf. + const int min_exp = -60; // alpha in Grisu. + int cached_exp10 = 0; // K in Grisu. + fp normalized = normalize(fp(converted_value)); + const auto cached_pow = get_cached_power(min_exp - (normalized.e + fp::num_significand_bits), cached_exp10); + normalized = normalized * cached_pow; + gen_digits_handler handler{buf.data(), 0, precision, -cached_exp10, fixed}; + if (grisu_gen_digits(normalized, 1, exp, handler) != digits::error && !is_constant_evaluated()) + { + exp += handler.exp10; + buf.try_resize(to_unsigned(handler.size)); + use_dragon = false; + } + else + { + exp += handler.size - cached_exp10 - 1; + precision = handler.precision; + } + } + if (use_dragon) + { + auto f = basic_fp(); + bool is_predecessor_closer = specs.binary32 ? f.assign(static_cast(value)) : f.assign(converted_value); + if (is_predecessor_closer) + dragon_flags |= dragon::predecessor_closer; + if (fixed) + dragon_flags |= dragon::fixed; + // Limit precision to the maximum possible number of significant digits in + // an IEEE754 double because we don't need to generate zeros. + const int max_double_digits = 767; + if (precision > max_double_digits) + precision = max_double_digits; + format_dragon(f, dragon_flags, precision, buf, exp); + } + if (!fixed && !specs.showpoint) + { + // Remove trailing zeros. + auto num_digits = buf.size(); + while (num_digits > 0 && buf[num_digits - 1] == '0') + { + --num_digits; + ++exp; + } + buf.try_resize(num_digits); + } + return exp; +} + +template::value)> +FMT_CONSTEXPR20 auto write(OutputIt out, T value, basic_format_specs specs, locale_ref loc = {}) -> OutputIt +{ + if (const_check(!is_supported_floating_point(value))) + return out; + float_specs fspecs = parse_float_type_spec(specs); + fspecs.sign = specs.sign; + if (detail::signbit(value)) + { // value < 0 is false for NaN so use signbit. + fspecs.sign = sign::minus; + value = -value; + } + else if (fspecs.sign == sign::minus) + { + fspecs.sign = sign::none; + } -template ::value)> -FMT_CONSTEXPR20 auto write(OutputIt out, T value) -> OutputIt { - if (is_constant_evaluated()) - return write(out, value, basic_format_specs()); - if (const_check(!is_supported_floating_point(value))) return out; - - auto fspecs = float_specs(); - if (detail::signbit(value)) { - fspecs.sign = sign::minus; - value = -value; - } - - constexpr auto specs = basic_format_specs(); - using floaty = conditional_t::value, double, T>; - using uint = typename dragonbox::float_info::carrier_uint; - uint mask = exponent_mask(); - if ((bit_cast(value) & mask) == mask) - return write_nonfinite(out, std::isnan(value), specs, fspecs); - - auto dec = dragonbox::to_decimal(static_cast(value)); - return write_float(out, dec, specs, fspecs, {}); -} + if (!detail::isfinite(value)) + return write_nonfinite(out, detail::isnan(value), specs, fspecs); + + if (specs.align == align::numeric && fspecs.sign) + { + auto it = reserve(out, 1); + *it++ = detail::sign(fspecs.sign); + out = base_iterator(out, it); + fspecs.sign = sign::none; + if (specs.width != 0) + --specs.width; + } -template ::value && - !is_fast_float::value)> -inline auto write(OutputIt out, T value) -> OutputIt { - return write(out, value, basic_format_specs()); -} + memory_buffer buffer; + if (fspecs.format == float_format::hex) + { + if (fspecs.sign) + buffer.push_back(detail::sign(fspecs.sign)); + snprintf_float(convert_float(value), specs.precision, fspecs, buffer); + return write_bytes(out, {buffer.data(), buffer.size()}, specs); + } + int precision = specs.precision >= 0 || specs.type == presentation_type::none ? specs.precision : 6; + if (fspecs.format == float_format::exp) + { + if (precision == max_value()) + throw_format_error("number is too big"); + else + ++precision; + } + else if (fspecs.format != float_format::fixed && precision == 0) + { + precision = 1; + } + if (const_check(std::is_same())) + fspecs.binary32 = true; + int exp = format_float(convert_float(value), precision, fspecs, buffer); + fspecs.precision = precision; + auto f = big_decimal_fp{buffer.data(), static_cast(buffer.size()), exp}; + return write_float(out, f, specs, fspecs, loc); +} + +template::value)> +FMT_CONSTEXPR20 auto write(OutputIt out, T value) -> OutputIt +{ + if (is_constant_evaluated()) + return write(out, value, basic_format_specs()); + if (const_check(!is_supported_floating_point(value))) + return out; + + auto fspecs = float_specs(); + if (detail::signbit(value)) + { + fspecs.sign = sign::minus; + value = -value; + } + + constexpr auto specs = basic_format_specs(); + using floaty = conditional_t::value, double, T>; + using uint = typename dragonbox::float_info::carrier_uint; + uint mask = exponent_mask(); + if ((bit_cast(value) & mask) == mask) + return write_nonfinite(out, std::isnan(value), specs, fspecs); -template -auto write(OutputIt out, monostate, basic_format_specs = {}, - locale_ref = {}) -> OutputIt { - FMT_ASSERT(false, ""); - return out; + auto dec = dragonbox::to_decimal(static_cast(value)); + return write_float(out, dec, specs, fspecs, {}); } -template -FMT_CONSTEXPR auto write(OutputIt out, basic_string_view value) - -> OutputIt { - auto it = reserve(out, value.size()); - it = copy_str_noinline(value.begin(), value.end(), it); - return base_iterator(out, it); +template::value && !is_fast_float::value)> +inline auto write(OutputIt out, T value) -> OutputIt +{ return write(out, value, basic_format_specs()); } + +template +auto write(OutputIt out, monostate, basic_format_specs = {}, locale_ref = {}) -> OutputIt +{ + FMT_ASSERT(false, ""); + return out; } -template ::value)> -constexpr auto write(OutputIt out, const T& value) -> OutputIt { - return write(out, to_string_view(value)); +template +FMT_CONSTEXPR auto write(OutputIt out, basic_string_view value) -> OutputIt +{ + auto it = reserve(out, value.size()); + it = copy_str_noinline(value.begin(), value.end(), it); + return base_iterator(out, it); } +template::value)> +constexpr auto write(OutputIt out, const T &value) -> OutputIt +{ return write(out, to_string_view(value)); } + // FMT_ENABLE_IF() condition separated to workaround an MSVC bug. -template < - typename Char, typename OutputIt, typename T, - bool check = - std::is_enum::value && !std::is_same::value && - mapped_type_constant>::value != - type::custom_type, +template::value && !std::is_same::value && + mapped_type_constant>::value != type::custom_type, FMT_ENABLE_IF(check)> -FMT_CONSTEXPR auto write(OutputIt out, T value) -> OutputIt { - return write(out, static_cast>(value)); -} +FMT_CONSTEXPR auto write(OutputIt out, T value) -> OutputIt +{ return write(out, static_cast>(value)); } -template ::value)> -FMT_CONSTEXPR auto write(OutputIt out, T value, - const basic_format_specs& specs = {}, - locale_ref = {}) -> OutputIt { - return specs.type != presentation_type::none && - specs.type != presentation_type::string - ? write(out, value ? 1 : 0, specs, {}) - : write_bytes(out, value ? "true" : "false", specs); +template::value)> +FMT_CONSTEXPR auto write(OutputIt out, T value, const basic_format_specs &specs = {}, locale_ref = {}) -> OutputIt +{ + return specs.type != presentation_type::none && specs.type != presentation_type::string + ? write(out, value ? 1 : 0, specs, {}) + : write_bytes(out, value ? "true" : "false", specs); } -template -FMT_CONSTEXPR auto write(OutputIt out, Char value) -> OutputIt { - auto it = reserve(out, 1); - *it++ = value; - return base_iterator(out, it); +template +FMT_CONSTEXPR auto write(OutputIt out, Char value) -> OutputIt +{ + auto it = reserve(out, 1); + *it++ = value; + return base_iterator(out, it); } -template -FMT_CONSTEXPR_CHAR_TRAITS auto write(OutputIt out, const Char* value) - -> OutputIt { - if (!value) { - throw_format_error("string pointer is null"); - } else { - out = write(out, basic_string_view(value)); - } - return out; +template +FMT_CONSTEXPR_CHAR_TRAITS auto write(OutputIt out, const Char *value) -> OutputIt +{ + if (!value) + { + throw_format_error("string pointer is null"); + } + else + { + out = write(out, basic_string_view(value)); + } + return out; } -template ::value)> -auto write(OutputIt out, const T* value, - const basic_format_specs& specs = {}, locale_ref = {}) - -> OutputIt { - check_pointer_type_spec(specs.type, error_handler()); - return write_ptr(out, bit_cast(value), &specs); +template::value)> +auto write(OutputIt out, const T *value, const basic_format_specs &specs = {}, locale_ref = {}) -> OutputIt +{ + check_pointer_type_spec(specs.type, error_handler()); + return write_ptr(out, bit_cast(value), &specs); } // A write overload that handles implicit conversions. -template > -FMT_CONSTEXPR auto write(OutputIt out, const T& value) -> enable_if_t< - std::is_class::value && !is_string::value && - !is_floating_point::value && !std::is_same::value && - !std::is_same().map(value))>::value, - OutputIt> { - return write(out, arg_mapper().map(value)); -} - -template > -FMT_CONSTEXPR auto write(OutputIt out, const T& value) - -> enable_if_t::value == type::custom_type, - OutputIt> { - using formatter_type = - conditional_t::value, - typename Context::template formatter_type, - fallback_formatter>; - auto ctx = Context(out, {}, {}); - return formatter_type().format(value, ctx); +template> +FMT_CONSTEXPR auto write(OutputIt out, const T &value) + -> enable_if_t::value && !is_string::value && !is_floating_point::value && !std::is_same::value && + !std::is_same().map(value))>::value, + OutputIt> +{ return write(out, arg_mapper().map(value)); } + +template> +FMT_CONSTEXPR auto write(OutputIt out, const T &value) + -> enable_if_t::value == type::custom_type, OutputIt> +{ + using formatter_type = + conditional_t::value, typename Context::template formatter_type, fallback_formatter>; + auto ctx = Context(out, {}, {}); + return formatter_type().format(value, ctx); } // An argument visitor that formats the argument and writes it via the output // iterator. It's a class and not a generic lambda for compatibility with C++11. -template struct default_arg_formatter { - using iterator = buffer_appender; - using context = buffer_context; - - iterator out; - basic_format_args args; - locale_ref loc; - - template auto operator()(T value) -> iterator { - return write(out, value); - } - auto operator()(typename basic_format_arg::handle h) -> iterator { - basic_format_parse_context parse_ctx({}); - context format_ctx(out, args, loc); - h.format(parse_ctx, format_ctx); - return format_ctx.out(); - } +template +struct default_arg_formatter +{ + using iterator = buffer_appender; + using context = buffer_context; + + iterator out; + basic_format_args args; + locale_ref loc; + + template + auto operator()(T value) -> iterator + { return write(out, value); } + auto operator()(typename basic_format_arg::handle h) -> iterator + { + basic_format_parse_context parse_ctx({}); + context format_ctx(out, args, loc); + h.format(parse_ctx, format_ctx); + return format_ctx.out(); + } }; -template struct arg_formatter { - using iterator = buffer_appender; - using context = buffer_context; - - iterator out; - const basic_format_specs& specs; - locale_ref locale; - - template - FMT_CONSTEXPR FMT_INLINE auto operator()(T value) -> iterator { - return detail::write(out, value, specs, locale); - } - auto operator()(typename basic_format_arg::handle) -> iterator { - // User-defined types are handled separately because they require access - // to the parse context. - return out; - } +template +struct arg_formatter +{ + using iterator = buffer_appender; + using context = buffer_context; + + iterator out; + const basic_format_specs &specs; + locale_ref locale; + + template + FMT_CONSTEXPR FMT_INLINE auto operator()(T value) -> iterator + { return detail::write(out, value, specs, locale); } + auto operator()(typename basic_format_arg::handle) -> iterator + { + // User-defined types are handled separately because they require access + // to the parse context. + return out; + } }; -template struct custom_formatter { - basic_format_parse_context& parse_ctx; - buffer_context& ctx; - - void operator()( - typename basic_format_arg>::handle h) const { - h.format(parse_ctx, ctx); - } - template void operator()(T) const {} +template +struct custom_formatter +{ + basic_format_parse_context &parse_ctx; + buffer_context &ctx; + + void operator()(typename basic_format_arg>::handle h) const + { h.format(parse_ctx, ctx); } + template + void operator()(T) const + {} }; -template -using is_integer = - bool_constant::value && !std::is_same::value && - !std::is_same::value && - !std::is_same::value>; - -template class width_checker { - public: - explicit FMT_CONSTEXPR width_checker(ErrorHandler& eh) : handler_(eh) {} - - template ::value)> - FMT_CONSTEXPR auto operator()(T value) -> unsigned long long { - if (is_negative(value)) handler_.on_error("negative width"); - return static_cast(value); - } - - template ::value)> - FMT_CONSTEXPR auto operator()(T) -> unsigned long long { - handler_.on_error("width is not integer"); - return 0; - } - - private: - ErrorHandler& handler_; -}; +template +using is_integer = bool_constant::value && !std::is_same::value && !std::is_same::value && + !std::is_same::value>; + +template +class width_checker +{ +public: + explicit FMT_CONSTEXPR width_checker(ErrorHandler &eh) + : handler_(eh) + {} + + template::value)> + FMT_CONSTEXPR auto operator()(T value) -> unsigned long long + { + if (is_negative(value)) + handler_.on_error("negative width"); + return static_cast(value); + } -template class precision_checker { - public: - explicit FMT_CONSTEXPR precision_checker(ErrorHandler& eh) : handler_(eh) {} + template::value)> + FMT_CONSTEXPR auto operator()(T) -> unsigned long long + { + handler_.on_error("width is not integer"); + return 0; + } - template ::value)> - FMT_CONSTEXPR auto operator()(T value) -> unsigned long long { - if (is_negative(value)) handler_.on_error("negative precision"); - return static_cast(value); - } +private: + ErrorHandler &handler_; +}; + +template +class precision_checker +{ +public: + explicit FMT_CONSTEXPR precision_checker(ErrorHandler &eh) + : handler_(eh) + {} + + template::value)> + FMT_CONSTEXPR auto operator()(T value) -> unsigned long long + { + if (is_negative(value)) + handler_.on_error("negative precision"); + return static_cast(value); + } - template ::value)> - FMT_CONSTEXPR auto operator()(T) -> unsigned long long { - handler_.on_error("precision is not integer"); - return 0; - } + template::value)> + FMT_CONSTEXPR auto operator()(T) -> unsigned long long + { + handler_.on_error("precision is not integer"); + return 0; + } - private: - ErrorHandler& handler_; +private: + ErrorHandler &handler_; }; -template