diff --git a/.github/actions/agent-package-mac/action.yml b/.github/actions/agent-package-mac/action.yml index 41b2b466b..af58100aa 100644 --- a/.github/actions/agent-package-mac/action.yml +++ b/.github/actions/agent-package-mac/action.yml @@ -5,9 +5,11 @@ inputs: required: true p12-password: required: true - appstore-connect-username: + notarization-username: required: true - appstore-connect-password: + notarization-team: + required: true + notarization-password: required: true runs: @@ -20,7 +22,7 @@ runs: with: p12-file-base64: ${{ inputs.p12-file-base64 }} p12-password: ${{ inputs.p12-password }} - + - name: Mac deploy Qt shell: sh run: | @@ -31,13 +33,13 @@ runs: if: "startsWith(matrix.config.qt_version, '5')" shell: sh run: | - python2 $KLOGG_BUILD_ROOT/macdeployqtfix.py $KLOGG_BUILD_ROOT/output/klogg.app/Contents/MacOS/klogg $Qt5_DIR + python3 $KLOGG_BUILD_ROOT/macdeployqtfix.py $KLOGG_BUILD_ROOT/output/klogg.app/Contents/MacOS/klogg $Qt5_DIR - name: Mac deploy Qt fixing if: "startsWith(matrix.config.qt_version, '6')" shell: sh run: | - python2 $KLOGG_BUILD_ROOT/macdeployqtfix.py $KLOGG_BUILD_ROOT/output/klogg.app/Contents/MacOS/klogg $Qt6_DIR + python3 $KLOGG_BUILD_ROOT/macdeployqtfix.py $KLOGG_BUILD_ROOT/output/klogg.app/Contents/MacOS/klogg $Qt6_DIR - name: Set packaging env shell: sh @@ -82,38 +84,34 @@ runs: pkgutil --expand ./output/klogg-${{ env.KLOGG_VERSION }}-OSX-product.pkg ./output/klogg_product_pkg pkgutil --flatten ./output/klogg_product_pkg ./output/klogg-${{ env.KLOGG_VERSION }}-OSX-flatten.pkg productsign --sign "${{ env.KLOGG_INSTALLERSIGN }}" --timestamp ./output/klogg-${{ env.KLOGG_VERSION }}-OSX-flatten.pkg ./packages/${{ env.KLOGG_PKG }} + + - name: Setup Xcode + shell: sh + run: sudo xcode-select -s /Applications/Xcode_13.2.1.app - - name: "Mac notarize DMG" + - name: Mac notarize DMG if: ${{ github.event_name != 'pull_request' }} - uses: variar/xcode-notarize@v1.0.3 - with: - verbose: true - product-path: "${{ env.KLOGG_BUILD_ROOT }}/packages/${{ env.KLOGG_DMG }}" - primary-bundle-id: "dev.filimonov.klogg" - appstore-connect-username: ${{ inputs.appstore-connect-username }} - appstore-connect-password: ${{ inputs.appstore-connect-password }} + shell: sh + run: | + xcrun notarytool submit --wait --apple-id "${{ inputs.notarization-username }}" --team-id "${{ inputs.notarization-team }}" --password "${{ inputs.notarization-password }}" "${{ env.KLOGG_BUILD_ROOT }}/packages/${{ env.KLOGG_DMG }}" - - name: "Mac staple DMG" + - name: Mac staple DMG if: ${{ github.event_name != 'pull_request' }} - uses: devbotsxyz/xcode-staple@v1 - with: - product-path: "${{ env.KLOGG_BUILD_ROOT }}/packages/${{ env.KLOGG_DMG }}" + shell: sh + run: | + xcrun stapler staple "${{ env.KLOGG_BUILD_ROOT }}/packages/${{ env.KLOGG_DMG }}" - - name: "Mac notarize PKG" + - name: Mac notarize PKG if: ${{ github.event_name != 'pull_request' }} - uses: variar/xcode-notarize@v1.0.3 - with: - verbose: true - product-path: "${{ env.KLOGG_BUILD_ROOT }}/packages/${{ env.KLOGG_PKG }}" - primary-bundle-id: "dev.filimonov.klogg" - appstore-connect-username: ${{ inputs.appstore-connect-username }} - appstore-connect-password: ${{ inputs.appstore-connect-password }} + shell: sh + run: | + xcrun notarytool submit --wait --apple-id "${{ inputs.notarization-username }}" --team-id "${{ inputs.notarization-team }}" --password "${{ inputs.notarization-password }}" "${{ env.KLOGG_BUILD_ROOT }}/packages/${{ env.KLOGG_PKG }}" - - name: "Mac staple PKG" + - name: Mac staple PKG if: ${{ github.event_name != 'pull_request' }} - uses: devbotsxyz/xcode-staple@v1 - with: - product-path: "${{ env.KLOGG_BUILD_ROOT }}/packages/${{ env.KLOGG_PKG }}" + shell: sh + run: | + xcrun stapler staple "${{ env.KLOGG_BUILD_ROOT }}/packages/${{ env.KLOGG_PKG }}" - name: Mac symbols shell: sh diff --git a/.github/actions/klogg-version/action.yml b/.github/actions/klogg-version/action.yml index 95bb2912d..c1e933a9f 100644 --- a/.github/actions/klogg-version/action.yml +++ b/.github/actions/klogg-version/action.yml @@ -6,4 +6,4 @@ runs: - name: Set klogg version shell: sh run: | - echo "KLOGG_VERSION=23.08.0.$((${{ github.run_number }} + 717))" >> $GITHUB_ENV \ No newline at end of file + echo "KLOGG_VERSION=24.11.0.$((${{ github.run_number }} + 717))" >> $GITHUB_ENV diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index bee562351..12d673c36 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -70,18 +70,6 @@ jobs: container: variar/klogg_oracle8 cmake_opts: -DCMAKE_BUILD_WITH_INSTALL_RPATH=on - - os: ubuntu_bionic - os_version: 18.04 - arch: x64 - check_command: apt-get update && apt install --dry-run /usr/local/klogg*.deb - cpack_gen: DEB - artifacts_id: bionic - package_suffix: deb - check_container: ubuntu:18.04 - container_root: docker/ubuntu18.04 - container: variar/klogg_ubuntu18.04 - cmake_opts: -DKLOGG_USE_LTO=OFF - - os: ubuntu_focal os_version: 20.04 arch: x64 @@ -106,16 +94,28 @@ jobs: container: variar/klogg_ubuntu22.04 cmake_opts: + - os: ubuntu_noble + os_version: 24.04 + arch: x64 + check_command: apt-get update && apt install --dry-run /usr/local/klogg*.deb + cpack_gen: DEB + artifacts_id: noble + package_suffix: deb + check_container: ubuntu:24.04 + container_root: docker/ubuntu24.04 + container: variar/klogg_ubuntu24.04 + cmake_opts: + - os: ubuntu_appimage - os_version: 18.04 + os_version: 20.04 arch: x64 #check_command: apt-get update && apt install --dry-run /usr/local/klogg*.deb #cpack_gen: DEB artifacts_id: appimage package_suffix: AppImage #check_container: ubuntu:18.04 - container_root: docker/ubuntu18.04_qt5.15 - container: variar/klogg_ubuntu18.04_qt5.15 + container_root: docker/ubuntu20.04_qt5.15 + container: variar/klogg_ubuntu20.04_qt5.15 cmake_opts: -DKLOGG_USE_LTO=OFF -DCMAKE_PREFIX_PATH=/opt/qt515/ @@ -152,19 +152,12 @@ jobs: matrix: config: - os: macos - os_version: 11 - qt_version: 5.15.2 - qt_modules: - arch: x64 - artifacts_id: macos-qt5 - cmake_opts: -DKLOGG_OSX_DEPLOYMENT_TARGET=10.14 - - os: macos - os_version: 11 - qt_version: 6.5.1 + os_version: 12 + qt_version: 6.7.3 qt_modules: qt5compat arch: x64 artifacts_id: macos-qt6 - cmake_opts: -DKLOGG_OSX_DEPLOYMENT_TARGET=10.15 + cmake_opts: -DKLOGG_OSX_DEPLOYMENT_TARGET=11.7 runs-on: ${{ matrix.config.os }}-${{ matrix.config.os_version }} steps: @@ -190,8 +183,9 @@ jobs: with: p12-file-base64: ${{ secrets.CODESIGN_BASE64 }} p12-password: ${{ secrets.CODESIGN_PASSWORD }} - appstore-connect-username: ${{ secrets.NOTARIZATION_USERNAME }} - appstore-connect-password: ${{ secrets.NOTARIZATION_PASSWORD }} + notarization-username: ${{ secrets.NOTARIZATION_USERNAME }} + notarization-team: ${{ secrets.NOTARIZATION_TEAM }} + notarization-password: ${{ secrets.NOTARIZATION_PASSWORD }} - uses: actions/upload-artifact@v3 with: @@ -207,15 +201,7 @@ jobs: config: - os: windows os_version: 2022 - qt_version: 5.15.2 - arch: x64 - ssl_arch: -x64 - cmake_opts: - artifacts_id: windows-x64-qt5 - - - os: windows - os_version: 2022 - qt_version: 6.5.1 + qt_version: 6.7.3 qt_modules: qt5compat arch: x64 ssl_arch: -x64 @@ -239,12 +225,12 @@ jobs: uses: actions/cache@v2 with: path: ${{ github.workspace }}\openssl-1.1 - key: OpensslCache-1-1-1n + key: OpensslCache-1-1-1w - name: Download openssl if: ${{ steps.cache-openssl.outputs.cache-hit != 'true' }} run: | - Invoke-WebRequest -Uri "https://www.firedaemon.com/download-firedaemon-openssl-1-zip" -OutFile openssl.zip + Invoke-WebRequest -Uri "https://www.firedaemon.com/download-firedaemon-openssl-1.1.1-zip" -OutFile openssl.zip 7z x openssl.zip - name: Set openssl paths diff --git a/.github/workflows/ci-release.yml b/.github/workflows/ci-release.yml index 4f53d3f85..b81ce39ad 100644 --- a/.github/workflows/ci-release.yml +++ b/.github/workflows/ci-release.yml @@ -50,44 +50,41 @@ jobs: - name: Upload symbols linux shell: sh run: | - xz -d ./packages-bionic/klogg_bionic.debug.xz xz -d ./packages-focal/klogg_focal.debug.xz xz -d ./packages-jammy/klogg_jammy.debug.xz + xz -d ./packages-noble/klogg_noble.debug.xz xz -d ./packages-oracle/klogg_oracle.debug.xz xz -d ./packages-appimage/klogg_appimage.debug.xz - sentry-cli upload-dif ./packages-bionic/klogg_bionic.debug ./packages-bionic/klogg_bionic sentry-cli upload-dif ./packages-focal/klogg_focal.debug ./packages-focal/klogg_focal sentry-cli upload-dif ./packages-jammy/klogg_jammy.debug ./packages-jammy/klogg_jammy + sentry-cli upload-dif ./packages-noble/klogg_noble.debug ./packages-noble/klogg_noble sentry-cli upload-dif ./packages-oracle/klogg_oracle.debug ./packages-oracle/klogg_oracle sentry-cli upload-dif ./packages-appimage/klogg_appimage.debug ./packages-appimage/klogg_appimage - name: Upload symbols mac shell: sh run: | - sentry-cli upload-dif ./packages-macos-qt5/klogg-Qt5.app/Contents/MacOS/klogg ./packages-macos-qt5/klogg-Qt5.dSym sentry-cli upload-dif ./packages-macos-qt6/klogg-Qt6.app/Contents/MacOS/klogg ./packages-macos-qt6/klogg-Qt6.dSym - name: Upload symbols win shell: sh run: | - sentry-cli upload-dif ./packages-windows-x64-qt5/klogg-$KLOGG_VERSION-x64-Qt5-pdb.zip sentry-cli upload-dif ./packages-windows-x86-qt5/klogg-$KLOGG_VERSION-x86-Qt5-pdb.zip sentry-cli upload-dif ./packages-windows-x64-qt6/klogg-$KLOGG_VERSION-x64-Qt6-pdb.zip - name: Cleanup release artifacts shell: sh run: | - rm -rf ./packages-bionic/klogg_bionic rm -rf ./packages-focal/klogg_focal rm -rf ./packages-jammy/klogg_jammy + rm -rf ./packages-noble/klogg_noble rm -rf ./packages-oracle/klogg_oracle rm -rf ./packages-appimage/klogg_appimage - rm -rf ./packages-macos-qt5/klogg-Qt5.app rm -rf ./packages-macos-qt6/klogg-Qt6.app mkdir ./linux-debug - mv ./packages-bionic/klogg_bionic.debug ./linux-debug mv ./packages-focal/klogg_focal.debug ./linux-debug mv ./packages-jammy/klogg_jammy.debug ./linux-debug + mv ./packages-noble/klogg_noble.debug ./linux-debug mv ./packages-oracle/klogg_oracle.debug ./linux-debug mv ./packages-appimage/klogg_appimage.debug ./linux-debug tar -cJf ./linux-debug/klogg-$KLOGG_VERSION-symbols.tar.xz ./linux-debug/* @@ -104,7 +101,7 @@ jobs: - name: Prepare checksums shell: sh run: | - sha256sum --binary ./packages-bin/* ./packages-bionic/* ./packages-focal/* ./packages-jammy/* ./packages-oracle/* ./packages-appimage/* > ./packages-bin/klogg-$KLOGG_VERSION-sha256.txt + sha256sum --binary ./packages-bin/* ./packages-focal/* ./packages-jammy/* ./packages-noble/* ./packages-oracle/* ./packages-appimage/* > ./packages-bin/klogg-$KLOGG_VERSION-sha256.txt - name: Release win uses: "marvinpinto/action-automatic-releases@latest" @@ -113,7 +110,6 @@ jobs: automatic_release_tag: continuous-win prerelease: true files: | - ./packages-windows-x64-qt5/* ./packages-windows-x86-qt5/* ./packages-windows-x64-qt6/* @@ -124,9 +120,9 @@ jobs: automatic_release_tag: continuous-linux prerelease: true files: | - ./packages-bionic/* ./packages-focal/* ./packages-jammy/* + ./packages-noble/* ./packages-oracle/* ./packages-appimage/* ./packages-bin/* @@ -139,7 +135,6 @@ jobs: automatic_release_tag: continuous-osx prerelease: true files: | - ./packages-macos-qt5/* ./packages-macos-qt6/* - name: Discord notification diff --git a/3rdparty/CMakeLists.txt b/3rdparty/CMakeLists.txt index e5b1c0472..2be860894 100644 --- a/3rdparty/CMakeLists.txt +++ b/3rdparty/CMakeLists.txt @@ -4,8 +4,9 @@ include(CPM) set(_TMP_CPM_USE_LOCAL_PACKAGES ${CPM_USE_LOCAL_PACKAGES}) -cpmaddpackage("gh:simdutf/simdutf@3.2.13") -cpmaddpackage("gh:foonathan/type_safe@0.2.3") +cpmaddpackage("gh:simdutf/simdutf@5.6.2") +cpmaddpackage("gh:foonathan/type_safe@0.2.4") +cpmaddpackage("gh:RoaringBitmap/CRoaring@4.2.1") if(APPLE) cpmaddpackage( @@ -14,7 +15,7 @@ if(APPLE) GITHUB_REPOSITORY arl/macdeployqtfix GIT_TAG - ffe980011dd7a08ac2bc79dbd5ac86a62b1c1f05 + df888505849d3c06d20a4338af276dfa7d11826a DOWNLOAD_ONLY YES ) @@ -23,19 +24,6 @@ if(APPLE) endif() endif() -cpmaddpackage( - NAME - CRoaring - GITHUB_REPOSITORY - variar/CRoaring - GIT_TAG - 80a8dcf4f683f00cc9be180f8b18de13491b7e27 - EXCLUDE_FROM_ALL - YES - OPTIONS - "ENABLE_ROARING_TESTS OFF" -) - cpmaddpackage( NAME maddy @@ -47,48 +35,38 @@ cpmaddpackage( YES ) -if(KLOGG_USE_HYPERSCAN) - cpmaddpackage( - NAME - hyperscan - GITHUB_REPOSITORY - variar/hyperscan - GIT_TAG - 0931a40e0cf1d7f92189bc546c3491ed5c113f8b - EXCLUDE_FROM_ALL - YES - ) - if(hyperscan_ADDED) - message("Adding alias for hyperscan") - add_library(hyperscan_wrapper INTERFACE) - target_link_libraries(hyperscan_wrapper INTERFACE hs) - target_include_directories(hyperscan_wrapper INTERFACE ${hyperscan_SOURCE_DIR}/src) - else() - add_library(hyperscan_wrapper INTERFACE) - target_link_libraries(hyperscan_wrapper INTERFACE ${HYPERSCAN_LIBRARY}) - target_include_directories(hyperscan_wrapper INTERFACE ${HYPERSCAN_INCLUDE_DIR}) - endif() -elseif(KLOGG_USE_VECTORSCAN) +if(KLOGG_USE_VECTORSCAN) cpmaddpackage( NAME vectorscan GITHUB_REPOSITORY VectorCamp/vectorscan GIT_TAG - b4bba94b1a250603b0b198e0394946e32f6c3f30 + d29730e1cb9daaa66bda63426cdce83505d2c809 EXCLUDE_FROM_ALL YES + OPTIONS + "BUILD_STATIC_LIBS ON" + "BUILD_UNIT OFF" + "BUILD_TOOLS OFF" + "BUILD_EXAMPLES OFF" + "BUILD_BENCHMARKS OFF" + "BUILD_DOC OFF" + "BUILD_CHIMERA OFF" + "BUIlD_AVX2 OFF" + "BUIlD_AVX512 OFF" + "BUIlD_AVX512VBMI OFF" + "FAT_RUNTIME OFF" ) - if(vectorscan_ADDED) - message("Adding alias for vectorscan") - add_library(vectorscan_wrapper INTERFACE) - target_link_libraries(vectorscan_wrapper INTERFACE hs) - target_include_directories(vectorscan_wrapper INTERFACE ${vectorscan_SOURCE_DIR}/src) - else() - add_library(vectorscan_wrapper INTERFACE) - target_link_libraries(vectorscan_wrapper INTERFACE ${VECTORSCAN_LIBRARY}) - target_include_directories(vectorscan_wrapper INTERFACE ${VECTORSCAN_INCLUDE_DIR}) - endif() + + message("Adding alias for vectorscan") + add_library(klogg_vectorscan INTERFACE) + target_link_libraries(klogg_vectorscan INTERFACE hs) + target_include_directories(klogg_vectorscan INTERFACE + ${vectorscan_SOURCE_DIR}/src + ${vectorscan_BINARY_DIR} + ) + endif() cpmaddpackage( @@ -220,7 +198,7 @@ cpmaddpackage( GITHUB_REPOSITORY gpakosz/whereami GIT_TAG - ba364cd54fd431c76c045393b6522b4bff547f50 + dcb52a058dc14530ba9ae05e4339bd3ddfae0e0e DOWNLOAD_ONLY YES ) @@ -262,7 +240,7 @@ cpmaddpackage( GITHUB_REPOSITORY KDAB/KDToolBox GIT_TAG - 253a6c087c626cd477e15c9dae4b0e3ec27afaee + 6468867d1a46eabe1bcb2cd342f338fe66f06675 DOWNLOAD_ONLY YES ) @@ -283,7 +261,7 @@ cpmaddpackage( GITHUB_REPOSITORY SpartanJ/efsw GIT_TAG - 2e73f8e96779a2895c6242d66cadb3a15aa5e192 + 1.4.1 EXCLUDE_FROM_ALL YES OPTIONS @@ -302,7 +280,7 @@ cpmaddpackage( GITHUB_REPOSITORY variar/oneTBB GIT_TAG - 281c5b4ae2f1a610a13ba9e812350bb01bb88365 + c9be1ac2930f02dea523003ed801b4489f3e6b6e EXCLUDE_FROM_ALL YES OPTIONS @@ -322,7 +300,7 @@ cpmaddpackage( GITHUB_REPOSITORY microsoft/mimalloc VERSION - 2.1.2 + 2.1.7 EXCLUDE_FROM_ALL YES OPTIONS @@ -374,7 +352,7 @@ if(KLOGG_USE_SENTRY) GITHUB_REPOSITORY getsentry/sentry-native GIT_TAG - 79899a808a4675a66db6b76a144cecea954506ea + a3d58622a807b9dda174cb9fc18fa0f98c89d043 EXCLUDE_FROM_ALL YES ) @@ -386,6 +364,29 @@ if(KLOGG_USE_SENTRY) endif() endif(KLOGG_USE_SENTRY) +cpmaddpackage( + NAME + simdcomp + GITHUB_REPOSITORY + lemire/simdcomp + GIT_TAG + 009c67807670d16f8984c0534aef0e630e5465a4 + DOWNLOAD_ONLY + YES +) +if(simdcomp_ADDED) + add_library(simdcomp STATIC + ${simdcomp_SOURCE_DIR}/src/avxbitpacking.c + ${simdcomp_SOURCE_DIR}/src/simdfor.c + ${simdcomp_SOURCE_DIR}/src/simdcomputil.c + ${simdcomp_SOURCE_DIR}/src/simdbitpacking.c + ${simdcomp_SOURCE_DIR}/src/simdintegratedbitpacking.c + ${simdcomp_SOURCE_DIR}/src/simdpackedsearch.c + ${simdcomp_SOURCE_DIR}/src/simdpackedselect.c + ) + target_include_directories(simdcomp PUBLIC ${simdcomp_SOURCE_DIR}/include) +endif() + set(klogg_cpm_targets xxhash Catch2 @@ -407,6 +408,7 @@ set(klogg_cpm_targets crashpad_compat crashpad_util mini_chromium + simdcomp ) foreach(target ${klogg_cpm_targets}) if(TARGET ${target}) diff --git a/BUILD.md b/BUILD.md index ca2554862..f3b5a5774 100644 --- a/BUILD.md +++ b/BUILD.md @@ -9,6 +9,7 @@ will be enabled if available on build machine. ## Getting the Source This project is [hosted on GitHub](https://github.com/variar/klogg). You can clone this project directly using this command: + ``` git clone https://github.com/variar/klogg ``` @@ -16,29 +17,32 @@ git clone https://github.com/variar/klogg ## Dependencies To build Klogg: - * cmake 3.12 or later to generate build files - * C++ compiler with decent C++17 support (at least gcc 7.5, clang 7, msvc 19.14) - * Qt libraries 5.9 or later (CI builds use Qt 5.9.5/5.12.5/5.15.2): - - QtCore - - QtGui - - QtWidgets - - QtConcurrent - - QtNetwork - - QtXml - - QtTools + +- cmake 3.12 or later to generate build files +- C++ compiler with decent C++17 support (at least gcc 7.5, clang 7, msvc 19.14) +- Qt libraries 5.9 or later (CI builds use Qt 5.9.5/5.12.5/5.15.2): + - QtCore + - QtGui + - QtWidgets + - QtConcurrent + - QtNetwork + - QtXml + - QtTools To build Hyperscan regular expressions backend (default): - * CPU with support for [SSSE3](https://en.wikipedia.org/wiki/SSSE3) instructions (for Hyperscan backend) - * Boost (1.58 or later, header-only part) - * Ragel (6.8 or later; precompiled binary is provided for Windows; has to be installed from package managers on Linux or Homebrew on Mac) + +- CPU with support for [SSSE3](https://en.wikipedia.org/wiki/SSSE3) instructions (for Hyperscan backend) +- Boost (1.58 or later, header-only part) +- Ragel (6.8 or later; precompiled binary is provided for Windows; has to be installed from package managers on Linux or Homebrew on Mac) To build installer for Windows: - * nsis to build installer for Windows - * Precompiled OpenSSl library to enable https support on Windows + +- nsis to build installer for Windows +- Precompiled OpenSSl library to enable https support on Windows Building tests: - * QtTest +- QtTest All other dependencies are provided by [CPM](https://github.com/cpm-cmake/CPM.cmake) during cmake configuration stage (see 3rdparty directory). @@ -63,6 +67,7 @@ Memory allocator override can be turned off by passing `-DKLOGG_OVERRIDE_MALLOC` Here is how to build klogg on Ubuntu 18.04. Install dependencies: + ``` sudo apt-get install build-essential cmake qtbase5-dev libboost-all-dev ragel ``` @@ -77,6 +82,12 @@ cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo .. cmake --build . ``` +**_If cmake gives error about missing "Qt5LinguistTools" configuration files, try running:_** + +```bash +sudo apt-get install qttools5-dev +``` + Binaries are placed into `build_root/output`. See `.github/workflows/ci-build.yml` for more information on build process. @@ -97,25 +108,31 @@ Extract to some folder. Directory structure should be something like `C:\Boost\b Then add `BOOST_ROOT` environment variable pointing to main directory of Boost sources so CMake is able to fine it. Prepare build environment for CMake. Open command prompt window and depending on version of Visual Studio run either + ``` call "%ProgramFiles(x86)%\Microsoft Visual Studio\2019\Community\Common7\Tools\vsdevcmd" -arch=x64 ``` + or + ``` call "%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Community\Common7\Tools\vsdevcmd" -arch=x64 ``` Next setup Qt paths: + ``` \bin\qtenv2.bat ``` Then add CMake to PATH: + ``` set PATH=:$PATH ``` Configure klogg solution (use CMake generator matching Visual Studio version): + ``` cd md build_root @@ -135,6 +152,7 @@ Put libcrypto-1_1 and libssl-1_1 for desired architecture near klogg binaries. Klogg requires macOS High Sierra (10.13) or higher. Install [Homebrew](https://brew.sh/) using terminal: + ``` /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" ``` @@ -142,6 +160,7 @@ Install [Homebrew](https://brew.sh/) using terminal: Homebrew installer should also install xcode command line tools. Download and install build dependencies: + ``` brew install cmake ninja qt boost ragel ``` @@ -149,6 +168,7 @@ brew install cmake ninja qt boost ragel Usually path to qt installation looks like `/usr/local/Cellar/qt/5.14.0/lib/cmake/Qt5` Configure and build klogg: + ``` cd mkdir build_root @@ -164,11 +184,12 @@ To override default cmake value pass an option `-DKLOGG_OSX_DEPLOYMENT_TARGET=` is one of `10.14`, `10.15`, `11`, `12`. Klogg's traget must be greater or equal to target used by Qt libraries. ## Running tests + Tests are built by default. To turn them off pass `-DBUILD_TESTS:BOOL=OFF` to cmake. Tests use catch2 (bundled with klogg sources) and require Qt5Test module. Tests can be run using ctest tool provider by CMake: + ``` cd cd build_root ctest --build-config RelWithDebInfo --verbose ``` - diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e65711a4..663ce6b23 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.12) project( klogg - VERSION 23.08.0 + VERSION 24.11.0 DESCRIPTION "klogg log viewer" LANGUAGES C CXX ASM ) @@ -116,10 +116,13 @@ if(MSVC) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W4") endif(CMAKE_C_FLAGS MATCHES "/W[0-4]") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D __SSE4_1__=1 /D __SSE4_2__=1") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D __SSE4_1__=1 /D __SSE4_2__=1") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj ") else() ucm_add_flags(CXX "-fno-sized-deallocation -fno-omit-frame-pointer") - ucm_add_flags(C CXX "-mmmx -msse -msse2 -msse3 -mssse3 -mpopcnt") + ucm_add_flags(C CXX "-mmmx -msse -msse2 -msse3 -mssse3 -msse4.1 -msse4.2 -mpopcnt") if(KLOGG_GENERIC_CPU) ucm_add_flags(C CXX "-march=x86-64 -mtune=generic") else() diff --git a/cmake/CompilerWarnings.cmake b/cmake/CompilerWarnings.cmake index ef936572d..9c43efb73 100644 --- a/cmake/CompilerWarnings.cmake +++ b/cmake/CompilerWarnings.cmake @@ -40,6 +40,7 @@ function(set_project_warnings project_name) /permissive- # standards conformance mode for MSVC compiler. /wd4996 #Your code uses a function, class member, variable, or typedef that's marked deprecated. /wd4702 #unreachable code + /wd4756 #overflow in constant arithmetic -- false positive in catch2 ) set(CLANG_WARNINGS @@ -58,7 +59,7 @@ function(set_project_warnings project_name) -Wpedantic # warn if non-standard C++ is used -Wconversion # warn on type conversions that may lose data -Wsign-conversion # warn on sign conversions - -Wnull-dereference # warn if a null dereference is detected + -Wno-null-dereference # warn if a null dereference is detected -Wdouble-promotion # warn if float is implicit promoted to double -Wformat=2 # warn on security issues around functions that format output # (ie printf) diff --git a/docker/oracle7/Dockerfile b/docker/oracle7/Dockerfile index 0bba4fd41..155462634 100644 --- a/docker/oracle7/Dockerfile +++ b/docker/oracle7/Dockerfile @@ -2,15 +2,16 @@ FROM oraclelinux:7 COPY epel.repo /etc/yum.repos.d -RUN yum update -y - -RUN yum install -y ragel make wget rpm-build git \ +RUN yum update -y && \ + yum install -y ragel make wget rpm-build git \ qt5-qtbase-devel openssl-devel boost-devel zlib-devel \ - devtoolset-7-gcc devtoolset-7-gcc-c++ ninja-build + devtoolset-7-gcc devtoolset-7-gcc-c++ ninja-build && \ + yum clean all RUN wget https://github.com/Kitware/CMake/releases/download/v3.20.2/cmake-3.20.2-linux-x86_64.sh && \ chmod 755 cmake-3.20.2-linux-x86_64.sh && \ - ./cmake-3.20.2-linux-x86_64.sh --prefix=/opt/ --exclude-subdir --skip-license + ./cmake-3.20.2-linux-x86_64.sh --prefix=/opt/ --exclude-subdir --skip-license && \ + rm cmake-3.20.2-linux-x86_64.sh ENV PATH=/opt/rh/devtoolset-7/root/usr/bin:/opt/bin:$PATH diff --git a/docker/oracle8/Dockerfile b/docker/oracle8/Dockerfile index 2bbcd5e46..ce1bae842 100644 --- a/docker/oracle8/Dockerfile +++ b/docker/oracle8/Dockerfile @@ -2,19 +2,20 @@ FROM oraclelinux:8 COPY epel.repo /etc/yum.repos.d -RUN yum update -y - -RUN yum install -y ragel make wget python38 rpm-build git \ +RUN yum update -y && \ + yum install -y ragel make wget python38 rpm-build git \ qt5-qtbase-devel qt5-linguist qt5-qttranslations \ openssl-devel boost-devel zlib-devel libcurl-devel \ - gcc gcc-c++ elfutils-devel + gcc gcc-c++ elfutils-devel && \ + yum clean all RUN wget https://github.com/Kitware/CMake/releases/download/v3.20.2/cmake-3.20.2-linux-x86_64.sh && \ chmod 755 cmake-3.20.2-linux-x86_64.sh && \ - ./cmake-3.20.2-linux-x86_64.sh --prefix=/opt/ --exclude-subdir --skip-license + ./cmake-3.20.2-linux-x86_64.sh --prefix=/opt/ --exclude-subdir --skip-license && \ + rm cmake-3.20.2-linux-x86_64.sh RUN wget https://github.com/ninja-build/ninja/releases/download/v1.10.2/ninja-linux.zip && \ - unzip ninja-linux.zip && chmod 755 ninja && mv ninja /opt/bin + unzip ninja-linux.zip && chmod 755 ninja && mv ninja /opt/bin && rm ninja-linux.zip ENV PATH=/opt/bin:$PATH diff --git a/docker/ubuntu18.04/Dockerfile b/docker/ubuntu18.04/Dockerfile deleted file mode 100644 index cedb14bd5..000000000 --- a/docker/ubuntu18.04/Dockerfile +++ /dev/null @@ -1,18 +0,0 @@ -FROM ubuntu:bionic - -ENV DEBIAN_FRONTEND=noninteractive - -RUN apt update -y - -RUN apt install build-essential \ - qtbase5-dev qt5-qmake qtbase5-dev-tools qttools5-dev qttranslations5-l10n \ - libboost-dev libicu-dev libssl-dev libcurl4-openssl-dev \ - ragel ninja-build zlib1g-dev git \ - wget fuse -y && \ - apt clean && rm -rf /var/lib/apt/lists/* - -RUN wget https://github.com/Kitware/CMake/releases/download/v3.20.2/cmake-3.20.2-linux-x86_64.sh && \ - chmod 755 cmake-3.20.2-linux-x86_64.sh && \ - ./cmake-3.20.2-linux-x86_64.sh --prefix=/opt/ --exclude-subdir --skip-license - -ENV PATH=/opt/bin:$PATH diff --git a/docker/ubuntu20.04/Dockerfile b/docker/ubuntu20.04/Dockerfile index ac9f0cbbd..9251205f9 100644 --- a/docker/ubuntu20.04/Dockerfile +++ b/docker/ubuntu20.04/Dockerfile @@ -2,17 +2,17 @@ FROM ubuntu:focal ENV DEBIAN_FRONTEND=noninteractive -RUN apt update -y - -RUN apt install build-essential \ +RUN apt-get update -y && \ + apt-get install --no-install-recommends build-essential \ qtbase5-dev qt5-qmake qtbase5-dev-tools qttools5-dev qttranslations5-l10n\ libboost-dev libssl-dev libicu-dev libcurl4-openssl-dev \ ragel ninja-build zlib1g-dev git \ - wget fuse -y && \ - apt clean && rm -rf /var/lib/apt/lists/* + wget ca-certificates fuse file -y && \ + apt-get clean && rm -rf /var/lib/apt/lists/* RUN wget https://github.com/Kitware/CMake/releases/download/v3.20.2/cmake-3.20.2-linux-x86_64.sh && \ chmod 755 cmake-3.20.2-linux-x86_64.sh && \ - ./cmake-3.20.2-linux-x86_64.sh --prefix=/opt/ --exclude-subdir --skip-license + ./cmake-3.20.2-linux-x86_64.sh --prefix=/opt/ --exclude-subdir --skip-license && \ + rm cmake-3.20.2-linux-x86_64.sh -ENV PATH=/opt/bin:$PATH \ No newline at end of file +ENV PATH=/opt/bin:$PATH diff --git a/docker/ubuntu18.04_qt5.15/Dockerfile b/docker/ubuntu20.04_qt5.15/Dockerfile similarity index 59% rename from docker/ubuntu18.04_qt5.15/Dockerfile rename to docker/ubuntu20.04_qt5.15/Dockerfile index 75106b106..7f27ab349 100644 --- a/docker/ubuntu18.04_qt5.15/Dockerfile +++ b/docker/ubuntu20.04_qt5.15/Dockerfile @@ -1,22 +1,22 @@ -FROM ubuntu:bionic +FROM ubuntu:focal ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update -y && \ - apt-get install software-properties-common -y && \ - add-apt-repository ppa:beineri/opt-qt-5.15.2-bionic -y && \ - apt-get update -y - -RUN apt-get install build-essential \ + apt-get install --no-install-recommends software-properties-common -y && \ + add-apt-repository ppa:beineri/opt-qt-5.15.3-focal -y && \ + apt-get update -y && \ + apt-get install --no-install-recommends build-essential \ qt515base qt515svg qt515tools qt515imageformats qt515translations \ mesa-common-dev libglu1-mesa-dev \ libboost-dev libicu-dev libssl-dev libcurl4-openssl-dev \ ragel ninja-build zlib1g-dev git \ - wget fuse -y && \ + wget ca-certificates fuse file -y && \ apt-get clean && rm -rf /var/lib/apt/lists/* RUN wget https://github.com/Kitware/CMake/releases/download/v3.20.2/cmake-3.20.2-linux-x86_64.sh && \ chmod 755 cmake-3.20.2-linux-x86_64.sh && \ - ./cmake-3.20.2-linux-x86_64.sh --prefix=/opt/ --exclude-subdir --skip-license + ./cmake-3.20.2-linux-x86_64.sh --prefix=/opt/ --exclude-subdir --skip-license && \ + rm cmake-3.20.2-linux-x86_64.sh -ENV PATH=/opt/bin:/opt/qt515/bin:$PATH \ No newline at end of file +ENV PATH=/opt/bin:/opt/qt515/bin:$PATH diff --git a/docker/ubuntu22.04/Dockerfile b/docker/ubuntu22.04/Dockerfile index ceffaff7b..6cb5a02ec 100644 --- a/docker/ubuntu22.04/Dockerfile +++ b/docker/ubuntu22.04/Dockerfile @@ -2,17 +2,17 @@ FROM ubuntu:jammy ENV DEBIAN_FRONTEND=noninteractive -RUN apt update -y - -RUN apt install build-essential \ +RUN apt update -y && \ + apt install --no-install-recommends build-essential \ qtbase5-dev qt5-qmake qtbase5-dev-tools qttools5-dev qttranslations5-l10n \ libboost-dev libssl-dev libcurl4-openssl-dev \ ragel ninja-build zlib1g-dev git \ - wget fuse file -y && \ + wget ca-certificates fuse file -y && \ apt clean && rm -rf /var/lib/apt/lists/* RUN wget https://github.com/Kitware/CMake/releases/download/v3.20.2/cmake-3.20.2-linux-x86_64.sh && \ chmod 755 cmake-3.20.2-linux-x86_64.sh && \ - ./cmake-3.20.2-linux-x86_64.sh --prefix=/opt/ --exclude-subdir --skip-license + ./cmake-3.20.2-linux-x86_64.sh --prefix=/opt/ --exclude-subdir --skip-license && \ + rm cmake-3.20.2-linux-x86_64.sh ENV PATH=/opt/bin:$PATH diff --git a/docker/ubuntu24.04/Dockerfile b/docker/ubuntu24.04/Dockerfile new file mode 100644 index 000000000..4025f54e6 --- /dev/null +++ b/docker/ubuntu24.04/Dockerfile @@ -0,0 +1,19 @@ +FROM ubuntu:noble + +ENV DEBIAN_FRONTEND=noninteractive + +RUN apt-get update -y && \ + apt-get install --no-install-recommends build-essential \ + qt6-base-dev qt6-5compat-dev qt6-translations-l10n \ + qt6-tools-dev-tools qt6-base-dev-tools qt6-tools-dev \ + libboost-dev libicu-dev libssl-dev libcurl4-openssl-dev \ + ragel ninja-build zlib1g-dev git \ + wget ca-certificates fuse file -y && \ + apt-get clean && rm -rf /var/lib/apt/lists/* + +RUN wget https://github.com/Kitware/CMake/releases/download/v3.20.2/cmake-3.20.2-linux-x86_64.sh && \ + chmod 755 cmake-3.20.2-linux-x86_64.sh && \ + ./cmake-3.20.2-linux-x86_64.sh --prefix=/opt/ --exclude-subdir --skip-license && \ + rm cmake-3.20.2-linux-x86_64.sh + +ENV PATH=/opt/bin:$PATH diff --git a/packaging/windows/klogg.nsi b/packaging/windows/klogg.nsi index c106b35c6..4d73e5d3c 100644 --- a/packaging/windows/klogg.nsi +++ b/packaging/windows/klogg.nsi @@ -123,7 +123,12 @@ Section "Qt Runtime libraries" qtlibs SetOutPath $INSTDIR\platforms File release\platforms\qwindows.dll SetOutPath $INSTDIR\styles +!if ${QT_MAJOR} == "Qt6" + File release\styles\qmodernwindowsstyle.dll +!else File release\styles\qwindowsvistastyle.dll +!endif + SectionEnd Section "MSVC Runtime libraries" vcruntime diff --git a/packaging/windows/prepare_release.cmd b/packaging/windows/prepare_release.cmd index 0b127b2e9..9b5338bae 100644 --- a/packaging/windows/prepare_release.cmd +++ b/packaging/windows/prepare_release.cmd @@ -12,15 +12,15 @@ xcopy %KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\output\klogg.pdb %KLOGG_WORKSPACE%\re xcopy %KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\output\klogg_crashpad_handler.exe %KLOGG_WORKSPACE%\release\ /y xcopy %KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\output\klogg_minidump_dump.exe %KLOGG_WORKSPACE%\release\ /y -xcopy %KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\msvc_19.35_cxx17_64_md_relwithdebinfo\tbb12.dll %KLOGG_WORKSPACE%\release\ /y -xcopy %KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\msvc_19.35_cxx17_64_md_relwithdebinfo\tbb12.pdb %KLOGG_WORKSPACE%\release\ /y -xcopy %KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\msvc_19.35_cxx17_32_md_relwithdebinfo\tbb12.dll %KLOGG_WORKSPACE%\release\ /y -xcopy %KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\msvc_19.35_cxx17_32_md_relwithdebinfo\tbb12.pdb %KLOGG_WORKSPACE%\release\ /y +xcopy %KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\msvc_19.41_cxx17_64_md_relwithdebinfo\tbb12.dll %KLOGG_WORKSPACE%\release\ /y +xcopy %KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\msvc_19.41_cxx17_64_md_relwithdebinfo\tbb12.pdb %KLOGG_WORKSPACE%\release\ /y +xcopy %KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\msvc_19.41_cxx17_32_md_relwithdebinfo\tbb12.dll %KLOGG_WORKSPACE%\release\ /y +xcopy %KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\msvc_19.41_cxx17_32_md_relwithdebinfo\tbb12.pdb %KLOGG_WORKSPACE%\release\ /y -xcopy %KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\msvc_19.36_cxx17_64_md_relwithdebinfo\tbb12.dll %KLOGG_WORKSPACE%\release\ /y -xcopy %KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\msvc_19.36_cxx17_64_md_relwithdebinfo\tbb12.pdb %KLOGG_WORKSPACE%\release\ /y -xcopy %KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\msvc_19.36_cxx17_32_md_relwithdebinfo\tbb12.dll %KLOGG_WORKSPACE%\release\ /y -xcopy %KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\msvc_19.36_cxx17_32_md_relwithdebinfo\tbb12.pdb %KLOGG_WORKSPACE%\release\ /y +xcopy %KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\msvc_19.42_cxx17_64_md_relwithdebinfo\tbb12.dll %KLOGG_WORKSPACE%\release\ /y +xcopy %KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\msvc_19.42_cxx17_64_md_relwithdebinfo\tbb12.pdb %KLOGG_WORKSPACE%\release\ /y +xcopy %KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\msvc_19.42_cxx17_32_md_relwithdebinfo\tbb12.dll %KLOGG_WORKSPACE%\release\ /y +xcopy %KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\msvc_19.42_cxx17_32_md_relwithdebinfo\tbb12.pdb %KLOGG_WORKSPACE%\release\ /y xcopy %KLOGG_WORKSPACE%\%KLOGG_BUILD_ROOT%\generated\documentation.html %KLOGG_WORKSPACE%\release\ /y xcopy %KLOGG_WORKSPACE%\COPYING %KLOGG_WORKSPACE%\release\ /y @@ -55,7 +55,7 @@ xcopy %QTDIR%\plugins\platforms\qwindows.dll %KLOGG_WORKSPACE%\release\platforms md %KLOGG_WORKSPACE%\release\styles xcopy %QTDIR%\plugins\styles\qwindowsvistastyle.dll %KLOGG_WORKSPACE%\release\styles /y - +xcopy %QTDIR%\plugins\styles\qmodernwindowsstyle.dll %KLOGG_WORKSPACE%\release\styles /y echo "Copying packaging files..." md %KLOGG_WORKSPACE%\chocolately diff --git a/src/app/i18n/Languages.xml b/src/app/i18n/Languages.xml index 78390b244..72e2e7bce 100644 --- a/src/app/i18n/Languages.xml +++ b/src/app/i18n/Languages.xml @@ -2,4 +2,5 @@ + diff --git a/src/app/i18n/zh_TW.ts b/src/app/i18n/zh_TW.ts new file mode 100644 index 000000000..bc1e56ec4 --- /dev/null +++ b/src/app/i18n/zh_TW.ts @@ -0,0 +1,2038 @@ + + + + + AbstractLogView + + + Copy the selection + 複製選取內容 + + + + + &Copy + 複製(&C) + + + + &Copy this line + 複製此行(&C) + + + + Copy this line with line number + 複製此行並附加行號 + + + + + Copy with line numbers + 複製並附加行號 + + + + None + + + + + Clear all + 清除全部標記 + + + + Saving content to %1 + 將內容儲存到 %1 + + + + &Mark + 標記(&M) + + + + Save to file + 儲存到檔案 + + + + Save selected to file + 儲存選取內容到檔案 + + + + Find &next + 尋找下一個(&n) + + + + Find the next occurrence + 尋找下一個符合項目 + + + + Find &previous + 尋找上一個(&p) + + + + / + / + + + + Find the previous occurrence + 尋找上一個符合項目 + + + + &Replace search + 取代(&R) + + + + Replace the search expression with the selection + 用選取內容取代搜尋表達式 + + + + &Add to search + 新增到搜尋(&A) + + + + Add the selection to the current search + 將選取內容新增到目前搜尋 + + + + &Exclude from search + 從搜尋中排除所選內容(&E) + + + + Excludes the selection from search + 從搜尋中排除所選內容 + + + + Set search start + 設定搜尋起點 + + + + Set search end + 設定搜尋終點 + + + + Clear search limits + 清除搜尋限制 + + + + Set selection start + 設定選取起點 + + + + Set selection end + 設定選取終點 + + + + Save splitter position + 儲存分隔線位置 + + + + Send to scratchpad + 傳送到便條 + + + + Replace scratchpad + 取代便條 + + + + Highlighters + 醒目提示 + + + + Color labels + 顏色標籤 + + + + CrawlerWidget + + + klogg + klogg + + + + Search history: + 搜尋歷史: + + + + Search in progress (%1 %)... + 正在搜尋(%1 %)... + + + + %1 matches found so far. + 到目前為止已找到 %1 個符合項目 + + + + %1 match found so far. + 到目前為止已找到 %1 個符合項目 + + + + Marks and matches + 標記和符合項目 + + + + Marks + 僅標記 + + + + Matches + 僅符合項目 + + + + Match case + 區分大小寫 + + + + Use regex + 使用正規表達式 + + + + Inverse match + 反向搜尋 + + + + Enable regular expression logical combining + 啟用正規表達式邏輯組合 + + + + Auto-refresh + 自動重新整理 + + + + Clear search history + 清除搜尋歷史 + + + + Edit search history + 編輯搜尋歷史 + + + + Save as Filter + 儲存為篩選器 + + + + Clear search text + 清除搜尋文字 + + + + Search + 搜尋 + + + + Error in expression + 表達式錯誤 + + + + %1 matches found + 找到 %1 個符合項目 + + + + %1 match found + 找到 %1 個符合項目 + + + + File truncated on disk + 磁碟上的檔案已被截斷 + + + + Displayed as %1 + 顯示為 %1 + + + + Detected as %1 + 偵測為 %1 + + + + HighlighterEdit + + + Form + 表單 + + + + Matching Pattern: + 搜尋模式: + + + + Pattern type: + 模式類型: + + + + Ignore case + 忽略大小寫 + + + + Highlight only match + 僅醒目顯示符合項目 + + + + Variate colors + 變化顏色 + + + + Fore Color: + 前景顏色: + + + + Back Color: + 背景顏色: + + + + Extended Regexp + 擴充正規表達式 + + + + Fixed Strings + 固定字串 + + + + HighlighterSetEdit + + + Highlighters + 醒目提示規則 + + + + Set name: + 設定名稱: + + + + New Highlighter + 新增醒目提示規則 + + + + Delete Highlighter + 刪除醒目提示規則 + + + + Move Highlighter Up + 向上移動 + + + + Move Highlighter Down + 向下移動 + + + + HighlightersDialog + + + + Highlighters + 醒目提示規則 + + + + Available sets + 可用列表 + + + + New Highlighter + 新增醒目提示規則 + + + + Delete Highlighter + 刪除醒目提示規則 + + + + Export + 匯出 + + + + Import + 匯入 + + + + Move Highlighter Up + 向上移動 + + + + Move Highlighter Down + 向下移動 + + + + Highlighters set properties + 醒目提示規則屬性 + + + + Color labels + 顏色標籤 + + + + Fore color + 前景顏色 + + + + Back color + 背景顏色 + + + + Include into cycle + 包含到標記佇列 + + + + Export highlighters configuration + 匯出醒目提示規則到檔案 + + + + Select one or more files to open + 選擇一個或多個檔案開啟 + + + + Highlighters (*.conf) + 醒目提示規則 (*.conf) + + + + MainWindow + + + Open URL as log file + 開啟 URL 作為日誌檔案 + + + + Select item to remove from favorites + 選擇從書籤中移除的項目 + + + + klogg -- switch to file + klogg -- 切換到已開啟的檔案 + + + + klogg - generate crash dump + klogg - 產生當機記錄 + + + + This will shutdown klogg and generate diagnostic crash dump. Continue? + 關閉 klogg 並產生診斷性的當機記錄。是否繼續? + + + + Open window + 開啟視窗 + + + + klogg - scratchpad + klogg - 便條 + + + + Open Recent + 最近開啟檔案 + + + + Quit + 退出 + + + + Open file + 開啟檔案 + + + + + All files (*) + 全部檔案 (*) + + + + Downloading %1 + 正在下載 %1 + + + + + Klogg - File download + klogg -- 檔案下載 + + + + Failed to create temp file + 建立臨時檔案失敗 + + + + klogg - remove from recent + klogg - 從最近檔案中移除 + + + + Could not read file %1. Remove it from recent files? + 無法讀取檔案 %1, 是否從最近的檔案中移除? + + + + klogg - remove from favorites + klogg - 從書籤中移除 + + + + Could not read file %1. Remove it from favorites? + 無法讀取檔案 %1, 從書籤夾中刪除它? + + + + klogg - clear file + klogg - 清除檔案內容 + + + + Clear file %1? + 清空檔案 %1? + + + + URL to download: + 下載檔案的URL: + + + + About klogg + 關於 klogg + + + + <h2>klogg %1</h2><p>A fast, advanced log explorer.</p><p>Built %2 from %3</p><p><a href="https://github.com/variar/klogg">https://github.com/variar/klogg</a></p><p>This is fork of glogg</p><p><a href="http://glogg.bonnefon.org/">http://glogg.bonnefon.org/</a></p><p>Using icons from <a href="https://icons8.com">icons8.com</a> project</p><p>Copyright &copy; 2020 Nicolas Bonnefon, Anton Filimonov and other contributors</p><p>You may modify and redistribute the program under the terms of the GPL (version 3 or later).</p> + <h2>klogg %1</h2><p>一款快速、先進的日誌檢視器。</p><p>建構於 %2 來自 %3</p><p><a href="https://github.com/variar/klogg">https://github.com/variar/klogg</a></p><p>這是 glogg 的分支</p><p><a href="http://glogg.bonnefon.org/">http://glogg.bonnefon.org/</a></p><p>使用來自 <a href="https://icons8.com">icons8.com</a> 專案的圖示</p><p>版權 &copy; 2020 Nicolas Bonnefon, Anton Filimonov 和其他貢獻者</p><p>您可以根據 GPL-3(或更新的版本)的條款修改和重新散佈該程式。</p> + + + + About Qt + 關於 Qt + + + + klogg documentation + klogg 文件 + + + + Open file from archive + 從壓縮檔中開啟檔案 + + + + Untitled + 未命名 + + + + %1 - %2%3 + %1 - %2%3 + + + + + + + klogg + klogg + + + + Ln:%1/%2 + 行數:%1/%2 + + + + Ln:%1/%2 Col:%3 Sel:%4|%5 + 行數:%1/%2 列數:%3 選取:%4|%5 + + + + Ln:%1/%2 Sel:%4|%5 + 行數:%1/%2 選取:%4|%5 + + + + - Indexing lines... (%1 %) + - 正在建立行數索引... (%1 %) + + + + Not enough memory. + 記憶體不足。 + + + + The system does not have enough memory to hold the index for this file. The file will now be closed. + 系統記憶體不足,無法存放此檔案的索引。檔案將會被關閉。 + + + + Extract archive to temp folder? + 將壓縮檔解壓縮到臨時資料夾? + + + + Extracting %1 + 正在解壓縮 %1 + + + + Failed to decompress %1 + 解壓縮 %1 失敗 + + + + Failed to extract %1 + 提取 %1 失敗 + + + + (build + (建構 + + + + &%1 %2 + &%1 %2 + + + + modified on %1 + 修改於 %1 + + + + Remove from favorites + 從書籤中移除 + + + + OptionsDialog + + + Klogg preferences + Klogg 偏好設定 + + + + General + 一般 + + + + Search options + 搜尋選項 + + + + Search history size: + 儲存搜尋歷史行數: + + + + Highlight matches + 醒目顯示符合項目 + + + + Incremental + 增量 + + + + Variate highlight + 醒目顯示變數 + + + + Run search on add or replace pattern + 在新增或取代模式上執行搜尋 + + + + Session options + 工作階段選項 + + + + Minimize to tray + 最小化到工具列 + + + + Load last session + 載入最後的工作階段 + + + + Follow file on load + 載入時追蹤檔案 + + + + Enable multiple windows + 開啟多視窗模式 + + + + Version checking options + 版本檢查選項 + + + + Check for new version + 檢查新版本 + + + + View + 檢視 + + + + QuickFind search type: + 快速尋找搜尋類型: + + + + Main search type: + 主要搜尋類型: + + + + Text + 文字 + + + + Font family: + 字型: + + + + Font size: + 大小: + + + + Force font anti-aliasing + 強制字型抗鋸齒 + + + + Wrap text + 文字換行 + + + + Language + 語言 + + + + Style + 主題 + + + + High DPI + 高解析度 + + + + Enable Qt High DPI support + 啟用 Qt 高解析度支援 + + + + Scale rounding: + 縮放類型: + + + + Round + 取近似值 + + + + Ceil + 向上取整 + + + + Floor + 向下取整 + + + + RoundPreferFloor + 優先向下取整 + + + + PassThrough + 透傳 + + + + Need to restart application to apply these settings + 設定生效需要重新啟動應用程式 + + + + Miscellaneous + 其他 + + + + Hide ANSI Colors (search performance will be reduced) + 隱藏 ANSI 顏色(搜尋效能會降低) + + + + File + 檔案 + + + + File change monitoring + 檔案變化時偵測 + + + + Enable filesystem change monitoring + 啟用檔案系統變化偵測 + + + + Enable polling + 啟用輪詢 + + + + Polling interval (ms): + 輪詢間隔 (ms): + + + + Use fast modification detection + 使用快速修改偵測 + + + + Turn on follow on scroll past the end + 允許越界捲動 + + + + Encoding + 編碼 + + + + Encoding for new files + 對新檔案進行編碼 + + + + Recent files + 最近開啟檔案 + + + + Show the number of recently opened files: + 最近開啟檔案列表長度: + + + + Archives + 歸檔 + + + + Extract archives + 自動解壓縮歸檔 + + + + Extract archives without confirmation + 無需確認即可提取檔案 + + + + File download + 檔案下載 + + + + Verify certificates for https connections + 驗證 HTTPS 憑證 + + + + Shortcuts + 快捷鍵 + + + + Advanced + 進階 + + + + Indexing and search + 索引和搜尋 + + + + Regular expressions engine: + 正規表達式引擎: + + + + Use parallel search + 使用並行搜尋 + + + + Index file read buffer (Mib): + 索引檔案讀取緩衝區大小(Mib): + + + + Search read buffer (lines): + 搜尋讀取緩衝區大小(行數): + + + + File will be kept closed as much as possible. Affects only files opened after check state changed + 檔案將盡可能地保持關閉。只影響到檢查狀態改變後開啟的檔案 + + + + Keep file closed + 保持檔案關閉 + + + + Optimize search for non-latin encodings + 最佳化非拉丁文編碼搜尋 + + + + Caching + 快取 + + + + Enable search results cache + 啟用搜尋結果快取 + + + + Search cache size (lines): + 搜尋快取行數: + + + + Logging + 日誌 + + + + Enable logging + 開啟日誌 + + + + Verbosity + 詳細級別 + + + + Extended Regexp + 擴充正規表達式 + + + + Fixed Strings + 固定字串 + + + + Hyperscan + Hyperscan + + + + Qt + Qt + + + + Klogg needs to be restarted to apply some changes. + Klogg 需要關閉後重新開啟才能套用這些更改 + + + + Action + 動作 + + + + Primary shortcut + 主要快捷鍵 + + + + Secondary shortcut + 次要快捷鍵 + + + + PathLine + + + Copy full path + 複製完整路徑 + + + + Copy file name + 複製檔案名稱 + + + + Open containing folder + 開啟包含此檔案的資料夾 + + + + Copy + 複製 + + + + Select all + 全選 + + + + PredefinedFiltersComboBox + + + Predefined filters + 預設篩選器 + + + + PredefinedFiltersDialog + + + Predefined Filters + 預設篩選器 + + + + New Filter + 新增篩選器 + + + + Remove Filter + 移除篩選器 + + + + Import Filters + 匯入篩選器 + + + + Import + 匯入 + + + + Export Filters + 匯出篩選器 + + + + Export + 匯出 + + + + Name + 名稱 + + + + Pattern + 模式 + + + + Regex + 正規表達式 + + + + Select file to import + 選擇要匯入的檔案 + + + + Predefined filters (*.conf);;All files (*) + 預設篩選器 (*.conf);;所有檔案 (*) + + + + Export predefined filters + 匯出預設篩選器 + + + + Predefined filters (*.conf) + 預設篩選器 (*.conf) + + + + QApplication + + + System (%1) + 系統(%1) + + + + Open new window + 開新視窗 + + + + Open file + 開啟檔案 + + + + Close file + 關閉檔案 + + + + Close all files + 關閉所有檔案 + + + + Select all + 全選 + + + + Copy selection to clipboard + 複製選取內容到剪貼簿 + + + + Exit application + 退出應用程式 + + + + Open quick find + 開啟快速尋找 + + + + Quick find forward + 向前快速尋找 + + + + Quick find backward + 向後快速尋找 + + + + Set focus to search input + 設定焦點到搜尋輸入 + + + + Clear file + 清除檔案 + + + + Open containing folder + 開啟包含此檔案的資料夾 + + + + Open file in editor + 在編輯器中開啟檔案 + + + + Copy file path to clipboard + 複製檔案路徑到剪貼簿 + + + + Paste text from clipboard + 從剪貼簿貼上文字 + + + + Open file from URL + 從 URL 開啟檔案 + + + + Monitor file changes + 監控檔案變更 + + + + Toggle text wrap + 切換文字換行 + + + + Reload file + 重新載入檔案 + + + + Stop file loading + 停止檔案載入 + + + + Open scratchpad + 開啟便條 + + + + Switch to file + 切換到檔案 + + + + Change filtered lines visibility + 調整過濾後行數的顯示狀態 + + + + Increase main view + 增加主要檢視 + + + + Decrease main view + 減少主要檢視 + + + + QuickFind: Find next + 快速尋找:找下一個 + + + + QuickFind: Find previous + 快速尋找:找上一個 + + + + Add line mark + 新增行標記 + + + + Jump to next mark + 跳到下一個標記 + + + + Jump to previous mark + 跳到上一個標記 + + + + Move selection up + 向上移動選取 + + + + Move selection down + 向下移動選取 + + + + Scroll up + 向上捲動 + + + + Scroll down + 向下捲動 + + + + Scroll left + 向左捲動 + + + + Scroll right + 向右捲動 + + + + Jump to the beginning of the current line + 跳到此行的開始 + + + + Jump to the end start of the current line + 跳到此行的結束 + + + + Jump to the right of the text + 跳到文字的右邊 + + + + Jump to the buttom of the text + 跳到文字的底端 + + + + Jump to the top of the text + 跳到文字的頂端 + + + + Jump to line + 跳至行數 + + + + Main view: find next + 主要檢視:找下一個 + + + + Main view: find previous + 主要檢視:找上一個 + + + + Set selection to QuickFind and find next + 設定選取為快速尋找並找下一個 + + + + Set selection to QuickFind and find previous + 設定選取為快速尋找並找上一個 + + + + Release focus from view + 從視窗釋放焦點 + + + + Highlight text with color 1 + 用顏色 1 醒目顯示文字 + + + + Highlight text with color 2 + 用顏色 2 醒目顯示文字 + + + + Highlight text with color 3 + 用顏色 3 醒目顯示文字 + + + + Highlight text with color 4 + 用顏色 4 醒目顯示文字 + + + + Highlight text with color 5 + 用顏色 5 醒目顯示文字 + + + + Highlight text with color 6 + 用顏色 6 醒目顯示文字 + + + + Highlight text with color 7 + 用顏色 7 醒目顯示文字 + + + + Highlight text with color 8 + 用顏色 8 醒目顯示文字 + + + + Highlight text with color 9 + 用顏色 9 醒目顯示文字 + + + + Highlight text with next color + 用下一個顏色醒目顯示文字 + + + + Clear all color labels + 清除所有顏色標籤 + + + + Send selection to scratchpad + 將選取內容送到便條 + + + + Replace scratchpad with selection + 用選取內容替換便條 + + + + Add selection to search pattern + 將選取內容加到搜尋模式 + + + + Exclude selection from search pattern + 從搜尋模式中排除選取內容 + + + + Replace search pattern with selection + 用選取內容替換搜尋模式 + + + + Select lines down + 向下選取行 + + + + Select lines up + 向上選取行 + + + + None + + + + + Color label 1 + 顏色標籤 1 + + + + Color label 2 + 顏色標籤 2 + + + + Color label 3 + 顏色標籤 3 + + + + Color label 4 + 顏色標籤 4 + + + + Color label 5 + 顏色標籤 5 + + + + Color label 6 + 顏色標籤 6 + + + + Color label 7 + 顏色標籤 7 + + + + Color label 8 + 顏色標籤 8 + + + + Color label 9 + 顏色標籤 9 + + + + QObject + + + Searching (position %1 %) + 搜尋中(位置 %1 %) + + + + TiB + TiB + + + + GiB + GiB + + + + MiB + MiB + + + + KiB + KiB + + + + B + B + + + + TabbedCrawlerWidget + + + Close this + 關閉此標籤 + + + + Close others + 關閉其他標籤 + + + + Close to the left + 關閉左側標籤 + + + + Close to the right + 關閉右側標籤 + + + + Close all + 全部關閉 + + + + Copy full path + 複製完整路徑 + + + + Open containing folder + 開啟所在資料夾 + + + + Rename tab + 重新命名標籤 + + + + Reset tab name + 重設標籤名稱 + + + + klogg::mainwindow::action + + + &New window + 開新視窗(&N) + + + + Create new klogg window + 建立新 klogg 視窗 + + + + &Open... + 開啟(&O)... + + + + Open a file + 開啟檔案 + + + + Clear List + 清空列表 + + + + &Close + 關閉(&C) + + + + Close document + 關閉文件 + + + + Close &All + 全部關閉(&A) + + + + Close all documents + 關閉所有文件 + + + + E&xit + 退出(&E) + + + + Exit the application + 退出應用程式 + + + + &Copy + 複製(&C) + + + + Copy the selection + 複製選取的內容 + + + + Select &All + 選擇全部(&A) + + + + Select all the text + 選擇全部文字 + + + + Go to line... + 跳至行數... + + + + Scrolls selected main view to specified line + 捲動選定的主檢視到指定行數 + + + + &Find... + 尋找(&F)... + + + + Find the text + 尋找目前文字 + + + + Clear file... + 清除檔案內容... + + + + Clear current file + 清除目前檔案 + + + + Open containing folder + 開啟所在資料夾 + + + + Open folder containing current file + 開啟包含目前檔案的資料夾 + + + + Open in editor + 在編輯器中開啟 + + + + Open current file in default editor + 預設編輯器中開啟目前檔案 + + + + Copy full path + 複製完整路徑 + + + + Copy full path for file to clipboard + 複製完整路徑到剪貼簿 + + + + Open from clipboard + 從剪貼簿開啟 + + + + Open clipboard as log file + 開啟剪貼簿作為日誌檔案 + + + + Open from URL... + 從 URL 中開啟... + + + + Open URL as log file + 開啟 URL 作為日誌檔案 + + + + Matches &overview + 符合項目概覽(&o) + + + + Line &numbers in main view + 主檢視中的行號(&n) + + + + Line &numbers in filtered view + 篩選檢視中的行號(&n) + + + + &Follow File + 跟隨檔案變化(&F) + + + + &Wrap text + 文字換行(&W) + + + + &Reload + 重新載入(&R) + + + + &Stop + 停止(&S) + + + + &Preferences... + 偏好設定(&P)... + + + + Show application settings dialog + 顯示應用程式設定對話方塊 + + + + Configure &highlighters... + 設定醒目提示(&h)... + + + + Show highlighters configuration + 展示醒目提示設定 + + + + &Documentation... + 文件(&D)... + + + + Show documentation + 顯示文件 + + + + &About + 關於(&A) + + + + Show the About box + 顯示關於對話匡 + + + + About &Qt + 關於 &QT + + + + Show the Qt library's About box + 顯示 Qt 函式庫的 "關於 "對話框 + + + + Report issue... + 回報問題... + + + + Report an issue on GitHub + 在 GitHub 上回報一個問題 + + + + Join Discord community... + 加入 Discord 社群... + + + + Join Klogg development community at Discord + 加入 Klogg 開發者 Discord 社群 + + + + Join Telegram community... + 加入 Telegram 社群... + + + + Join Klogg development community at Telegram + 加入 Klogg 開發者 Telegram 社群 + + + + Generate crash dump + 產生當機報告 + + + + Generate diagnostic crash dump + 產生當機診斷報告 + + + + Scratchpad + 便條 + + + + Show the scratchpad + 顯示便條 + + + + Add to favorites + 加入書籤 + + + + Remove from favorites... + 從書籤中移除... + + + + Switch to opened file... + 切換到已開啟檔案... + + + + Predefined filters... + 預設篩選器... + + + + Show dialog to configure filters + 顯示設定篩選器的對話方塊 + + + + Auto + 自動 + + + + Automatically detect the file's encoding + 自動偵測檔案的編碼 + + + + klogg::mainwindow::menu + + + &File + 檔案(&F) + + + + &Edit + 編輯(&E) + + + + &View + 檢視(&V) + + + + Opened files + 已開啟檔案 + + + + &Tools + 工具(&T) + + + + Highlighters + 醒目提示 + + + + F&avorites + 書籤(&F) + + + + &Help + 支援(&H) + + + + E&ncoding + 編碼(&E) + + + + klogg::mainwindow::toolbar + + + &Toolbar + 工具列(&T) + + + + klogg::mainwindow::trayicon + + + klogg log viewer + Klogg 日誌檢視器 + + + diff --git a/src/app/kloggapp.h b/src/app/kloggapp.h index 472ef1595..47402d46b 100644 --- a/src/app/kloggapp.h +++ b/src/app/kloggapp.h @@ -30,9 +30,7 @@ #include #include -#if QT_VERSION >= QT_VERSION_CHECK( 5, 12, 0 ) #include -#endif #include #include @@ -124,13 +122,8 @@ class KloggApp : public QApplication { data.insert( "version", kloggVersion() ); data.insert( "files", QVariant{ filesToOpen } ); -#if QT_VERSION >= QT_VERSION_CHECK( 5, 12, 0 ) auto cbor = QCborValue::fromVariant( data ); singleApplication_.sendMessageWithTimeout( cbor.toCbor(), 5000 ); -#else - auto json = QJsonDocument::fromVariant( data ); - singleApplication_.sendMessageWithTimeout( json.toBinaryData(), 5000 ); -#endif QTimer::singleShot( 100, this, &QApplication::quit ); } ); @@ -302,7 +295,7 @@ class KloggApp : public QApplication { if ( !changes.empty() ) { message.append( "

