From 3d51aa9c8f8d5879b7918bddfd4ff705b2b7fb7e Mon Sep 17 00:00:00 2001 From: Adrian Woeltche Date: Thu, 10 Oct 2024 16:31:38 +0200 Subject: [PATCH] some performance improvements in the graph and tags preparation process, added version info to the built memory mapped files, please re-prepare your network with every new version as the data structure might have changed, also disabled the edge_ids export by default (can be enabled manually, in that case, please prepare the network with simplify=osm-aware in advance) --- CMakeLists.txt | 2 +- README.md | 127 ++++++++++----- data/floating-car-data/README.md | 10 ++ data/gis-cup/README.md | 10 ++ data/hengfeng-li/README.md | 15 +- data/kubicka-et-al/README.md | 16 +- data/newson-krumm/README.md | 9 ++ deploy/appimage/package.sh | 2 +- docker/build/clang/19-ubuntu-2004/Dockerfile | 35 ++++ docker/build/clang/19/Dockerfile | 37 +++++ src/app/CMakeLists.txt | 5 - src/app/src/app/options.cpp | 10 +- src/library/CMakeLists.txt | 11 +- src/library/include/graph/adjacency_list.hpp | 43 ++--- .../include/io/helper/osm_handler_helper.hpp | 6 +- src/library/include/io/helper/tag_helper.hpp | 20 +-- .../io/memory_mapped/storage/base_storage.hpp | 151 +++++++++++------- .../storage/osm_handler_storage.hpp | 18 +-- .../io/memory_mapped/storage/tag_storage.hpp | 82 +++++++++- .../include/io/memory_mapped/utils.hpp | 11 +- .../matcher/matcher_output_settings.hpp | 2 +- .../include/util/version.hpp} | 10 +- src/library/src/io/importer.cpp | 17 +- src/library/src/util/version.cpp.in | 24 +++ 24 files changed, 481 insertions(+), 192 deletions(-) create mode 100644 docker/build/clang/19-ubuntu-2004/Dockerfile create mode 100644 docker/build/clang/19/Dockerfile rename src/{app/include/app/version.hpp.in => library/include/util/version.hpp} (79%) create mode 100644 src/library/src/util/version.cpp.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 0ad2873..8fc6fd5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.28) # project project(map_matching_2 - VERSION 1.0.0 + VERSION 1.0.1 DESCRIPTION "Map Matching 2" LANGUAGES CXX) diff --git a/README.md b/README.md index 6ce6539..debee6c 100644 --- a/README.md +++ b/README.md @@ -234,11 +234,21 @@ Note: For any advanced usage, consider the [help.txt](help.txt) or add `--help` The basic usage is a two- or three-step approach: -1. Prepare the network graph (only once). -2. Match your tracks on the prepared network graph (and repeat as often as needed). +1. Prepare the network graph (only once). Base command:\ + `./map_matching_2 --prepare --file openstreetmap.osm.pbf --output data/network/` +2. Match your tracks on the prepared network graph (and repeat as often as needed). Base command:\ + `./map_matching_2 --match --input data/network --tracks data/tracks.csv --output data/results` 3. Optional: Compare your matches to any given comparison matches or ground truth (if available). You can also compare the matches from different runs of this software with different settings with each other and - review the differences. + review the differences. Base command:\ + `./map_matching_2 --compare --match-tracks data/results/matches.csv --compare-tracks data/ground_truth.csv --output data/results` + +#### More details and in-depth explanation + +Please note that a new release might render the prepared network graph invalid, you might need to re-prepare the network +graph again if you download a new version. +The prepared binary network graph files are not compatible between compilers. +They are individual for each compiler and thus also not compatible between Linux and Windows. In case you used an older version of this software, all steps could be combined into one run. However, now with memory mapped files available, this is not practical anymore. @@ -298,26 +308,42 @@ different folders. If you want a prebuilt binary, please see the [Download](#download) section. -Building the software is straightforward. You need the following prerequisites: +Building the software is straightforward. The following tools and versions are tested to work: -- **CMake:** Version 3.28.6 or higher -- **On Linux:** either one of - - **GCC:** Version 14.2 or higher, or - - **Clang:** Version 18 or higher +- **CMake:** Version 3.28.6 +- **Ninja:** Version 1.12.1 +- **On Linux:** + - **GCC:** Version 14.2 + - **Clang:** Version 18 - **On Windows:** - - **Visual Studio C++:** Version 17.11.4 or higher (equivalent to MSVC 1940 or higher) + - **Visual Studio C++:** Version 17.11.5 (equivalent to MSVC 1940) +- **Architecture:** Only 64-bit compiler and operating system are supported We provide for Linux various Dockerfiles in the `docker` folder. They contain all necessary information for building the software with these recent versions even on older operating systems.
-Hint for Windows building +Hints for Linux building + +There currently is an issue to build this software with Boost 1.86 and Clang 19: +https://github.com/boostorg/thread/issues/402 + +Therefore, we currently only recommend building this software with the compiler versions that we tested during +development. +
+ +
+Hints for Windows building + +Please make sure that you use the 64-bit MSVC compiler by applying `-A x64` to the cmake command. For the dependency on Boost to build correctly, you might need to enable long paths in Windows, see [Windows help](https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=registry). -You might need to enable the registry setting if you receive "failed" messages in the Boost build log. +We recommend enabling the registry setting if you receive "failed" messages in the Boost build log during CMake +configuration. Alternatively, you can try to move the build directory of the whole project to an upper directory, for example `C:\map-matching-2`. + This is because Boost internally uses quite some long paths during build, and depending on the file system position of this repository on your computer, it might lead to errors without long paths enabled. @@ -325,11 +351,23 @@ this repository on your computer, it might lead to errors without long paths ena Building and installing, when the prerequisites are fulfilled, are then straightforward: +Run the build commands from the `map-matching-2` base directory as the working directory. + ```shell +# Linux cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -B build cmake --build build --parallel $(nproc) --target install ``` +```shell +# Windows cmd.exe (in PowerShell first enter: cmd) +# Initialize compiler environment +"C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat" +# Now build the program +"C:\path\to\cmake.exe" -DCMAKE_MAKE_PROGRAM="C:\path\to\ninja.exe" -G Ninja -DCMAKE_BUILD_TYPE=Release -B build +"C:\path\to\cmake.exe" --build build --parallel %NUMBER_OF_PROCESSORS% --target install +``` + Building needs multiple GB of disk space and needs several minutes even on fast systems. In the first step during configuration, CMake resolves all dependencies automatically, @@ -379,11 +417,11 @@ with full and without intermediate MMap in the operating system activity monitor The size of the new MMap binaries is a bit larger than the old memory dump format because it contains a bit more overhead, however, it can be opened near instantaneously. -| Mode | Time (s) | CPU resources (s) | Max RAM (MB) | `.osm.pbf` size (MB) | binary size (MB) | -|:----------------------------------|---------:|------------------:|-------------:|---------------------:|-----------------:| -| Prepare (Old Version 0.3) | 17.20 | 19.42 | 1816 | 74 | 283 | -| Prepare with full MMap (Default) | 42.16 | 44.31 | 2529 | 74 | 527 | -| Prepare without intermediate MMap | 15.28 | 17.33 | 2054 | 74 | 527 | +| Mode | Time (s) | CPU resources (s) | Max RAM (MiB) | `.osm.pbf` size (MiB) | binary size (MiB) | +|:----------------------------------|---------:|------------------:|--------------:|----------------------:|------------------:| +| Prepare (Old Version 0.3) | 17.03 | 19.21 | 1,824 | 74 | 283 | +| Prepare with full MMap (Default) | 39.41 | 41.51 | 2,508 | 74 | 527 | +| Prepare without intermediate MMap | 14.66 | 16.72 | 2,052 | 74 | 527 |
Prepare Commands @@ -398,14 +436,14 @@ overhead, however, it can be opened near instantaneously. ```shell # Prepare with full MMap (Default) -./map_matching_2-1.0.0-x86_64.AppImage \ +./map_matching_2-1.0.1-x86_64.AppImage \ --config data/floating-car-data/conf/prepare.conf \ --verbose ``` ```shell # Prepare without intermediate MMap -./map_matching_2-1.0.0-x86_64.AppImage \ +./map_matching_2-1.0.1-x86_64.AppImage \ --config data/floating-car-data/conf/prepare.conf \ --memory-mapped-preparation off \ --verbose @@ -421,16 +459,16 @@ publication (https://doi.org/10.1111/tgis.13107). The benchmarks are based on the `data/floating-car-data/conf/match.conf` and the `data/floating-car-data/conf/match_raw.conf` files. -| Mode | Threads | Track points | Sanitized track points | Candidates | Combinations | Total Time (s) | CPU resources (s) | Actual matching time (s) | Max RAM (MB) | -|:----------------------------|--------:|-------------:|-----------------------:|-----------:|-------------:|---------------:|------------------:|-------------------------:|-------------:| -| Match (Old Version 0.3) | 256 | 14,651 | 5,745 | 135,088 | 3,713,118 | 7.33 | 118.56 | 0.79 | 3,453 | -| Match (New Version 1.0) | 256 | 14,651 | 5,745 | 135,123 | 3,715,146 | 0.70 | 16.88 | 0.33 | 466 | -| Match (Old Version 0.3) | 1 | 14,651 | 5,745 | 135,088 | 3,713,118 | 20.75 | 20.73 | 14.57 | 924 | -| Match (New Version 1.0) | 1 | 14,651 | 5,745 | 135,123 | 3,715,146 | 11.40 | 11.45 | 11.28 | 134 | -| Match RAW (Old Version 0.3) | 256 | 88,807 | 32,599 | 811,417 | 27,835,497 | 12.32 | 944.05 | 4.87 | 5,459 | -| Match RAW (New Version 1.0) | 256 | 88,825 | 32,617 | 811,700 | 27,840,536 | 5.46 | 120.10 | 4.73 | 1,678 | -| Match RAW (Old Version 0.3) | 1 | 88,807 | 32,599 | 811,417 | 27,835,497 | 94.44 | 93.39 | 86.53 | 959 | -| Match RAW (New Version 1.0) | 1 | 88,825 | 32,617 | 811,700 | 27,840,536 | 68.23 | 68.76 | 68.07 | 370 | +| Mode | Threads | Track points | Sanitized track points | Candidates | Combinations | Total Time (s) | CPU resources (s) | Actual matching time (s) | Max RAM (MiB) | +|:----------------------------|--------:|-------------:|-----------------------:|-----------:|-------------:|---------------:|------------------:|-------------------------:|--------------:| +| Match (Old Version 0.3) | 256 | 14,651 | 5,745 | 135,088 | 3,713,118 | 7.31 | 108.28 | 0.71 | 3,447 | +| Match (New Version 1.0) | 256 | 14,651 | 5,745 | 135,123 | 3,715,146 | 0.67 | 16.96 | 0.31 | 488 | +| Match (Old Version 0.3) | 1 | 14,651 | 5,745 | 135,088 | 3,713,118 | 20.59 | 20.57 | 14.43 | 923 | +| Match (New Version 1.0) | 1 | 14,651 | 5,745 | 135,123 | 3,715,146 | 11.20 | 11.23 | 11.08 | 134 | +| Match RAW (Old Version 0.3) | 256 | 88,807 | 32,599 | 811,417 | 27,835,497 | 11.92 | 933.23 | 4.73 | 5,438 | +| Match RAW (New Version 1.0) | 256 | 88,825 | 32,617 | 811,700 | 27,840,536 | 5.70 | 115.15 | 4.98 | 1,692 | +| Match RAW (Old Version 0.3) | 1 | 88,807 | 32,599 | 811,417 | 27,835,497 | 93.49 | 93.45 | 87.09 | 958 | +| Match RAW (New Version 1.0) | 1 | 88,825 | 32,617 | 811,700 | 27,840,536 | 67.60 | 68.18 | 67.44 | 372 |
Match Commands @@ -447,7 +485,7 @@ The benchmarks are based on the `data/floating-car-data/conf/match.conf` and the ```shell # Match (New Version 1.0) with all threads -./map_matching_2-1.0.0-x86_64.AppImage \ +./map_matching_2-1.0.1-x86_64.AppImage \ --config data/floating-car-data/conf/match.conf \ --verbose ``` @@ -465,7 +503,7 @@ The benchmarks are based on the `data/floating-car-data/conf/match.conf` and the ```shell # Match (New Version 1.0) with 1 thread -./map_matching_2-1.0.0-x86_64.AppImage \ +./map_matching_2-1.0.1-x86_64.AppImage \ --config data/floating-car-data/conf/match.conf \ --threads 1 \ --verbose @@ -486,7 +524,7 @@ The benchmarks are based on the `data/floating-car-data/conf/match.conf` and the ```shell # Match RAW (New Version 1.0) with all threads -./map_matching_2-1.0.0-x86_64.AppImage \ +./map_matching_2-1.0.1-x86_64.AppImage \ --config data/floating-car-data/conf/match_raw.conf \ --verbose ``` @@ -507,7 +545,7 @@ The benchmarks are based on the `data/floating-car-data/conf/match.conf` and the ```shell # Match RAW (New Version 1.0) with 1 thread -./map_matching_2-1.0.0-x86_64.AppImage \ +./map_matching_2-1.0.1-x86_64.AppImage \ --config data/floating-car-data/conf/match_raw.conf \ --threads 1 \ --verbose @@ -527,10 +565,10 @@ the new memory mapped network files, which is a lot faster and reduces the total Reading the network graph alone in the old version needs quite some resources, compared to opening the memory mapped network files in the new version: -| Mode | Time (s) | CPU resources (s) | Max RAM (MB) | -|:-------------------------------|---------:|------------------:|-------------:| -| Read Network (Old Version 0.3) | 5.88 | 5.87 | 915 | -| Open Network (New Version 1.0) | 0.17 | 1.65 | 22 | +| Mode | Time (s) | CPU resources (s) | Max RAM (MiB) | +|:-------------------------------|---------:|------------------:|--------------:| +| Read Network (Old Version 0.3) | 5.85 | 5.84 | 921 | +| Open Network (New Version 1.0) | 0.16 | 0.41 | 22 |
Read / Open Network Commands @@ -545,7 +583,7 @@ echo "" | ./map_matching_2 \ ```shell # Open Network (New Version 1.0) -echo "" | ./map_matching_2-1.0.0-x86_64.AppImage \ +echo "" | ./map_matching_2-1.0.1-x86_64.AppImage \ --match \ --input data/floating-car-data/network/ \ --read-line --console \ @@ -565,13 +603,14 @@ The comparison is based on the `data/floating-car-data/conf/compare.conf` file. We compared the results of the old version with the `ground_truth.csv` with the old version and the new version, and we compared the results of the new version with the `ground_truth.csv` with the new version. -| Mode | Time (s) | CPU resources (s) | Actual comparison time (s) | Max RAM (MB) | Mean correct fraction (%) | Weighted mean correct fraction (%) | -|:-----------------------------------------|---------:|------------------:|---------------------------:|-------------:|--------------------------:|-----------------------------------:| -| Comparison Old Matches (Old Version 0.3) | 6.47 | 15.49 | 0.32 | 927 | 99.40 | NA | -| Comparison Old Matches (New Version 1.0) | 0.56 | 7.40 | 0.30 | 42 | 99.40 | 99.58 | -| Comparison New Matches (New Version 1.0) | 0.51 | 7.61 | 0.29 | 38 | 99.40 | 99.58 | +| Mode | Time (s) | CPU resources (s) | Actual comparison time (s) | Max RAM (MiB) | Mean correct fraction (%) | Weighted mean correct fraction (%) | +|:-----------------------------------------|---------:|------------------:|---------------------------:|--------------:|--------------------------:|-----------------------------------:| +| Comparison Old Matches (Old Version 0.3) | 6.51 | 15.93 | 0.36 | 925 | 99.40 | N/A | +| Comparison Old Matches (New Version 1.0) | 0.41 | 8.31 | 0.24 | 30 | 99.40 | 99.58 | +| Comparison New Matches (New Version 1.0) | 0.46 | 7.07 | 0.29 | 32 | 99.40 | 99.58 | We can see that the accuracy is exactly the same. However, the new version is faster comparing the results. +The sub-second times and small memory differences are subject to measurement uncertainty and in practice equal. Since the old version needs to load the network even for making a comparison, it takes significantly longer time. Moreover, the old version only computes a mean accuracy but not a weighted mean accuracy. @@ -598,7 +637,7 @@ but very accurate track. The weighted mean accuracy is the true accuracy over al ```shell # Comparison Old Matches (New Version 1.0), there is no config file given in the examples directory -./map_matching_2-1.0.0-x86_64.AppImage \ +./map_matching_2-1.0.1-x86_64.AppImage \ --compare \ --output /data/floating-car-data/old/ \ --filename comparison.csv \ @@ -611,7 +650,7 @@ but very accurate track. The weighted mean accuracy is the true accuracy over al ```shell # Comparison New Matches (New Version 1.0) -./map_matching_2-1.0.0-x86_64.AppImage \ +./map_matching_2-1.0.1-x86_64.AppImage \ --config data/floating-car-data/conf/compare.conf \ --verbose ``` diff --git a/data/floating-car-data/README.md b/data/floating-car-data/README.md index d949640..d8b0ddc 100644 --- a/data/floating-car-data/README.md +++ b/data/floating-car-data/README.md @@ -54,3 +54,13 @@ Also given is an example on how to use custom tags for OpenStreetMap, for exampl ``` The results will be in the `results` folder that is automatically created. + +Results on our test system (accuracy is the weighted mean correct fraction in percent): + +| Mode | Time (s) | Max RAM (MiB) | Accuracy (%) | +|:--------------|---------:|--------------:|-------------:| +| Prepare | 39.41 | 2,508 | N/A | +| Match | 0.67 | 488 | N/A | +| Compare | 0.46 | 32 | 99.58 | +| Match (RAW) | 5.70 | 1,692 | N/A | +| Prepare (All) | 47.84 | 2,899 | N/A | diff --git a/data/gis-cup/README.md b/data/gis-cup/README.md index 148ede9..85677fb 100644 --- a/data/gis-cup/README.md +++ b/data/gis-cup/README.md @@ -49,3 +49,13 @@ for MSVC: `run\msvc\release\bin\map_matching_2.exe`. ``` The results will be in the `results` folder that is automatically created. + +Results (with ground truth corrections from above applied) on our test system +(accuracy is the weighted mean correct fraction in percent): + +| Mode | Time (s) | Max RAM (MiB) | Accuracy (%) | +|:---------------------|---------:|--------------:|-------------:| +| Prepare | 20.63 | 1,327 | N/A | +| Convert Ground Truth | 0.48 | 354 | N/A | +| Match | 0.79 | 244 | N/A | +| Compare | 0.28 | 24 | 98.59 | diff --git a/data/hengfeng-li/README.md b/data/hengfeng-li/README.md index fb3f5d7..ce30340 100644 --- a/data/hengfeng-li/README.md +++ b/data/hengfeng-li/README.md @@ -31,7 +31,7 @@ for MSVC: `run\msvc\release\bin\map_matching_2.exe`. # prepare osm network ./map_matching_2 --conf data/hengfeng-li/conf/prepare_osm.conf -# prepare ground truth network +# prepare ground truth network (not simplified!) ./map_matching_2 --conf data/hengfeng-li/conf/prepare_ground_truth.conf # convert ground truth route @@ -51,3 +51,16 @@ for MSVC: `run\msvc\release\bin\map_matching_2.exe`. ``` The results will be in the `results` folder that is automatically created. + +Results on our test system (accuracy is the weighted mean correct fraction in percent): + +| Mode | Time (s) | Max RAM (MiB) | Accuracy (%) | +|:-----------------------|---------:|--------------:|-------------:| +| Prepare | 1.65 | 160 | N/A | +| Prepare (OSM) | 3.07 | 261 | N/A | +| Prepare (Ground Truth) | 1.51 | 166 | N/A | +| Convert Ground Truth | 0.22 | 84 | N/A | +| Match | 0.49 | 72 | N/A | +| Match (OSM) | 0.79 | 84 | N/A | +| Compare | 0.23 | 26 | 99.80 | +| Compare (OSM) | 0.23 | 24 | 99.86 | diff --git a/data/kubicka-et-al/README.md b/data/kubicka-et-al/README.md index 9525c73..70f618c 100644 --- a/data/kubicka-et-al/README.md +++ b/data/kubicka-et-al/README.md @@ -22,7 +22,7 @@ for MSVC: `run\msvc\release\bin\map_matching_2.exe`. # prepare networks ./map_matching_2 --conf data/kubicka-et-al/conf/prepare.conf -# prepare ground truth networks +# prepare ground truth networks (not simplified!) ./map_matching_2 --conf data/kubicka-et-al/conf/prepare_ground_truth.conf # convert ground truth routes @@ -31,7 +31,7 @@ for MSVC: `run\msvc\release\bin\map_matching_2.exe`. # match tracks ./map_matching_2 --conf data/kubicka-et-al/conf/match.conf -# match tracks with export-edges mode +# match tracks with export-edges mode (uses the slower ground truth network!) ./map_matching_2 --conf data/kubicka-et-al/conf/match_edges.conf # compare matches with ground truth @@ -42,3 +42,15 @@ for MSVC: `run\msvc\release\bin\map_matching_2.exe`. ``` The results will be in the `results` folder that is automatically created. + +Results on our test system (accuracy is the weighted mean correct fraction in percent): + +| Mode | Time (s) | Max RAM (MiB) | Accuracy (%) | +|:-----------------------|---------:|--------------:|-------------:| +| Prepare | 31.46 | 3,075 | N/A | +| Prepare (Ground Truth) | 29.24 | 3,038 | N/A | +| Convert Ground Truth | 8.57 | 1,437 | N/A | +| Match | 7.83 | 1,278 | N/A | +| Match (Export-Edges) | 25.38 | 3,137 | N/A | +| Compare | 0.94 | 51 | 98.73 | +| Compare (Export-Edges) | 0.88 | 44 | 98.93 | diff --git a/data/newson-krumm/README.md b/data/newson-krumm/README.md index ce66853..fca291d 100644 --- a/data/newson-krumm/README.md +++ b/data/newson-krumm/README.md @@ -34,3 +34,12 @@ for MSVC: `run\msvc\release\bin\map_matching_2.exe`. ``` The results will be in the `results` folder that is automatically created. + +Results on our test system (accuracy is the weighted mean correct fraction in percent): + +| Mode | Time (s) | Max RAM (MiB) | Accuracy (%) | +|:---------------------|---------:|--------------:|-------------:| +| Prepare | 4.02 | 254 | N/A | +| Convert Ground Truth | 1.32 | 50 | N/A | +| Match | 2.09 | 98 | N/A | +| Compare | 0.51 | 22 | 99.89 | diff --git a/deploy/appimage/package.sh b/deploy/appimage/package.sh index 9f2be25..19df27c 100755 --- a/deploy/appimage/package.sh +++ b/deploy/appimage/package.sh @@ -92,7 +92,7 @@ fi # build appimage VERSION="$version" "./$appimagetool" "$appdir" || exit 1 -appimage=$(ls map_matching_2*.AppImage) +appimage=$(ls -rt map_matching_2*.AppImage | tail -n 1) chmod +x "$appimage" # clean up diff --git a/docker/build/clang/19-ubuntu-2004/Dockerfile b/docker/build/clang/19-ubuntu-2004/Dockerfile new file mode 100644 index 0000000..ea09c3e --- /dev/null +++ b/docker/build/clang/19-ubuntu-2004/Dockerfile @@ -0,0 +1,35 @@ +# Build and run from project directory: +# docker build -t map_matching_2-clang-ubuntu-2004-build -f docker/build/clang/19-ubuntu-2004/Dockerfile . +# docker run -u $(id -u):$(id -g) -v .:/tmp/map-matching-2 -it --rm map_matching_2-clang-ubuntu-2004-build + +FROM ubuntu:20.04 AS build + +ARG DEBIAN_FRONTEND="noninteractive" +# only use major LLVM version +ARG LLVM_VERSION=19 +ARG CMAKE_VERSION=3.28.6 + +RUN apt-get update && apt-get dist-upgrade -y && \ + apt-get install --no-install-recommends -y \ + tzdata make lsb-release ca-certificates wget software-properties-common gnupg libssl-dev && \ + # LLVM + wget https://apt.llvm.org/llvm.sh && \ + chmod +x llvm.sh && \ + ./llvm.sh $LLVM_VERSION all && \ + rm llvm.sh && \ + update-alternatives --install /usr/bin/clang clang /usr/bin/clang-$LLVM_VERSION 100 \ + --slave /usr/bin/clang++ clang++ /usr/bin/clang++-$LLVM_VERSION \ + --slave /usr/bin/lldb lldb /usr/bin/lldb-$LLVM_VERSION && \ + # CMake + wget "https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}.tar.gz" && \ + tar -xzf "cmake-${CMAKE_VERSION}.tar.gz" && \ + rm -f "cmake-${CMAKE_VERSION}.tar.gz" && \ + cd "cmake-${CMAKE_VERSION}" && \ + ./bootstrap --parallel=$(nproc) && make -j $(nproc) && make install && \ + cd .. && rm -rf "cmake-${CMAKE_VERSION}" && \ + update-alternatives --install /usr/bin/cmake cmake /usr/local/bin/cmake 100 && \ + # debug tools + apt-get install --no-install-recommends -y \ + gdb ninja-build valgrind \ + locales-all dos2unix rsync tar python3 python3-dev linux-tools-$(uname -r) time git && \ + rm -rf /var/lib/apt/lists/* diff --git a/docker/build/clang/19/Dockerfile b/docker/build/clang/19/Dockerfile new file mode 100644 index 0000000..4fc7dfc --- /dev/null +++ b/docker/build/clang/19/Dockerfile @@ -0,0 +1,37 @@ +# Build and run from project directory: +# docker build -t map_matching_2-clang-build -f docker/build/clang/19/Dockerfile . +# docker run -u $(id -u):$(id -g) -v .:/tmp/map-matching-2 -it --rm map_matching_2-clang-build + +FROM debian:12 AS build + +ARG DEBIAN_FRONTEND="noninteractive" +# only use major LLVM version +ARG LLVM_VERSION=19 +ARG CMAKE_VERSION=3.28.6 + +RUN apt-get update && apt-get dist-upgrade -y && \ + apt-get install --no-install-recommends -y \ + tzdata make lsb-release ca-certificates wget software-properties-common gnupg libssl-dev && \ + # https://github.com/hof/bookworm-apt-add-repository-issue + [ ! -e /etc/apt/sources.list ] && echo "#" | tee /etc/apt/sources.list && \ + # LLVM + wget https://apt.llvm.org/llvm.sh && \ + chmod +x llvm.sh && \ + ./llvm.sh $LLVM_VERSION all && \ + rm llvm.sh && \ + update-alternatives --install /usr/bin/clang clang /usr/bin/clang-$LLVM_VERSION 100 \ + --slave /usr/bin/clang++ clang++ /usr/bin/clang++-$LLVM_VERSION \ + --slave /usr/bin/lldb lldb /usr/bin/lldb-$LLVM_VERSION && \ + # CMake + wget "https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}.tar.gz" && \ + tar -xzf "cmake-${CMAKE_VERSION}.tar.gz" && \ + rm -f "cmake-${CMAKE_VERSION}.tar.gz" && \ + cd "cmake-${CMAKE_VERSION}" && \ + ./bootstrap --parallel=$(nproc) && make -j $(nproc) && make install && \ + cd .. && rm -rf "cmake-${CMAKE_VERSION}" && \ + update-alternatives --install /usr/bin/cmake cmake /usr/local/bin/cmake 100 && \ + # debug tools + apt-get install --no-install-recommends -y \ + gdb ninja-build valgrind \ + locales-all dos2unix rsync tar python3 python3-dev linux-perf time git && \ + rm -rf /var/lib/apt/lists/* diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index 973f612..07d1d1f 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -3,11 +3,6 @@ set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) find_package(Boost REQUIRED COMPONENTS thread program_options) -configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/include/app/version.hpp.in - ${CMAKE_CURRENT_BINARY_DIR}/include/app/version.hpp - @ONLY) - add_library(app STATIC) target_sources(app diff --git a/src/app/src/app/options.cpp b/src/app/src/app/options.cpp index 38d022c..7af4028 100644 --- a/src/app/src/app/options.cpp +++ b/src/app/src/app/options.cpp @@ -15,7 +15,6 @@ #include "app/options.hpp" #include "app/general.hpp" -#include "app/version.hpp" #include #include @@ -28,6 +27,7 @@ #include "io/network/osm_pattern.hpp" #include "compare/comparator/compare_output_settings.hpp" #include "matching/matcher/matcher_output_settings.hpp" +#include "util/version.hpp" namespace map_matching_2::app { @@ -468,7 +468,7 @@ namespace map_matching_2::app { " \ttrack_length: track length in meter\n" " \tprepared_length: prepared track length in meter\n" " \tmatch_length: match length in meter\n" - " \tedge_ids: list of original edge IDs") + " \tedge_ids: list of original edge IDs (off by default; if used, combine with simplify osm-aware") ("export-edges", po::value(&data.export_edges)->default_value(false, "off"), "export matched routes based on the complete network edges instead of the actual parts, " "this is only useful if the routes are later compared to matches that come from a list of edge IDs, " @@ -793,7 +793,9 @@ namespace map_matching_2::app { " \tsimplify, but don't combine roads with different osm ids and tags,\n" " \tthis mode is usually not recommended, except special .csv extracts are of interest\n" " \tor when the map matching metrics later down the line respect the osm tags,\n" - " \twhich they do not by design currently\n" + " \twhich they do not by design currently;\n" + " \thowever, use this when you export edge_ids with the matches later,\n" + " \tas only then the ids are correctly preserved during simplification\n" "default is \"all\"") ("remove-unconnected", po::value(&data.remove_unconnected)->default_value(false, "off"), "remove weakly unconnected components so that only the largest subgraph remains;\n" @@ -1371,7 +1373,7 @@ namespace map_matching_2::app { bool show_version(const po::variables_map &vm) { if (vm.count("version")) { - std::cout << "Version: " << version() << std::endl; + std::cout << "Version: " << util::version() << std::endl; return true; } return false; diff --git a/src/library/CMakeLists.txt b/src/library/CMakeLists.txt index b97ea62..6c16f26 100644 --- a/src/library/CMakeLists.txt +++ b/src/library/CMakeLists.txt @@ -4,6 +4,11 @@ find_package(Threads REQUIRED) find_package(Boost REQUIRED COMPONENTS serialization thread chrono) find_package(Osmium REQUIRED COMPONENTS io) +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/src/util/version.cpp.in + ${CMAKE_CURRENT_BINARY_DIR}/src/util/version.cpp + @ONLY) + add_library(library STATIC) target_sources(library @@ -23,7 +28,8 @@ target_sources(library src/io/importer.cpp src/matching/matcher/match_task.cpp src/matching/defect.cpp - src/util/compiler.cpp) + src/util/compiler.cpp + src/util/version.cpp) if (EXPLICIT_TEMPLATES) target_sources(library @@ -134,7 +140,8 @@ endif () target_include_directories(library PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/include) + ${CMAKE_CURRENT_SOURCE_DIR}/include + ${CMAKE_CURRENT_BINARY_DIR}/include) target_include_directories(library SYSTEM PUBLIC diff --git a/src/library/include/graph/adjacency_list.hpp b/src/library/include/graph/adjacency_list.hpp index d5e6d4a..6a2dc9b 100644 --- a/src/library/include/graph/adjacency_list.hpp +++ b/src/library/include/graph/adjacency_list.hpp @@ -724,7 +724,8 @@ namespace map_matching_2::graph { } [[nodiscard]] vertex_descriptor _add_vertex(vertex_type &&vertex) { - return try_add(vertices, std::move(vertex)); + const auto &additional_tidy = []() constexpr -> void {}; + return try_add(vertices, additional_tidy, std::move(vertex)); } edge_descriptor add_edge(const vertex_descriptor &source_desc, const vertex_descriptor &target_desc) requires @@ -756,7 +757,8 @@ namespace map_matching_2::graph { const auto index = vertex_index(source_desc); // std::cout << "From " << vertex_index(source_desc) << " to " << vertex_index(target_desc) << std::endl; // std::cout << "Size Before: " << get_vertex(source_desc).out_edges.size() << std::endl; - edge_descriptor edge_desc = try_add(edges, std::move(edge)); + const auto &additional_tidy = []() constexpr -> void {}; + edge_descriptor edge_desc = try_add(edges, additional_tidy, std::move(edge)); edge_type &edge_r = get_edge(edge_desc); auto edges_tidy = [&]() { @@ -767,7 +769,7 @@ namespace map_matching_2::graph { }; vertex_type &source_vertex = get_vertex(source_desc); - try_add(source_vertex.out_edges, edge_descriptor{edge_desc}, edges_tidy); + try_add(source_vertex.out_edges, edges_tidy, edge_descriptor{edge_desc}); if constexpr (is_undirected_v or is_bidirectional_v) { auto source_out_edges_tidy = [&]() { @@ -782,7 +784,7 @@ namespace map_matching_2::graph { if constexpr (is_undirected_v) { if (std::addressof(source_vertex) != std::addressof(target_vertex)) { - try_add(target_vertex.out_edges, edge_descriptor{edge_desc}, source_out_edges_tidy); + try_add(target_vertex.out_edges, source_out_edges_tidy, edge_descriptor{edge_desc}); } } @@ -797,7 +799,7 @@ namespace map_matching_2::graph { source_out_edges_tidy(); }; - try_add(target_vertex.in_edges, edge_descriptor{edge_desc}, target_out_edges_tidy); + try_add(target_vertex.in_edges, target_out_edges_tidy, edge_descriptor{edge_desc}); } } @@ -936,29 +938,23 @@ namespace map_matching_2::graph { } } - template requires - requires(Container container, typename Container::value_type value) { - { container.emplace_back(value) }; + template requires + requires(Container container, Args &&... args) { + { container.emplace_back(std::forward(args)...) }; { container.pop_back() }; } std::conditional_t, typename Container::size_type, typename Container::iterator> - try_add(Container &container, typename Container::value_type &&value, const AdditionalTidy &additional_tidy) { - std::exception_ptr eptr = nullptr; - + try_add(Container &container, const AdditionalTidy &additional_tidy, Args &&... args) { typename Container::size_type current_size = container.size(); try { - container.emplace_back(std::move(value)); + container.emplace_back(std::forward(args)...); } catch (...) { - eptr = std::current_exception(); while (container.size() > current_size) { container.pop_back(); } additional_tidy(); - } - - if (eptr) { - std::rethrow_exception(eptr); + throw; } if constexpr (util::is_random_access_v) { @@ -968,19 +964,6 @@ namespace map_matching_2::graph { } } - template requires - requires(Container container, typename Container::value_type value) { - { container.emplace_back(value) }; - { container.pop_back() }; - } - std::conditional_t, - typename Container::size_type, typename Container::iterator> - try_add(Container &container, typename Container::value_type &&value) { - const auto &additional_tidy = []() constexpr -> void {}; - - return try_add(container, std::move(value), additional_tidy); - } - void reindex() requires (not util::is_random_access_v and not util::is_random_access_v) { if constexpr (not util::is_random_access_v) { diff --git a/src/library/include/io/helper/osm_handler_helper.hpp b/src/library/include/io/helper/osm_handler_helper.hpp index 4e45c7f..cc233fc 100644 --- a/src/library/include/io/helper/osm_handler_helper.hpp +++ b/src/library/include/io/helper/osm_handler_helper.hpp @@ -118,10 +118,8 @@ namespace map_matching_2::io::helper { const auto node_location = osm_node.location(); const std::size_t index = vertices().size(); vertices().emplace_back(osm_vertex_type{ - vertex_type{ - osm_node.id(), osm_point_type{node_location.lon(), node_location.lat()}, - reprojector_variant, tags(osm_node.tags()) - } + osm_node.id(), osm_point_type{node_location.lon(), node_location.lat()}, + reprojector_variant, tags(osm_node.tags()) }); return index; }; diff --git a/src/library/include/io/helper/tag_helper.hpp b/src/library/include/io/helper/tag_helper.hpp index 4da787d..eda63b8 100644 --- a/src/library/include/io/helper/tag_helper.hpp +++ b/src/library/include/io/helper/tag_helper.hpp @@ -71,19 +71,19 @@ namespace map_matching_2::io::helper { } const auto &_id = [this, &key, &value]() -> std::uint64_t { - key_type _key = _tag_storage.string(key); - value_type _value = _tag_storage.string(value); + // key_type _key = _tag_storage.string(key); + // value_type _value = _tag_storage.string(value); std::uint64_t key_id, value_id, tag_id; - auto key_search = _tag_storage.key_id_map().find(_key); + auto key_search = _tag_storage.key_id_map().find(key); if (key_search == _tag_storage.key_id_map().end()) { key_id = _tag_storage.key_id_map().size(); try { - _tag_storage.key_id_map().emplace(_key, key_id); - _tag_storage.id_key_map().emplace(key_id, _key); + _tag_storage.key_id_map().emplace(_tag_storage.string(key), key_id); + _tag_storage.id_key_map().emplace(key_id, _tag_storage.string(key)); } catch (...) { - _tag_storage.key_id_map().erase(_key); + _tag_storage.key_id_map().erase(key); _tag_storage.id_key_map().erase(key_id); std::rethrow_exception(std::current_exception()); } @@ -91,14 +91,14 @@ namespace map_matching_2::io::helper { key_id = key_search->second; } - auto value_search = _tag_storage.value_id_map().find(_value); + auto value_search = _tag_storage.value_id_map().find(value); if (value_search == _tag_storage.value_id_map().end()) { value_id = _tag_storage.value_id_map().size(); try { - _tag_storage.value_id_map().emplace(_value, value_id); - _tag_storage.id_value_map().emplace(value_id, _value); + _tag_storage.value_id_map().emplace(_tag_storage.string(value), value_id); + _tag_storage.id_value_map().emplace(value_id, _tag_storage.string(value)); } catch (...) { - _tag_storage.value_id_map().erase(_value); + _tag_storage.value_id_map().erase(value); _tag_storage.id_value_map().erase(value_id); std::rethrow_exception(std::current_exception()); } diff --git a/src/library/include/io/memory_mapped/storage/base_storage.hpp b/src/library/include/io/memory_mapped/storage/base_storage.hpp index 168a07e..f9abfec 100644 --- a/src/library/include/io/memory_mapped/storage/base_storage.hpp +++ b/src/library/include/io/memory_mapped/storage/base_storage.hpp @@ -25,6 +25,7 @@ #include "util/macros.hpp" #include "util/compiler.hpp" +#include "util/version.hpp" #include "../concepts.hpp" #include "../utils.hpp" @@ -58,7 +59,43 @@ namespace map_matching_2::io::memory_mapped::storage { using types = Types; using mmap_type = typename types::mmap_type; - constexpr static const char *compiler_info_identifier = "compiler_info"; + constexpr static const char *info_identifier = "info"; + + class info { + + public: + using allocator_type = typename types::template allocator_type; + using string_type = boost::interprocess::basic_string, allocator_type>; + + info(const std::string &compiler, const std::string &version, const allocator_type &allocator) + : _compiler(std::cbegin(compiler), std::cend(compiler), allocator), + _version(std::cbegin(version), std::cend(version), allocator) {} + + void assign(const std::string &compiler, const std::string &version) { + _compiler.assign(std::cbegin(compiler), std::cend(compiler)); + _version.assign(std::cbegin(version), std::cend(version)); + } + + constexpr const string_type &compiler() const { + return _compiler; + } + + constexpr const string_type &version() const { + return _version; + } + + [[nodiscard]] std::string compiler_str() const { + return {std::cbegin(_compiler), std::cend(_compiler)}; + } + + [[nodiscard]] std::string version_str() const { + return {std::cbegin(_version), std::cend(_version)}; + } + + private: + string_type _compiler; + string_type _version; + }; constexpr mmap_base_container() = default; @@ -87,7 +124,7 @@ namespace map_matching_2::io::memory_mapped::storage { open(name); #else _storage = new mmap_type{boost::interprocess::create_only, name.c_str(), size}; - process_compiler_info(boost::interprocess::create_only, *_storage, name); + process_info(boost::interprocess::create_only, *_storage, name); #endif } @@ -99,106 +136,112 @@ namespace map_matching_2::io::memory_mapped::storage { open(name); #else _storage = new mmap_type{boost::interprocess::open_or_create, name.c_str(), size}; - process_compiler_info(boost::interprocess::open_or_create, *_storage, name); + process_info(boost::interprocess::open_or_create, *_storage, name); #endif } void open_read_only(const std::string &name) { _storage = new mmap_type{boost::interprocess::open_read_only, name.c_str()}; - process_compiler_info(boost::interprocess::open_read_only, *_storage, name); + process_info(boost::interprocess::open_read_only, *_storage, name); } void open(const std::string &name) { _storage = new mmap_type{boost::interprocess::open_only, name.c_str()}; - process_compiler_info(boost::interprocess::open_only, *_storage, name); + process_info(boost::interprocess::open_only, *_storage, name); } void open_copy_on_write(const std::string &name) { _storage = new mmap_type{boost::interprocess::open_copy_on_write, name.c_str()}; - process_compiler_info(boost::interprocess::open_copy_on_write, *_storage, name); + process_info(boost::interprocess::open_copy_on_write, *_storage, name); } - [[nodiscard]] static auto *find_compiler_info(mmap_type &storage) { - using allocator_type = typename types::template allocator_type; - using string_type = boost::interprocess::basic_string, allocator_type>; - - return storage.template find(compiler_info_identifier).first; + [[nodiscard]] static auto *find_info(mmap_type &storage) { + return storage.template find(info_identifier).first; } - static auto *construct_compiler_info(mmap_type &storage, const std::string &compiler_info) { - using allocator_type = typename types::template allocator_type; - using string_type = boost::interprocess::basic_string, allocator_type>; - - allocator_type allocator{storage.get_segment_manager()}; - return storage.template construct(compiler_info_identifier) - (compiler_info.cbegin(), compiler_info.cend(), allocator); + static auto *construct_info(mmap_type &storage, const std::string &compiler, const std::string &version) { + typename info::allocator_type allocator{storage.get_segment_manager()}; + return storage.template construct(info_identifier)(compiler, version, allocator); } - static auto *write_compiler_info(mmap_type &storage) { - const auto compiler_info = util::get_compiler_info(); - auto *saved_compiler_info = find_compiler_info(storage); - if (saved_compiler_info) { - saved_compiler_info->assign(compiler_info.cbegin(), compiler_info.cend()); + static auto *write_info(mmap_type &storage) { + const auto compiler = util::get_compiler_info(); + const auto version = util::version(); + + auto *saved_info = find_info(storage); + if (saved_info) { + saved_info->assign(compiler, version); } else { - return construct_compiler_info(storage, compiler_info); + return construct_info(storage, compiler, version); } - return saved_compiler_info; + return saved_info; } - static auto *write_and_compare_compiler_info(mmap_type &storage, const std::string &name) { - write_compiler_info(storage); - return compare_compiler_info(storage, name); + static auto *write_and_compare_info(mmap_type &storage, const std::string &name) { + write_info(storage); + return compare_info(storage, name); } - static auto *contains_compiler_info(mmap_type &storage, const std::string &name) { - auto *saved_compiler_info = find_compiler_info(storage); + static auto *contains_info(mmap_type &storage, const std::string &name) { + auto *saved_info = find_info(storage); - if (not saved_compiler_info) { - const auto compiler_info = util::get_compiler_info(); + if (not saved_info) { + const auto compiler = util::get_compiler_info(); + const auto version = util::version(); throw std::runtime_error{ - std::format("storage '{}' does not contain compiler info '{}', please rebuild storage", - name, compiler_info) + std::format( + "storage '{}' does not contain compiler info '{}' and version number '{}', please rebuild storage", + name, compiler, version) }; } - return saved_compiler_info; + return saved_info; } - static auto *compare_compiler_info(mmap_type &storage, const std::string &name) { - auto *saved_compiler_info = contains_compiler_info(storage, name); - - const auto compiler_info = util::get_compiler_info(); + static auto *compare_info(mmap_type &storage, const std::string &name) { + auto *saved_info = contains_info(storage, name); - const std::string converted_compiler_info{saved_compiler_info->cbegin(), saved_compiler_info->cend()}; - if (compiler_info != converted_compiler_info) { + const auto compiler = util::get_compiler_info(); + const std::string converted_compiler = saved_info->compiler_str(); + if (compiler != converted_compiler) { throw std::runtime_error{ std::format( "storage '{}' was built with compiler '{}' but current compiler is '{}', please rebuild storage", - name, converted_compiler_info, compiler_info) + name, converted_compiler, compiler) + }; + } + + const auto version = util::version(); + const std::string converted_version = saved_info->version_str(); + if (version != converted_version) { + throw std::runtime_error{ + std::format( + "storage '{}' was built with software version '{}' but current version is '{}', please rebuild storage", + name, converted_version, version) }; } - return saved_compiler_info; + return saved_info; } template - static auto *process_compiler_info(CreationTag creation_tag, mmap_type &storage, const std::string &name) { + static auto *process_info(CreationTag creation_tag, mmap_type &storage, const std::string &name) { if constexpr (std::same_as) { - return write_and_compare_compiler_info(storage, name); + return write_and_compare_info(storage, name); } else if constexpr (std::same_as) { - return compare_compiler_info(storage, name); + return compare_info(storage, name); } else if constexpr (std::same_as) { - return compare_compiler_info(storage, name); + return compare_info(storage, name); } else if constexpr (std::same_as) { - return compare_compiler_info(storage, name); + return compare_info(storage, name); } else if constexpr (std::same_as) { - return compare_compiler_info(storage, name); + return compare_info(storage, name); } else if constexpr (std::same_as) { - if (const auto *saved_compiler_info = find_compiler_info(storage); saved_compiler_info) { - return compare_compiler_info(storage, name); + if (const auto *saved_info = find_info(storage); saved_info) { + return compare_info(storage, name); } else { - return write_and_compare_compiler_info(storage, name); + return write_and_compare_info(storage, name); } } else { throw std::invalid_argument{"unknown creation_tag"}; @@ -247,7 +290,7 @@ namespace map_matching_2::io::memory_mapped::storage { static void _make_sparse_file(CreationTag creation_tag, const std::string &filename, const std::size_t init) { { mmap_type storage{creation_tag, filename.c_str(), init}; - process_compiler_info(creation_tag, storage, filename); + process_info(creation_tag, storage, filename); } make_sparse_file(filename); } @@ -256,7 +299,7 @@ namespace map_matching_2::io::memory_mapped::storage { if (size > offset) { grow_file(filename, size); mmap_type storage{boost::interprocess::open_only, filename.c_str()}; - process_compiler_info(boost::interprocess::open_only, storage, filename); + process_info(boost::interprocess::open_only, storage, filename); storage.get_segment_manager()->grow(size - offset); } } diff --git a/src/library/include/io/memory_mapped/storage/osm_handler_storage.hpp b/src/library/include/io/memory_mapped/storage/osm_handler_storage.hpp index 029481f..e75f3f5 100644 --- a/src/library/include/io/memory_mapped/storage/osm_handler_storage.hpp +++ b/src/library/include/io/memory_mapped/storage/osm_handler_storage.hpp @@ -36,23 +36,17 @@ namespace map_matching_2::io::memory_mapped::storage { constexpr explicit osm_vertex(vertex_type vertex) : vertex{std::move(vertex)} {} + template + constexpr explicit osm_vertex(Args &&... args) + : vertex{std::forward(args)...} {} + constexpr osm_vertex(const osm_vertex &other) = delete; - constexpr osm_vertex(osm_vertex &&other) noexcept - : vertex{std::move(other.vertex)}, - vertex_index{std::move(other.vertex_index)}, - added{std::move(other.added)} {} + constexpr osm_vertex(osm_vertex &&other) noexcept = default; constexpr osm_vertex &operator=(const osm_vertex &other) = delete; - constexpr osm_vertex &operator=(osm_vertex &&other) noexcept { - if (this != &other) { - vertex = std::move(other.vertex); - vertex_index = std::move(other.vertex_index); - added = std::move(other.added); - } - return *this; - } + constexpr osm_vertex &operator=(osm_vertex &&other) noexcept = default; constexpr ~osm_vertex() = default; diff --git a/src/library/include/io/memory_mapped/storage/tag_storage.hpp b/src/library/include/io/memory_mapped/storage/tag_storage.hpp index e177f29..40bd908 100644 --- a/src/library/include/io/memory_mapped/storage/tag_storage.hpp +++ b/src/library/include/io/memory_mapped/storage/tag_storage.hpp @@ -34,6 +34,84 @@ namespace map_matching_2::io::memory_mapped::storage { + template + struct tag_comparator; + + template requires + (std::same_as) + struct tag_comparator { + + using is_transparent = void; + + using string_type_a = StringA; + using string_type_b = StringB; + + constexpr bool operator()(const string_type_a &left, const string_type_b &right) const { + return left == right; + } + + }; + + template requires + (not std::same_as) + struct tag_comparator { + + using is_transparent = void; + + using string_type_a = StringA; + using string_type_b = StringB; + + constexpr bool operator()(const string_type_a &left, const string_type_a &right) const { + return left == right; + } + + constexpr bool operator()(const string_type_b &left, const string_type_b &right) const { + return left == right; + } + + constexpr bool operator()(const string_type_a &left, const string_type_b &right) const { + return left == right.c_str(); + } + + constexpr bool operator()(const string_type_b &left, const string_type_a &right) const { + return left == right.c_str(); + } + + }; + + template + struct tag_hash; + + template requires + (std::same_as) + struct tag_hash { + using is_transparent = void; + + using string_type_a = StringA; + using string_type_b = StringB; + + constexpr std::size_t operator()(const string_type_a &str) const { + return boost::hash_value(str); + } + }; + + template requires + (not std::same_as) + struct tag_hash { + using is_transparent = void; + + using string_type_a = StringA; + using string_type_b = StringB; + + constexpr std::size_t operator()(const string_type_a &str) const { + return boost::hash_value(str); + } + + constexpr std::size_t operator()(const string_type_b &str) const { + return boost::hash_value(str); + } + }; + template class tag_storage; @@ -66,7 +144,7 @@ namespace map_matching_2::io::memory_mapped::storage { using key_map_type = boost::unordered_flat_map, std::equal_to<>, key_allocator_type>; using value_map_type = boost::unordered_flat_map, std::equal_to<>, value_allocator_type>; + tag_hash, tag_comparator, value_allocator_type>; using tags_map_type = boost::unordered_flat_map, std::equal_to<>, tags_allocator_type>; using ids_map_type = boost::unordered_flat_map, std::equal_to<>, key_allocator_type>; using value_map_type = boost::unordered_flat_map, std::equal_to<>, value_allocator_type>; + tag_hash, tag_comparator, value_allocator_type>; using tags_map_type = boost::unordered_flat_map, std::equal_to<>, tags_allocator_type>; using ids_map_type = boost::unordered_flat_map auto retry_alloc(const Try &try_function, const Catch &catch_function, const std::size_t retries = 1) { - std::exception_ptr eptr; - std::size_t tries = 0; while (tries <= retries) { try { return try_function(); } catch (boost::interprocess::bad_alloc &ex) { - tries++; - eptr = std::current_exception(); catch_function(ex); + if (++tries > retries) { + throw; + } } } - if (eptr) { - std::rethrow_exception(eptr); - } - throw boost::interprocess::bad_alloc{}; } diff --git a/src/library/include/matching/matcher/matcher_output_settings.hpp b/src/library/include/matching/matcher/matcher_output_settings.hpp index 0bc3578..1cf29da 100644 --- a/src/library/include/matching/matcher/matcher_output_settings.hpp +++ b/src/library/include/matching/matcher/matcher_output_settings.hpp @@ -21,7 +21,7 @@ namespace map_matching_2::matching { static const std::string DEFAULT_COLUMNS{ - "id,duration,track,prepared,match,track_length,prepared_length,match_length,edge_ids" + "id,duration,track,prepared,match,track_length,prepared_length,match_length" }; static const std::string DEFAULT_CANDIDATE_COLUMNS{ diff --git a/src/app/include/app/version.hpp.in b/src/library/include/util/version.hpp similarity index 79% rename from src/app/include/app/version.hpp.in rename to src/library/include/util/version.hpp index 1eb6dac..ecedd63 100644 --- a/src/app/include/app/version.hpp.in +++ b/src/library/include/util/version.hpp @@ -13,16 +13,14 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see https://www.gnu.org/licenses/. -#ifndef MAP_MATCHING_2_APP_VERSION_HPP -#define MAP_MATCHING_2_APP_VERSION_HPP +#ifndef MAP_MATCHING_2_UTIL_VERSION_HPP +#define MAP_MATCHING_2_UTIL_VERSION_HPP #include -namespace map_matching_2::app { +namespace map_matching_2::util { - [[nodiscard]] const std::string version() { - return "@PROJECT_VERSION@"; - } + [[nodiscard]] const std::string version(); } diff --git a/src/library/src/io/importer.cpp b/src/library/src/io/importer.cpp index 7e94c36..01233fc 100644 --- a/src/library/src/io/importer.cpp +++ b/src/library/src/io/importer.cpp @@ -17,7 +17,7 @@ #include -// __clang_major__ >= 18 # chrono not yet supported +// __clang_major__ >= 19 # chrono parse not yet supported #if (__cplusplus >= 202002L and (defined(__GNUC__) and __GNUC__ >= 14)) or \ (defined(_MSC_VER) and _MSC_VER >= 1939) #define HAS_CHRONO_PARSE 1 @@ -31,7 +31,9 @@ namespace map_matching_2::io { [[nodiscard]] bool importer::is_number(const std::string &str) { if (not str.empty()) { - for (char c : str) { + for (auto it = std::cbegin(str); it != std::cend(str); ++it) { + const char c = *it; + if (not std::isdigit(c)) { return false; } @@ -45,7 +47,9 @@ namespace map_matching_2::io { std::vector delimiters; delimiters.reserve(delimiter.size()); bool escaped = false; - for (const char &c : delimiter) { + for (auto it = std::cbegin(delimiter); it != std::cend(delimiter); ++it) { + const char c = *it; + if (escaped) { if (c == 't') { delimiters.emplace_back('\t'); @@ -68,9 +72,12 @@ namespace map_matching_2::io { [[nodiscard]] static std::vector parse_delimiter(const std::string &delimiter) { std::vector delimiters; - delimiters.reserve(delimiter.size()); + delimiters.reserve(delimiter.length()); + bool escaped = false; - for (const char &c : delimiter) { + for (auto it = std::cbegin(delimiter); it != std::cend(delimiter); ++it) { + const char c = *it; + if (c == '\\') { escaped = true; continue; diff --git a/src/library/src/util/version.cpp.in b/src/library/src/util/version.cpp.in new file mode 100644 index 0000000..d311c44 --- /dev/null +++ b/src/library/src/util/version.cpp.in @@ -0,0 +1,24 @@ +// Copyright (C) 2024 Adrian Wöltche +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see https://www.gnu.org/licenses/. + +#include "util/version.hpp" + +namespace map_matching_2::util { + + const std::string version() { + return "@PROJECT_VERSION@"; + } + +}