Important changes:

    " ); - for ( const auto& change : qAsConst( changes ) ) { + for ( const auto& change : changes ) { message.append( QString( "
  • %1
  • " ).arg( change ) ); } message.append( "
" ); diff --git a/src/app/messagereceiver.h b/src/app/messagereceiver.h index 49c041d3a..86737598a 100644 --- a/src/app/messagereceiver.h +++ b/src/app/messagereceiver.h @@ -20,9 +20,7 @@ #ifndef MESSAGERECEIVER_H #define MESSAGERECEIVER_H -#if QT_VERSION >= QT_VERSION_CHECK( 5, 12, 0 ) #include -#endif #include #include @@ -51,12 +49,7 @@ class MessageReceiver final : public QObject { public Q_SLOTS: void receiveMessage( const QByteArray& message ) { - -#if QT_VERSION >= QT_VERSION_CHECK( 5, 12, 0 ) const auto data = QCborValue::fromCbor( message ).toVariant().toMap(); -#else - const auto data = QJsonDocument::fromBinaryData( message ).toVariant().toMap(); -#endif LOG_INFO << "Message " << QJsonDocument::fromVariant(data).toJson(); diff --git a/src/logdata/CMakeLists.txt b/src/logdata/CMakeLists.txt index be9e65bfa..f3b33cb4c 100644 --- a/src/logdata/CMakeLists.txt +++ b/src/logdata/CMakeLists.txt @@ -1,7 +1,6 @@ add_library( klogg_logdata STATIC ${CMAKE_CURRENT_SOURCE_DIR}/include/abstractlogdata.h - ${CMAKE_CURRENT_SOURCE_DIR}/include/blockpool.h ${CMAKE_CURRENT_SOURCE_DIR}/include/compressedlinestorage.h ${CMAKE_CURRENT_SOURCE_DIR}/include/encodingdetector.h ${CMAKE_CURRENT_SOURCE_DIR}/include/linepositionarray.h @@ -16,7 +15,6 @@ add_library( ${CMAKE_CURRENT_SOURCE_DIR}/include/filedigest.h ${CMAKE_CURRENT_SOURCE_DIR}/include/readablesize.h ${CMAKE_CURRENT_SOURCE_DIR}/src/abstractlogdata.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/blockpool.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/compressedlinestorage.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/encodingdetector.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/logdata.cpp @@ -54,6 +52,7 @@ target_link_libraries( kdtoolbox robin_hood simdutf + simdcomp klogg_mimalloc_wrapper ) diff --git a/src/logdata/include/blockpool.h b/src/logdata/include/blockpool.h deleted file mode 100644 index 70a1110b9..000000000 --- a/src/logdata/include/blockpool.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C) 2016 -- 2019 Anton Filimonov and other contributors - * - * This file is part of klogg. - * - * klogg is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * klogg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with klogg. If not, see . - */ - -#ifndef BLOCKPOOL_H -#define BLOCKPOOL_H - -#include -#include - -#include - -class BlockPoolBase -{ -public: - BlockPoolBase( const BlockPoolBase& ) = delete; - BlockPoolBase& operator =( const BlockPoolBase& ) = delete; - - BlockPoolBase( BlockPoolBase&& other ) noexcept ; - BlockPoolBase& operator=( BlockPoolBase&& other ) noexcept ; - - size_t getElementSize() const; - size_t getPaddedElementSize() const; - - uint8_t* at(size_t index); - const uint8_t* at(size_t index) const; - - uint32_t currentBlock() const; - - size_t allocatedSize() const; - -protected: - BlockPoolBase( size_t elementSize, size_t alignment ); - - uint8_t* getBlock( size_t elementsCount ); - uint8_t* resizeLastBlock( size_t newSize ); - - void freeLastBlock(); - - size_t lastBlockSize() const; - -private: - klogg::vector pool_; - - size_t elementSize_; - size_t alignment_; - - size_t allocationSize_; - - klogg::vector blockIndex_; -}; - -template -class BlockPool : public BlockPoolBase -{ -public: - BlockPool() : BlockPoolBase( sizeof( ElementType ), alignof( ElementType ) ) - {} - - uint32_t get_block( size_t block_elements_count, ElementType initial_position, size_t* next_offset ) - { - auto ptr = getBlock( block_elements_count ); - if ( ptr ) { - *( reinterpret_cast( ptr ) ) = initial_position; - if ( next_offset ) { - *next_offset = sizeof( ElementType ); - } - } - - return currentBlock(); - } - - uint8_t* resize_last_block( size_t new_size ) - { - return resizeLastBlock( new_size ); - } - - uint32_t free_last_block() - { - freeLastBlock(); - return currentBlock(); - } -}; - -#endif // BLOCKPOOL_H diff --git a/src/logdata/include/compressedlinestorage.h b/src/logdata/include/compressedlinestorage.h index 532fe7957..e2596dd2c 100644 --- a/src/logdata/include/compressedlinestorage.h +++ b/src/logdata/include/compressedlinestorage.h @@ -1,22 +1,3 @@ -/* - * Copyright (C) 2015 Nicolas Bonnefon and other contributors - * - * This file is part of glogg. - * - * glogg is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * glogg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with glogg. If not, see . - */ - /* * Copyright (C) 2016 -- 2019 Anton Filimonov and other contributors * @@ -36,89 +17,34 @@ * along with klogg. If not, see . */ +#include #include #include -#include -#include "blockpool.h" #include "linetypes.h" #include - // This class is a compressed storage backend for LinePositionArray // It emulates the interface of a vector, but take advantage of the nature // of the stored data (increasing end of line addresses) to apply some // compression in memory, while still providing fast, constant-time look-up. -/* The current algorithm takes advantage of the fact most lines are reasonably - * short, it codes each line on: - * - Line < 127 bytes : 1 byte - * - 127 < line < 16383 : 2 bytes - * - line > 16383 : 6 bytes (or 10 bytes) - * Uncompressed backend stores line on 4 bytes or 8 bytes. - * - * The algorithm is quite simple, the file is first divided in two parts: - * - The lines whose end are located before UINT32_MAX - * - The lines whose end are located after UINT32_MAX - * Those end of lines are stored separately in the table32 and the table64 - * respectively. - * - * The EOL list is then divided in blocks of IndexBlockSize (256) lines. - * A block index vector (per table) contains pointers to each block. - * - * Each block is then defined as such: - * Block32 (sizes in byte) - * 00 - Absolute EOF address (4 bytes) - * 04 - ( 0xxx xxxx if second line is < 127 ) (1 byte, relative) - * - ( 10xx xxxx - * xxxx xxxx if second line is < 16383 ) (2 bytes, relative) - * - ( 1111 1111 - * xxxx xxxx - * xxxx xxxx if second line is > 16383 ) (6 bytes, absolute) - * ... - * (126 more lines) - * - * Block64 (sizes in byte) - * 00 - Absolute EOF address (8 bytes) - * 08 - ( 0xxx xxxx if second line is < 127 ) (1 byte, relative) - * - ( 10xx xxxx - * xxxx xxxx if second line is < 16383 ) (2 bytes, relative) - * - ( 1111 1111 - * xxxx xxxx - * xxxx xxxx - * xxxx xxxx - * xxxx xxxx if second line is > 16383 ) (10 bytes, absolute) - * ... - * (126 more lines) - * - * Absolute addressing has been adopted for line > 16383 to bound memory usage in case - * of pathologically long (MBs or GBs) lines, even if it is a bit less efficient for - * long-ish (30 KB) lines. - * - * The table32 always starts at 0, the table64 starts at first_long_line_ - */ - -#ifndef COMPRESSEDLINESTORAGE_H -#define COMPRESSEDLINESTORAGE_H +#ifndef SIMDCOMPRESSEDLINESTORAGE_H +#define SIMDCOMPRESSEDLINESTORAGE_H class CompressedLinePositionStorage { - public: - // Default constructor - CompressedLinePositionStorage() - : block_index_{ 0 } - , long_block_index_{ 0 } - { - } +public: + CompressedLinePositionStorage(); // Copy constructor would be slow, delete! CompressedLinePositionStorage( const CompressedLinePositionStorage& orig ) = delete; CompressedLinePositionStorage& operator=( const CompressedLinePositionStorage& orig ) = delete; - // Move constructor CompressedLinePositionStorage( CompressedLinePositionStorage&& orig ) noexcept; - // Move assignement CompressedLinePositionStorage& operator=( CompressedLinePositionStorage&& orig ) noexcept; + ~CompressedLinePositionStorage() = default; + // Append the passed end-of-line to the storage void append( OffsetInFile pos ); void push_back( OffsetInFile pos ) @@ -129,36 +55,19 @@ class CompressedLinePositionStorage { // Size of the array LinesCount size() const { - return nb_lines_; + return nbLines_; } size_t allocatedSize() const; - struct BlockOffset - : type_safe::strong_typedef - , type_safe::strong_typedef_op::increment - , type_safe::strong_typedef_op::addition - , type_safe::strong_typedef_op::relational_comparison - , type_safe::strong_typedef_op::equality_comparison - , type_safe::strong_typedef_op::explicit_bool - { - using strong_typedef::strong_typedef; - }; - - // Cache the last position read - // This is to speed up consecutive reads (whole page) - struct Cache { - LineNumber index {std::numeric_limits::max() - 1U}; - OffsetInFile position {0}; - BlockOffset offset {0}; - }; - // Element at index - OffsetInFile at( size_t i, Cache* lastPosition = nullptr ) const + OffsetInFile at( size_t i ) const { - return at( LineNumber( i ), lastPosition ); + return at( LineNumber( i ) ); } - OffsetInFile at( LineNumber i, Cache* lastPosition = nullptr ) const; + OffsetInFile at( LineNumber i ) const; + + klogg::vector range( LineNumber firstLine, LinesCount count ) const; // Add one list to the other void append_list( const klogg::vector& positions ); @@ -166,39 +75,35 @@ class CompressedLinePositionStorage { // Pop the last element of the storage void pop_back(); - private: +private: // Utility for move ctor/assign void move_from( CompressedLinePositionStorage&& orig ) noexcept; - // The two indexes - BlockPool pool32_; - BlockPool pool64_; + void compress_current_block(); + void uncompress_last_block(); + struct BlockMetadata { + OffsetInFile firstLineOffset{}; + uint8_t packetBitWidth{}; + size_t packetStorageOffset{}; + }; - // Total number of lines in storage - LinesCount nb_lines_; + klogg::vector blocks_; - // Current position (position of the end of the last line added) - OffsetInFile current_pos_; - - uint32_t block_index_; - uint32_t long_block_index_; + struct alignas( 16 ) AlignedStorage { + std::array d; + }; + klogg::vector packedLinesStorage_; - // The index of the first line whose end is stored in a block64 - // this is the origin point for all calculations in block64 - OptionalLineNumber first_long_line_; + klogg::vector currentLinesBlock_; + klogg::vector currentLinesBlockShifted_; - // Offset of the next position (not yet written) within the current - // block. null means there is no current block (previous block - // finished or no data) - BlockOffset block_offset_; + // Total number of lines in storage + LinesCount nbLines_; - // For pop_back: + // Current position (position of the end of the last line added) + OffsetInFile lastPos_; - // Previous offset to block element, it is restored when we - // "pop_back" the last element. - // A null here means pop_back need to free the block - // that has just been created. - BlockOffset previous_block_offset_; + bool canUseSimdSelect_{ false }; }; #endif diff --git a/src/logdata/include/linepositionarray.h b/src/logdata/include/linepositionarray.h index ab00d547e..e45c2c4b0 100644 --- a/src/logdata/include/linepositionarray.h +++ b/src/logdata/include/linepositionarray.h @@ -39,14 +39,20 @@ #ifndef LINEPOSITIONARRAY_H #define LINEPOSITIONARRAY_H +#include #include +#include +#include #include #include "compressedlinestorage.h" + +#include "containers.h" +#include "linetypes.h" #include "log.h" class SimpleLinePositionStorage { - public: +public: SimpleLinePositionStorage() { storage_.reserve( 10000 ); @@ -58,7 +64,6 @@ class SimpleLinePositionStorage { SimpleLinePositionStorage( SimpleLinePositionStorage&& ) = default; SimpleLinePositionStorage& operator=( SimpleLinePositionStorage&& ) = default; - using Cache = void*; // Append the passed end-of-line to the storage void append( OffsetInFile pos ) { @@ -78,20 +83,34 @@ class SimpleLinePositionStorage { size_t allocatedSize() const { - return storage_.capacity(); + return storage_.size() * sizeof( OffsetInFile ); } // Element at index - OffsetInFile at( size_t i, Cache* = nullptr ) const + OffsetInFile at( size_t i ) const { return storage_.at( i ); } - OffsetInFile at( LineNumber i, Cache* = nullptr ) const + OffsetInFile at( LineNumber i ) const { return at( i.get() ); } + klogg::vector range( LineNumber firstLine, LinesCount count ) const + { + klogg::vector result; + result.reserve( count.get() ); + const int64_t beginIndex = static_cast( firstLine.get() ); + const int64_t endIndex = std::min( beginIndex + static_cast( count.get() ), + static_cast( storage_.size() ) ); + + std::copy_n( storage_.begin() + beginIndex, endIndex - beginIndex, + std::back_inserter( result ) ); + + return result; + } + // Add one list to the other void append_list( const SimpleLinePositionStorage& positions ) { @@ -109,7 +128,7 @@ class SimpleLinePositionStorage { return storage_; } - private: +private: klogg::vector storage_; }; @@ -119,7 +138,7 @@ class SimpleLinePositionStorage { // files) and remove it when more data are added. template class LinePosition { - public: +public: template friend class LinePosition; @@ -162,14 +181,18 @@ class LinePosition { } // Extract an element - inline OffsetInFile at( LineNumber::UnderlyingType i, - typename Storage::Cache* lastPosition = nullptr ) const + inline OffsetInFile at( LineNumber::UnderlyingType i ) const { - const auto pos = array.at( i, lastPosition ); - LOG_DEBUG << "Line pos at " << i << " is " << pos; + const auto pos = array.at( i ); + // LOG_DEBUG << "Line pos at " << i << " is " << pos; return pos; } + klogg::vector range( LineNumber firstLine, LinesCount count ) const + { + return array.range( firstLine, count ); + } + // Set the presence of a fake final LF // Must be used after 'append'-ing a fake LF at the end. void setFakeFinalLF( bool finalLF = true ) @@ -194,7 +217,7 @@ class LinePosition { this->fakeFinalLF_ = other.fakeFinalLF_; } - private: +private: Storage array; bool fakeFinalLF_ = false; }; diff --git a/src/logdata/include/logdataworker.h b/src/logdata/include/logdataworker.h index 3e53a7b1f..56dcc751f 100644 --- a/src/logdata/include/logdataworker.h +++ b/src/logdata/include/logdataworker.h @@ -40,14 +40,15 @@ #define LOGDATAWORKERTHREAD_H #include "containers.h" +#include "linetypes.h" #include #include -#include #include +#include #include -#if !defined(Q_MOC_RUN) +#if !defined( Q_MOC_RUN ) #include #include #include @@ -75,7 +76,7 @@ struct IndexedHash { template class IndexingDataAccessor { - public: +public: IndexingDataAccessor( Data data ) : data_( data ) , guard_( data->dataMutex_ ) @@ -113,6 +114,11 @@ class IndexingDataAccessor { return data_->getEndOfLineOffset( line ); } + klogg::vector getEndOfLineOffsets( LineNumber line, LinesCount count ) const + { + return data_->getEndOfLineOffsets(line, count); + } + // Get the guessed encoding for the content. QTextCodec* getEncodingGuess() const { @@ -174,18 +180,18 @@ class IndexingDataAccessor { return data_->allocatedSize(); } - private: +private: Data data_; LockGuard guard_; }; // This class is a thread-safe set of indexing data. class IndexingData { - public: +public: using ConstAccessor = IndexingDataAccessor; using MutateAccessor = IndexingDataAccessor; - private: +private: qint64 getIndexedSize() const; IndexedHash getHash() const; @@ -199,6 +205,7 @@ class IndexingData { // Get the position (in byte from the beginning of the file) // of the end of the passed line. OffsetInFile getEndOfLineOffset( LineNumber line ) const; + klogg::vector getEndOfLineOffsets( LineNumber line, LinesCount count ) const; // Get the guessed encoding for the content. QTextCodec* getEncodingGuess() const; @@ -220,11 +227,11 @@ class IndexingData { int getProgress() const; void setProgress( int progress ); - private: +private: mutable SharedMutex dataMutex_; - LinePositionArray linePosition_; - mutable tbb::enumerable_thread_specific linePositionCache_; + using LinePositionArrayType = std::variant; + LinePositionArrayType linePosition_; LineLength maxLength_; @@ -259,7 +266,7 @@ using OperationResult = std::variant; class IndexOperation : public QObject { Q_OBJECT - public: +public: IndexOperation( const QString& fileName, const std::shared_ptr& indexingData, AtomicFlag& interruptRequest ) : fileName_( fileName ) @@ -272,12 +279,12 @@ class IndexOperation : public QObject { // and false if it has been cancelled (results not copied) virtual OperationResult run() = 0; - Q_SIGNALS: +Q_SIGNALS: void indexingProgressed( int ); void indexingFinished( bool ); void fileCheckFinished( MonitoredFileStatus ); - protected: +protected: using BlockBuffer = klogg::vector; using BlockData = std::pair; using BlockPrefetcher = tbb::flow::limiter_node; @@ -290,7 +297,7 @@ class IndexOperation : public QObject { std::shared_ptr indexing_data_; AtomicFlag& interruptRequest_; - private: +private: FastLinePositionArray parseDataBlock( OffsetInFile::UnderlyingType blockBegining, const BlockBuffer& block, IndexingState& state ) const; @@ -303,7 +310,7 @@ class IndexOperation : public QObject { class FullIndexOperation : public IndexOperation { Q_OBJECT - public: +public: FullIndexOperation( const QString& fileName, const std::shared_ptr& indexingData, AtomicFlag& interruptRequest, QTextCodec* forcedEncoding = nullptr ) : IndexOperation( fileName, indexingData, interruptRequest ) @@ -312,13 +319,13 @@ class FullIndexOperation : public IndexOperation { } OperationResult run() override; - private: +private: QTextCodec* forcedEncoding_; }; class PartialIndexOperation : public IndexOperation { Q_OBJECT - public: +public: PartialIndexOperation( const QString& fileName, const std::shared_ptr& indexingData, AtomicFlag& interruptRequest ) @@ -331,7 +338,7 @@ class PartialIndexOperation : public IndexOperation { class CheckFileChangesOperation : public IndexOperation { Q_OBJECT - public: +public: CheckFileChangesOperation( const QString& fileName, const std::shared_ptr& indexingData, AtomicFlag& interruptRequest ) @@ -341,14 +348,14 @@ class CheckFileChangesOperation : public IndexOperation { OperationResult run() override; - private: +private: MonitoredFileStatus doCheckFileChanges(); }; class LogDataWorker : public QObject { Q_OBJECT - public: +public: // Pass a pointer to the IndexingData (initially empty) // This object will change it when indexing (IndexingData must be thread safe!) explicit LogDataWorker( const std::shared_ptr& indexing_data ); @@ -375,7 +382,7 @@ class LogDataWorker : public QObject { // Interrupts the indexing if one is in progress void interrupt(); - Q_SIGNALS: +Q_SIGNALS: // Sent during the indexing process to signal progress // percent being the percentage of completion. void indexingProgressed( int percent ); @@ -387,11 +394,11 @@ class LogDataWorker : public QObject { // to copy the new data back. void checkFileChangesFinished( MonitoredFileStatus status ); - private Q_SLOTS: +private Q_SLOTS: void onIndexingFinished( bool result ); void onCheckFileFinished( MonitoredFileStatus result ); - private: +private: OperationResult connectSignalsAndRun( IndexOperation* operationRequested ); // Mutex to wait for operations diff --git a/src/logdata/include/logfiltereddataworker.h b/src/logdata/include/logfiltereddataworker.h index 0163ebaa0..688cbf1b0 100644 --- a/src/logdata/include/logfiltereddataworker.h +++ b/src/logdata/include/logfiltereddataworker.h @@ -43,16 +43,15 @@ #include - #ifndef Q_MOC_RUN -#include #include #include +#include #endif #include "atomicflag.h" -#include "regularexpression.h" #include "linetypes.h" +#include "regularexpression.h" #include "synchronization.h" class LogData; @@ -60,7 +59,7 @@ class LogData; // Class encapsulating a single matching line // Contains the line number the line was found in and its content. class MatchingLine { - public: +public: MatchingLine( LineNumber line ) : lineNumber_{ line } { @@ -77,7 +76,7 @@ class MatchingLine { return lineNumber_ < other.lineNumber_; } - private: +private: LineNumber lineNumber_; }; @@ -95,12 +94,13 @@ struct SearchResults { // This class is a mutex protected set of search result data. // It is thread safe. class SearchData { - public: +public: // will clear new matches SearchResults takeCurrentResults() const; // Atomically add to all the existing search data. - void addAll( LineLength length, const SearchResultArray& matches, LinesCount nbLinesProcessed ); + void addAll( LineLength length, const SearchResultArray& matches, LinesCount nbMatches, + LinesCount nbLinesProcessed ); // Get the number of matches LinesCount getNbMatches() const; // Get the last matched line number @@ -116,7 +116,7 @@ class SearchData { // Atomically clear the data. void clear(); - private: +private: mutable SharedMutex dataMutex_; SearchResultArray matches_; @@ -128,7 +128,7 @@ class SearchData { class SearchOperation : public QObject { Q_OBJECT - public: +public: SearchOperation( const LogData& sourceLogData, AtomicFlag& interruptRequested, const RegularExpressionPattern& regExp, LineNumber startLine, LineNumber endLine ); @@ -137,11 +137,11 @@ class SearchOperation : public QObject { // and false if it has been cancelled (results not copied) virtual void run( SearchData& result ) = 0; - Q_SIGNALS: +Q_SIGNALS: void searchProgressed( LinesCount nbMatches, int percent, LineNumber initialLine ); void searchFinished(); - protected: +protected: // Implement the common part of the search, passing // the shared results and the line to begin the search from. void doSearch( SearchData& result, LineNumber initialLine ); @@ -155,7 +155,7 @@ class SearchOperation : public QObject { class FullSearchOperation : public SearchOperation { Q_OBJECT - public: +public: FullSearchOperation( const LogData& sourceLogData, AtomicFlag& interruptRequested, const RegularExpressionPattern& regExp, LineNumber startLine, LineNumber endLine ) @@ -168,7 +168,7 @@ class FullSearchOperation : public SearchOperation { class UpdateSearchOperation : public SearchOperation { Q_OBJECT - public: +public: UpdateSearchOperation( const LogData& sourceLogData, AtomicFlag& interruptRequested, const RegularExpressionPattern& regExp, LineNumber startLine, LineNumber endLine, LineNumber position ) @@ -179,14 +179,14 @@ class UpdateSearchOperation : public SearchOperation { void run( SearchData& result ) override; - private: +private: LineNumber initialPosition_; }; class LogFilteredDataWorker : public QObject { Q_OBJECT - public: +public: explicit LogFilteredDataWorker( const LogData& sourceLogData ); ~LogFilteredDataWorker() noexcept override; @@ -209,7 +209,7 @@ class LogFilteredDataWorker : public QObject { // get the current indexing data SearchResults getSearchResults() const; - Q_SIGNALS: +Q_SIGNALS: // Sent during the indexing process to signal progress // percent being the percentage of completion. void searchProgressed( LinesCount nbMatches, int percent, LineNumber initialLine ); @@ -217,10 +217,10 @@ class LogFilteredDataWorker : public QObject { // to copy the new data back. void searchFinished(); - private: +private: void connectSignalsAndRun( SearchOperation* operationRequested ); - private: +private: const LogData& sourceLogData_; AtomicFlag interruptRequested_; diff --git a/src/logdata/src/blockpool.cpp b/src/logdata/src/blockpool.cpp deleted file mode 100644 index d27b7bdef..000000000 --- a/src/logdata/src/blockpool.cpp +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (C) 2016 -- 2019 Anton Filimonov and other contributors - * - * This file is part of klogg. - * - * klogg is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * klogg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with klogg. If not, see . - */ - -#include "blockpool.h" - -#include "log.h" - -namespace { - -size_t getElementSizeWithHeader( std::size_t elementSize ) -{ - return elementSize + sizeof( uint16_t ); -} - -size_t getAlignedSize( size_t required_size, size_t alignement ) -{ - return required_size + alignement - required_size % alignement; -} - -size_t getBlockStorageSize( size_t elementsCount, std::size_t elementSize, size_t alignement ) -{ - // doubling the size is overestimate to compensate for possible alignment - // but block will be shrinked to real size after completion - return getAlignedSize( elementSize + 2 * elementsCount * getElementSizeWithHeader( elementSize ), alignement ); -} - -template -void increasePool(PoolType& pool) -{ - const auto oldSize = pool.size(); - pool.resize( oldSize + (oldSize >> 1 ) ); -} - -} - -BlockPoolBase::BlockPoolBase( size_t elementSize, size_t alignment ) - : pool_(1024*1024) - , elementSize_ {elementSize} - , alignment_ {alignment} - , allocationSize_{} -{ - blockIndex_.reserve( 10000 ); -} - -BlockPoolBase::BlockPoolBase( BlockPoolBase&& other ) noexcept -{ - *this = std::move( other ); -} - -BlockPoolBase& BlockPoolBase::operator=( BlockPoolBase&& other ) noexcept -{ - pool_ = std::move( other.pool_ ); - - elementSize_ = other.elementSize_; - alignment_ = other.alignment_; - - allocationSize_ = other.allocationSize_; - - blockIndex_ = std::move( other.blockIndex_ ); - - return *this; -} - -uint8_t* BlockPoolBase::at(size_t index) -{ - return pool_.data() + blockIndex_.at( index ); -} - -const uint8_t* BlockPoolBase::at(size_t index) const -{ - return pool_.data() + blockIndex_.at( index ); -} - -size_t BlockPoolBase::getElementSize() const -{ - return elementSize_; -} - -size_t BlockPoolBase::getPaddedElementSize() const -{ - return getElementSizeWithHeader( elementSize_ ); -} - -uint32_t BlockPoolBase::currentBlock() const -{ - return blockIndex_.empty() ? 0 : type_safe::narrow_cast( blockIndex_.size() - 1 ); -} - -uint8_t* BlockPoolBase::getBlock( size_t elementsCount ) -{ - const auto requiredSize = getBlockStorageSize( elementsCount, elementSize_, alignment_ ); - - const auto alignedAllocationSize = getAlignedSize(allocationSize_, alignment_); - - LOG_DEBUG << "Get block " << elementSize_ - << " pool " << pool_.size() - << " alloc " << allocationSize_ - << " blocks " << blockIndex_.size(); - - if ( alignedAllocationSize + requiredSize >= pool_.size() ) { - increasePool( pool_ ); - } - - blockIndex_.push_back( alignedAllocationSize ); - allocationSize_ = alignedAllocationSize + requiredSize; - - return pool_.data() + blockIndex_.back(); -} - -uint8_t* BlockPoolBase::resizeLastBlock( size_t newSize ) -{ - const auto alignedNewSize = getAlignedSize( newSize, alignment_ ); - const auto currentBlockSize = lastBlockSize(); - - LOG_DEBUG << "Resizing block " - << " from " << currentBlockSize - << " to " << newSize - << " aligned " << alignedNewSize - << " alloc " << allocationSize_; - - if ( alignedNewSize <= currentBlockSize ) { - allocationSize_ -= ( currentBlockSize - alignedNewSize ); - } - else { - const auto delta = alignedNewSize - currentBlockSize; - LOG_DEBUG << "Increasing last block size by " << delta; - - if ( allocationSize_ + delta >= pool_.size() ) { - increasePool( pool_ ); - } - allocationSize_ += delta; - } - - LOG_DEBUG << "Resized block, alloc " << allocationSize_; - - return pool_.data() + blockIndex_.back(); -} - -size_t BlockPoolBase::lastBlockSize() const -{ - if ( blockIndex_.empty() ) { - return 0; - } - - return allocationSize_ - blockIndex_.back(); -} - -void BlockPoolBase::freeLastBlock() -{ - if ( blockIndex_.empty() ) { - return; - } - - const auto freeSize = lastBlockSize(); - LOG_DEBUG << "Free block " << freeSize; - - allocationSize_ = blockIndex_.back(); - - LOG_DEBUG << "Free block, alloc " << allocationSize_; - - blockIndex_.pop_back(); -} - -size_t BlockPoolBase::allocatedSize() const -{ - return allocationSize_; -} diff --git a/src/logdata/src/compressedlinestorage.cpp b/src/logdata/src/compressedlinestorage.cpp index 112796943..5c0a5e4eb 100644 --- a/src/logdata/src/compressedlinestorage.cpp +++ b/src/logdata/src/compressedlinestorage.cpp @@ -1,22 +1,3 @@ -/* - * Copyright (C) 2015 Nicolas Bonnefon and other contributors - * - * This file is part of glogg. - * - * glogg is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * glogg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with glogg. If not, see . - */ - /* * Copyright (C) 2016 -- 2019 Anton Filimonov and other contributors * @@ -37,178 +18,56 @@ */ #include +#include +#include #include +#include +#include +#include +#include #include #include #include "compressedlinestorage.h" +#include "containers.h" +#include "cpu_info.h" #include "linetypes.h" #include "log.h" -static constexpr size_t IndexBlockSize = 256; - -namespace { -// Functions to manipulate blocks - -using BlockOffset = CompressedLinePositionStorage::BlockOffset; - -void set_value_at_offset( uint8_t* block, const BlockOffset& offset, uint8_t value ) -{ - *( block + type_safe::get( offset ) ) = value; -} -template -void set_value_at_offset( uint8_t* block, const BlockOffset& offset, T value ) -{ - *reinterpret_cast( block + type_safe::get( offset ) ) = value; -} - -template -T get_value_at_offset( const uint8_t* block, const BlockOffset& offset ) -{ - return *reinterpret_cast( block + type_safe::get( offset ) ); -} - -// Add a one byte relative delta (0-127) and inc pointer -// First bit is always 0 -void block_add_one_byte_relative( uint8_t* block, BlockOffset& offset, uint8_t value ) -{ - set_value_at_offset( block, offset, value ); - offset += BlockOffset( sizeof( value ) ); -} - -uint8_t block_get_alignment_offset( uint8_t alignment, uint64_t offset ) -{ - return static_cast( alignment - offset % alignment ); -} - -// Add a two bytes relative delta (0-16383) and inc pointer -// First 2 bits are always 10 -void block_add_two_bytes_relative( uint8_t* block, BlockOffset& offset, uint16_t value ) -{ - const uint8_t alignmentOffset - = block_get_alignment_offset( alignof( uint16_t ), type_safe::get( offset ) ); - if ( alignmentOffset != 0 ) { - set_value_at_offset( block, offset, 0xC0 | alignmentOffset ); - offset += BlockOffset( alignmentOffset ); - } - - // Stored in big endian format in order to recognise the initial pattern: - // 10xx xxxx xxxx xxxx - // HO byte | LO byte - set_value_at_offset( block, offset, - qToBigEndian( static_cast( value | ( 1 << 15 ) ) ) ); - offset += BlockOffset( sizeof( value ) ); -} - -template -void block_add_absolute( uint8_t* block, BlockOffset& offset, ElementType value ) -{ - uint8_t alignmentOffset - = block_get_alignment_offset( alignof( uint16_t ), type_safe::get( offset ) ); - if ( alignmentOffset != 0 ) { - set_value_at_offset( block, offset, 0xC0 | alignmentOffset ); - offset += BlockOffset( alignmentOffset ); - } - - alignmentOffset = block_get_alignment_offset( alignof( ElementType ), - type_safe::get( offset ) + sizeof( uint16_t ) ); - - // 2 bytes marker (actually only the first two bits are tested) - set_value_at_offset( block, offset, uint8_t( 0xFF ) ); - set_value_at_offset( block + 1, offset, alignmentOffset ); - offset += BlockOffset( sizeof( uint16_t ) + alignmentOffset ); - - // Absolute value (machine endian) - // This might be unaligned, can cause problem on some CPUs - set_value_at_offset( block, offset, value ); - offset += BlockOffset( sizeof( ElementType ) ); -} +#include -// Initialise the passed block for reading, returning -// the initial position and a pointer to the second entry. -template -OffsetInFile block_initial_pos( const uint8_t* block, BlockOffset& offset ) -{ - offset = BlockOffset( sizeof( ElementType ) ); - return OffsetInFile( *( reinterpret_cast( block ) ) ); -} +static constexpr size_t SimdIndexBlockSize = 128; -// Give the next position in the block based on the previous -// position, then increase the pointer. -template -OffsetInFile block_next_pos( const uint8_t* block, BlockOffset& offset, OffsetInFile previous_pos ) +void CompressedLinePositionStorage::move_from( CompressedLinePositionStorage&& orig ) noexcept { - OffsetInFile pos = previous_pos; - - uint8_t byte = get_value_at_offset( block, offset ); - - if ( !( byte & 0x80 ) ) { - // High order bit is 0 - pos += OffsetInFile( byte ); - ++offset; - return pos; - } - - if ( byte != 0xFF && ( byte & 0xC0 ) == 0xC0 ) { - // need to skip aligned bytes; - const auto alignmentOffset = static_cast( byte & ( ~0xC0 ) ); - offset += BlockOffset( alignmentOffset ); - byte = get_value_at_offset( block, offset ); - } - ++offset; - - if ( ( byte & 0xC0 ) == 0x80 ) { - // Remove the starting 10b - const auto hi_byte = static_cast( byte & ( ~0xC0 ) ); - // We need to read the low order byte - const auto lo_byte = static_cast( get_value_at_offset( block, offset ) ); - // And form the displacement (stored as big endian) - pos += OffsetInFile( ( hi_byte << 8 ) | lo_byte ); + blocks_ = std::move( orig.blocks_ ); + packedLinesStorage_ = std::move( orig.packedLinesStorage_ ); + currentLinesBlock_ = std::move( orig.currentLinesBlock_ ); + currentLinesBlockShifted_ = std::move( orig.currentLinesBlockShifted_ ); - ++offset; - } - else { - // skip aligned bytes - const auto alignmentOffset = get_value_at_offset( block, offset ); - offset += BlockOffset( alignmentOffset + 1u ); + nbLines_ = orig.nbLines_; + lastPos_ = orig.lastPos_; + canUseSimdSelect_ = orig.canUseSimdSelect_; - // And read the new absolute pos (machine endian) - pos = OffsetInFile( get_value_at_offset( block, offset ) ); - offset += BlockOffset( sizeof( ElementType ) ); - } - - return pos; + orig.nbLines_ = 0_lcount; + orig.lastPos_ = 0_offset; } -} // namespace -void CompressedLinePositionStorage::move_from( CompressedLinePositionStorage&& orig ) noexcept +CompressedLinePositionStorage::CompressedLinePositionStorage() { - nb_lines_ = orig.nb_lines_; - first_long_line_ = orig.first_long_line_; - current_pos_ = orig.current_pos_; - block_index_ = orig.block_index_; - long_block_index_ = orig.long_block_index_; - block_offset_ = orig.block_offset_; - previous_block_offset_ = orig.previous_block_offset_; - - orig.nb_lines_ = 0_lcount; + auto requiredInstructions = CpuInstructions::SSE41; + canUseSimdSelect_ = hasRequiredInstructions( supportedCpuInstructions(), requiredInstructions ); } -// Move constructor CompressedLinePositionStorage::CompressedLinePositionStorage( CompressedLinePositionStorage&& orig ) noexcept - : pool32_( std::move( orig.pool32_ ) ) - , pool64_( std::move( orig.pool64_ ) ) { move_from( std::move( orig ) ); } -// Move assignement CompressedLinePositionStorage& CompressedLinePositionStorage::operator=( CompressedLinePositionStorage&& orig ) noexcept { - pool32_ = std::move( orig.pool32_ ); - pool64_ = std::move( orig.pool64_ ); move_from( std::move( orig ) ); return *this; } @@ -216,148 +75,70 @@ CompressedLinePositionStorage::operator=( CompressedLinePositionStorage&& orig ) void CompressedLinePositionStorage::append( OffsetInFile pos ) { // Lines must be stored in order - assert( ( pos > current_pos_ ) || ( pos == 0_offset ) ); - - // Save the pointer in case we need to "pop_back" - previous_block_offset_ = block_offset_; - - bool store_in_big = false; - if ( pos.get() > std::numeric_limits::max() ) { - store_in_big = true; - if ( !first_long_line_ ) { - // First "big" end of line, we will start a new (64) block - first_long_line_ = LineNumber( nb_lines_.get() ); - block_offset_ = {}; - } - } - - if ( !block_offset_ ) { - // We need to start a new block - size_t nextOffset{}; - if ( !store_in_big ) { - block_index_ = pool32_.get_block( IndexBlockSize, pos.get(), &nextOffset ); - } - else { - long_block_index_ = pool64_.get_block( IndexBlockSize, pos.get(), &nextOffset ); - } - block_offset_ = BlockOffset{ nextOffset }; - } - else { - const auto block - = ( !store_in_big ) ? pool32_.at( block_index_ ) : pool64_.at( long_block_index_ ); - auto delta = pos - current_pos_; - if ( delta < 128_offset ) { - // Code relative on one byte - block_add_one_byte_relative( block, block_offset_, delta.get() ); - } - else if ( delta < 16384_offset ) { - // Code relative on two bytes - block_add_two_bytes_relative( block, block_offset_, delta.get() ); - } - else { - // Code absolute - if ( !store_in_big ) - block_add_absolute( block, block_offset_, pos.get() ); - else - block_add_absolute( block, block_offset_, pos.get() ); - } - } + assert( ( pos > lastPos_ ) || ( pos == 0_offset ) ); - current_pos_ = pos; - ++nb_lines_; + currentLinesBlock_.push_back( pos ); + currentLinesBlockShifted_.push_back( + type_safe::narrow_cast( pos.get() - currentLinesBlock_.front().get() ) ); - const auto shrinkBlock = [ this ]( auto& blockPool ) { - const auto effective_block_size = type_safe::get( previous_block_offset_ ); + if ( currentLinesBlock_.size() == SimdIndexBlockSize ) { + compress_current_block(); + } - // We allocate extra space for the last element in case it - // is replaced by an absolute value in the future (following a pop_back) - const auto new_size = effective_block_size + blockPool.getPaddedElementSize(); - blockPool.resize_last_block( new_size ); + lastPos_ = pos; + ++nbLines_; +} - block_offset_ = {}; - previous_block_offset_ = BlockOffset( effective_block_size ); - }; +void CompressedLinePositionStorage::compress_current_block() +{ + BlockMetadata& block = blocks_.emplace_back(); + block.firstLineOffset = currentLinesBlock_.front(); + block.packetBitWidth + = static_cast( simdmaxbitsd1( 0, currentLinesBlockShifted_.data() ) ); - if ( !store_in_big ) { - if ( nb_lines_.get() % IndexBlockSize == 0 ) { - // We have finished the block + const size_t packedLinesSize = block.packetBitWidth; + packedLinesStorage_.resize( packedLinesStorage_.size() + packedLinesSize ); + block.packetStorageOffset = packedLinesStorage_.size() - packedLinesSize; - // Let's reduce its size to what is actually used - shrinkBlock( pool32_ ); - } - } - else { - if ( ( nb_lines_.get() - first_long_line_->get() ) % IndexBlockSize == 0 ) { - // We have finished the block + simdpackd1( 0, currentLinesBlockShifted_.data(), + (__m128i*)( packedLinesStorage_.data() + block.packetStorageOffset ), + block.packetBitWidth ); - // Let's reduce its size to what is actually used - shrinkBlock( pool64_ ); - } - } + currentLinesBlock_.clear(); + currentLinesBlockShifted_.clear(); } -OffsetInFile CompressedLinePositionStorage::at( LineNumber index, Cache* lastPosition ) const +OffsetInFile CompressedLinePositionStorage::at( LineNumber index ) const { - if ( index >= nb_lines_ ) { + if ( index >= nbLines_ ) { LOG_ERROR << "Line number not in storage: " << index.get() << ", storage size is " - << nb_lines_; + << nbLines_; throw std::runtime_error( "Line number not in storage" ); } - auto last_read = lastPosition != nullptr ? *lastPosition : Cache{}; - - const uint8_t* block = nullptr; - BlockOffset offset; - OffsetInFile position; - - if ( !first_long_line_ || index < *first_long_line_ ) { - block = pool32_.at( index.get() / IndexBlockSize ); + const size_t blockIndex = index.get() / SimdIndexBlockSize; + const size_t indexInBlock = index.get() % SimdIndexBlockSize; - if ( ( index.get() == last_read.index.get() + 1 ) - && ( index.get() % IndexBlockSize != 0 ) ) { - position = last_read.position; - offset = last_read.offset; - - position = block_next_pos( block, offset, position ); - } - else { - position = block_initial_pos( block, offset ); - - for ( uint32_t i = 0; i < index.get() % IndexBlockSize; i++ ) { - // Go through all the lines in the block till the one we want - position = block_next_pos( block, offset, position ); - } - } + if ( blockIndex == blocks_.size() ) { + return currentLinesBlock_[ indexInBlock ]; } - else { - const auto index_in_64 = index - *first_long_line_; - block = pool64_.at( index_in_64.get() / IndexBlockSize ); - - if ( ( index.get() == last_read.index.get() + 1 ) - && ( index_in_64.get() % IndexBlockSize != 0 ) ) { - position = last_read.position; - offset = last_read.offset; - - position = block_next_pos( block, offset, position ); - } - else { - position = block_initial_pos( block, offset ); - for ( uint32_t i = 0; i < index_in_64.get() % IndexBlockSize; i++ ) { - // Go through all the lines in the block till the one we want - position = block_next_pos( block, offset, position ); - } - } + const BlockMetadata& block = blocks_[ blockIndex ]; + std::array unpackedBlock; + if ( canUseSimdSelect_ ) { + unpackedBlock[ indexInBlock ] = simdselectd1( + 0, + reinterpret_cast( &packedLinesStorage_[ block.packetStorageOffset ] ), + block.packetBitWidth, static_cast( indexInBlock ) ); } - - // Populate our cache ready for next consecutive read - if ( lastPosition != nullptr ) { - lastPosition->index = index; - lastPosition->position = position; - lastPosition->offset = offset; + else { + simdunpackd1( + 0, + reinterpret_cast( &packedLinesStorage_[ block.packetStorageOffset ] ), + unpackedBlock.data(), block.packetBitWidth ); } - return position; + return block.firstLineOffset + OffsetInFile( unpackedBlock[ indexInBlock ] ); } void CompressedLinePositionStorage::append_list( const klogg::vector& positions ) @@ -368,41 +149,95 @@ void CompressedLinePositionStorage::append_list( const klogg::vector( &packedLinesStorage_[ block.packetStorageOffset ] ), + currentLinesBlockShifted_.data(), block.packetBitWidth ); + + std::transform( currentLinesBlockShifted_.begin(), currentLinesBlockShifted_.end(), + currentLinesBlock_.begin(), [ &block ]( uint32_t pos ) { + return OffsetInFile( pos ) + block.firstLineOffset; + } ); + + blocks_.pop_back(); +} + void CompressedLinePositionStorage::pop_back() { - // Removing the last entered data, there are two cases - if ( previous_block_offset_ ) { - // The last append was a normal entry in an existing block, - // so we can just revert the pointer - block_offset_ = previous_block_offset_; - previous_block_offset_ = {}; + if ( currentLinesBlock_.empty() && !blocks_.empty() ) { + // Last entry caused block compression, so we need to uncompress it + // to de-alloc last entry. + uncompress_last_block(); } - else { - // A new block has been created for the last entry, we need - // to de-alloc it. - - if ( !first_long_line_ ) { - assert( ( nb_lines_.get() - 1 ) % IndexBlockSize == 0 ); - block_index_ = pool32_.free_last_block(); - } - else { - assert( ( nb_lines_.get() - first_long_line_->get() - 1 ) % IndexBlockSize == 0 ); - long_block_index_ = pool64_.free_last_block(); - } - block_offset_ = {}; + if ( !currentLinesBlock_.empty() ) { + currentLinesBlock_.pop_back(); + currentLinesBlockShifted_.pop_back(); } - if ( nb_lines_.get() == 0 ) { - current_pos_ = 0_offset; + if ( nbLines_.get() == 0 ) { + lastPos_ = 0_offset; } else { - --nb_lines_; - current_pos_ = nb_lines_.get() > 0 ? at( nb_lines_.get() - 1 ) : 0_offset; + --nbLines_; + lastPos_ = nbLines_.get() > 0 ? at( nbLines_.get() - 1 ) : 0_offset; } } size_t CompressedLinePositionStorage::allocatedSize() const { - return pool32_.allocatedSize() + pool64_.allocatedSize(); -} \ No newline at end of file + return packedLinesStorage_.size() + blocks_.size() * sizeof( BlockMetadata ); +} + +klogg::vector CompressedLinePositionStorage::range( LineNumber firstLine, + LinesCount count ) const +{ + const size_t firstBlockIndex = firstLine.get() / SimdIndexBlockSize; + const size_t indexInFirstBlock = firstLine.get() % SimdIndexBlockSize; + + const LineNumber lastLine = firstLine + count - 1_lcount; + const size_t lastBlockIndex = lastLine.get() / SimdIndexBlockSize; + const size_t indexInLastBlock = lastLine.get() % SimdIndexBlockSize; + + klogg::vector result; + result.reserve( count.get() ); + + if ( firstBlockIndex == blocks_.size() ) { + std::copy( currentLinesBlock_.begin() + static_cast(indexInFirstBlock), + currentLinesBlock_.begin() + static_cast(indexInLastBlock + 1), + std::back_inserter( result ) ); + } + else { + size_t lastBlockToUnpack = std::min( lastBlockIndex, blocks_.size() - 1 ); + for ( size_t blockIndex = firstBlockIndex; blockIndex <= lastBlockToUnpack; ++blockIndex ) { + const BlockMetadata& block = blocks_[ blockIndex ]; + std::array unpackedBlock; + simdunpackd1( 0, + reinterpret_cast( + &packedLinesStorage_[ block.packetStorageOffset ] ), + unpackedBlock.data(), block.packetBitWidth ); + const size_t copyFromIndex = blockIndex == firstBlockIndex ? indexInFirstBlock : 0u; + const size_t copyToIndex + = blockIndex == lastBlockIndex ? indexInLastBlock + 1 : unpackedBlock.size(); + + std::transform( unpackedBlock.begin() + copyFromIndex, + unpackedBlock.begin() + copyToIndex, std::back_inserter( result ), + [ &block ]( uint32_t pos ) { + return OffsetInFile( pos ) + block.firstLineOffset; + } ); + } + + if ( lastBlockIndex == blocks_.size() ) { + std::copy( currentLinesBlock_.begin(), + currentLinesBlock_.begin() + static_cast(indexInLastBlock + 1), + std::back_inserter( result ) ); + } + } + + return result; +} diff --git a/src/logdata/src/logdata.cpp b/src/logdata/src/logdata.cpp index 4f9c1ea56..a2cd318d3 100644 --- a/src/logdata/src/logdata.cpp +++ b/src/logdata/src/logdata.cpp @@ -352,34 +352,34 @@ LogData::RawLines LogData::getLinesRaw( LineNumber firstLine, LinesCount number rawLines.startLine = firstLine; try { - rawLines.endOfLines.reserve( number.get() ); - klogg::vector lineNumbers{ static_cast( number.get() ) }; - std::iota( lineNumbers.begin(), lineNumbers.end(), firstLine ); - IndexingData::ConstAccessor scopedAccessor{ indexing_data_.get() }; - rawLines.prefilterPattern - = !prefilterPattern_.isEmpty() ? QRegularExpression( - prefilterPattern_, QRegularExpression::CaseInsensitiveOption ) - : QRegularExpression{}; - - if ( lineNumbers.back() >= scopedAccessor.getNbLines() ) { + if ( (firstLine + number).get() > scopedAccessor.getNbLines().get() ) { LOG_WARNING << "Lines out of bound asked for"; return {}; /* exception? */ } + rawLines.endOfLines.reserve( number.get() ); + rawLines.prefilterPattern + = !prefilterPattern_.isEmpty() + ? QRegularExpression( prefilterPattern_, + QRegularExpression::CaseInsensitiveOption ) + : QRegularExpression{}; + ScopedFileHolder fileHolder( attached_file_.get() ); const auto firstByte = ( firstLine == 0_lnum ) ? 0 : scopedAccessor.getEndOfLineOffset( firstLine - 1_lcount ).get(); - const auto lastByte = scopedAccessor.getEndOfLineOffset( lineNumbers.back() ).get(); - std::transform( lineNumbers.begin(), lineNumbers.end(), - std::back_inserter( rawLines.endOfLines ), - [ &scopedAccessor, firstByte ]( const LineNumber& line ) { - return scopedAccessor.getEndOfLineOffset( line ).get() - firstByte; - } ); + klogg::vector endOfLines + = scopedAccessor.getEndOfLineOffsets( firstLine, number ); + + const auto lastByte = endOfLines.back().get(); + + std::transform( + endOfLines.begin(), endOfLines.end(), std::back_inserter( rawLines.endOfLines ), + [ firstByte ]( const OffsetInFile& offset ) { return offset.get() - firstByte; } ); const auto bytesToRead = lastByte - firstByte; LOG_DEBUG << "will try to read:" << bytesToRead << " bytes"; diff --git a/src/logdata/src/logdataworker.cpp b/src/logdata/src/logdataworker.cpp index beed2a4ff..dcdeb8f20 100644 --- a/src/logdata/src/logdataworker.cpp +++ b/src/logdata/src/logdataworker.cpp @@ -51,9 +51,11 @@ #include #include "configuration.h" +#include "containers.h" #include "dispatch_to.h" #include "encodingdetector.h" #include "issuereporter.h" +#include "linepositionarray.h" #include "linetypes.h" #include "log.h" #include "logdata.h" @@ -83,12 +85,23 @@ LineLength IndexingData::getMaxLength() const LinesCount IndexingData::getNbLines() const { - return LinesCount( linePosition_.size() ); + return LinesCount( std::visit( []( const auto& linePosition ) { return linePosition.size(); }, + linePosition_ ) ); } OffsetInFile IndexingData::getEndOfLineOffset( LineNumber line ) const { - return linePosition_.at( line.get(), &linePositionCache_.local() ); + return std::visit( + [ line ]( const auto& linePosition ) { return linePosition.at( line.get() ); }, + linePosition_ ); +} + +klogg::vector IndexingData::getEndOfLineOffsets( LineNumber line, + LinesCount count ) const +{ + return std::visit( + [ line, count ]( const auto& linePosition ) { return linePosition.range( line, count ); }, + linePosition_ ); } QTextCodec* IndexingData::getEncodingGuess() const @@ -112,11 +125,13 @@ QTextCodec* IndexingData::getForcedEncoding() const } void IndexingData::addAll( const klogg::vector& block, LineLength length, - const FastLinePositionArray& linePosition, QTextCodec* encoding ) + const FastLinePositionArray& newLinePosition, QTextCodec* encoding ) { maxLength_ = std::max( maxLength_, length ); - linePosition_.append_list( linePosition ); + std::visit( + [ &newLinePosition ]( auto& linePosition ) { linePosition.append_list( newLinePosition ); }, + linePosition_ ); if ( !block.empty() ) { hash_.size += klogg::ssize( block ); @@ -142,23 +157,28 @@ void IndexingData::setProgress( int progress ) void IndexingData::clear() { + const auto& config = Configuration::get(); + maxLength_ = 0_length; hash_ = {}; hashBuilder_.reset(); - linePosition_ = LinePositionArray(); + if ( config.useCompressedIndex() ) { + linePosition_ = LinePositionArrayType( LinePositionArray{} ); + } + else { + linePosition_ = LinePositionArrayType( FastLinePositionArray{} ); + } encodingGuess_ = nullptr; encodingForced_ = nullptr; progress_ = {}; - linePositionCache_.clear(); - - const auto& config = Configuration::get(); useFastModificationDetection_ = config.fastModificationDetection(); } size_t IndexingData::allocatedSize() const { - return linePosition_.allocatedSize(); + return std::visit( []( const auto& linePosition ) { return linePosition.allocatedSize(); }, + linePosition_ ); } LogDataWorker::LogDataWorker( const std::shared_ptr& indexing_data ) diff --git a/src/logdata/src/logfiltereddataworker.cpp b/src/logdata/src/logfiltereddataworker.cpp index a0c80ebe2..ee4cb9884 100644 --- a/src/logdata/src/logfiltereddataworker.cpp +++ b/src/logdata/src/logfiltereddataworker.cpp @@ -49,6 +49,7 @@ #include "configuration.h" #include "dispatch_to.h" #include "issuereporter.h" +#include "linetypes.h" #include "log.h" #include "progress.h" #include "runnable_lambda.h" @@ -129,13 +130,14 @@ SearchResults SearchData::takeCurrentResults() const return SearchResults{ std::exchange( newMatches_, {} ), maxLength_, nbLinesProcessed_ }; } -void SearchData::addAll( LineLength length, const SearchResultArray& matches, LinesCount lines ) +void SearchData::addAll( LineLength length, const SearchResultArray& matches, + LinesCount matchedLines, LinesCount processedLines ) { UniqueLock lock( dataMutex_ ); maxLength_ = qMax( maxLength_, length ); - nbLinesProcessed_ = qMax( nbLinesProcessed_, lines ); - nbMatches_ += LinesCount( matches.cardinality() ); + nbLinesProcessed_ = qMax( nbLinesProcessed_, processedLines ); + nbMatches_ += matchedLines; newMatches_ |= matches; } @@ -173,7 +175,6 @@ LogFilteredDataWorker::LogFilteredDataWorker( const LogData& sourceLogData ) : sourceLogData_( sourceLogData ) { operationsPool_.setMaxThreadCount( 1 ); - LOG_INFO << "Roaring hw " << roaring::internal::croaring_hardware_support(); } LogFilteredDataWorker::~LogFilteredDataWorker() noexcept @@ -376,7 +377,9 @@ void SearchOperation::doSearch( SearchData& searchData, LineNumber initialLine ) if ( matchResults.processedLines.get() ) { maxLength = qMax( maxLength, matchResults.maxLength ); - nbMatches += LinesCount( matchResults.matchingLines.cardinality() ); + const LinesCount matchesCount + = LinesCount( matchResults.matchingLines.cardinality() ); + nbMatches += matchesCount; const auto processedLines = LinesCount{ matchResults.chunkStart.get() + matchResults.processedLines.get() }; @@ -385,12 +388,18 @@ void SearchOperation::doSearch( SearchData& searchData, LineNumber initialLine ) // After each block, copy the data to shared data // and update the client - searchData.addAll( maxLength, matchResults.matchingLines, processedLines ); + searchData.addAll( maxLength, matchResults.matchingLines, matchesCount, + processedLines ); LOG_DEBUG << "done Searching chunk starting at " << matchResults.chunkStart << ", " << matchResults.processedLines << " lines read."; } + delete blockData; + + const auto matchProcessorEndTime = high_resolution_clock::now(); + matchCombiningDuration += duration_cast( matchProcessorEndTime + - matchProcessorStartTime ); const int percentage = calculateProgress( totalProcessedLines.get(), totalLines.get() ); @@ -402,10 +411,6 @@ void SearchOperation::doSearch( SearchData& searchData, LineNumber initialLine ) reportedMatches = nbMatches; } - const auto matchProcessorEndTime = high_resolution_clock::now(); - matchCombiningDuration += duration_cast( matchProcessorEndTime - - matchProcessorStartTime ); - delete blockData; return tbb::flow::continue_msg{}; } ); @@ -431,8 +436,8 @@ void SearchOperation::doSearch( SearchData& searchData, LineNumber initialLine ) /*LOG_DEBUG << "Sending chunk starting at " << chunkStart << ", " << lines.second.size() << " lines read.";*/ - BlockDataType blockData = new SearchBlockData{chunkStart, std::move(lines)}; - + BlockDataType blockData = new SearchBlockData{ chunkStart, std::move( lines ) }; + const auto lineSourceEndTime = high_resolution_clock::now(); const auto chunkReadTime = duration_cast( lineSourceEndTime - lineSourceStartTime ); diff --git a/src/regex/CMakeLists.txt b/src/regex/CMakeLists.txt index aa94963dd..2e80d83b8 100644 --- a/src/regex/CMakeLists.txt +++ b/src/regex/CMakeLists.txt @@ -21,11 +21,8 @@ target_link_libraries( exprtk ) -if(KLOGG_USE_HYPERSCAN) - target_link_libraries(klogg_regex PUBLIC hyperscan_wrapper) - target_compile_definitions(klogg_regex PUBLIC KLOGG_HAS_HS) -elseif(KLOGG_USE_VECTORSCAN) - target_link_libraries(klogg_regex PUBLIC vectorscan_wrapper) +if(KLOGG_USE_VECTORSCAN) + target_link_libraries(klogg_regex PUBLIC klogg_vectorscan) target_compile_definitions(klogg_regex PUBLIC KLOGG_HAS_HS) endif() diff --git a/src/settings/include/configuration.h b/src/settings/include/configuration.h index 4c3ecb1d6..2e0efe077 100644 --- a/src/settings/include/configuration.h +++ b/src/settings/include/configuration.h @@ -231,6 +231,14 @@ class Configuration final : public Persistable { { keepFileClosed_ = shouldKeepClosed; } + bool useCompressedIndex() const + { + return useCompressedIndex_; + } + void setUseCompressedIndex( bool useCompressedIndex ) + { + useCompressedIndex_ = useCompressedIndex; + } RegexpEngine regexpEngine() const { @@ -552,6 +560,7 @@ class Configuration final : public Persistable { int searchReadBufferSizeLines_ = 10000; int searchThreadPoolSize_ = 0; bool keepFileClosed_ = false; + bool useCompressedIndex_ = true; bool enableLogging_ = false; int loggingLevel_ = 4; diff --git a/src/settings/include/shortcuts.h b/src/settings/include/shortcuts.h index aa2181bf8..8c0f04e34 100644 --- a/src/settings/include/shortcuts.h +++ b/src/settings/include/shortcuts.h @@ -37,6 +37,12 @@ struct ShortcutAction { static constexpr auto CrawlerChangeVisibilityToMatches = "crawler.change_visibility_to_matches"; static constexpr auto CrawlerIncreseTopViewSize = "crawler.increase_top_view_size"; static constexpr auto CrawlerDecreaseTopViewSize = "crawler.decrease_top_view_size"; + static constexpr auto CrawlerEnableCaseMatching = "crawler.enable_case_matching"; + static constexpr auto CrawlerEnableRegex = "crawler.enable_regex"; + static constexpr auto CrawlerEnableInverseMatching = "crawler.enable_inverse_matching"; + static constexpr auto CrawlerEnableRegexCombining = "crawler.enable_regex_combining"; + static constexpr auto CrawlerEnableAutoRefresh = "crawler.enable_auto_refresh"; + static constexpr auto CrawlerKeepResults = "crawler.enable_keep_results"; static constexpr auto QfFindNext = "qf.find_next"; static constexpr auto QfFindPrev = "qf.find_prev"; @@ -133,4 +139,4 @@ struct ShortcutAction { const ConfiguredShortcuts& configuredShortcuts ); }; -#endif \ No newline at end of file +#endif diff --git a/src/settings/src/configuration.cpp b/src/settings/src/configuration.cpp index f18eb04bd..e23619f1c 100644 --- a/src/settings/src/configuration.cpp +++ b/src/settings/src/configuration.cpp @@ -138,17 +138,27 @@ void Configuration::retrieveFromStorage( QSettings& settings ) DefaultConfiguration.enableMainSearchHighlightVariance_ ) .toBool(); - mainSearchBackColor_.setNamedColor( - settings - .value( "regexpType.mainBackColor", - DefaultConfiguration.mainSearchBackColor_.name( QColor::HexArgb ) ) - .toString() ); - - qfBackColor_.setNamedColor( - settings - .value( "regexpType.quickfindBackColor", - DefaultConfiguration.qfBackColor_.name( QColor::HexArgb ) ) - .toString() ); + mainSearchBackColor_ +#if QT_VERSION <= QT_VERSION_CHECK( 6, 4, 0 ) + .setNamedColor( +#else + .fromString( +#endif + settings + .value( "regexpType.mainBackColor", + DefaultConfiguration.mainSearchBackColor_.name( QColor::HexArgb ) ) + .toString() ); + + qfBackColor_ +#if QT_VERSION <= QT_VERSION_CHECK( 6, 4, 0 ) + .setNamedColor( +#else + .fromString( +#endif + settings + .value( "regexpType.quickfindBackColor", + DefaultConfiguration.qfBackColor_.name( QColor::HexArgb ) ) + .toString() ); qfIgnoreCase_ = settings.value( "quickfind.ignore_case", DefaultConfiguration.qfIgnoreCase_ ).toBool(); @@ -240,6 +250,10 @@ void Configuration::retrieveFromStorage( QSettings& settings ) DefaultConfiguration.optimizeForNotLatinEncodings_ ) .toBool(); + useCompressedIndex_ + = settings.value( "perf.useCompressedIndex", DefaultConfiguration.useCompressedIndex_ ) + .toBool(); + verifySslPeers_ = settings.value( "net.verifySslPeers", DefaultConfiguration.verifySslPeers_ ).toBool(); @@ -300,7 +314,7 @@ void Configuration::retrieveFromStorage( QSettings& settings ) const auto mapping = settings.value( "shortcuts.mapping" ).toMap(); for ( auto keys = mapping.begin(); keys != mapping.end(); ++keys ) { auto action = keys.key().toStdString(); - if (action == ShortcutAction::LogViewJumpToButtom) { + if ( action == ShortcutAction::LogViewJumpToButtom ) { action = ShortcutAction::LogViewJumpToBottom; } shortcuts_.emplace( action, keys.value().toStringList() ); @@ -314,7 +328,7 @@ void Configuration::retrieveFromStorage( QSettings& settings ) settings.setArrayIndex( static_cast( shortcutIndex ) ); auto action = settings.value( "action", "" ).toString(); if ( !action.isEmpty() ) { - if (action == ShortcutAction::LogViewJumpToButtom) { + if ( action == ShortcutAction::LogViewJumpToButtom ) { action = ShortcutAction::LogViewJumpToBottom; } const auto keys = settings.value( "keys", QStringList() ).toStringList(); @@ -379,6 +393,7 @@ void Configuration::saveToStorage( QSettings& settings ) const settings.setValue( "perf.searchReadBufferSizeLines", searchReadBufferSizeLines_ ); settings.setValue( "perf.searchThreadPoolSize", searchThreadPoolSize_ ); settings.setValue( "perf.keepFileClosed", keepFileClosed_ ); + settings.setValue( "perf.useCompressedIndex", useCompressedIndex_ ); settings.setValue( "perf.optimizeForNotLatinEncodings", optimizeForNotLatinEncodings_ ); settings.setValue( "net.verifySslPeers", verifySslPeers_ ); diff --git a/src/settings/src/shortcuts.cpp b/src/settings/src/shortcuts.cpp index ad92e40df..9c5ca8ada 100644 --- a/src/settings/src/shortcuts.cpp +++ b/src/settings/src/shortcuts.cpp @@ -85,6 +85,18 @@ const std::map& ShortcutAction::defaultShortcuts() QStringList() << QKeySequence( Qt::Key_Plus ).toString() ); shortcuts.emplace( CrawlerDecreaseTopViewSize, QStringList() << QKeySequence( Qt::Key_Minus ).toString() ); + shortcuts.emplace( CrawlerEnableCaseMatching, + QStringList() << QKeySequence( Qt::Key_4 ).toString() ); + shortcuts.emplace( CrawlerEnableRegex, + QStringList() << QKeySequence( Qt::Key_5 ).toString() ); + shortcuts.emplace( CrawlerEnableInverseMatching, + QStringList() << QKeySequence( Qt::Key_6 ).toString() ); + shortcuts.emplace( CrawlerEnableRegexCombining, + QStringList() << QKeySequence( Qt::Key_7 ).toString() ); + shortcuts.emplace( CrawlerEnableAutoRefresh, + QStringList() << QKeySequence( Qt::Key_8 ).toString() ); + shortcuts.emplace( CrawlerKeepResults, + QStringList() << QKeySequence( Qt::Key_9 ).toString() ); // shortcuts.emplace( QfFindNext, getKeyBindings( QKeySequence::FindNext ) ); // shortcuts.emplace( QfFindPrev, getKeyBindings( QKeySequence::FindPrevious ) ); @@ -220,6 +232,12 @@ QString ShortcutAction::actionName( const std::string& action ) QApplication::tr( "Change filtered lines visibility to matches" ) ); shortcuts.emplace( CrawlerIncreseTopViewSize, QApplication::tr( "Increase main view" ) ); shortcuts.emplace( CrawlerDecreaseTopViewSize, QApplication::tr( "Decrease main view" ) ); + shortcuts.emplace( CrawlerEnableCaseMatching, QApplication::tr( "Enable case matching" ) ); + shortcuts.emplace( CrawlerEnableRegex, QApplication::tr( "Enable regex" ) ); + shortcuts.emplace( CrawlerEnableInverseMatching, QApplication::tr( "Enable inverse matching" ) ); + shortcuts.emplace( CrawlerEnableRegexCombining, QApplication::tr( "Enable regex combining" ) ); + shortcuts.emplace( CrawlerEnableAutoRefresh, QApplication::tr( "Enable auto refresh" ) ); + shortcuts.emplace( CrawlerKeepResults, QApplication::tr( "Keep search results" ) ); shortcuts.emplace( QfFindNext, QApplication::tr( "QuickFind: Find next" ) ); shortcuts.emplace( QfFindPrev, QApplication::tr( "QuickFind: Find previous" ) ); @@ -312,7 +330,7 @@ void ShortcutAction::registerShortcut( const ConfiguredShortcuts& configuredShor ? keysConfiguration->second : ShortcutAction::defaultShortcuts( action ); - for ( const auto& key : qAsConst( keys ) ) { + for ( const auto& key : keys ) { if ( key.isEmpty() ) { continue; } @@ -351,4 +369,4 @@ QList ShortcutAction::shortcutKeys( const std::string& action, []( const QString& hotkeys ) { return QKeySequence( hotkeys ); } ); return shortcuts; -} \ No newline at end of file +} diff --git a/src/ui/include/abstractlogview.h b/src/ui/include/abstractlogview.h index 97ee9b4d8..de1a5867a 100644 --- a/src/ui/include/abstractlogview.h +++ b/src/ui/include/abstractlogview.h @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -65,6 +66,7 @@ #include "regularexpressionpattern.h" #include "selection.h" #include "viewtools.h" +#include "wrappedstring.h" class QMenu; class QAction; @@ -367,7 +369,12 @@ class AbstractLogView : public QAbstractScrollArea, public SearchableWidgetInter bool useTextWrap_ = false; LineColumn firstCol_ = 0_lcol; - klogg::vector> wrappedLinesNumbers_; + struct WrappedLineData { + LineNumber lineNumber; + size_t wrappedLineIndex; + WrappedString wrappedString; + }; + klogg::vector wrappedLinesInfo_; LineNumber searchStart_; LineNumber searchEnd_; diff --git a/src/ui/include/fontutils.h b/src/ui/include/fontutils.h index 429d930d9..1e0ffd66d 100644 --- a/src/ui/include/fontutils.h +++ b/src/ui/include/fontutils.h @@ -37,14 +37,14 @@ class FontUtils { #if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) QFontDatabase database; - auto families = database.families(); - for ( const auto& family : qAsConst( families ) ) { + const auto families = database.families(); + for ( const auto& family : families ) { if ( database.isFixedPitch( family ) ) fixedFamilies << family; } #else - auto families = QFontDatabase::families(); - for ( const auto& family : qAsConst( families ) ) { + const auto families = QFontDatabase::families(); + for ( const auto& family : families ) { if ( QFontDatabase::isFixedPitch( family ) ) fixedFamilies << family; } diff --git a/src/ui/include/optionsdialog.ui b/src/ui/include/optionsdialog.ui index ac145c456..330dc9cef 100644 --- a/src/ui/include/optionsdialog.ui +++ b/src/ui/include/optionsdialog.ui @@ -677,96 +677,108 @@ Indexing and search - - - QFormLayout::ExpandingFieldsGrow - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - Regular expressions engine: - - - - - - - Use parallel search - - - true - - - - - - - Index file read buffer (Mib): - - - - - - - - 0 - 0 - - - - - - - - Search read buffer (lines): - - - - - - - - 0 - 0 - - - - - - - 100000 - - - - - - - File will be kept closed as much as possible. Affects only files opened after check state changed - - - Keep file closed - - - - - - - - 0 - 0 - - - - - - - - Optimize search for non-latin encodings - - + + + + + + + + + Regular expressions engine: + + + + + + + + 0 + 0 + + + + + + + + Index file read buffer (Mib): + + + + + + + + 0 + 0 + + + + + + + + Search read buffer (lines): + + + + + + + + 0 + 0 + + + + + + + 100000 + + + + + + + + + File will be kept closed as much as possible. Affects only files opened after check state changed + + + Keep file closed (file reload required) + + + + + + + Use compressed index (file reload required) + + + true + + + + + + + Use parallel search + + + true + + + + + + + Optimize search for non-latin encodings + + + + diff --git a/src/ui/include/predefinedfilterscombobox.h b/src/ui/include/predefinedfilterscombobox.h index 59a536af7..d45714235 100644 --- a/src/ui/include/predefinedfilterscombobox.h +++ b/src/ui/include/predefinedfilterscombobox.h @@ -51,6 +51,7 @@ class PredefinedFiltersComboBox final : public QComboBox { public: explicit PredefinedFiltersComboBox( QWidget* parent ); + ~PredefinedFiltersComboBox(); PredefinedFiltersComboBox( const PredefinedFiltersComboBox& other ) = delete; PredefinedFiltersComboBox( PredefinedFiltersComboBox&& other ) noexcept = delete; diff --git a/src/ui/include/wrappedstring.h b/src/ui/include/wrappedstring.h new file mode 100644 index 000000000..1c512cfd7 --- /dev/null +++ b/src/ui/include/wrappedstring.h @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2023 -- 2024 Anton Filimonov and other contributors + * + * This file is part of klogg. + * + * klogg is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * klogg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with klogg. If not, see . + */ + +#include +#include +#include +#include + +#include + +#include "containers.h" +#include "linetypes.h" + +class WrappedString { +public: + using WrappedStringPart = QStringView; + + static WrappedStringPart makeWrappedStringPart(const QString& lineText, + LineColumn firstCol, LineLength length ) { + return QStringView( lineText ).mid( firstCol.get(), length.get() ); + } + + explicit WrappedString( QString longLine, LineLength visibleColumns ) + { + unwrappedLine_ = longLine; + if ( longLine.isEmpty() ) { + wrappedLines_.push_back( WrappedStringPart{} ); + } + else { + WrappedStringPart lineToWrap( longLine ); + while ( lineToWrap.size() > visibleColumns.get() ) { + WrappedStringPart stringToWrap = lineToWrap.left( visibleColumns.get() ); + auto lastSpaceIt = std::find_if( stringToWrap.rbegin(), stringToWrap.rend(), + []( QChar c ) { return c.isSpace(); } ); + if ( lastSpaceIt == stringToWrap.rend() ) { + wrappedLines_.push_back( lineToWrap.left( visibleColumns.get() ) ); + lineToWrap = lineToWrap.mid( visibleColumns.get() ); + } + else { + auto spacePos = std::distance( stringToWrap.begin(), lastSpaceIt.base() ); + wrappedLines_.push_back( lineToWrap.left( spacePos ) ); + lineToWrap = lineToWrap.mid( spacePos ); + } + } + if ( lineToWrap.size() > 0 ) { + wrappedLines_.push_back( lineToWrap ); + } + } + } + + size_t wrappedLinesCount() const + { + return wrappedLines_.size(); + } + + klogg::vector mid( LineColumn start, LineLength length ) const + { + auto getLength = []( const auto& view ) -> LineLength::UnderlyingType { + return type_safe::narrow_cast( view.size() ); + }; + + klogg::vector resultChunks; + if ( wrappedLines_.size() == 1 ) { + auto& wrappedLine = wrappedLines_.front(); + auto len = std::min( length.get(), getLength( wrappedLine ) - start.get() ); + resultChunks.push_back( wrappedLine.mid( start.get(), ( len > 0 ? len : 0 ) ) ); + return resultChunks; + } + + size_t wrappedLineIndex = 0; + auto positionInWrappedLine = start.get(); + while ( positionInWrappedLine > getLength( wrappedLines_[ wrappedLineIndex ] ) ) { + positionInWrappedLine -= getLength( wrappedLines_[ wrappedLineIndex ] ); + wrappedLineIndex++; + if ( wrappedLineIndex >= wrappedLines_.size() ) { + return resultChunks; + } + } + + auto chunkLength = length.get(); + while ( positionInWrappedLine + chunkLength + > getLength( wrappedLines_[ wrappedLineIndex ] ) ) { + resultChunks.push_back( + wrappedLines_[ wrappedLineIndex ].mid( positionInWrappedLine ) ); + wrappedLineIndex++; + positionInWrappedLine = 0; + chunkLength -= getLength( resultChunks.back() ); + if ( wrappedLineIndex >= wrappedLines_.size() ) { + return resultChunks; + } + } + + if ( chunkLength > 0 ) { + auto& wrappedLine = wrappedLines_[ wrappedLineIndex ]; + auto len = std::min( chunkLength, getLength( wrappedLine ) - positionInWrappedLine ); + resultChunks.push_back( + wrappedLine.mid( positionInWrappedLine, ( len > 0 ? len : 0 ) ) ); + } + + return resultChunks; + } + + bool isEmpty() const + { + return unwrappedLine_.isEmpty(); + } + + WrappedStringPart unwrappedLine() const { + return WrappedStringPart{unwrappedLine_}; + } + + WrappedStringPart wrappedLine(size_t index) const { + return wrappedLines_[index]; + } + +private: + klogg::vector wrappedLines_; + QString unwrappedLine_; +}; \ No newline at end of file diff --git a/src/ui/src/abstractlogview.cpp b/src/ui/src/abstractlogview.cpp index 2625661c0..e12cd20d2 100644 --- a/src/ui/src/abstractlogview.cpp +++ b/src/ui/src/abstractlogview.cpp @@ -47,10 +47,13 @@ #include #include #include +#include +#include #include #include #include #include +#include #include #include #include @@ -70,11 +73,7 @@ #include #include #include -#if QT_VERSION >= QT_VERSION_CHECK( 5, 10, 0 ) #include -#else -#include -#endif #include #include @@ -176,14 +175,9 @@ int countDigits( uint64_t x ) int textWidth( const QFontMetrics& fm, const QString& text ) { -#if ( QT_VERSION >= QT_VERSION_CHECK( 5, 11, 0 ) ) return fm.horizontalAdvance( text ); -#else - return fm.width( text ); -#endif } -#if QT_VERSION >= QT_VERSION_CHECK( 5, 10, 0 ) int textWidth( const QFontMetrics& fm, const QStringView& text ) { if ( text.isEmpty() ) { @@ -191,15 +185,6 @@ int textWidth( const QFontMetrics& fm, const QStringView& text ) } return textWidth( fm, QString::fromRawData( text.data(), klogg::isize( text ) ) ); } -#else -int textWidth( const QFontMetrics& fm, const QStringRef& text ) -{ - if ( text.isEmpty() ) { - return 0; - } - return textWidth( fm, QString::fromRawData( text.data(), klogg::isize( text ) ) ); -} -#endif std::unique_ptr pixmapPainter( QPaintDevice* paintDevice, const QFont& font ) { @@ -220,97 +205,8 @@ QFontMetrics pixmapFontMetrics( const QFont& font ) return devicePainter->fontMetrics(); } -class WrappedLinesView { - public: -#if QT_VERSION >= QT_VERSION_CHECK( 5, 10, 0 ) - using WrappedString = QStringView; -#else - using WrappedString = QStringRef; -#endif - - explicit WrappedLinesView( const QString& longLine, LineLength visibleColumns ) - { - if ( longLine.isEmpty() ) { - wrappedLines_.emplace_back( ); - } - else { -#if QT_VERSION >= QT_VERSION_CHECK( 5, 10, 0 ) - WrappedString lineToWrap( longLine ); -#else - WrappedString lineToWrap( &longLine ); -#endif - while ( lineToWrap.size() > visibleColumns.get() ) { - wrappedLines_.push_back( lineToWrap.left( visibleColumns.get() ) ); - lineToWrap = lineToWrap.mid( visibleColumns.get() ); - } - if ( lineToWrap.size() > 0 ) { - wrappedLines_.push_back( lineToWrap ); - } - } - } - - size_t wrappedLinesCount() const - { - return wrappedLines_.size(); - } - - klogg::vector mid( LineColumn start, LineLength length ) const - { - auto getLength = []( const auto& view ) -> LineLength::UnderlyingType { - return type_safe::narrow_cast( view.size() ); - }; - - klogg::vector resultChunks; - if ( wrappedLines_.size() == 1 ) { - auto& wrappedLine = wrappedLines_.front(); - auto len = std::min( length.get(), getLength( wrappedLine ) - start.get() ); - resultChunks.emplace_back( wrappedLine.mid( start.get(), ( len > 0 ? len : 0 ) ) ); - return resultChunks; - } - - size_t wrappedLineIndex = 0; - auto positionInWrappedLine = start.get(); - while ( positionInWrappedLine > getLength( wrappedLines_[ wrappedLineIndex ] ) ) { - positionInWrappedLine -= getLength( wrappedLines_[ wrappedLineIndex ] ); - wrappedLineIndex++; - if ( wrappedLineIndex >= wrappedLines_.size() ) { - return resultChunks; - } - } - - auto chunkLength = length.get(); - while ( positionInWrappedLine + chunkLength - > getLength( wrappedLines_[ wrappedLineIndex ] ) ) { - resultChunks.emplace_back( - wrappedLines_[ wrappedLineIndex ].mid( positionInWrappedLine ) ); - wrappedLineIndex++; - positionInWrappedLine = 0; - chunkLength -= getLength( resultChunks.back() ); - if ( wrappedLineIndex >= wrappedLines_.size() ) { - return resultChunks; - } - } - - if ( chunkLength > 0 ) { - auto& wrappedLine = wrappedLines_[ wrappedLineIndex ]; - auto len = std::min( chunkLength, getLength( wrappedLine ) - positionInWrappedLine ); - resultChunks.emplace_back( - wrappedLine.mid( positionInWrappedLine, ( len > 0 ? len : 0 ) ) ); - } - - return resultChunks; - } - - bool isEmpty() const - { - return wrappedLines_.empty() || wrappedLines_.front().isEmpty(); - } - - klogg::vector wrappedLines_; -}; - class LineChunk { - public: +public: LineChunk( LineColumn firstCol, LineColumn endCol, QColor foreColor, QColor backColor ) : start_{ firstCol } , end_{ endCol } @@ -344,7 +240,7 @@ class LineChunk { return backColor_; } - private: +private: LineColumn start_ = {}; LineColumn end_ = {}; @@ -356,7 +252,7 @@ class LineChunk { // It stores the chunks of line to draw // each chunk having a different colour class LineDrawer { - public: +public: explicit LineDrawer( const QColor& backColor ) : backColor_( backColor ) { @@ -386,7 +282,7 @@ class LineDrawer { // the coloured // background, going all the way to the element // left of the line looks better. void draw( QPainter* painter, int initialXPos, int initialYPos, int lineWidth, - const WrappedLinesView& wrappedLines, int leftExtraBackgroundPx ) + const WrappedString& wrappedLines, int leftExtraBackgroundPx ) { QFontMetrics fm = painter->fontMetrics(); const int fontHeight = fm.height(); @@ -441,7 +337,7 @@ class LineDrawer { painter->fillRect( xPos, yPos, blankWidth, fontHeight, backColor_ ); } - private: +private: klogg::vector chunks_; QColor backColor_; }; @@ -536,9 +432,11 @@ AbstractLogView::~AbstractLogView() try { if ( quickFind_ ) { quickFind_->stopSearch(); + delete quickFind_; } } catch ( const std::exception& e ) { LOG_ERROR << "Failed to stop search: " << e.what(); + delete quickFind_; } } @@ -1047,9 +945,7 @@ void AbstractLogView::wheelEvent( QWheelEvent* wheelEvent ) followElasticHook_.hold(); } else if ( wheelEvent->phase() == Qt::ScrollEnd -#if QT_VERSION >= QT_VERSION_CHECK( 5, 12, 0 ) || wheelEvent->phase() == Qt::ScrollMomentum -#endif ) { followElasticHook_.release(); } @@ -1853,8 +1749,8 @@ OptionalLineNumber AbstractLogView::convertCoordToLine( int yPos ) const { const auto offset = std::abs( ( yPos - drawingTopOffset_ ) / charHeight_ ); const auto wrappedLineInfoIndex = static_cast( std::floor( offset ) ); - if ( wrappedLineInfoIndex < wrappedLinesNumbers_.size() && !wrappedLinesNumbers_.empty() ) { - return wrappedLinesNumbers_[ wrappedLineInfoIndex ].first; + if ( wrappedLineInfoIndex < wrappedLinesInfo_.size() && !wrappedLinesInfo_.empty() ) { + return wrappedLinesInfo_[ wrappedLineInfoIndex ].lineNumber; } else { return OptionalLineNumber{}; @@ -1867,48 +1763,47 @@ FilePosition AbstractLogView::convertCoordToFilePos( const QPoint& pos ) const { const auto offset = std::abs( ( pos.y() - drawingTopOffset_ ) / charHeight_ ); - if ( wrappedLinesNumbers_.empty() ) { + if ( wrappedLinesInfo_.empty() ) { return FilePosition{ 0_lnum, 0_lcol }; } - const auto wrappedLineInfoIndex - = wrappedLinesNumbers_.size() > 1 - ? std::clamp( static_cast( std::floor( offset ) ), size_t{ 0 }, - wrappedLinesNumbers_.size() - 1 ) - : 0; + const auto wrappedLineInfoIndex = wrappedLinesInfo_.size() > 1 + ? std::clamp( static_cast( std::floor( offset ) ), + size_t{ 0 }, wrappedLinesInfo_.size() - 1 ) + : 0; - auto [ line, wrappedLine ] = wrappedLinesNumbers_[ wrappedLineInfoIndex ]; - if ( line >= logData_->getNbLine() ) - line = LineNumber( logData_->getNbLine().get() ) - 1_lcount; + const auto [ lineIndex, wrappedLineIndex, wrappedString ] + = wrappedLinesInfo_[ wrappedLineInfoIndex ]; - const auto lineText = logData_->getExpandedLineString( line ); - if ( lineText.size() <= 1 ) { - return FilePosition{ line, 0_lcol }; + auto clampedLineIndex = lineIndex; + if ( clampedLineIndex >= logData_->getNbLine() ) { + clampedLineIndex = LineNumber( logData_->getNbLine().get() ) - 1_lcount; } - WrappedLinesView::WrappedString visibleText; - if ( useTextWrap_ ) { - WrappedLinesView wrapped{ lineText, getNbVisibleCols() }; - visibleText = wrapped.wrappedLines_[ wrappedLine ]; - } - else { -#if QT_VERSION >= QT_VERSION_CHECK( 5, 10, 0 ) - visibleText = QStringView( lineText ).mid( firstCol_.get(), getNbVisibleCols().get() ); -#else - visibleText = QStringRef( &lineText ).mid( firstCol_.get(), getNbVisibleCols().get() ); -#endif + const WrappedString::WrappedStringPart lineText = wrappedString.unwrappedLine(); + + if ( lineText.size() <= 1 ) { + return FilePosition{ clampedLineIndex, 0_lcol }; } + const WrappedString::WrappedStringPart visibleText + = useTextWrap_ ? wrappedString.wrappedLine( wrappedLineIndex ) + : lineText.mid( firstCol_.get(), getNbVisibleCols().get() ); + klogg::vector possibleColumns( static_cast( visibleText.size() ) ); + klogg::vector columnsWidth( static_cast( visibleText.size() ), -1 ); std::iota( possibleColumns.begin(), possibleColumns.end(), 0_lcol ); const auto columnIt = std::lower_bound( possibleColumns.cbegin(), possibleColumns.cend(), pos, - [ this, &visibleText ]( LineColumn c, const QPoint& p ) { - const auto width - = textWidth( pixmapFontMetrics_, visibleText.left( c.get() ) ) + leftMarginPx_; + [ this, &visibleText, &columnsWidth ]( LineColumn c, const QPoint& p ) { + const size_t columnIndex = static_cast( c.get() ); + if ( columnsWidth[ columnIndex ] == -1 ) { + columnsWidth[ columnIndex ] + = textWidth( pixmapFontMetrics_, visibleText.left( c.get() ) ) + leftMarginPx_; + } - return width < p.x(); + return columnsWidth[ columnIndex ] < p.x(); } ); const auto length @@ -1916,16 +1811,26 @@ FilePosition AbstractLogView::convertCoordToFilePos( const QPoint& pos ) const auto column = ( columnIt != possibleColumns.end() ? *columnIt : length ) - 1_length; if ( useTextWrap_ ) { - column += LineLength{ getNbVisibleCols().get() * static_cast( wrappedLine ) }; + for ( auto i = 0u; i < wrappedLineIndex; ++i ) { + column += LineLength{ type_safe::narrow_cast( + wrappedString.wrappedLine( i ).size() ) }; + } } else { column += LineLength{ firstCol_.get() }; } - column = std::clamp( column, 0_lcol, LineColumn( lineText.size() ) - 1_length ); + const auto maxColumn + = LineColumn( type_safe::narrow_cast( std::min( + lineText.size(), static_cast( + std::numeric_limits::max() ) ) ) ) + - 1_length; - LOG_DEBUG << "AbstractLogView::convertCoordToFilePos col=" << column << " line=" << line; - return FilePosition{ line, column }; + column = std::clamp( column, 0_lcol, maxColumn ); + + LOG_DEBUG << "AbstractLogView::convertCoordToFilePos col=" << column + << " line=" << clampedLineIndex; + return FilePosition{ clampedLineIndex, column }; } // Makes the widget adjust itself to display the passed line. @@ -2028,13 +1933,8 @@ void AbstractLogView::jumpToTop() // Jump to the last line void AbstractLogView::jumpToBottom() { - const auto newTopLine - = ( logData_->getNbLine().get() < getNbVisibleLines().get() ) - ? 0 - : logData_->getNbLine().get() - getNbBottomWrappedVisibleLines().get() + 1; - // This will also trigger a scrollContents event - verticalScrollBar()->setValue( lineNumberToVerticalScroll( LineNumber( newTopLine ) ) ); + verticalScrollBar()->setValue( verticalScrollBar()->maximum() ); forceRefresh(); } @@ -2215,7 +2115,7 @@ void AbstractLogView::considerMouseHovering( int xPos, int yPos ) // Mouse moved in the margin, send event up // (possibly to highlight the overview) if ( line != lastHoveredLine_ ) { - LOG_DEBUG << "Mouse moved in margin line: " << line; + LOG_DEBUG << "Mouse moved in margin line: " << *line; Q_EMIT mouseHoveredOverLine( *line ); lastHoveredLine_ = line; } @@ -2230,49 +2130,61 @@ void AbstractLogView::considerMouseHovering( int xPos, int yPos ) LinesCount AbstractLogView::getNbBottomWrappedVisibleLines() const { - const auto visibleLines = getNbVisibleLines(); - + const LinesCount visibleLines = getNbVisibleLines(); + const LineLength visibleColumns = getNbVisibleCols(); if ( useTextWrap_ ) { const auto totalLines = logData_->getNbLine(); - - LinesCount wrappedLinesCount{ 0 }; - LinesCount offset = 0_lcount; - for ( ; offset < visibleLines && offset < totalLines && wrappedLinesCount < visibleLines; - ++offset ) { - LineNumber line = LineNumber{ totalLines.get() } - offset; - wrappedLinesCount += LinesCount{ static_cast( - logData_->getLineLength( line ).get() / getNbVisibleCols().get() + 1 ) }; + LinesCount wrappedVisibleLines; + LinesCount unwrappedLines; + LineNumber unwrappedLineNumber {logData_->getNbLine().get() - 1}; + while ( unwrappedLines < totalLines && unwrappedLines < visibleLines ) { + QString expandedLine + = logData_->getExpandedLineString(unwrappedLineNumber ); + WrappedString wrapped{ expandedLine, visibleColumns }; + wrappedVisibleLines += LinesCount( + type_safe::narrow_cast( wrapped.wrappedLinesCount() ) ); + unwrappedLines++; + unwrappedLineNumber--; } - return offset; + LOG_INFO << "Bottom visible lines " << visibleLines.get() << " wrapped " + << wrappedVisibleLines.get(); + return wrappedVisibleLines; + } + else { + return visibleLines; } - return visibleLines; } void AbstractLogView::updateScrollBars() { - if ( logData_->getNbLine() < getNbVisibleLines() ) { + const LinesCount visibleLines = getNbVisibleLines(); + const LineLength visibleColumns = getNbVisibleCols(); + if ( logData_->getNbLine() < visibleLines ) { verticalScrollBar()->setRange( 0, 0 ); } else { const auto visibleWrappedLines = getNbBottomWrappedVisibleLines(); - const auto wrappedLinesScrollAdjust = ( getNbVisibleLines() - visibleWrappedLines ).get(); + const auto wrappedLinesScrollAdjust = ( visibleWrappedLines - visibleLines ).get(); verticalScrollBar()->setRange( - 0, static_cast( std::min( logData_->getNbLine().get() - getNbVisibleLines().get() + 0, static_cast( std::min( logData_->getNbLine().get() - visibleLines.get() + LinesCount::UnderlyingType{ 1 } + wrappedLinesScrollAdjust, maxValue().get() ) ) ); } int64_t hScrollMaxValue = 0; - if ( !useTextWrap_ && logData_->getMaxLength().get() >= getNbVisibleCols().get() ) { - hScrollMaxValue = logData_->getMaxLength().get() - getNbVisibleCols().get() + 1; + if ( !useTextWrap_ && logData_->getMaxLength().get() >= visibleColumns.get() ) { + hScrollMaxValue = logData_->getMaxLength().get() - visibleColumns.get() + 1; } + hScrollMaxValue + = std::min( hScrollMaxValue, static_cast( std::numeric_limits::max() ) ); + horizontalScrollBar()->setRange( 0, type_safe::narrow_cast( hScrollMaxValue ) ); horizontalScrollBar()->setPageStep( - type_safe::narrow_cast( getNbVisibleCols().get() * 7 / 8 ) ); + type_safe::narrow_cast( visibleColumns.get() * 7 / 8 ) ); } void AbstractLogView::drawTextArea( QPaintDevice* paintDevice ) @@ -2425,7 +2337,7 @@ void AbstractLogView::drawTextArea( QPaintDevice* paintDevice ) // Position in pixel of the base line of the line to print int yPos = 0; - wrappedLinesNumbers_.clear(); + wrappedLinesInfo_.clear(); for ( auto currentLine = 0_lcount; currentLine < nbLines; ++currentLine ) { const auto lineNumber = firstLine_ + currentLine; const QString logLine = logData_->getLineString( lineNumber ); @@ -2477,14 +2389,9 @@ void AbstractLogView::drawTextArea( QPaintDevice* paintDevice ) } const auto untabifyHighlight = [ &logLine ]( const auto& match ) { -#if QT_VERSION >= QT_VERSION_CHECK( 5, 10, 0 ) const auto prefix = QStringView{ logLine }.left( match.startColumn().get() ); const auto matchPart = QStringView{ logLine }.mid( match.startColumn().get(), match.size().get() ); -#else - const auto prefix = logLine.leftRef( match.startColumn().get() ); - const auto matchPart = logLine.midRef( match.startColumn().get(), match.size().get() ); -#endif const auto expandedPrefixLength = untabify( prefix.toString() ).size(); const LineLength startDelta = LineLength{ type_safe::narrow_cast( @@ -2531,7 +2438,7 @@ void AbstractLogView::drawTextArea( QPaintDevice* paintDevice ) const auto wrappedLineLength = useTextWrap_ ? nbVisibleCols : LineLength{ klogg::isize( expandedLine ) + 1 }; - const WrappedLinesView wrappedLineView{ expandedLine, wrappedLineLength }; + const WrappedString wrappedLineView{ expandedLine, wrappedLineLength }; const auto finalLineHeight = fontHeight * static_cast( wrappedLineView.wrappedLinesCount() ); // LOG_INFO << "Draw line " << lineNumber << ": " << expandedLine; @@ -2668,9 +2575,10 @@ void AbstractLogView::drawTextArea( QPaintDevice* paintDevice ) painter->drawText( lineNumberAreaStartX + LineNumberPadding, yPos + fontAscent, lineNumberStr ); } - wrappedLinesNumbers_.reserve(wrappedLineView.wrappedLinesCount()); - for ( auto i = 0u; i < wrappedLineView.wrappedLinesCount(); ++i ) { - wrappedLinesNumbers_.emplace_back( lineNumber, i ); + + wrappedLinesInfo_.reserve(wrappedLinesInfo_.size() + wrappedLineView.wrappedLinesCount()); + for ( size_t i = 0u; i < wrappedLineView.wrappedLinesCount(); ++i ) { + wrappedLinesInfo_.emplace_back( WrappedLineData{ lineNumber, i, wrappedLineView } ); } yPos += finalLineHeight; diff --git a/src/ui/src/crawlerwidget.cpp b/src/ui/src/crawlerwidget.cpp index 492f76113..707e101a8 100644 --- a/src/ui/src/crawlerwidget.cpp +++ b/src/ui/src/crawlerwidget.cpp @@ -840,7 +840,7 @@ void CrawlerWidget::changeFilteredViewVisibility( int index ) void CrawlerWidget::setSearchPatternFromPredefinedFilters( const QList& filters ) { QString searchPattern; - for ( const auto& filter : qAsConst( filters ) ) { + for ( const auto& filter : filters ) { combinePatterns( searchPattern, escapeSearchPattern( filter.pattern, filter.useRegex ) ); } setSearchPattern( searchPattern ); @@ -1438,6 +1438,42 @@ void CrawlerWidget::registerShortcuts() % visibilityBox_->count() ); } ); + ShortcutAction::registerShortcut( + configuredShortcuts, shortcuts_, this, Qt::WidgetWithChildrenShortcut, + ShortcutAction::CrawlerEnableCaseMatching, [ this ]() { + matchCaseButton_->toggle(); + } ); + + ShortcutAction::registerShortcut( + configuredShortcuts, shortcuts_, this, Qt::WidgetWithChildrenShortcut, + ShortcutAction::CrawlerEnableRegex, [ this ]() { + useRegexpButton_->toggle(); + } ); + + ShortcutAction::registerShortcut( + configuredShortcuts, shortcuts_, this, Qt::WidgetWithChildrenShortcut, + ShortcutAction::CrawlerEnableInverseMatching, [ this ]() { + inverseButton_->toggle(); + } ); + + ShortcutAction::registerShortcut( + configuredShortcuts, shortcuts_, this, Qt::WidgetWithChildrenShortcut, + ShortcutAction::CrawlerEnableRegexCombining, [ this ]() { + booleanButton_->toggle(); + } ); + + ShortcutAction::registerShortcut( + configuredShortcuts, shortcuts_, this, Qt::WidgetWithChildrenShortcut, + ShortcutAction::CrawlerEnableAutoRefresh, [ this ]() { + searchRefreshButton_->toggle(); + } ); + + ShortcutAction::registerShortcut( + configuredShortcuts, shortcuts_, this, Qt::WidgetWithChildrenShortcut, + ShortcutAction::CrawlerKeepResults, [ this ]() { + keepSearchResultsButton_->toggle(); + } ); + ShortcutAction::registerShortcut( configuredShortcuts, shortcuts_, this, Qt::WidgetWithChildrenShortcut, ShortcutAction::CrawlerChangeVisibilityBackward, [ this ]() { diff --git a/src/ui/src/highlightersdialog.cpp b/src/ui/src/highlightersdialog.cpp index 8d1f0a30f..17f58f45c 100644 --- a/src/ui/src/highlightersdialog.cpp +++ b/src/ui/src/highlightersdialog.cpp @@ -46,6 +46,7 @@ #include #include +#include "containers.h" #include "dispatch_to.h" #include "highlightersdialog.h" #include "highlighterset.h" @@ -206,15 +207,15 @@ void HighlightersDialog::exportHighlighters() void HighlightersDialog::importHighlighters() { - QStringList files = QFileDialog::getOpenFileNames( + const QStringList files = QFileDialog::getOpenFileNames( this, tr( "Select one or more files to open" ), "", tr( "Highlighters (*.conf)" ) ); - for ( const auto& file : qAsConst( files ) ) { + for ( const auto& file : files ) { LOG_DEBUG << "Loading highlighters from " << file; QSettings settings{ file, QSettings::IniFormat }; HighlighterSetCollection collection; collection.retrieveFromStorage( settings ); - for ( const auto& set : qAsConst( collection.highlighters_ ) ) { + for ( const auto& set : klogg::as_const( collection.highlighters_ ) ) { if ( highlighterSetCollection_.hasSet( set.id() ) ) { continue; } @@ -382,7 +383,7 @@ void HighlightersDialog::populateHighlighterList() { highlighterListWidget->clear(); for ( const HighlighterSet& highlighterSet : - qAsConst( highlighterSetCollection_.highlighters_ ) ) { + klogg::as_const( highlighterSetCollection_.highlighters_ ) ) { auto* new_item = new QListWidgetItem( highlighterSet.name() ); // new_item->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled ); highlighterListWidget->addItem( new_item ); diff --git a/src/ui/src/highlightersetedit.cpp b/src/ui/src/highlightersetedit.cpp index 86da52a3c..4e8258242 100644 --- a/src/ui/src/highlightersetedit.cpp +++ b/src/ui/src/highlightersetedit.cpp @@ -44,6 +44,7 @@ #include "highlighterset.h" #include "highlightersetedit.h" +#include "containers.h" #include "dispatch_to.h" #include "iconloader.h" #include "log.h" @@ -281,7 +282,7 @@ void HighlighterSetEdit::updateHighlighterProperties() void HighlighterSetEdit::populateHighlighterList() { highlighterListWidget->clear(); - for ( const Highlighter& highlighter : qAsConst( highlighterSet_.highlighterList_ ) ) { + for ( const Highlighter& highlighter : klogg::as_const( highlighterSet_.highlighterList_ ) ) { auto* new_item = new QListWidgetItem( highlighter.pattern() ); // new_item->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled ); new_item->setForeground( QBrush( highlighter.foreColor() ) ); diff --git a/src/ui/src/highlightersmenu.cpp b/src/ui/src/highlightersmenu.cpp index 70d84a7f1..7bbfced18 100644 --- a/src/ui/src/highlightersmenu.cpp +++ b/src/ui/src/highlightersmenu.cpp @@ -52,7 +52,7 @@ void HighlightersMenu::populateHighlightersMenu() addSeparator(); - for ( const auto& highlighter : qAsConst( highlighterSets ) ) { + for ( const auto& highlighter : highlighterSets ) { auto setAction = addAction( highlighter.name() ); setAction->setActionGroup( highLighters_ ); setAction->setCheckable( true ); diff --git a/src/ui/src/mainwindow.cpp b/src/ui/src/mainwindow.cpp index cd343fe2c..e53066863 100644 --- a/src/ui/src/mainwindow.cpp +++ b/src/ui/src/mainwindow.cpp @@ -1276,7 +1276,7 @@ void MainWindow::encodingChanged( QAction* action ) mib = mibData.toInt(); } - LOG_DEBUG << "encodingChanged, encoding " << mib; + LOG_DEBUG << "encodingChanged, encoding " << mib.value_or(0); if ( auto crawler = currentCrawlerWidget() ) { crawler->setEncoding( mib ); updateInfoLine(); @@ -1610,9 +1610,9 @@ void MainWindow::dragEnterEvent( QDragEnterEvent* event ) // Tries and loads the file if the URL dropped is local void MainWindow::dropEvent( QDropEvent* event ) { - QList urls = event->mimeData()->urls(); + const QList urls = event->mimeData()->urls(); - for ( const auto& url : qAsConst( urls ) ) { + for ( const auto& url : urls ) { auto fileName = url.toLocalFile(); if ( fileName.isEmpty() ) continue; @@ -1752,7 +1752,7 @@ bool MainWindow::loadFile( const QString& fileName, bool followFile ) const auto previousViewContext = [ &fileName ]() { const auto& session = SessionInfo::getSynced(); const auto& windows = session.windows(); - for ( const auto& windowId : qAsConst( windows ) ) { + for ( const auto& windowId : windows ) { const auto openedFiles = session.openFiles( windowId ); const auto existingContext = std::find_if( openedFiles.begin(), openedFiles.end(), diff --git a/src/ui/src/optionsdialog.cpp b/src/ui/src/optionsdialog.cpp index 4e6b6905e..77e3fe3fd 100644 --- a/src/ui/src/optionsdialog.cpp +++ b/src/ui/src/optionsdialog.cpp @@ -128,7 +128,7 @@ void OptionsDialog::setupTabs() void OptionsDialog::setupFontList() { const auto families = FontUtils::availableFonts(); - for ( const QString& str : qAsConst( families ) ) { + for ( const QString& str : families ) { fontFamilyBox->addItem( str ); } } @@ -361,6 +361,7 @@ void OptionsDialog::updateDialogFromConfig() indexReadBufferSpinBox->setValue( config.indexReadBufferSizeMb() ); searchReadBufferSpinBox->setValue( config.searchReadBufferSizeLines() ); keepFileClosedCheckBox->setChecked( config.keepFileClosed() ); + compressedIndexCheckBox->setChecked( config.useCompressedIndex() ); optimizeForNotLatinEncodingsCheckBox->setChecked( config.optimizeForNotLatinEncodings() ); // version checking @@ -528,6 +529,7 @@ void OptionsDialog::updateConfigFromDialog() config.setIndexReadBufferSizeMb( indexReadBufferSpinBox->value() ); config.setSearchReadBufferSizeLines( searchReadBufferSpinBox->value() ); config.setKeepFileClosed( keepFileClosedCheckBox->isChecked() ); + config.setUseCompressedIndex( compressedIndexCheckBox->isChecked() ); config.setOptimizeForNotLatinEncodings( optimizeForNotLatinEncodingsCheckBox->isChecked() ); // version checking diff --git a/src/ui/src/overview.cpp b/src/ui/src/overview.cpp index 45fa5bc0a..62de0cf6e 100644 --- a/src/ui/src/overview.cpp +++ b/src/ui/src/overview.cpp @@ -82,8 +82,7 @@ std::pair Overview::getViewLines() const if ( linesInFile_.get() > 0 ) { top = static_cast( ( topLine_.get() ) * height_ / ( linesInFile_.get() ) ); - bottom = static_cast( ( static_cast( top ) + nbLines_.get() ) * height_ - / ( linesInFile_.get() ) ); + bottom = top + static_cast( nbLines_.get() * height_ / ( linesInFile_.get() ) ); } return std::make_pair( top, bottom ); diff --git a/src/ui/src/predefinedfilters.cpp b/src/ui/src/predefinedfilters.cpp index 2ab3768cb..f83a84c29 100644 --- a/src/ui/src/predefinedfilters.cpp +++ b/src/ui/src/predefinedfilters.cpp @@ -79,7 +79,7 @@ void PredefinedFiltersCollection::saveToStorage( QSettings& settings ) const settings.beginWriteArray( "filters" ); int arrayIndex = 0; - for ( const auto& filter : qAsConst( filters_ ) ) { + for ( const auto& filter : filters_ ) { settings.setArrayIndex( arrayIndex ); settings.setValue( "name", filter.name ); settings.setValue( "filter", filter.pattern ); diff --git a/src/ui/src/predefinedfilterscombobox.cpp b/src/ui/src/predefinedfilterscombobox.cpp index f49b33048..b330eb3c9 100644 --- a/src/ui/src/predefinedfilterscombobox.cpp +++ b/src/ui/src/predefinedfilterscombobox.cpp @@ -102,6 +102,11 @@ PredefinedFiltersComboBox::PredefinedFiltersComboBox( QWidget* parent ) setSizeAdjustPolicy( QComboBox::AdjustToContents ); } +PredefinedFiltersComboBox::~PredefinedFiltersComboBox() +{ + delete model_; +} + void PredefinedFiltersComboBox::populatePredefinedFilters() { model_->clear(); @@ -172,6 +177,7 @@ void PredefinedFiltersComboBox::setTitle( const QString& title ) { auto* titleItem = new QStandardItem( title ); model_->insertRow( 0, titleItem ); + delete titleItem; } void PredefinedFiltersComboBox::insertFilters( diff --git a/src/utils/include/containers.h b/src/utils/include/containers.h index 6b0ec1c72..5a81d1f71 100644 --- a/src/utils/include/containers.h +++ b/src/utils/include/containers.h @@ -43,6 +43,14 @@ constexpr int isize( const C& c ) { return type_safe::narrow_cast( ssize( c ) ); } + + +template +constexpr std::add_const_t& as_const(C& c) noexcept +{ + return c; +} + } // namespace klogg #endif \ No newline at end of file diff --git a/src/utils/include/dispatch_to.h b/src/utils/include/dispatch_to.h index 4517c7df1..a6238e768 100644 --- a/src/utils/include/dispatch_to.h +++ b/src/utils/include/dispatch_to.h @@ -28,7 +28,6 @@ // by // https://github.com/KubaO/stackoverflown/blob/master/questions/metacall-21646467/main.cpp -#if QT_VERSION >= QT_VERSION_CHECK( 5, 10, 0 ) template static void dispatchToObject( F&& fun, QObject* obj = qApp ) { @@ -42,49 +41,6 @@ static void dispatchToThread( F&& fun, QThread* thread = qApp->thread() ) Q_ASSERT( obj ); QMetaObject::invokeMethod( obj, std::forward( fun ), Qt::QueuedConnection ); } -#else -namespace detail { -template -struct FEvent : public QEvent { - using Fun = typename std::decay::type; - - FEvent( Fun&& fun ) - : QEvent( QEvent::None ) - , fun_( std::move( fun ) ) - { - } - FEvent( const Fun& fun ) - : QEvent( QEvent::None ) - , fun_( fun ) - { - } - ~FEvent() - { - fun_(); - } - - private: - Fun fun_; -}; -} // namespace detail - -template -static void dispatchToObject( F&& fun, QObject* obj = qApp ) -{ - if ( qobject_cast( obj ) ) { - LOG_WARNING << "posting a call to a thread object - consider using postToThread"; - } - QCoreApplication::postEvent( obj, new detail::FEvent( std::forward( fun ) ) ); -} - -template -static void dispatchToThread( F&& fun, QThread* thread = qApp->thread() ) -{ - QObject* obj = QAbstractEventDispatcher::instance( thread ); - Q_ASSERT( obj ); - QCoreApplication::postEvent( obj, new detail::FEvent( std::forward( fun ) ) ); -} -#endif template static void dispatchToMainThread( F&& fun ) diff --git a/src/versioncheck/src/versionchecker.cpp b/src/versioncheck/src/versionchecker.cpp index 3e867f5c2..c41fda24f 100644 --- a/src/versioncheck/src/versionchecker.cpp +++ b/src/versioncheck/src/versionchecker.cpp @@ -46,7 +46,7 @@ namespace { #if defined( Q_OS_WIN ) static constexpr QLatin1String OsSuffix = QLatin1String( "-win", 4 ); -#elif defined( Q_OS_OSX ) +#elif defined( Q_OS_MACOS ) static constexpr QLatin1String OsSuffix = QLatin1String( "-osx", 4 ); #else static constexpr QLatin1String OsSuffix = QLatin1String( "-linux", 6 ); @@ -177,7 +177,7 @@ void VersionChecker::checkVersionData( QByteArray versionData ) const auto changeLog = latestVersionMap.value( "changelog" ).toList(); QStringList changes; - for ( const auto& entry : qAsConst( changeLog ) ) { + for ( const auto& entry : changeLog ) { const auto entryData = entry.toMap(); const auto version = entryData.value( "version" ).toString(); diff --git a/tests/ui/logdata_test.cpp b/tests/ui/logdata_test.cpp index 649709fc1..f81dc7edd 100644 --- a/tests/ui/logdata_test.cpp +++ b/tests/ui/logdata_test.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include "file_write_helper.h" #include "log.h" @@ -117,7 +118,7 @@ TEST_CASE( "Logdata decoding lines", "[logdata]" ) auto finishedSpy = std::make_unique( &logData, SIGNAL( loadingFinished( LoadingStatus ) ) ); - logData.attachFile( file.fileName() ); + logData.attachFile( QFileInfo{ file }.absoluteFilePath() ); REQUIRE( finishedSpy->safeWait() ); REQUIRE( finishedSpy->count() == 1 ); @@ -147,7 +148,7 @@ TEST_CASE( "Logdata reading changing file", "[logdata]" ) SafeQSignalSpy finishedSpy( &logData, SIGNAL( loadingFinished( LoadingStatus ) ) ); // Start loading it - logData.attachFile( file.fileName() ); + logData.attachFile( QFileInfo{ file }.absoluteFilePath() ); waitUiState( [ &logData ] { return logData.getNbLine() == 200_lcount; } ); REQUIRE( finishedSpy.safeWait() ); REQUIRE( finishedSpy.count() == 1 ); @@ -234,7 +235,7 @@ SCENARIO( "Attaching log data to files", "[logdata]" ) SafeQSignalSpy endSpy( &log_data, SIGNAL( loadingFinished( LoadingStatus ) ) ); // Start loading the VBL - log_data.attachFile( bigFile.fileName() ); + log_data.attachFile( QFileInfo{ bigFile }.absoluteFilePath() ); // Immediately interrupt the loading log_data.interruptLoading(); @@ -260,12 +261,12 @@ SCENARIO( "Attaching log data to files", "[logdata]" ) LogData log_data; SafeQSignalSpy endSpy( &log_data, SIGNAL( loadingFinished( LoadingStatus ) ) ); - log_data.attachFile( smallFile.fileName() ); + log_data.attachFile( QFileInfo{ smallFile }.absoluteFilePath() ); endSpy.safeWait( 10000 ); THEN( "Throws" ) { - CHECK_THROWS_AS( log_data.attachFile( bigFile.fileName() ), CantReattachErr ); + CHECK_THROWS_AS( log_data.attachFile( QFileInfo{ bigFile }.absoluteFilePath() ), CantReattachErr ); } } } diff --git a/tests/unit/linepositionarray_test.cpp b/tests/unit/linepositionarray_test.cpp index f4b045934..54c697d3f 100644 --- a/tests/unit/linepositionarray_test.cpp +++ b/tests/unit/linepositionarray_test.cpp @@ -25,10 +25,10 @@ #include "linepositionarray.h" #include -#include -#include #include #include +#include +#include #include @@ -36,9 +36,9 @@ SCENARIO( "LinePositionArray with small number of lines", "[linepositionarray]" { std::array offsets = { 4_offset, 8_offset, 10_offset, - 345_offset, // A longer (>128) line - 20000_offset, // An even longer (>16384) line - 20020_offset }; + 345_offset, // A longer (>128) line + 20000_offset, // An even longer (>16384) line + 20020_offset }; GIVEN( "LinePositionArray with small number of lines" ) { @@ -102,9 +102,9 @@ SCENARIO( "LinePositionArray with small number of lines", "[linepositionarray]" WHEN( "Add line to single line array with fake lf" ) { LinePositionArray one_line_array; - one_line_array.append(10_offset); + one_line_array.append( 10_offset ); one_line_array.setFakeFinalLF(); - one_line_array.append(20_offset); + one_line_array.append( 20_offset ); THEN( "New last offset is returned" ) { REQUIRE( one_line_array.at( 0 ) == 20_offset ); @@ -129,8 +129,8 @@ SCENARIO( "LinePositionArray with small number of lines", "[linepositionarray]" for ( auto i = 0u; i < offsets.size(); ++i ) { REQUIRE( line_array.at( i ) == offsets[ i ] ); } - REQUIRE( line_array.at( 6 ) == other_array.at( 0 )); - REQUIRE( line_array.at( 7 ) == other_array.at( 1 )); + REQUIRE( line_array.at( 6 ) == other_array.at( 0 ) ); + REQUIRE( line_array.at( 7 ) == other_array.at( 1 ) ); } } @@ -145,8 +145,8 @@ SCENARIO( "LinePositionArray with small number of lines", "[linepositionarray]" for ( auto i = 0u; i < offsets.size() - 1; ++i ) { REQUIRE( line_array.at( i ) == offsets[ i ] ); } - REQUIRE( line_array.at( 5 ) == other_array.at( 0 )); - REQUIRE( line_array.at( 6 ) == other_array.at( 1 )); + REQUIRE( line_array.at( 5 ) == other_array.at( 0 ) ); + REQUIRE( line_array.at( 6 ) == other_array.at( 1 ) ); } } } @@ -165,18 +165,18 @@ SCENARIO( "LinePositionArray with full block of lines", "[linepositionarray]" ) // Add 255 lines (of various sizes) const int lines = 255; for ( int i = 0; i < lines; ++i ) - line_array.append(OffsetInFile( i * 4 ) ); + line_array.append( OffsetInFile( i * 4 ) ); // Line no 256 - line_array.append(OffsetInFile( 255 * 4 ) ); + line_array.append( OffsetInFile( 255 * 4 ) ); WHEN( "Adding line after block" ) { // Add line no 257 - line_array.append(OffsetInFile( 255 * 4 + 10 ) ); + line_array.append( OffsetInFile( 255 * 4 + 10 ) ); THEN( "Correct offset is returned" ) { - REQUIRE( line_array.at( 256 ) ==OffsetInFile( 255 * 4 + 10 ) ); + REQUIRE( line_array.at( 256 ) == OffsetInFile( 255 * 4 + 10 ) ); } } @@ -185,11 +185,11 @@ SCENARIO( "LinePositionArray with full block of lines", "[linepositionarray]" ) THEN( "Correct offset is returned" ) for ( uint32_t i = 0; i < 1000; ++i ) { int64_t pos = ( 257LL * 4 ) + i * 35LL; - line_array.append(OffsetInFile( pos ) ); + line_array.append( OffsetInFile( pos ) ); line_array.setFakeFinalLF(); - REQUIRE( line_array.at( 256 + i ) ==OffsetInFile( pos ) ); - line_array.append(OffsetInFile( pos + 21LL ) ); - REQUIRE( line_array.at( 256 + i ) ==OffsetInFile( pos + 21LL ) ); + REQUIRE( line_array.at( 256 + i ) == OffsetInFile( pos ) ); + line_array.append( OffsetInFile( pos + 21LL ) ); + REQUIRE( line_array.at( 256 + i ) == OffsetInFile( pos + 21LL ) ); } } } @@ -198,25 +198,21 @@ SCENARIO( "LinePositionArray with full block of lines", "[linepositionarray]" ) SCENARIO( "LinePositionArray with UINT32_MAX offsets", "[linepositionarray]" ) { - std::array offsets = { 4_offset, - 8_offset, - OffsetInFile( UINT32_MAX - 10 ), - OffsetInFile( (uint64_t)UINT32_MAX + 10LL ), - OffsetInFile( (uint64_t)UINT32_MAX + 30LL ), - OffsetInFile( (uint64_t)2 * UINT32_MAX ), - OffsetInFile( (uint64_t)2 * UINT32_MAX + 10LL ), - OffsetInFile( (uint64_t)2 * UINT32_MAX + 1000LL ), - OffsetInFile( (uint64_t)3 * UINT32_MAX ) }; - GIVEN( "LinePositionArray with long offsets" ) { + std::array offsets = { + OffsetInFile( UINT32_MAX - 10 ), + OffsetInFile( (uint64_t)UINT32_MAX + 10LL ), + OffsetInFile( (uint64_t)UINT32_MAX + 30LL ), + }; + LinePositionArray line_array; for ( const auto& offset : offsets ) { line_array.append( offset ); } - REQUIRE( line_array.size() == 9_lcount ); + REQUIRE( line_array.size() == 3_lcount ); WHEN( "Access items in linear order" ) { @@ -232,28 +228,32 @@ SCENARIO( "LinePositionArray with UINT32_MAX offsets", "[linepositionarray]" ) { THEN( "Correct offset is returned" ) for ( uint32_t i = 0; i < 1000; ++i ) { - int64_t pos = 3LL * UINT32_MAX + 524LL + i * 35LL; - line_array.append(OffsetInFile( pos ) ); + int64_t pos = UINT32_MAX + 524LL + i * 35LL; + line_array.append( OffsetInFile( pos ) ); line_array.setFakeFinalLF(); - REQUIRE( line_array.at( 9 + i ) ==OffsetInFile( pos ) ); - line_array.append(OffsetInFile( pos + 21LL ) ); - REQUIRE( line_array.at( 9 + i ) ==OffsetInFile( pos + 21LL ) ); + REQUIRE( line_array.at( offsets.size() + i ) == OffsetInFile( pos ) ); + line_array.append( OffsetInFile( pos + 21LL ) ); + REQUIRE( line_array.at( offsets.size() + i ) == OffsetInFile( pos + 21LL ) ); } } } GIVEN( "LinePositionArray with small lines" ) { - + std::array offsets = { + OffsetInFile( (uint64_t)UINT32_MAX / 2 + 10LL ), + OffsetInFile( (uint64_t)UINT32_MAX / 2 + 12LL ), + }; LinePositionArray line_array; - line_array.append( 4_offset ); - line_array.append( 8_offset ); + for ( const auto& offset : offsets ) { + line_array.append( offset ); + } WHEN( "Appending large lines" ) { FastLinePositionArray other_array; - other_array.append(OffsetInFile( (uint64_t)UINT32_MAX + 10LL ) ); - other_array.append(OffsetInFile( (uint64_t)UINT32_MAX + 30LL ) ); + other_array.append( OffsetInFile( (uint64_t)UINT32_MAX + 10LL ) ); + other_array.append( OffsetInFile( (uint64_t)UINT32_MAX + 30LL ) ); line_array.append_list( other_array ); @@ -261,10 +261,10 @@ SCENARIO( "LinePositionArray with UINT32_MAX offsets", "[linepositionarray]" ) { REQUIRE( line_array.size() == 4_lcount ); - REQUIRE( line_array.at( 0 ) == 4_offset ); - REQUIRE( line_array.at( 1 ) == 8_offset ); - REQUIRE( line_array.at( 2 ) ==OffsetInFile( (uint64_t)UINT32_MAX + 10 ) ); - REQUIRE( line_array.at( 3 ) ==OffsetInFile( (uint64_t)UINT32_MAX + 30 ) ); + REQUIRE( line_array.at( 0 ) == offsets[ 0 ] ); + REQUIRE( line_array.at( 1 ) == offsets[ 1 ] ); + REQUIRE( line_array.at( 2 ) == OffsetInFile( (uint64_t)UINT32_MAX + 10 ) ); + REQUIRE( line_array.at( 3 ) == OffsetInFile( (uint64_t)UINT32_MAX + 30 ) ); } } } diff --git a/website/themes/hugo-book/i18n/zh_TW.yaml b/website/themes/hugo-book/i18n/zh_TW.yaml new file mode 100644 index 000000000..5132ca2eb --- /dev/null +++ b/website/themes/hugo-book/i18n/zh_TW.yaml @@ -0,0 +1,20 @@ +- id: Search + translation: 搜尋 + +- id: Edit this page + translation: 編輯本頁 + +- id: Last modified by + translation: 最後修改者 + +- id: Expand + translation: 展開 + +- id: bookSearchConfig + translation: | + { + encode: false, + tokenize: function(str) { + return str.replace(/[\x00-\x7F]/g, '').split(''); + } + }