diff --git a/.clang-tidy b/.clang-tidy index 1d41cdd58..495e4fc6a 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -17,6 +17,7 @@ Checks: > -bugprone-incorrect-enable-if, -bugprone-switch-missing-default-case, -bugprone-empty-catch, + -bugprone-unchecked-optional-access, -clang-analyzer-*, -clang-diagnostic-deprecated-declarations, -clang-diagnostic-constant-conversion, diff --git a/.github/workflows/osrm-backend.yml b/.github/workflows/osrm-backend.yml index b743ee942..454e273f4 100644 --- a/.github/workflows/osrm-backend.yml +++ b/.github/workflows/osrm-backend.yml @@ -177,39 +177,41 @@ jobs: CXXCOMPILER: g++-13 ENABLE_COVERAGE: ON - - name: clang-15-debug-asan-ubsan + - name: clang-18-debug-asan-ubsan continue-on-error: false node: 20 - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 BUILD_TOOLS: ON BUILD_TYPE: Debug - CCOMPILER: clang-15 + CCOMPILER: clang-18 CUCUMBER_TIMEOUT: 20000 - CXXCOMPILER: clang++-15 + CXXCOMPILER: clang++-18 ENABLE_SANITIZER: ON TARGET_ARCH: x86_64-asan-ubsan OSRM_CONNECTION_RETRIES: 10 OSRM_CONNECTION_EXP_BACKOFF_COEF: 1.5 - - name: clang-15-release + - name: clang-18-release continue-on-error: false node: 18 - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 BUILD_TOOLS: ON BUILD_TYPE: Release - CCOMPILER: clang-15 - CXXCOMPILER: clang++-15 + CCOMPILER: clang-18 + CXXCOMPILER: clang++-18 CUCUMBER_TIMEOUT: 60000 + ENABLE_LTO: OFF - - name: clang-15-debug + - name: clang-18-debug continue-on-error: false node: 18 - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 BUILD_TOOLS: ON BUILD_TYPE: Debug - CCOMPILER: clang-15 - CXXCOMPILER: clang++-15 + CCOMPILER: clang-18 + CXXCOMPILER: clang++-18 CUCUMBER_TIMEOUT: 60000 + ENABLE_LTO: OFF - name: clang-18-debug-clang-tidy continue-on-error: false @@ -223,46 +225,50 @@ jobs: ENABLE_CLANG_TIDY: ON - - name: clang-14-release + - name: clang-17-release continue-on-error: false node: 18 - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 BUILD_TOOLS: ON BUILD_TYPE: Release - CCOMPILER: clang-14 - CXXCOMPILER: clang++-14 + CCOMPILER: clang-17 + CXXCOMPILER: clang++-17 CUCUMBER_TIMEOUT: 60000 + ENABLE_LTO: OFF - - name: clang-13-release + - name: clang-16-release continue-on-error: false node: 18 - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 BUILD_TOOLS: ON BUILD_TYPE: Release - CCOMPILER: clang-13 - CXXCOMPILER: clang++-13 + CCOMPILER: clang-16 + CXXCOMPILER: clang++-16 CUCUMBER_TIMEOUT: 60000 + ENABLE_LTO: OFF - name: conan-linux-debug-asan-ubsan continue-on-error: false node: 18 - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 BUILD_TOOLS: ON BUILD_TYPE: Release - CCOMPILER: clang-15 - CXXCOMPILER: clang++-15 + CCOMPILER: clang-18 + CXXCOMPILER: clang++-18 ENABLE_CONAN: ON ENABLE_SANITIZER: ON + ENABLE_LTO: OFF - name: conan-linux-release continue-on-error: false node: 18 - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 BUILD_TOOLS: ON BUILD_TYPE: Release - CCOMPILER: clang-15 - CXXCOMPILER: clang++-15 + CCOMPILER: clang-18 + CXXCOMPILER: clang++-18 ENABLE_CONAN: ON + ENABLE_LTO: OFF - name: gcc-14-release continue-on-error: false @@ -298,10 +304,10 @@ jobs: build_node_package: true continue-on-error: false node: 20 - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 BUILD_TYPE: Release - CCOMPILER: clang-13 - CXXCOMPILER: clang++-13 + CCOMPILER: clang-16 + CXXCOMPILER: clang++-16 ENABLE_CONAN: ON NODE_PACKAGE_TESTS_ONLY: ON @@ -309,10 +315,10 @@ jobs: build_node_package: true continue-on-error: false node: 20 - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 BUILD_TYPE: Debug - CCOMPILER: clang-13 - CXXCOMPILER: clang++-13 + CCOMPILER: clang-16 + CXXCOMPILER: clang++-16 ENABLE_CONAN: ON NODE_PACKAGE_TESTS_ONLY: ON @@ -361,6 +367,7 @@ jobs: TARGET_ARCH: ${{ matrix.TARGET_ARCH }} OSRM_CONNECTION_RETRIES: ${{ matrix.OSRM_CONNECTION_RETRIES }} OSRM_CONNECTION_EXP_BACKOFF_COEF: ${{ matrix.OSRM_CONNECTION_EXP_BACKOFF_COEF }} + ENABLE_LTO: ${{ matrix.ENABLE_LTO }} steps: - uses: actions/checkout@v4 - name: Build machine architecture @@ -488,6 +495,13 @@ jobs: tar zxvf onetbb.tgz sudo cp -a oneapi-tbb-${TBB_VERSION}/lib/. /usr/local/lib/ sudo cp -a oneapi-tbb-${TBB_VERSION}/include/. /usr/local/include/ + - name: Add Clang 18 to list of Conan compilers # workaround for the issue that Conan 1.x doesn't know about Clang 18 + if: ${{ matrix.ENABLE_CONAN == 'ON' && matrix.CCOMPILER == 'clang-18' }} + run: | + sudo wget https://github.com/mikefarah/yq/releases/download/v4.9.6/yq_linux_amd64 -O /usr/bin/yq && sudo chmod +x /usr/bin/yq + + conan config init + yq eval '.compiler.clang.version += ["18"]' -i "$HOME/.conan/settings.yml" - name: Prepare build run: | mkdir ${OSRM_BUILD_DIR} @@ -521,6 +535,7 @@ jobs: -DENABLE_SANITIZER=${ENABLE_SANITIZER:-OFF} \ -DBUILD_TOOLS=${BUILD_TOOLS:-OFF} \ -DENABLE_CCACHE=ON \ + -DENABLE_LTO=${ENABLE_LTO:-ON} \ -DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR} make --jobs=${JOBS} @@ -638,12 +653,12 @@ jobs: benchmarks: if: github.event_name == 'pull_request' needs: [format-taginfo-docs] - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 env: - CCOMPILER: clang-13 - CXXCOMPILER: clang++-13 - CC: clang-13 - CXX: clang++-13 + CCOMPILER: clang-16 + CXXCOMPILER: clang++-16 + CC: clang-16 + CXX: clang++-16 GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} PR_NUMBER: ${{ github.event.pull_request.number }} GITHUB_REPOSITORY: ${{ github.repository }} @@ -678,7 +693,7 @@ jobs: path: pr - name: Install dependencies run: | - python3 -m pip install "conan<2.0.0" "requests==2.31.0" "numpy==1.26.4" + python3 -m pip install "conan<2.0.0" "requests==2.31.0" "numpy==1.26.4" --break-system-packages sudo apt-get update -y && sudo apt-get install ccache - name: Prepare data run: | @@ -723,14 +738,34 @@ jobs: make -j$(nproc) benchmarks cd .. make -C test/data + # we run benchmarks in tmpfs to avoid impact of disk IO + - name: Create folder for tmpfs + run: mkdir -p /opt/benchmarks - name: Run PR Benchmarks run: | - ./pr/scripts/ci/run_benchmarks.sh -f $(pwd)/pr -r $(pwd)/pr_results -s $(pwd)/pr -b $(pwd)/pr/build -o ~/data.osm.pbf -g ~/gps_traces.csv + sudo mount -t tmpfs -o size=4g none /opt/benchmarks + cp -rf pr/build /opt/benchmarks/build + mkdir -p /opt/benchmarks/test + cp -rf pr/test/data /opt/benchmarks/test/data + cp -rf pr/profiles /opt/benchmarks/profiles + + ./pr/scripts/ci/run_benchmarks.sh -f /opt/benchmarks -r $(pwd)/pr_results -s $(pwd)/pr -b /opt/benchmarks/build -o ~/data.osm.pbf -g ~/gps_traces.csv + sudo umount /opt/benchmarks - name: Run Base Benchmarks run: | - # we intentionally use scripts from PR branch to be able to update them and see results in the same PR - ./pr/scripts/ci/run_benchmarks.sh -f $(pwd)/base -r $(pwd)/base_results -s $(pwd)/pr -b $(pwd)/base/build -o ~/data.osm.pbf -g ~/gps_traces.csv + sudo mount -t tmpfs -o size=4g none /opt/benchmarks + cp -rf base/build /opt/benchmarks/build + mkdir -p /opt/benchmarks/test + cp -rf base/test/data /opt/benchmarks/test/data + cp -rf base/profiles /opt/benchmarks/profiles + # TODO: remove it when base branch will have this file at needed location + if [ ! -f /opt/benchmarks/test/data/portugal_to_korea.json ]; then + cp base/src/benchmarks/portugal_to_korea.json /opt/benchmarks/test/data/portugal_to_korea.json + fi + # we intentionally use scripts from PR branch to be able to update them and see results in the same PR + ./pr/scripts/ci/run_benchmarks.sh -f /opt/benchmarks -r $(pwd)/base_results -s $(pwd)/pr -b /opt/benchmarks/build -o ~/data.osm.pbf -g ~/gps_traces.csv + sudo umount /opt/benchmarks - name: Post Benchmark Results run: | python3 pr/scripts/ci/post_benchmark_results.py base_results pr_results diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 72cf595ee..d8f4a2f4d 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -1,5 +1,9 @@ name: 'Close stale issues' on: + # uncomment if you want to test changes to this file in PRs CI + # pull_request: + # branches: + # - master schedule: - cron: '30 1 * * *' # every day at 1:30am permissions: @@ -12,6 +16,7 @@ jobs: steps: - uses: actions/stale@v9 with: + operations-per-run: 3000 stale-issue-message: 'This issue seems to be stale. It will be closed in 30 days if no further activity occurs.' stale-pr-message: 'This PR seems to be stale. Is it still relevant?' days-before-issue-stale: 180 # 6 months diff --git a/CHANGELOG.md b/CHANGELOG.md index a0abc407c..1b64ad1e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,14 @@ - NodeJS: - CHANGED: Use node-api instead of NAN. [#6452](https://github.com/Project-OSRM/osrm-backend/pull/6452) - Misc: + - CHANGED: Add .reserve(...) to assembleGeometry function. [#6983](https://github.com/Project-OSRM/osrm-backend/pull/6983) + - CHANGED: Get rid of boost::optional leftovers. [#6977](https://github.com/Project-OSRM/osrm-backend/pull/6977) + - CHANGED: Use Link Time Optimisation whenever possible. [#6967](https://github.com/Project-OSRM/osrm-backend/pull/6967) + - CHANGED: Use struct instead of tuple to define UnpackedPath. [#6974](https://github.com/Project-OSRM/osrm-backend/pull/6974) + - CHANGED: Micro performance optimisation in map matching. [#6976](https://github.com/Project-OSRM/osrm-backend/pull/6976) + - CHANGED: Re-use priority queue in StaticRTree. [#6952](https://github.com/Project-OSRM/osrm-backend/pull/6952) + - CHANGED: Optimise encodePolyline function. [#6940](https://github.com/Project-OSRM/osrm-backend/pull/6940) + - CHANGED: Avoid reallocations in base64 encoding. [#6951](https://github.com/Project-OSRM/osrm-backend/pull/6951) - CHANGED: Get rid of unused Boost dependencies. [#6960](https://github.com/Project-OSRM/osrm-backend/pull/6960) - CHANGED: Apply micro-optimisation for Table & Trip APIs. [#6949](https://github.com/Project-OSRM/osrm-backend/pull/6949) - CHANGED: Apply micro-optimisation for Route API. [#6948](https://github.com/Project-OSRM/osrm-backend/pull/6948) diff --git a/CMakeLists.txt b/CMakeLists.txt index aa9be6f50..08e0a64fa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,11 +31,12 @@ option(ENABLE_ASSERTIONS "Use assertions in release mode" OFF) option(ENABLE_DEBUG_LOGGING "Use debug logging in release mode" OFF) option(ENABLE_COVERAGE "Build with coverage instrumentalisation" OFF) option(ENABLE_SANITIZER "Use memory sanitizer for Debug build" OFF) -option(ENABLE_LTO "Use LTO if available" OFF) +option(ENABLE_LTO "Use Link Time Optimisation" ON) option(ENABLE_FUZZING "Fuzz testing using LLVM's libFuzzer" OFF) option(ENABLE_NODE_BINDINGS "Build NodeJs bindings" OFF) option(ENABLE_CLANG_TIDY "Enables clang-tidy checks" OFF) + if (ENABLE_CLANG_TIDY) find_program(CLANG_TIDY_COMMAND NAMES clang-tidy) if(NOT CLANG_TIDY_COMMAND) @@ -57,6 +58,18 @@ if (POLICY CMP0074) endif() project(OSRM C CXX) + +if(ENABLE_LTO AND (CMAKE_BUILD_TYPE MATCHES Release OR CMAKE_BUILD_TYPE MATCHES MinRelSize OR CMAKE_BUILD_TYPE MATCHES RelWithDebInfo)) + include(CheckIPOSupported) + check_ipo_supported(RESULT LTO_SUPPORTED OUTPUT error) + if(LTO_SUPPORTED) + message(STATUS "IPO / LTO enabled") + set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) + else() + message(FATAL_ERROR "IPO / LTO not supported: <${error}>") + endif() +endif() + # add @loader_path/$ORIGIN to rpath to make binaries relocatable if (APPLE) set(CMAKE_BUILD_RPATH "@loader_path") @@ -209,17 +222,6 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Og -ggdb") endif() -if(ENABLE_LTO AND (CMAKE_BUILD_TYPE MATCHES Release OR CMAKE_BUILD_TYPE MATCHES MinRelSize OR CMAKE_BUILD_TYPE MATCHES RelWithDebInfo)) - include(CheckIPOSupported) - check_ipo_supported(RESULT LTO_SUPPORTED OUTPUT error) - if(LTO_SUPPORTED) - message(STATUS "IPO / LTO enabled") - set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) - else() - message(WARNING "IPO / LTO not supported: <${error}>") - endif() -endif() - set(MAYBE_COVERAGE_LIBRARIES "") if (ENABLE_COVERAGE) if (NOT CMAKE_BUILD_TYPE MATCHES "Debug") @@ -291,6 +293,7 @@ include_directories(SYSTEM ${MICROTAR_INCLUDE_DIR}) add_library(MICROTAR OBJECT "${CMAKE_CURRENT_SOURCE_DIR}/third_party/microtar/src/microtar.c") set_property(TARGET MICROTAR PROPERTY POSITION_INDEPENDENT_CODE ON) + target_no_warning(MICROTAR unused-variable) target_no_warning(MICROTAR format) diff --git a/cmake/warnings.cmake b/cmake/warnings.cmake index 4006b0f2e..fa52d6279 100644 --- a/cmake/warnings.cmake +++ b/cmake/warnings.cmake @@ -64,7 +64,6 @@ add_warning(init-self) add_warning(bool-compare) add_warning(logical-not-parentheses) add_warning(logical-op) -add_warning(maybe-uninitialized) add_warning(misleading-indentation) # `no-` prefix is part of warning name(i.e. doesn't mean we are disabling it) add_warning(no-return-local-addr) @@ -84,3 +83,6 @@ no_warning(comma-subscript) no_warning(ambiguous-reversed-operator) no_warning(restrict) no_warning(free-nonheap-object) +if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") + no_warning(stringop-overflow) +endif() \ No newline at end of file diff --git a/docker/Dockerfile-alpine b/docker/Dockerfile-alpine index 42c20ae38..fe22173f9 100644 --- a/docker/Dockerfile-alpine +++ b/docker/Dockerfile-alpine @@ -31,7 +31,7 @@ RUN NPROC=${BUILD_CONCURRENCY:-$(nproc)} && \ case ${DOCKER_TAG} in *"-debug"*) BUILD_TYPE="Debug";; esac && \ case ${DOCKER_TAG} in *"-assertions"*) BUILD_TYPE="RelWithDebInfo" && ENABLE_ASSERTIONS="On" && BUILD_TOOLS="On";; esac && \ echo "Building ${BUILD_TYPE} with ENABLE_ASSERTIONS=${ENABLE_ASSERTIONS} BUILD_TOOLS=${BUILD_TOOLS}" && \ - cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DENABLE_ASSERTIONS=${ENABLE_ASSERTIONS} -DBUILD_TOOLS=${BUILD_TOOLS} -DENABLE_LTO=On && \ + cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DENABLE_ASSERTIONS=${ENABLE_ASSERTIONS} -DBUILD_TOOLS=${BUILD_TOOLS} -DENABLE_LTO=OFF && \ make -j${NPROC} install && \ cd ../profiles && \ cp -r * /opt && \ diff --git a/docker/Dockerfile-debian b/docker/Dockerfile-debian index cfec9cbed..8b51c5168 100644 --- a/docker/Dockerfile-debian +++ b/docker/Dockerfile-debian @@ -21,7 +21,7 @@ COPY . /src WORKDIR /src RUN NPROC=${BUILD_CONCURRENCY:-$(nproc)} && \ - export CXXFLAGS="-Wno-array-bounds -Wno-uninitialized" && \ + export CXXFLAGS="-Wno-array-bounds -Wno-uninitialized -Wno-stringop-overflow" && \ echo "Building OSRM ${DOCKER_TAG}" && \ git show --format="%H" | head -n1 > /opt/OSRM_GITSHA && \ echo "Building OSRM gitsha $(cat /opt/OSRM_GITSHA)" && \ diff --git a/include/engine/api/base_parameters.hpp b/include/engine/api/base_parameters.hpp index d7422566f..1a35a030d 100644 --- a/include/engine/api/base_parameters.hpp +++ b/include/engine/api/base_parameters.hpp @@ -33,7 +33,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "engine/hint.hpp" #include "util/coordinate.hpp" -#include +#include #include #include @@ -74,12 +74,12 @@ struct BaseParameters }; std::vector coordinates; - std::vector> hints; - std::vector> radiuses; - std::vector> bearings; - std::vector> approaches; + std::vector> hints; + std::vector> radiuses; + std::vector> bearings; + std::vector> approaches; std::vector exclude; - boost::optional format = OutputFormatType::JSON; + std::optional format = OutputFormatType::JSON; // Adds hints to response which can be included in subsequent requests, see `hints` above. bool generate_hints = true; @@ -90,10 +90,10 @@ struct BaseParameters SnappingType snapping = SnappingType::Default; BaseParameters(std::vector coordinates_ = {}, - std::vector> hints_ = {}, - std::vector> radiuses_ = {}, - std::vector> bearings_ = {}, - std::vector> approaches_ = {}, + std::vector> hints_ = {}, + std::vector> radiuses_ = {}, + std::vector> bearings_ = {}, + std::vector> approaches_ = {}, bool generate_hints_ = true, std::vector exclude = {}, const SnappingType snapping_ = SnappingType::Default) @@ -112,7 +112,7 @@ struct BaseParameters (approaches.empty() || approaches.size() == coordinates.size()) && std::all_of(bearings.begin(), bearings.end(), - [](const boost::optional &bearing_and_range) + [](const std::optional &bearing_and_range) { if (bearing_and_range) { diff --git a/include/engine/api/json_factory.hpp b/include/engine/api/json_factory.hpp index 1175dcd7e..001f44ff8 100644 --- a/include/engine/api/json_factory.hpp +++ b/include/engine/api/json_factory.hpp @@ -12,7 +12,7 @@ #include "util/coordinate.hpp" #include "util/json_container.hpp" -#include +#include #include #include @@ -90,7 +90,7 @@ util::json::Object makeRouteStep(guidance::RouteStep step, util::json::Value geo util::json::Object makeRoute(const guidance::Route &route, util::json::Array legs, - boost::optional geometry, + std::optional geometry, const char *weight_name); // Creates a Waypoint without Hint, see the Hint overload below diff --git a/include/engine/api/nearest_api.hpp b/include/engine/api/nearest_api.hpp index beae38cec..0e2a9edbf 100644 --- a/include/engine/api/nearest_api.hpp +++ b/include/engine/api/nearest_api.hpp @@ -45,7 +45,7 @@ class NearestAPI final : public BaseAPI flatbuffers::FlatBufferBuilder &fb_result) const { auto data_timestamp = facade.GetTimestamp(); - boost::optional> data_version_string = boost::none; + std::optional> data_version_string = std::nullopt; if (!data_timestamp.empty()) { data_version_string = fb_result.CreateString(data_timestamp); diff --git a/include/engine/api/route_api.hpp b/include/engine/api/route_api.hpp index 211be7f8d..fb1830ce3 100644 --- a/include/engine/api/route_api.hpp +++ b/include/engine/api/route_api.hpp @@ -184,10 +184,10 @@ class RouteAPI : public BaseAPI return builder.CreateVectorOfStructs(coordinates); } - boost::optional - MakeGeometry(boost::optional> &&annotations) const + std::optional + MakeGeometry(std::optional> &&annotations) const { - boost::optional json_geometry; + std::optional json_geometry; if (annotations) { auto begin = annotations->begin(); @@ -720,8 +720,7 @@ class RouteAPI : public BaseAPI std::vector &leg_geometries = legs_info.second; auto route = guidance::assembleRoute(legs); - boost::optional json_overview = - MakeGeometry(MakeOverview(leg_geometries)); + std::optional json_overview = MakeGeometry(MakeOverview(leg_geometries)); std::vector step_geometries; const auto total_step_count = @@ -997,10 +996,10 @@ class RouteAPI : public BaseAPI return result; } - boost::optional> + std::optional> MakeOverview(const std::vector &leg_geometries) const { - boost::optional> overview; + std::optional> overview; if (parameters.overview != RouteParameters::OverviewType::False) { const auto use_simplification = diff --git a/include/engine/api/route_parameters.hpp b/include/engine/api/route_parameters.hpp index 267058a46..a28f34b8c 100644 --- a/include/engine/api/route_parameters.hpp +++ b/include/engine/api/route_parameters.hpp @@ -82,7 +82,7 @@ struct RouteParameters : public BaseParameters const bool alternatives_, const GeometriesType geometries_, const OverviewType overview_, - const boost::optional continue_straight_, + const std::optional continue_straight_, Args &&...args_) // Once we perfectly-forward `args` (see #2990) this constructor can delegate to the one // below. @@ -100,7 +100,7 @@ struct RouteParameters : public BaseParameters const bool annotations_, const GeometriesType geometries_, const OverviewType overview_, - const boost::optional continue_straight_, + const std::optional continue_straight_, Args &&...args_) : BaseParameters{std::forward(args_)...}, steps{steps_}, alternatives{alternatives_}, number_of_alternatives{alternatives_ ? 1u : 0u}, annotations{annotations_}, @@ -118,7 +118,7 @@ struct RouteParameters : public BaseParameters const AnnotationsType annotations_, const GeometriesType geometries_, const OverviewType overview_, - const boost::optional continue_straight_, + const std::optional continue_straight_, Args &&...args_) : BaseParameters{std::forward(args_)...}, steps{steps_}, alternatives{alternatives_}, number_of_alternatives{alternatives_ ? 1u : 0u}, @@ -135,7 +135,7 @@ struct RouteParameters : public BaseParameters const bool annotations_, const GeometriesType geometries_, const OverviewType overview_, - const boost::optional continue_straight_, + const std::optional continue_straight_, std::vector waypoints_, const Args &&...args_) : BaseParameters{std::forward(args_)...}, steps{steps_}, alternatives{alternatives_}, @@ -153,7 +153,7 @@ struct RouteParameters : public BaseParameters const AnnotationsType annotations_, const GeometriesType geometries_, const OverviewType overview_, - const boost::optional continue_straight_, + const std::optional continue_straight_, std::vector waypoints_, Args &&...args_) : BaseParameters{std::forward(args_)...}, steps{steps_}, alternatives{alternatives_}, @@ -172,7 +172,7 @@ struct RouteParameters : public BaseParameters AnnotationsType annotations_type = AnnotationsType::None; GeometriesType geometries = GeometriesType::Polyline; OverviewType overview = OverviewType::Simplified; - boost::optional continue_straight; + std::optional continue_straight; std::vector waypoints; bool IsValid() const diff --git a/include/engine/api/trip_parameters.hpp b/include/engine/api/trip_parameters.hpp index 7ad785ac0..cc3f4d938 100644 --- a/include/engine/api/trip_parameters.hpp +++ b/include/engine/api/trip_parameters.hpp @@ -30,7 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "engine/api/route_parameters.hpp" -#include +#include #include namespace osrm::engine::api diff --git a/include/engine/base64.hpp b/include/engine/base64.hpp index d1fa8753c..042aa6d59 100644 --- a/include/engine/base64.hpp +++ b/include/engine/base64.hpp @@ -47,24 +47,29 @@ namespace engine // Encodes a chunk of memory to Base64. inline std::string encodeBase64(const unsigned char *first, std::size_t size) { - std::vector bytes{first, first + size}; - BOOST_ASSERT(!bytes.empty()); + BOOST_ASSERT(size > 0); - std::size_t bytes_to_pad{0}; + std::string encoded; + encoded.reserve(((size + 2) / 3) * 4); - while (bytes.size() % 3 != 0) + auto padding = (3 - size % 3) % 3; + + BOOST_ASSERT(padding == 0 || padding == 1 || padding == 2); + + for (auto itr = detail::Base64FromBinary(first); itr != detail::Base64FromBinary(first + size); + ++itr) { - bytes_to_pad += 1; - bytes.push_back(0); + encoded.push_back(*itr); } - BOOST_ASSERT(bytes_to_pad == 0 || bytes_to_pad == 1 || bytes_to_pad == 2); - BOOST_ASSERT_MSG(0 == bytes.size() % 3, "base64 input data size is not a multiple of 3"); + for (size_t index = 0; index < padding; ++index) + { + encoded.push_back('='); + } - std::string encoded{detail::Base64FromBinary{bytes.data()}, - detail::Base64FromBinary{bytes.data() + (bytes.size() - bytes_to_pad)}}; + BOOST_ASSERT(encoded.size() == (size + 2) / 3 * 4); - return encoded.append(bytes_to_pad, '='); + return encoded; } // C++11 standard 3.9.1/1: Plain char, signed char, and unsigned char are three distinct types diff --git a/include/engine/datafacade/contiguous_internalmem_datafacade.hpp b/include/engine/datafacade/contiguous_internalmem_datafacade.hpp index 7a495e86f..466c56694 100644 --- a/include/engine/datafacade/contiguous_internalmem_datafacade.hpp +++ b/include/engine/datafacade/contiguous_internalmem_datafacade.hpp @@ -369,7 +369,7 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade std::vector NearestPhantomNodesInRange(const util::Coordinate input_coordinate, const double max_distance, - const boost::optional bearing, + const std::optional bearing, const Approach approach, const bool use_all_edges) const override final { @@ -382,20 +382,20 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade std::vector NearestPhantomNodes(const util::Coordinate input_coordinate, const size_t max_results, - const boost::optional max_distance, - const boost::optional bearing, + const std::optional max_distance, + const std::optional bearing, const Approach approach) const override final { BOOST_ASSERT(m_geospatial_query.get()); return m_geospatial_query->NearestPhantomNodes( - input_coordinate, approach, max_results, max_distance, bearing, boost::none); + input_coordinate, approach, max_results, max_distance, bearing, std::nullopt); } PhantomCandidateAlternatives NearestCandidatesWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, - const boost::optional max_distance, - const boost::optional bearing, + const std::optional max_distance, + const std::optional bearing, const Approach approach, const bool use_all_edges) const override final { diff --git a/include/engine/datafacade/datafacade_base.hpp b/include/engine/datafacade/datafacade_base.hpp index 2d110e7da..ecf25577a 100644 --- a/include/engine/datafacade/datafacade_base.hpp +++ b/include/engine/datafacade/datafacade_base.hpp @@ -35,6 +35,7 @@ #include #include +#include #include #include #include @@ -126,21 +127,21 @@ class BaseDataFacade virtual std::vector NearestPhantomNodesInRange(const util::Coordinate input_coordinate, const double max_distance, - const boost::optional bearing, + const std::optional bearing, const Approach approach, const bool use_all_edges) const = 0; virtual std::vector NearestPhantomNodes(const util::Coordinate input_coordinate, const size_t max_results, - const boost::optional max_distance, - const boost::optional bearing, + const std::optional max_distance, + const std::optional bearing, const Approach approach) const = 0; virtual PhantomCandidateAlternatives NearestCandidatesWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, - const boost::optional max_distance, - const boost::optional bearing, + const std::optional max_distance, + const std::optional bearing, const Approach approach, const bool use_all_edges) const = 0; diff --git a/include/engine/engine_config.hpp b/include/engine/engine_config.hpp index 439ec8aa6..e46f2c5e2 100644 --- a/include/engine/engine_config.hpp +++ b/include/engine/engine_config.hpp @@ -79,7 +79,7 @@ struct EngineConfig final int max_locations_map_matching = -1; double max_radius_map_matching = -1.0; int max_results_nearest = -1; - boost::optional default_radius = -1.0; + double default_radius = -1.0; int max_alternatives = 3; // set an arbitrary upper bound; can be adjusted by user bool use_shared_memory = true; std::filesystem::path memory_file; diff --git a/include/engine/geospatial_query.hpp b/include/engine/geospatial_query.hpp index c4efbcbbb..915dfec3e 100644 --- a/include/engine/geospatial_query.hpp +++ b/include/engine/geospatial_query.hpp @@ -12,7 +12,7 @@ #include "osrm/coordinate.hpp" -#include +#include #include #include @@ -53,8 +53,8 @@ template class GeospatialQuery NearestPhantomNodes(const util::Coordinate input_coordinate, const Approach approach, const double max_distance, - const boost::optional bearing_with_range, - const boost::optional use_all_edges) const + const std::optional bearing_with_range, + const std::optional use_all_edges) const { auto results = rtree.SearchInRange( input_coordinate, @@ -85,9 +85,9 @@ template class GeospatialQuery NearestPhantomNodes(const util::Coordinate input_coordinate, const Approach approach, const size_t max_results, - const boost::optional max_distance, - const boost::optional bearing_with_range, - const boost::optional use_all_edges) const + const std::optional max_distance, + const std::optional bearing_with_range, + const std::optional use_all_edges) const { auto results = rtree.Nearest( input_coordinate, @@ -121,9 +121,9 @@ template class GeospatialQuery PhantomCandidateAlternatives NearestCandidatesWithAlternativeFromBigComponent( const util::Coordinate input_coordinate, const Approach approach, - const boost::optional max_distance, - const boost::optional bearing_with_range, - const boost::optional use_all_edges) const + const std::optional max_distance, + const std::optional bearing_with_range, + const std::optional use_all_edges) const { bool has_nearest = false; bool has_big_component = false; diff --git a/include/engine/guidance/assemble_geometry.hpp b/include/engine/guidance/assemble_geometry.hpp index 4001f6089..e6925c51f 100644 --- a/include/engine/guidance/assemble_geometry.hpp +++ b/include/engine/guidance/assemble_geometry.hpp @@ -37,6 +37,14 @@ inline LegGeometry assembleGeometry(const datafacade::BaseDataFacade &facade, { LegGeometry geometry; + // each container will at most have `leg_data.size()` + 1/2 elements in it + // these additional 1/2 elements come from processing of very first and very last segment + geometry.locations.reserve(leg_data.size() + 2); + geometry.segment_distances.reserve(leg_data.size() + 1); + geometry.segment_offsets.reserve(leg_data.size() + 1); + geometry.annotations.reserve(leg_data.size() + 1); + geometry.node_ids.reserve(leg_data.size() + 2); + // segment 0 first and last geometry.segment_offsets.push_back(0); geometry.locations.push_back(source_node.location); diff --git a/include/engine/guidance/assemble_steps.hpp b/include/engine/guidance/assemble_steps.hpp index b25b9976d..588e402b3 100644 --- a/include/engine/guidance/assemble_steps.hpp +++ b/include/engine/guidance/assemble_steps.hpp @@ -17,9 +17,9 @@ #include "util/guidance/turn_lanes.hpp" #include "util/typedefs.hpp" -#include #include #include +#include #include namespace osrm::engine::guidance diff --git a/include/engine/guidance/route_leg.hpp b/include/engine/guidance/route_leg.hpp index 681c4c40e..43149e4fc 100644 --- a/include/engine/guidance/route_leg.hpp +++ b/include/engine/guidance/route_leg.hpp @@ -3,7 +3,7 @@ #include "engine/guidance/route_step.hpp" -#include +#include #include #include diff --git a/include/engine/internal_route_result.hpp b/include/engine/internal_route_result.hpp index e2bc6f475..78f5d1196 100644 --- a/include/engine/internal_route_result.hpp +++ b/include/engine/internal_route_result.hpp @@ -15,7 +15,7 @@ #include "util/integer_range.hpp" #include "util/typedefs.hpp" -#include +#include #include namespace osrm::engine @@ -42,7 +42,7 @@ struct PathData // Source of the speed value on this road segment DatasourceID datasource_id; // If segment precedes a turn, ID of the turn itself - boost::optional turn_edge; + std::optional turn_edge; }; struct InternalRouteResult diff --git a/include/engine/plugins/match.hpp b/include/engine/plugins/match.hpp index d56be60fe..bfad1b778 100644 --- a/include/engine/plugins/match.hpp +++ b/include/engine/plugins/match.hpp @@ -22,7 +22,7 @@ class MatchPlugin : public BasePlugin MatchPlugin(const int max_locations_map_matching, const double max_radius_map_matching, - const boost::optional default_radius) + const std::optional default_radius) : BasePlugin(default_radius), max_locations_map_matching(max_locations_map_matching), max_radius_map_matching(max_radius_map_matching) { diff --git a/include/engine/plugins/nearest.hpp b/include/engine/plugins/nearest.hpp index 415639b2c..caa7463fd 100644 --- a/include/engine/plugins/nearest.hpp +++ b/include/engine/plugins/nearest.hpp @@ -13,7 +13,7 @@ namespace osrm::engine::plugins class NearestPlugin final : public BasePlugin { public: - explicit NearestPlugin(const int max_results, const boost::optional default_radius); + explicit NearestPlugin(const int max_results, const std::optional default_radius); Status HandleRequest(const RoutingAlgorithmsInterface &algorithms, const api::NearestParameters ¶ms, diff --git a/include/engine/plugins/plugin_base.hpp b/include/engine/plugins/plugin_base.hpp index 3a98022e9..fbda15664 100644 --- a/include/engine/plugins/plugin_base.hpp +++ b/include/engine/plugins/plugin_base.hpp @@ -29,7 +29,7 @@ class BasePlugin protected: BasePlugin() = default; - BasePlugin(const boost::optional default_radius_) : default_radius(default_radius_) {} + BasePlugin(const std::optional default_radius_) : default_radius(default_radius_) {} bool CheckAllCoordinates(const std::vector &coordinates) const { @@ -200,8 +200,8 @@ class BasePlugin phantom_nodes[i] = facade.NearestPhantomNodesInRange( parameters.coordinates[i], radiuses[i], - use_bearings ? parameters.bearings[i] : boost::none, - use_approaches && parameters.approaches[i] ? parameters.approaches[i].get() + use_bearings ? parameters.bearings[i] : std::nullopt, + use_approaches && parameters.approaches[i] ? parameters.approaches[i].value() : engine::Approach::UNRESTRICTED, use_all_edges); } @@ -242,8 +242,8 @@ class BasePlugin parameters.coordinates[i], number_of_results, use_radiuses ? parameters.radiuses[i] : default_radius, - use_bearings ? parameters.bearings[i] : boost::none, - use_approaches && parameters.approaches[i] ? parameters.approaches[i].get() + use_bearings ? parameters.bearings[i] : std::nullopt, + use_approaches && parameters.approaches[i] ? parameters.approaches[i].value() : engine::Approach::UNRESTRICTED); // we didn't find a fitting node, return error @@ -284,8 +284,8 @@ class BasePlugin alternatives[i] = facade.NearestCandidatesWithAlternativeFromBigComponent( parameters.coordinates[i], use_radiuses ? parameters.radiuses[i] : default_radius, - use_bearings ? parameters.bearings[i] : boost::none, - use_approaches && parameters.approaches[i] ? parameters.approaches[i].get() + use_bearings ? parameters.bearings[i] : std::nullopt, + use_approaches && parameters.approaches[i] ? parameters.approaches[i].value() : engine::Approach::UNRESTRICTED, use_all_edges); @@ -325,7 +325,7 @@ class BasePlugin std::to_string(missing_index); } - const boost::optional default_radius; + const std::optional default_radius; }; } // namespace osrm::engine::plugins diff --git a/include/engine/plugins/table.hpp b/include/engine/plugins/table.hpp index e4cf9a33c..9755cff3b 100644 --- a/include/engine/plugins/table.hpp +++ b/include/engine/plugins/table.hpp @@ -15,7 +15,7 @@ class TablePlugin final : public BasePlugin { public: explicit TablePlugin(const int max_locations_distance_table, - const boost::optional default_radius); + const std::optional default_radius); Status HandleRequest(const RoutingAlgorithmsInterface &algorithms, const api::TableParameters ¶ms, diff --git a/include/engine/plugins/trip.hpp b/include/engine/plugins/trip.hpp index 9cfdab094..a08eaeed0 100644 --- a/include/engine/plugins/trip.hpp +++ b/include/engine/plugins/trip.hpp @@ -32,7 +32,7 @@ class TripPlugin final : public BasePlugin const bool roundtrip) const; public: - explicit TripPlugin(const int max_locations_trip_, boost::optional default_radius) + explicit TripPlugin(const int max_locations_trip_, std::optional default_radius) : BasePlugin(default_radius), max_locations_trip(max_locations_trip_) { } diff --git a/include/engine/plugins/viaroute.hpp b/include/engine/plugins/viaroute.hpp index e036ac90e..56040a58f 100644 --- a/include/engine/plugins/viaroute.hpp +++ b/include/engine/plugins/viaroute.hpp @@ -27,7 +27,7 @@ class ViaRoutePlugin final : public BasePlugin public: explicit ViaRoutePlugin(int max_locations_viaroute, int max_alternatives, - boost::optional default_radius); + std::optional default_radius); Status HandleRequest(const RoutingAlgorithmsInterface &algorithms, const api::RouteParameters &route_parameters, diff --git a/include/engine/polyline_compressor.hpp b/include/engine/polyline_compressor.hpp index b2a505764..af58b0422 100644 --- a/include/engine/polyline_compressor.hpp +++ b/include/engine/polyline_compressor.hpp @@ -12,7 +12,7 @@ namespace osrm::engine { namespace detail { -std::string encode(std::vector &numbers); +void encode(int number_to_encode, std::string &output); std::int32_t decode_polyline_integer(std::string::const_iterator &first, std::string::const_iterator last); } // namespace detail @@ -30,27 +30,24 @@ std::string encodePolyline(CoordVectorForwardIter begin, CoordVectorForwardIter return {}; } - std::vector delta_numbers; - BOOST_ASSERT(size > 0); - delta_numbers.reserve((size - 1) * 2); + std::string output; + // just a guess that we will need ~4 bytes per coordinate to avoid reallocations + output.reserve(size * 4); + int current_lat = 0; int current_lon = 0; - std::for_each( - begin, - end, - [&delta_numbers, ¤t_lat, ¤t_lon, coordinate_to_polyline]( - const util::Coordinate loc) - { - const int lat_diff = - std::round(static_cast(loc.lat) * coordinate_to_polyline) - current_lat; - const int lon_diff = - std::round(static_cast(loc.lon) * coordinate_to_polyline) - current_lon; - delta_numbers.emplace_back(lat_diff); - delta_numbers.emplace_back(lon_diff); - current_lat += lat_diff; - current_lon += lon_diff; - }); - return detail::encode(delta_numbers); + for (auto it = begin; it != end; ++it) + { + const int lat_diff = + std::round(static_cast(it->lat) * coordinate_to_polyline) - current_lat; + const int lon_diff = + std::round(static_cast(it->lon) * coordinate_to_polyline) - current_lon; + detail::encode(lat_diff, output); + detail::encode(lon_diff, output); + current_lat += lat_diff; + current_lon += lon_diff; + } + return output; } // Decodes geometry from polyline format diff --git a/include/engine/routing_algorithms.hpp b/include/engine/routing_algorithms.hpp index 93c310a4a..1be8020c4 100644 --- a/include/engine/routing_algorithms.hpp +++ b/include/engine/routing_algorithms.hpp @@ -25,7 +25,7 @@ class RoutingAlgorithmsInterface virtual InternalRouteResult ShortestPathSearch(const std::vector &waypoint_candidates, - const boost::optional continue_straight_at_waypoint) const = 0; + const std::optional continue_straight_at_waypoint) const = 0; virtual InternalRouteResult DirectShortestPathSearch(const PhantomEndpointCandidates &endpoint_candidates) const = 0; @@ -40,7 +40,7 @@ class RoutingAlgorithmsInterface MapMatching(const routing_algorithms::CandidateLists &candidates_list, const std::vector &trace_coordinates, const std::vector &trace_timestamps, - const std::vector> &trace_gps_precision, + const std::vector> &trace_gps_precision, const bool allow_splitting) const = 0; virtual std::vector @@ -78,7 +78,7 @@ template class RoutingAlgorithms final : public RoutingAlgo InternalRouteResult ShortestPathSearch( const std::vector &waypoint_candidates, - const boost::optional continue_straight_at_waypoint) const final override; + const std::optional continue_straight_at_waypoint) const final override; InternalRouteResult DirectShortestPathSearch( const PhantomEndpointCandidates &endpoint_candidates) const final override; @@ -93,7 +93,7 @@ template class RoutingAlgorithms final : public RoutingAlgo MapMatching(const routing_algorithms::CandidateLists &candidates_list, const std::vector &trace_coordinates, const std::vector &trace_timestamps, - const std::vector> &trace_gps_precision, + const std::vector> &trace_gps_precision, const bool allow_splitting) const final override; std::vector @@ -160,7 +160,7 @@ InternalManyRoutesResult RoutingAlgorithms::AlternativePathSearch( template InternalRouteResult RoutingAlgorithms::ShortestPathSearch( const std::vector &waypoint_candidates, - const boost::optional continue_straight_at_waypoint) const + const std::optional continue_straight_at_waypoint) const { return routing_algorithms::shortestPathSearch( heaps, *facade, waypoint_candidates, continue_straight_at_waypoint); @@ -178,7 +178,7 @@ inline routing_algorithms::SubMatchingList RoutingAlgorithms::MapMatc const routing_algorithms::CandidateLists &candidates_list, const std::vector &trace_coordinates, const std::vector &trace_timestamps, - const std::vector> &trace_gps_precision, + const std::vector> &trace_gps_precision, const bool allow_splitting) const { return routing_algorithms::mapMatching(heaps, diff --git a/include/engine/routing_algorithms/map_matching.hpp b/include/engine/routing_algorithms/map_matching.hpp index c739aac99..e9bcfac26 100644 --- a/include/engine/routing_algorithms/map_matching.hpp +++ b/include/engine/routing_algorithms/map_matching.hpp @@ -24,7 +24,7 @@ SubMatchingList mapMatching(SearchEngineData &engine_working_data, const CandidateLists &candidates_list, const std::vector &trace_coordinates, const std::vector &trace_timestamps, - const std::vector> &trace_gps_precision, + const std::vector> &trace_gps_precision, const bool allow_splitting); } // namespace osrm::engine::routing_algorithms diff --git a/include/engine/routing_algorithms/routing_base.hpp b/include/engine/routing_algorithms/routing_base.hpp index 0c61c1c37..d4dcdac58 100644 --- a/include/engine/routing_algorithms/routing_base.hpp +++ b/include/engine/routing_algorithms/routing_base.hpp @@ -258,7 +258,7 @@ void annotatePath(const FacadeT &facade, alias_cast(duration_vector[segment_idx]), {0}, datasource_vector[segment_idx], - boost::none}); + std::nullopt}); } BOOST_ASSERT(!unpacked_path.empty()); @@ -315,7 +315,7 @@ void annotatePath(const FacadeT &facade, alias_cast(duration_vector[segment_idx]), {0}, datasource_vector[segment_idx], - boost::none}); + std::nullopt}); } if (!unpacked_path.empty()) diff --git a/include/engine/routing_algorithms/routing_base_mld.hpp b/include/engine/routing_algorithms/routing_base_mld.hpp index a02d4a095..aedbcf75a 100644 --- a/include/engine/routing_algorithms/routing_base_mld.hpp +++ b/include/engine/routing_algorithms/routing_base_mld.hpp @@ -487,7 +487,13 @@ void routingStep(const DataFacade &facade, using UnpackedNodes = std::vector; using UnpackedEdges = std::vector; -using UnpackedPath = std::tuple; + +struct UnpackedPath +{ + EdgeWeight weight; + UnpackedNodes nodes; + UnpackedEdges edges; +}; template std::optional> runSearch(const DataFacade &facade, @@ -551,7 +557,7 @@ UnpackedPath search(SearchEngineData &engine_working_data, facade, forward_heap, reverse_heap, force_step_nodes, weight_upper_bound, args...); if (!searchResult) { - return std::make_tuple(INVALID_EDGE_WEIGHT, std::vector(), std::vector()); + return {INVALID_EDGE_WEIGHT, std::vector(), std::vector()}; } auto [middle, weight] = *searchResult; @@ -595,25 +601,27 @@ UnpackedPath search(SearchEngineData &engine_working_data, forward_heap.Insert(source, {0}, {source}); reverse_heap.Insert(target, {0}, {target}); - auto [subpath_weight, subpath_nodes, subpath_edges] = search(engine_working_data, - facade, - forward_heap, - reverse_heap, - force_step_nodes, - INVALID_EDGE_WEIGHT, - sublevel, - parent_cell_id); - BOOST_ASSERT(!subpath_edges.empty()); - BOOST_ASSERT(subpath_nodes.size() > 1); - BOOST_ASSERT(subpath_nodes.front() == source); - BOOST_ASSERT(subpath_nodes.back() == target); - unpacked_nodes.insert( - unpacked_nodes.end(), std::next(subpath_nodes.begin()), subpath_nodes.end()); - unpacked_edges.insert(unpacked_edges.end(), subpath_edges.begin(), subpath_edges.end()); + auto unpacked_subpath = search(engine_working_data, + facade, + forward_heap, + reverse_heap, + force_step_nodes, + INVALID_EDGE_WEIGHT, + sublevel, + parent_cell_id); + BOOST_ASSERT(!unpacked_subpath.edges.empty()); + BOOST_ASSERT(unpacked_subpath.nodes.size() > 1); + BOOST_ASSERT(unpacked_subpath.nodes.front() == source); + BOOST_ASSERT(unpacked_subpath.nodes.back() == target); + unpacked_nodes.insert(unpacked_nodes.end(), + std::next(unpacked_subpath.nodes.begin()), + unpacked_subpath.nodes.end()); + unpacked_edges.insert( + unpacked_edges.end(), unpacked_subpath.edges.begin(), unpacked_subpath.edges.end()); } } - return std::make_tuple(weight, std::move(unpacked_nodes), std::move(unpacked_edges)); + return {weight, std::move(unpacked_nodes), std::move(unpacked_edges)}; } template @@ -654,13 +662,15 @@ inline void search(SearchEngineData &engine_working_data, const EdgeWeight weight_upper_bound = INVALID_EDGE_WEIGHT) { // TODO: change search calling interface to use unpacked_edges result - std::tie(weight, unpacked_nodes, std::ignore) = search(engine_working_data, - facade, - forward_heap, - reverse_heap, - force_step_nodes, - weight_upper_bound, - endpoints); + auto unpacked_path = search(engine_working_data, + facade, + forward_heap, + reverse_heap, + force_step_nodes, + weight_upper_bound, + endpoints); + weight = unpacked_path.weight; + unpacked_nodes = std::move(unpacked_path.nodes); } // TODO: refactor CH-related stub to use unpacked_edges diff --git a/include/engine/routing_algorithms/shortest_path.hpp b/include/engine/routing_algorithms/shortest_path.hpp index 00e85234a..c9c24b939 100644 --- a/include/engine/routing_algorithms/shortest_path.hpp +++ b/include/engine/routing_algorithms/shortest_path.hpp @@ -14,7 +14,7 @@ InternalRouteResult shortestPathSearch(SearchEngineData &engine_working_data, const DataFacade &facade, const std::vector &waypoint_candidates, - const boost::optional continue_straight_at_waypoint); + const std::optional continue_straight_at_waypoint); } // namespace osrm::engine::routing_algorithms diff --git a/include/engine/routing_algorithms/shortest_path_impl.hpp b/include/engine/routing_algorithms/shortest_path_impl.hpp index b9e74fd02..2cd3ccffb 100644 --- a/include/engine/routing_algorithms/shortest_path_impl.hpp +++ b/include/engine/routing_algorithms/shortest_path_impl.hpp @@ -4,7 +4,7 @@ #include "engine/routing_algorithms/shortest_path.hpp" #include -#include +#include namespace osrm::engine::routing_algorithms { @@ -339,10 +339,10 @@ struct leg_connections { // X_to_Y = i can be read as // sources[i].X is the source of the shortest leg path to target.Y - boost::optional forward_to_forward; - boost::optional reverse_to_forward; - boost::optional forward_to_reverse; - boost::optional reverse_to_reverse; + std::optional forward_to_forward; + std::optional reverse_to_forward; + std::optional forward_to_reverse; + std::optional reverse_to_reverse; }; // Identify which of the source candidates segments is being used for paths to the @@ -771,7 +771,7 @@ InternalRouteResult shortestPathSearch(SearchEngineData &engine_working_data, const DataFacade &facade, const std::vector &waypoint_candidates, - const boost::optional continue_straight_at_waypoint) + const std::optional continue_straight_at_waypoint) { const bool allow_uturn_at_waypoint = !(continue_straight_at_waypoint ? *continue_straight_at_waypoint diff --git a/include/nodejs/node_osrm_support.hpp b/include/nodejs/node_osrm_support.hpp index cd0043bb4..f428308e5 100644 --- a/include/nodejs/node_osrm_support.hpp +++ b/include/nodejs/node_osrm_support.hpp @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include @@ -395,11 +395,11 @@ inline engine_config_ptr argumentsToEngineConfig(const Napi::CallbackInfo &args) return engine_config; } -inline boost::optional> +inline std::optional> parseCoordinateArray(const Napi::Array &coordinates_array) { Napi::HandleScope scope(coordinates_array.Env()); - boost::optional> resulting_coordinates; + std::optional> resulting_coordinates; std::vector temp_coordinates; for (uint32_t i = 0; i < coordinates_array.Length(); ++i) @@ -450,7 +450,7 @@ parseCoordinateArray(const Napi::Array &coordinates_array) osrm::util::FloatLatitude{std::move(lat)}); } - resulting_coordinates = boost::make_optional(std::move(temp_coordinates)); + resulting_coordinates = std::make_optional(std::move(temp_coordinates)); return resulting_coordinates; } @@ -1023,7 +1023,7 @@ inline bool parseCommonParameters(const Napi::Object &obj, ParamType ¶ms) inline PluginParameters argumentsToPluginParameters( const Napi::CallbackInfo &args, - const boost::optional &output_format = {}) + const std::optional &output_format = {}) { if (args.Length() < 3 || !args[1].IsObject()) { diff --git a/include/server/api/base_parameters_grammar.hpp b/include/server/api/base_parameters_grammar.hpp index 80fda760b..0891439e9 100644 --- a/include/server/api/base_parameters_grammar.hpp +++ b/include/server/api/base_parameters_grammar.hpp @@ -7,9 +7,9 @@ #include "engine/hint.hpp" #include "engine/polyline_compressor.hpp" -#include #include #include +#include #include #include @@ -88,7 +88,7 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar } else { - base_parameters.hints.emplace_back(boost::none); + base_parameters.hints.emplace_back(std::nullopt); } }; @@ -96,13 +96,24 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar [](engine::api::BaseParameters &base_parameters, boost::optional> bearing_range) { - boost::optional bearing; + std::optional bearing; if (bearing_range) { bearing = engine::Bearing{boost::fusion::at_c<0>(*bearing_range), boost::fusion::at_c<1>(*bearing_range)}; } - base_parameters.bearings.push_back(std::move(bearing)); + base_parameters.bearings.push_back(bearing); + }; + + const auto add_approach = [](engine::api::BaseParameters &base_parameters, + boost::optional approach) { + base_parameters.approaches.push_back(approach ? std::make_optional(*approach) + : std::nullopt); + }; + + const auto add_radius = [](engine::api::BaseParameters &base_parameters, + boost::optional radius) { + base_parameters.radiuses.push_back(radius ? std::make_optional(*radius) : std::nullopt); }; polyline_chars = qi::char_("a-zA-Z0-9_.--[]{}@?|\\%~`^"); @@ -144,9 +155,9 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar ((location_rule % ';') | polyline_rule | polyline6_rule)[ph::bind(&engine::api::BaseParameters::coordinates, qi::_r1) = qi::_1]; - radiuses_rule = qi::lit("radiuses=") > - (-(qi::double_ | unlimited_rule) % - ';')[ph::bind(&engine::api::BaseParameters::radiuses, qi::_r1) = qi::_1]; + radiuses_rule = + qi::lit("radiuses=") > + (-(qi::double_ | unlimited_rule))[ph::bind(add_radius, qi::_r1, qi::_1)] % ';'; hints_rule = qi::lit("hints=") > @@ -170,8 +181,7 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar "curb", engine::Approach::CURB)("opposite", engine::Approach::OPPOSITE); approach_rule = qi::lit("approaches=") > - (-approach_type % - ';')[ph::bind(&engine::api::BaseParameters::approaches, qi::_r1) = qi::_1]; + (-approach_type)[ph::bind(add_approach, qi::_r1, qi::_1)] % ';'; snapping_type.add("default", engine::api::BaseParameters::SnappingType::Default)( "any", engine::api::BaseParameters::SnappingType::Any); diff --git a/include/server/api/parameters_parser.hpp b/include/server/api/parameters_parser.hpp index db16ad77b..c6ee4edec 100644 --- a/include/server/api/parameters_parser.hpp +++ b/include/server/api/parameters_parser.hpp @@ -26,13 +26,13 @@ using is_parameter_t = // Starts parsing and iter and modifies it until iter == end or parsing failed template ::value, int>::type = 0> -boost::optional parseParameters(std::string::iterator &iter, - const std::string::iterator end); +std::optional parseParameters(std::string::iterator &iter, + const std::string::iterator end); // Copy on purpose because we need mutability template ::value, int>::type = 0> -boost::optional parseParameters(std::string options_string) +std::optional parseParameters(std::string options_string) { auto first = options_string.begin(); const auto last = options_string.end(); diff --git a/include/server/api/url_parser.hpp b/include/server/api/url_parser.hpp index 227fddfcb..84c07bc7b 100644 --- a/include/server/api/url_parser.hpp +++ b/include/server/api/url_parser.hpp @@ -3,7 +3,7 @@ #include "server/api/parsed_url.hpp" -#include +#include #include @@ -11,9 +11,9 @@ namespace osrm::server::api { // Starts parsing and iter and modifies it until iter == end or parsing failed -boost::optional parseURL(std::string::iterator &iter, const std::string::iterator end); +std::optional parseURL(std::string::iterator &iter, const std::string::iterator end); -inline boost::optional parseURL(std::string url_string) +inline std::optional parseURL(std::string url_string) { auto iter = url_string.begin(); return parseURL(iter, url_string.end()); diff --git a/include/util/binary_heap.hpp b/include/util/binary_heap.hpp new file mode 100644 index 000000000..3189addc7 --- /dev/null +++ b/include/util/binary_heap.hpp @@ -0,0 +1,40 @@ +#pragma once +#include +#include +#include + +namespace osrm::util +{ + +// in its essence it is std::priority_queue, but with `clear` method +template class BinaryHeap +{ + public: + bool empty() const { return heap_.empty(); } + + const T &top() const + { + BOOST_ASSERT(!heap_.empty()); + return heap_.front(); + } + + void pop() + { + BOOST_ASSERT(!heap_.empty()); + std::pop_heap(heap_.begin(), heap_.end()); + heap_.pop_back(); + } + + template void emplace(Args &&...args) + { + heap_.emplace_back(std::forward(args)...); + std::push_heap(heap_.begin(), heap_.end()); + } + + void clear() { heap_.clear(); } + + private: + std::vector heap_; +}; + +} // namespace osrm::util \ No newline at end of file diff --git a/include/util/static_rtree.hpp b/include/util/static_rtree.hpp index f9d72c144..bbb12efa5 100644 --- a/include/util/static_rtree.hpp +++ b/include/util/static_rtree.hpp @@ -2,7 +2,9 @@ #define STATIC_RTREE_HPP #include "storage/tar_fwd.hpp" +#include "osrm/coordinate.hpp" #include "util/bearing.hpp" +#include "util/binary_heap.hpp" #include "util/coordinate_calculation.hpp" #include "util/deallocating_vector.hpp" #include "util/exception.hpp" @@ -15,8 +17,6 @@ #include "util/vector_view.hpp" #include "util/web_mercator.hpp" -#include "osrm/coordinate.hpp" - #include "storage/shared_memory_ownership.hpp" #include @@ -554,9 +554,12 @@ class StaticRTree auto projected_coordinate = web_mercator::fromWGS84(input_coordinate); Coordinate fixed_projected_coordinate{projected_coordinate}; + // we re-use queue for each query to avoid re-allocating memory + static thread_local util::BinaryHeap traversal_queue; + + traversal_queue.clear(); // initialize queue with root element - std::priority_queue traversal_queue; - traversal_queue.push(QueryCandidate{0, TreeIndex{}}); + traversal_queue.emplace(QueryCandidate{0, TreeIndex{}}); while (!traversal_queue.empty()) { @@ -710,10 +713,11 @@ class StaticRTree // distance must be non-negative BOOST_ASSERT(0. <= squared_distance); BOOST_ASSERT(i < std::numeric_limits::max()); - traversal_queue.push(QueryCandidate{squared_distance, - leaf_id, - static_cast(i), - Coordinate{projected_nearest}}); + + traversal_queue.emplace(QueryCandidate{squared_distance, + leaf_id, + static_cast(i), + Coordinate{projected_nearest}}); } } @@ -742,7 +746,7 @@ class StaticRTree child.minimum_bounding_rectangle.GetMinSquaredDist( fixed_projected_input_coordinate); - traversal_queue.push(QueryCandidate{ + traversal_queue.emplace(QueryCandidate{ squared_lower_bound_to_element, TreeIndex(parent.level + 1, child_index - m_tree_level_starts[parent.level + 1])}); } diff --git a/scripts/ci/e2e_benchmark.py b/scripts/ci/e2e_benchmark.py index 02a0b59b8..e928c720b 100644 --- a/scripts/ci/e2e_benchmark.py +++ b/scripts/ci/e2e_benchmark.py @@ -86,9 +86,9 @@ def bootstrap_confidence_interval(data, num_samples=1000, confidence_level=0.95) mean = np.mean(means) return mean, lower_bound, upper_bound -def calculate_confidence_interval(data): +def calculate_confidence_interval(data, min_is_best=True): mean, lower, upper = bootstrap_confidence_interval(data) - min_value = np.min(data) + min_value = np.min(data) if min_is_best else np.max(data) return mean, (upper - lower) / 2, min_value @@ -117,7 +117,7 @@ def main(): total_time, total_ci, total_best = calculate_confidence_interval(np.sum(all_times, axis=1)) - ops_per_sec, ops_per_sec_ci, ops_per_sec_best = calculate_confidence_interval(float(all_times.shape[1]) / np.sum(all_times / 1000, axis=1)) + ops_per_sec, ops_per_sec_ci, ops_per_sec_best = calculate_confidence_interval(float(all_times.shape[1]) / np.sum(all_times / 1000, axis=1), min_is_best=False) min_time, min_ci, _ = calculate_confidence_interval(np.min(all_times, axis=1)) mean_time, mean_ci, _ = calculate_confidence_interval(np.mean(all_times, axis=1)) median_time, median_ci, _ = calculate_confidence_interval(np.median(all_times, axis=1)) diff --git a/scripts/ci/run_benchmarks.sh b/scripts/ci/run_benchmarks.sh index a0f32ece5..0d0324d13 100755 --- a/scripts/ci/run_benchmarks.sh +++ b/scripts/ci/run_benchmarks.sh @@ -64,7 +64,7 @@ function run_benchmarks_for_folder { echo "Running alias" $BENCHMARKS_FOLDER/alias-bench > "$RESULTS_FOLDER/alias.bench" echo "Running json-render-bench" - $BENCHMARKS_FOLDER/json-render-bench "$FOLDER/src/benchmarks/portugal_to_korea.json" > "$RESULTS_FOLDER/json-render.bench" + $BENCHMARKS_FOLDER/json-render-bench "$FOLDER/test/data/portugal_to_korea.json" > "$RESULTS_FOLDER/json-render.bench" echo "Running packedvector-bench" $BENCHMARKS_FOLDER/packedvector-bench > "$RESULTS_FOLDER/packedvector.bench" echo "Running rtree-bench" diff --git a/scripts/ci/windows-build.bat b/scripts/ci/windows-build.bat index a74bdd2c2..2102c9340 100644 --- a/scripts/ci/windows-build.bat +++ b/scripts/ci/windows-build.bat @@ -62,7 +62,7 @@ SET test_region_ch=ch\monaco SET test_region_corech=corech\monaco SET test_region_mld=mld\monaco SET test_osm=%test_region%.osm.pbf -COPY %PROJECT_DIR%\test\data\%test_region%.osm.pbf %test_osm% +COPY %PROJECT_DIR%\test\data\%test_region%.osm.pbf %test_osm% %CONFIGURATION%\osrm-extract.exe -p %PROJECT_DIR%\profiles\car.lua %test_osm% IF %ERRORLEVEL% NEQ 0 GOTO ERROR diff --git a/src/benchmarks/bench.cpp b/src/benchmarks/bench.cpp index b1d88aa0e..019ff6456 100644 --- a/src/benchmarks/bench.cpp +++ b/src/benchmarks/bench.cpp @@ -134,6 +134,7 @@ struct ConfidenceInterval double mean; double confidence; double min; + double max; }; // Helper function to calculate the bootstrap confidence interval @@ -161,8 +162,10 @@ ConfidenceInterval confidenceInterval(const std::vector &data, double upper_bound = means[(int)((1 + confidence_level) / 2 * num_samples)]; double mean = std::accumulate(means.begin(), means.end(), 0.0) / means.size(); - ConfidenceInterval ci = { - mean, (upper_bound - lower_bound) / 2, *std::min_element(data.begin(), data.end())}; + ConfidenceInterval ci = {mean, + (upper_bound - lower_bound) / 2, + *std::min_element(data.begin(), data.end()), + *std::max_element(data.begin(), data.end())}; return ci; } @@ -260,7 +263,7 @@ std::ostream &operator<<(std::ostream &os, Statistics &statistics) ConfidenceInterval ops_ci = statistics.ops_per_sec(); os << "ops: " << ops_ci.mean << " ± " << ops_ci.confidence << " ops/s. " - << "best: " << ops_ci.min << "ops/s." << std::endl; + << "best: " << ops_ci.max << "ops/s." << std::endl; os << "total: " << total_ci.mean << " ± " << total_ci.confidence << "ms. " << "best: " << total_ci.min << "ms." << std::endl; os << "avg: " << mean_ci.mean << " ± " << mean_ci.confidence << "ms" << std::endl; @@ -357,8 +360,8 @@ void runRouteBenchmark(const OSRM &osrm, const GPSTraces &gpsTraces, int iterati if (benchmark.radius) { - params.radiuses = std::vector>( - params.coordinates.size(), boost::make_optional(*benchmark.radius)); + params.radiuses = std::vector>( + params.coordinates.size(), std::make_optional(*benchmark.radius)); } engine::api::ResultT result = json::Object(); diff --git a/src/benchmarks/route.cpp b/src/benchmarks/route.cpp index e63a1039e..ada7a1d5e 100644 --- a/src/benchmarks/route.cpp +++ b/src/benchmarks/route.cpp @@ -66,8 +66,8 @@ try if (benchmark.radius) { - params.radiuses = std::vector>( - params.coordinates.size(), boost::make_optional(*benchmark.radius)); + params.radiuses = std::vector>( + params.coordinates.size(), std::make_optional(*benchmark.radius)); } TIMER_START(routes); diff --git a/src/engine/api/json_factory.cpp b/src/engine/api/json_factory.cpp index 6765c9351..a17ea7799 100644 --- a/src/engine/api/json_factory.cpp +++ b/src/engine/api/json_factory.cpp @@ -11,7 +11,7 @@ #include "util/typedefs.hpp" #include -#include +#include #include #include @@ -215,7 +215,7 @@ util::json::Object makeRouteStep(guidance::RouteStep step, util::json::Value geo util::json::Object makeRoute(const guidance::Route &route, util::json::Array legs, - boost::optional geometry, + std::optional geometry, const char *weight_name) { util::json::Object json_route; diff --git a/src/engine/engine_config.cpp b/src/engine/engine_config.cpp index bfe92841c..ddc7651d4 100644 --- a/src/engine/engine_config.cpp +++ b/src/engine/engine_config.cpp @@ -12,15 +12,13 @@ bool EngineConfig::IsValid() const const auto unlimited_or_more_than = [](const auto v, const auto limit) { return v == -1 || v > limit; }; - const bool limits_valid = - unlimited_or_more_than(max_locations_distance_table, 2) && - unlimited_or_more_than(max_locations_map_matching, 2) && - unlimited_or_more_than(max_radius_map_matching, 0) && - unlimited_or_more_than(max_locations_trip, 2) && - unlimited_or_more_than(max_locations_viaroute, 2) && - unlimited_or_more_than(max_results_nearest, 0) && - (!default_radius.has_value() || unlimited_or_more_than(*default_radius, 0)) && - max_alternatives >= 0; + const bool limits_valid = unlimited_or_more_than(max_locations_distance_table, 2) && + unlimited_or_more_than(max_locations_map_matching, 2) && + unlimited_or_more_than(max_radius_map_matching, 0) && + unlimited_or_more_than(max_locations_trip, 2) && + unlimited_or_more_than(max_locations_viaroute, 2) && + unlimited_or_more_than(max_results_nearest, 0) && + unlimited_or_more_than(default_radius, 0) && max_alternatives >= 0; return ((use_shared_memory && all_path_are_empty) || (use_mmap && storage_config.IsValid()) || storage_config.IsValid()) && diff --git a/src/engine/plugins/match.cpp b/src/engine/plugins/match.cpp index fef9aac4e..6fe8f6699 100644 --- a/src/engine/plugins/match.cpp +++ b/src/engine/plugins/match.cpp @@ -194,7 +194,7 @@ Status MatchPlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms, tidied.parameters.radiuses.begin(), tidied.parameters.radiuses.end(), search_radiuses.begin(), - [default_radius = this->default_radius](const boost::optional &maybe_radius) + [default_radius = this->default_radius](const std::optional &maybe_radius) { if (maybe_radius) { diff --git a/src/engine/plugins/nearest.cpp b/src/engine/plugins/nearest.cpp index 671dbe3f2..b8d43a5a6 100644 --- a/src/engine/plugins/nearest.cpp +++ b/src/engine/plugins/nearest.cpp @@ -10,7 +10,7 @@ namespace osrm::engine::plugins { -NearestPlugin::NearestPlugin(const int max_results_, const boost::optional default_radius_) +NearestPlugin::NearestPlugin(const int max_results_, const std::optional default_radius_) : BasePlugin(default_radius_), max_results{max_results_} { } diff --git a/src/engine/plugins/table.cpp b/src/engine/plugins/table.cpp index 451811305..5fd214c1a 100644 --- a/src/engine/plugins/table.cpp +++ b/src/engine/plugins/table.cpp @@ -15,7 +15,7 @@ namespace osrm::engine::plugins { TablePlugin::TablePlugin(const int max_locations_distance_table, - const boost::optional default_radius) + const std::optional default_radius) : BasePlugin(default_radius), max_locations_distance_table(max_locations_distance_table) { } diff --git a/src/engine/plugins/viaroute.cpp b/src/engine/plugins/viaroute.cpp index a8a1b2ee6..a59a2c467 100644 --- a/src/engine/plugins/viaroute.cpp +++ b/src/engine/plugins/viaroute.cpp @@ -17,7 +17,7 @@ namespace osrm::engine::plugins ViaRoutePlugin::ViaRoutePlugin(int max_locations_viaroute, int max_alternatives, - boost::optional default_radius) + std::optional default_radius) : BasePlugin(default_radius), max_locations_viaroute(max_locations_viaroute), max_alternatives(max_alternatives) { diff --git a/src/engine/polyline_compressor.cpp b/src/engine/polyline_compressor.cpp index 3d4500643..7435fed3f 100644 --- a/src/engine/polyline_compressor.cpp +++ b/src/engine/polyline_compressor.cpp @@ -10,9 +10,19 @@ namespace osrm::engine::detail // anonymous to keep TU local { -std::string encode(int number_to_encode) +void encode(int number_to_encode, std::string &output) { - std::string output; + if (number_to_encode < 0) + { + const unsigned binary = std::llabs(number_to_encode); + const unsigned twos = (~binary) + 1u; + const unsigned shl = twos << 1u; + number_to_encode = static_cast(~shl); + } + else + { + number_to_encode <<= 1u; + } while (number_to_encode >= 0x20) { const int next_value = (0x20 | (number_to_encode & 0x1f)) + 63; @@ -22,31 +32,6 @@ std::string encode(int number_to_encode) number_to_encode += 63; output += static_cast(number_to_encode); - return output; -} - -std::string encode(std::vector &numbers) -{ - std::string output; - for (auto &number : numbers) - { - if (number < 0) - { - const unsigned binary = std::llabs(number); - const unsigned twos = (~binary) + 1u; - const unsigned shl = twos << 1u; - number = static_cast(~shl); - } - else - { - number <<= 1u; - } - } - for (const int number : numbers) - { - output += encode(number); - } - return output; } // https://developers.google.com/maps/documentation/utilities/polylinealgorithm diff --git a/src/engine/routing_algorithms/alternative_path_mld.cpp b/src/engine/routing_algorithms/alternative_path_mld.cpp index 27bd0a4d5..9c0a579f5 100644 --- a/src/engine/routing_algorithms/alternative_path_mld.cpp +++ b/src/engine/routing_algorithms/alternative_path_mld.cpp @@ -621,27 +621,24 @@ void unpackPackedPaths(InputIt first, BOOST_ASSERT(!facade.ExcludeNode(source)); BOOST_ASSERT(!facade.ExcludeNode(target)); - // TODO: when structured bindings will be allowed change to - // auto [subpath_weight, subpath_source, subpath_target, subpath] = ... - EdgeWeight subpath_weight; - std::vector subpath_nodes; - std::vector subpath_edges; - std::tie(subpath_weight, subpath_nodes, subpath_edges) = search(search_engine_data, - facade, - forward_heap, - reverse_heap, - {}, - INVALID_EDGE_WEIGHT, - sublevel, - parent_cell_id); - BOOST_ASSERT(!subpath_edges.empty()); - BOOST_ASSERT(subpath_nodes.size() > 1); - BOOST_ASSERT(subpath_nodes.front() == source); - BOOST_ASSERT(subpath_nodes.back() == target); - unpacked_nodes.insert( - unpacked_nodes.end(), std::next(subpath_nodes.begin()), subpath_nodes.end()); - unpacked_edges.insert( - unpacked_edges.end(), subpath_edges.begin(), subpath_edges.end()); + auto unpacked_subpath = search(search_engine_data, + facade, + forward_heap, + reverse_heap, + {}, + INVALID_EDGE_WEIGHT, + sublevel, + parent_cell_id); + BOOST_ASSERT(!unpacked_subpath.edges.empty()); + BOOST_ASSERT(unpacked_subpath.nodes.size() > 1); + BOOST_ASSERT(unpacked_subpath.nodes.front() == source); + BOOST_ASSERT(unpacked_subpath.nodes.back() == target); + unpacked_nodes.insert(unpacked_nodes.end(), + std::next(unpacked_subpath.nodes.begin()), + unpacked_subpath.nodes.end()); + unpacked_edges.insert(unpacked_edges.end(), + unpacked_subpath.edges.begin(), + unpacked_subpath.edges.end()); } } diff --git a/src/engine/routing_algorithms/direct_shortest_path.cpp b/src/engine/routing_algorithms/direct_shortest_path.cpp index 65e924cf5..397bdf6e6 100644 --- a/src/engine/routing_algorithms/direct_shortest_path.cpp +++ b/src/engine/routing_algorithms/direct_shortest_path.cpp @@ -70,20 +70,19 @@ InternalRouteResult directShortestPathSearch(SearchEngineData &e auto &reverse_heap = *engine_working_data.reverse_heap_1; insertNodesInHeaps(forward_heap, reverse_heap, endpoint_candidates); - // TODO: when structured bindings will be allowed change to - // auto [weight, source_node, target_node, unpacked_edges] = ... - EdgeWeight weight = INVALID_EDGE_WEIGHT; - std::vector unpacked_nodes; - std::vector unpacked_edges; - std::tie(weight, unpacked_nodes, unpacked_edges) = mld::search(engine_working_data, - facade, - forward_heap, - reverse_heap, - {}, - INVALID_EDGE_WEIGHT, - endpoint_candidates); + auto unpacked_path = mld::search(engine_working_data, + facade, + forward_heap, + reverse_heap, + {}, + INVALID_EDGE_WEIGHT, + endpoint_candidates); - return extractRoute(facade, weight, endpoint_candidates, unpacked_nodes, unpacked_edges); + return extractRoute(facade, + unpacked_path.weight, + endpoint_candidates, + unpacked_path.nodes, + unpacked_path.edges); } } // namespace osrm::engine::routing_algorithms diff --git a/src/engine/routing_algorithms/map_matching.cpp b/src/engine/routing_algorithms/map_matching.cpp index 9f8a1d2a5..45133551e 100644 --- a/src/engine/routing_algorithms/map_matching.cpp +++ b/src/engine/routing_algorithms/map_matching.cpp @@ -70,7 +70,7 @@ SubMatchingList mapMatching(SearchEngineData &engine_working_data, const CandidateLists &candidates_list, const std::vector &trace_coordinates, const std::vector &trace_timestamps, - const std::vector> &trace_gps_precision, + const std::vector> &trace_gps_precision, const bool allow_splitting) { map_matching::MatchingConfidence confidence; @@ -401,6 +401,7 @@ SubMatchingList mapMatching(SearchEngineData &engine_working_data, auto trace_distance = 0.0; matching.nodes.reserve(reconstructed_indices.size()); matching.indices.reserve(reconstructed_indices.size()); + matching.alternatives_count.reserve(reconstructed_indices.size()); for (const auto &idx : reconstructed_indices) { const auto timestamp_index = idx.first; @@ -428,7 +429,7 @@ SubMatchingList mapMatching(SearchEngineData &engine_working_data, matching.confidence = confidence(trace_distance, matching_distance); - sub_matchings.push_back(matching); + sub_matchings.emplace_back(std::move(matching)); sub_matching_begin = sub_matching_end; } @@ -436,24 +437,22 @@ SubMatchingList mapMatching(SearchEngineData &engine_working_data, } // CH -template SubMatchingList -mapMatching(SearchEngineData &engine_working_data, - const DataFacade &facade, - const CandidateLists &candidates_list, - const std::vector &trace_coordinates, - const std::vector &trace_timestamps, - const std::vector> &trace_gps_precision, - const bool allow_splitting); +template SubMatchingList mapMatching(SearchEngineData &engine_working_data, + const DataFacade &facade, + const CandidateLists &candidates_list, + const std::vector &trace_coordinates, + const std::vector &trace_timestamps, + const std::vector> &trace_gps_precision, + const bool allow_splitting); // MLD -template SubMatchingList -mapMatching(SearchEngineData &engine_working_data, - const DataFacade &facade, - const CandidateLists &candidates_list, - const std::vector &trace_coordinates, - const std::vector &trace_timestamps, - const std::vector> &trace_gps_precision, - const bool allow_splitting); +template SubMatchingList mapMatching(SearchEngineData &engine_working_data, + const DataFacade &facade, + const CandidateLists &candidates_list, + const std::vector &trace_coordinates, + const std::vector &trace_timestamps, + const std::vector> &trace_gps_precision, + const bool allow_splitting); } // namespace osrm::engine::routing_algorithms diff --git a/src/engine/routing_algorithms/shortest_path.cpp b/src/engine/routing_algorithms/shortest_path.cpp index fc3481066..36899631a 100644 --- a/src/engine/routing_algorithms/shortest_path.cpp +++ b/src/engine/routing_algorithms/shortest_path.cpp @@ -9,12 +9,12 @@ template InternalRouteResult shortestPathSearch(SearchEngineData &engine_working_data, const DataFacade &facade, const std::vector &waypoint_candidates, - const boost::optional continue_straight_at_waypoint); + const std::optional continue_straight_at_waypoint); template InternalRouteResult shortestPathSearch(SearchEngineData &engine_working_data, const DataFacade &facade, const std::vector &waypoint_candidates, - const boost::optional continue_straight_at_waypoint); + const std::optional continue_straight_at_waypoint); } // namespace osrm::engine::routing_algorithms diff --git a/src/extractor/extractor_callbacks.cpp b/src/extractor/extractor_callbacks.cpp index aec61ee9f..ea4744f0e 100644 --- a/src/extractor/extractor_callbacks.cpp +++ b/src/extractor/extractor_callbacks.cpp @@ -23,8 +23,6 @@ #include #ifdef _MSC_VER -#if (_MSC_VER >= 1928) -#ifdef _DEBUG namespace osrm { namespace extractor @@ -37,8 +35,6 @@ const ByEdgeOrByMeterValue::ValueByMeter ByEdgeOrByMeterValue::by_meter; } // namespace extractor } // namespace osrm #endif -#endif -#endif namespace osrm::extractor { diff --git a/src/server/api/parameters_parser.cpp b/src/server/api/parameters_parser.cpp index 7d3db1d16..8e3f50270 100644 --- a/src/server/api/parameters_parser.cpp +++ b/src/server/api/parameters_parser.cpp @@ -28,8 +28,8 @@ template ::value, int>::type = 0, typename std::enable_if::value, int>::type = 0> -boost::optional parseParameters(std::string::iterator &iter, - const std::string::iterator end) +std::optional parseParameters(std::string::iterator &iter, + const std::string::iterator end) { using It = std::decay::type; @@ -56,52 +56,52 @@ boost::optional parseParameters(std::string::iterator &iter, // as normal parser error } - return boost::none; + return std::nullopt; } } // namespace detail template <> -boost::optional parseParameters(std::string::iterator &iter, - const std::string::iterator end) +std::optional parseParameters(std::string::iterator &iter, + const std::string::iterator end) { return detail::parseParameters>(iter, end); } template <> -boost::optional parseParameters(std::string::iterator &iter, - const std::string::iterator end) +std::optional parseParameters(std::string::iterator &iter, + const std::string::iterator end) { return detail::parseParameters>(iter, end); } template <> -boost::optional parseParameters(std::string::iterator &iter, - const std::string::iterator end) +std::optional parseParameters(std::string::iterator &iter, + const std::string::iterator end) { return detail::parseParameters>(iter, end); } template <> -boost::optional parseParameters(std::string::iterator &iter, - const std::string::iterator end) +std::optional parseParameters(std::string::iterator &iter, + const std::string::iterator end) { return detail::parseParameters>(iter, end); } template <> -boost::optional parseParameters(std::string::iterator &iter, - const std::string::iterator end) +std::optional parseParameters(std::string::iterator &iter, + const std::string::iterator end) { return detail::parseParameters>(iter, end); } template <> -boost::optional parseParameters(std::string::iterator &iter, - const std::string::iterator end) +std::optional parseParameters(std::string::iterator &iter, + const std::string::iterator end) { return detail::parseParameters>(iter, end); } diff --git a/src/server/api/url_parser.cpp b/src/server/api/url_parser.cpp index a7323d308..c870e512e 100644 --- a/src/server/api/url_parser.cpp +++ b/src/server/api/url_parser.cpp @@ -65,7 +65,7 @@ struct URLParser final : qi::grammar namespace osrm::server::api { -boost::optional parseURL(std::string::iterator &iter, const std::string::iterator end) +std::optional parseURL(std::string::iterator &iter, const std::string::iterator end) { using It = std::decay::type; @@ -77,7 +77,7 @@ boost::optional parseURL(std::string::iterator &iter, const std::stri const auto ok = boost::spirit::qi::parse(iter, end, parser(boost::phoenix::val(iter)), out); if (ok && iter == end) - return boost::make_optional(out); + return std::make_optional(out); } catch (const qi::expectation_failure &failure) { @@ -86,7 +86,7 @@ boost::optional parseURL(std::string::iterator &iter, const std::stri iter = failure.first; } - return boost::none; + return std::nullopt; } } // namespace osrm::server::api diff --git a/src/tools/routed.cpp b/src/tools/routed.cpp index 07dcf864c..8c35413f6 100644 --- a/src/tools/routed.cpp +++ b/src/tools/routed.cpp @@ -186,7 +186,7 @@ inline unsigned generateServerProgramOptions(const int argc, value(&config.max_radius_map_matching)->default_value(-1.0), "Max. radius size supported in map matching query. Default: unlimited.") // ("default-radius", - value>(&config.default_radius)->default_value(-1.0), + value(&config.default_radius)->default_value(-1.0), "Default radius size for queries. Default: unlimited."); // hidden options, will be allowed on command line, but will not be shown to the user diff --git a/src/benchmarks/portugal_to_korea.json b/test/data/portugal_to_korea.json similarity index 100% rename from src/benchmarks/portugal_to_korea.json rename to test/data/portugal_to_korea.json diff --git a/unit_tests/engine/base64.cpp b/unit_tests/engine/base64.cpp index 3adb7db3e..60e5d73ca 100644 --- a/unit_tests/engine/base64.cpp +++ b/unit_tests/engine/base64.cpp @@ -74,4 +74,98 @@ BOOST_AUTO_TEST_CASE(hint_encoding_decoding_roundtrip_bytewise) reinterpret_cast(&decoded))); } +BOOST_AUTO_TEST_CASE(long_string_encoding) +{ + using namespace osrm::engine; + std::string long_string(1000, 'A'); // String of 1000 'A's + std::string encoded = encodeBase64(long_string); + BOOST_CHECK_EQUAL(decodeBase64(encoded), long_string); +} + +BOOST_AUTO_TEST_CASE(invalid_base64_decoding) +{ + using namespace osrm::engine; + BOOST_CHECK_THROW(decodeBase64("Invalid!"), std::exception); +} + +BOOST_AUTO_TEST_CASE(hint_serialization_size) +{ + using namespace osrm::engine; + using namespace osrm::util; + + const Coordinate coordinate; + const PhantomNode phantom; + const osrm::test::MockDataFacade facade{}; + + const SegmentHint hint{phantom, facade.GetCheckSum()}; + const auto base64 = hint.ToBase64(); + + BOOST_CHECK_EQUAL(base64.size(), 112); +} + +BOOST_AUTO_TEST_CASE(extended_roundtrip_tests) +{ + using namespace osrm::engine; + + std::vector test_strings = { + "Hello, World!", // Simple ASCII string + "1234567890", // Numeric string + "!@#$%^&*()_+", // Special characters + std::string(1000, 'A'), // Long repeating string + "¡Hola, mundo!", // Non-ASCII characters + "こんにちは、世界!", // Unicode characters + std::string("\x00\x01\x02\x03", 4), // Binary data + "a", // Single character + "ab", // Two characters + "abc", // Three characters (no padding in Base64) + std::string(190, 'x') // String that doesn't align with Base64 padding + }; + + for (const auto &test_str : test_strings) + { + std::string encoded = encodeBase64(test_str); + std::string decoded = decodeBase64(encoded); + BOOST_CHECK_EQUAL(decoded, test_str); + + // Additional checks + BOOST_CHECK(encoded.find_first_not_of( + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=") == + std::string::npos); + if (test_str.length() % 3 != 0) + { + BOOST_CHECK(encoded.back() == '='); + } + } +} + +BOOST_AUTO_TEST_CASE(roundtrip_with_url_safe_chars) +{ + using namespace osrm::engine; + + std::string original = "Hello+World/Nothing?Is:Impossible"; + std::string encoded = encodeBase64(original); + + // Replace '+' with '-' and '/' with '_' + std::replace(encoded.begin(), encoded.end(), '+', '-'); + std::replace(encoded.begin(), encoded.end(), '/', '_'); + + std::string decoded = decodeBase64(encoded); + BOOST_CHECK_EQUAL(decoded, original); +} + +BOOST_AUTO_TEST_CASE(roundtrip_stress_test) +{ + using namespace osrm::engine; + + std::string test_str; + for (int i = 0; i < 1000; ++i) + { + test_str += static_cast(i % 256); + } + + std::string encoded = encodeBase64(test_str); + std::string decoded = decodeBase64(encoded); + BOOST_CHECK_EQUAL(decoded, test_str); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/unit_tests/engine/collapse_internal_route_result.cpp b/unit_tests/engine/collapse_internal_route_result.cpp index 6d00e12d1..982055279 100644 --- a/unit_tests/engine/collapse_internal_route_result.cpp +++ b/unit_tests/engine/collapse_internal_route_result.cpp @@ -19,8 +19,8 @@ BOOST_AUTO_TEST_CASE(unchanged_collapse_route_result) PhantomNode target; source.forward_segment_id = {1, true}; target.forward_segment_id = {6, true}; - PathData pathy{0, 2, {2}, {3}, {4}, {5}, 2, boost::none}; - PathData kathy{0, 1, {1}, {2}, {3}, {4}, 1, boost::none}; + PathData pathy{0, 2, {2}, {3}, {4}, {5}, 2, std::nullopt}; + PathData kathy{0, 1, {1}, {2}, {3}, {4}, 1, std::nullopt}; InternalRouteResult one_leg_result; one_leg_result.unpacked_path_segments = {{pathy, kathy}}; one_leg_result.leg_endpoints = {PhantomEndpoints{source, target}}; @@ -39,9 +39,9 @@ BOOST_AUTO_TEST_CASE(two_legs_to_one_leg) { // from_edge_based_node, turn_via_node, weight_until_turn, weight_of_turn, // duration_until_turn, duration_of_turn, datasource_id, turn_edge - PathData pathy{0, 2, {2}, {3}, {4}, {5}, 2, boost::none}; - PathData kathy{0, 1, {1}, {2}, {3}, {4}, 1, boost::none}; - PathData cathy{0, 3, {1}, {2}, {3}, {4}, 1, boost::none}; + PathData pathy{0, 2, {2}, {3}, {4}, {5}, 2, std::nullopt}; + PathData kathy{0, 1, {1}, {2}, {3}, {4}, 1, std::nullopt}; + PathData cathy{0, 3, {1}, {2}, {3}, {4}, 1, std::nullopt}; PhantomNode node_1; PhantomNode node_2; PhantomNode node_3; @@ -74,11 +74,11 @@ BOOST_AUTO_TEST_CASE(two_legs_to_one_leg) BOOST_AUTO_TEST_CASE(three_legs_to_two_legs) { - PathData pathy{0, 2, {2}, {3}, {4}, {5}, 2, boost::none}; - PathData kathy{0, 1, {1}, {2}, {3}, {4}, 1, boost::none}; - PathData qathy{0, 5, {1}, {2}, {3}, {4}, 1, boost::none}; - PathData cathy{0, 3, {1}, {2}, {3}, {4}, 1, boost::none}; - PathData mathy{0, 4, {8}, {9}, {13}, {4}, 2, boost::none}; + PathData pathy{0, 2, {2}, {3}, {4}, {5}, 2, std::nullopt}; + PathData kathy{0, 1, {1}, {2}, {3}, {4}, 1, std::nullopt}; + PathData qathy{0, 5, {1}, {2}, {3}, {4}, 1, std::nullopt}; + PathData cathy{0, 3, {1}, {2}, {3}, {4}, 1, std::nullopt}; + PathData mathy{0, 4, {8}, {9}, {13}, {4}, 2, std::nullopt}; PhantomNode node_1; PhantomNode node_2; PhantomNode node_3; @@ -131,9 +131,9 @@ BOOST_AUTO_TEST_CASE(three_legs_to_two_legs) BOOST_AUTO_TEST_CASE(two_legs_to_two_legs) { - PathData pathy{0, 2, {2}, {3}, {4}, {5}, 2, boost::none}; - PathData kathy{0, 1, {1}, {2}, {3}, {4}, 1, boost::none}; - PathData cathy{0, 3, {1}, {2}, {3}, {4}, 1, boost::none}; + PathData pathy{0, 2, {2}, {3}, {4}, {5}, 2, std::nullopt}; + PathData kathy{0, 1, {1}, {2}, {3}, {4}, 1, std::nullopt}; + PathData cathy{0, 3, {1}, {2}, {3}, {4}, 1, std::nullopt}; PhantomNode node_1; PhantomNode node_2; PhantomNode node_3; diff --git a/unit_tests/engine/offline_facade.cpp b/unit_tests/engine/offline_facade.cpp index 822d02f4f..ae9307e1a 100644 --- a/unit_tests/engine/offline_facade.cpp +++ b/unit_tests/engine/offline_facade.cpp @@ -219,7 +219,7 @@ class ContiguousInternalMemoryDataFacade std::vector NearestPhantomNodesInRange(const util::Coordinate /*input_coordinate*/, const double /*max_distance*/, - const boost::optional /*bearing*/, + const std::optional /*bearing*/, const engine::Approach /*approach*/, const bool /*use_all_edges*/) const override { @@ -229,8 +229,8 @@ class ContiguousInternalMemoryDataFacade std::vector NearestPhantomNodes(const util::Coordinate /*input_coordinate*/, const size_t /*max_results*/, - const boost::optional /*max_distance*/, - const boost::optional /*bearing*/, + const std::optional /*max_distance*/, + const std::optional /*bearing*/, const engine::Approach /*approach*/) const override { return {}; @@ -238,8 +238,8 @@ class ContiguousInternalMemoryDataFacade engine::PhantomCandidateAlternatives NearestCandidatesWithAlternativeFromBigComponent( const util::Coordinate /*input_coordinate*/, - const boost::optional /*max_distance*/, - const boost::optional /*bearing*/, + const std::optional /*max_distance*/, + const std::optional /*bearing*/, const engine::Approach /*approach*/, const bool /*use_all_edges*/) const override { diff --git a/unit_tests/engine/polyline_compressor.cpp b/unit_tests/engine/polyline_compressor.cpp index fa05512a9..e2a9a5fd7 100644 --- a/unit_tests/engine/polyline_compressor.cpp +++ b/unit_tests/engine/polyline_compressor.cpp @@ -45,4 +45,96 @@ BOOST_AUTO_TEST_CASE(polyline6_test_case) decodePolyline<1000000>(encodePolyline<1000000>(coords.begin(), coords.end())).begin())); } +BOOST_AUTO_TEST_CASE(empty_polyline_test) +{ + using namespace osrm::engine; + using namespace osrm::util; + + std::vector empty_coords; + BOOST_CHECK_EQUAL(encodePolyline(empty_coords.begin(), empty_coords.end()), ""); + BOOST_CHECK(decodePolyline("").empty()); +} +BOOST_AUTO_TEST_CASE(polyline_single_point_test) +{ + using namespace osrm::engine; + using namespace osrm::util; + + const std::vector coords({{FixedLongitude{-122414000}, FixedLatitude{37776000}}}); + + const std::string encoded = encodePolyline(coords.begin(), coords.end()); + BOOST_CHECK_EQUAL(encoded, "_cqeFn~cjV"); + + const auto decoded = decodePolyline(encoded); + BOOST_CHECK_EQUAL(decoded.size(), 1); + BOOST_CHECK_EQUAL(decoded[0].lon, FixedLongitude{-122414000}); + BOOST_CHECK_EQUAL(decoded[0].lat, FixedLatitude{37776000}); +} + +BOOST_AUTO_TEST_CASE(polyline_multiple_points_test) +{ + using namespace osrm::engine; + using namespace osrm::util; + + const std::vector coords({{FixedLongitude{-122414000}, FixedLatitude{37776000}}, + {FixedLongitude{-122420000}, FixedLatitude{37779000}}, + {FixedLongitude{-122421000}, FixedLatitude{37780000}}}); + + const std::string encoded = encodePolyline(coords.begin(), coords.end()); + BOOST_CHECK_EQUAL(encoded, "_cqeFn~cjVwQnd@gEfE"); + + const auto decoded = decodePolyline(encoded); + BOOST_CHECK_EQUAL(decoded.size(), 3); + for (size_t i = 0; i < coords.size(); ++i) + { + BOOST_CHECK_EQUAL(decoded[i].lon, coords[i].lon); + BOOST_CHECK_EQUAL(decoded[i].lat, coords[i].lat); + } +} + +BOOST_AUTO_TEST_CASE(polyline_large_coordinate_difference_test) +{ + using namespace osrm::engine; + using namespace osrm::util; + + const std::vector coords({{FixedLongitude{-179000000}, FixedLatitude{-89000000}}, + {FixedLongitude{179000000}, FixedLatitude{89000000}}}); + + const std::string encoded = encodePolyline(coords.begin(), coords.end()); + BOOST_CHECK_EQUAL(encoded, "~xe~O~|oca@_sl}`@_{`hcA"); + + const auto decoded = decodePolyline(encoded); + BOOST_CHECK_EQUAL(decoded.size(), 2); + for (size_t i = 0; i < coords.size(); ++i) + { + BOOST_CHECK_EQUAL(decoded[i].lon, coords[i].lon); + BOOST_CHECK_EQUAL(decoded[i].lat, coords[i].lat); + } +} + +BOOST_AUTO_TEST_CASE(roundtrip) +{ + using namespace osrm::engine; + using namespace osrm::util; + + { + const auto encoded = "_chxEn`zvN\\\\]]"; + const auto decoded = decodePolyline(encoded); + const auto reencoded = encodePolyline(decoded.begin(), decoded.end()); + BOOST_CHECK_EQUAL(encoded, reencoded); + } + { + const auto encoded = + "gcneIpgxzRcDnBoBlEHzKjBbHlG`@`IkDxIiKhKoMaLwTwHeIqHuAyGXeB~Ew@fFjAtIzExF"; + const auto decoded = decodePolyline(encoded); + const auto reencoded = encodePolyline(decoded.begin(), decoded.end()); + BOOST_CHECK_EQUAL(encoded, reencoded); + } + { + const auto encoded = "_p~iF~ps|U_ulLnnqC_mqNvxq`@"; + const auto decoded = decodePolyline(encoded); + const auto reencoded = encodePolyline(decoded.begin(), decoded.end()); + BOOST_CHECK_EQUAL(encoded, reencoded); + } +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/unit_tests/library/table.cpp b/unit_tests/library/table.cpp index e1caafdae..c29d58f54 100644 --- a/unit_tests/library/table.cpp +++ b/unit_tests/library/table.cpp @@ -271,8 +271,8 @@ void test_table_no_segment_for_some_coordinates(bool use_json_only_api) params.coordinates.push_back(get_dummy_location()); params.coordinates.push_back(get_dummy_location()); // resembles query option: `&radiuses=0;` - params.radiuses.push_back(boost::make_optional(0.)); - params.radiuses.push_back(boost::none); + params.radiuses.push_back(std::make_optional(0.)); + params.radiuses.push_back(std::nullopt); json::Object json_result; const auto rc = run_table_json(osrm, params, json_result, use_json_only_api); diff --git a/unit_tests/mocks/mock_datafacade.hpp b/unit_tests/mocks/mock_datafacade.hpp index dc2541713..45e9c87f2 100644 --- a/unit_tests/mocks/mock_datafacade.hpp +++ b/unit_tests/mocks/mock_datafacade.hpp @@ -107,7 +107,7 @@ class MockBaseDataFacade : public engine::datafacade::BaseDataFacade std::vector NearestPhantomNodesInRange(const util::Coordinate /*input_coordinate*/, const double /*max_distance*/, - const boost::optional /*bearing*/, + const std::optional /*bearing*/, const engine::Approach /*approach*/, const bool /*use_all_edges*/) const override { @@ -117,8 +117,8 @@ class MockBaseDataFacade : public engine::datafacade::BaseDataFacade std::vector NearestPhantomNodes(const util::Coordinate /*input_coordinate*/, const size_t /*max_results*/, - const boost::optional /*max_distance*/, - const boost::optional /*bearing*/, + const std::optional /*max_distance*/, + const std::optional /*bearing*/, const engine::Approach /*approach*/) const override { return {}; @@ -126,8 +126,8 @@ class MockBaseDataFacade : public engine::datafacade::BaseDataFacade engine::PhantomCandidateAlternatives NearestCandidatesWithAlternativeFromBigComponent( const util::Coordinate /*input_coordinate*/, - const boost::optional /*max_distance*/, - const boost::optional /*bearing*/, + const std::optional /*max_distance*/, + const std::optional /*bearing*/, const engine::Approach /*approach*/, const bool /*use_all_edges*/) const override { diff --git a/unit_tests/server/parameters_parser.cpp b/unit_tests/server/parameters_parser.cpp index 22b03f6fd..fee69f8b2 100644 --- a/unit_tests/server/parameters_parser.cpp +++ b/unit_tests/server/parameters_parser.cpp @@ -32,6 +32,11 @@ (R2)[i]->segment_hints.end()); \ } \ } +// TODO: we should be able to somehow make Boost.Test to print std::optional types +BOOST_TEST_DONT_PRINT_LOG_VALUE(std::optional) +BOOST_TEST_DONT_PRINT_LOG_VALUE(std::optional) +BOOST_TEST_DONT_PRINT_LOG_VALUE(std::optional) +BOOST_TEST_DONT_PRINT_LOG_VALUE(std::optional) BOOST_AUTO_TEST_SUITE(api_parameters_parser) @@ -216,7 +221,7 @@ BOOST_AUTO_TEST_CASE(valid_route_urls) phantom_1.input_location = coords_1[0]; engine::PhantomNode phantom_2; phantom_2.input_location = coords_1[1]; - std::vector> hints_4 = { + std::vector> hints_4 = { engine::Hint{{engine::SegmentHint{phantom_1, 0x1337}}}, engine::Hint{{engine::SegmentHint{phantom_2, 0x1337}}}}; RouteParameters reference_4{false, @@ -224,11 +229,11 @@ BOOST_AUTO_TEST_CASE(valid_route_urls) false, RouteParameters::GeometriesType::Polyline, RouteParameters::OverviewType::Simplified, - boost::optional{}, + std::optional{}, coords_1, hints_4, - std::vector>{}, - std::vector>{}}; + std::vector>{}, + std::vector>{}}; auto result_4 = parseParameters( "1,2;3,4?steps=false&hints=" + hints_4[0]->ToBase64() + ";" + hints_4[1]->ToBase64()); BOOST_CHECK(result_4); @@ -244,8 +249,8 @@ BOOST_AUTO_TEST_CASE(valid_route_urls) CHECK_EQUAL_RANGE(reference_4.coordinates, result_4->coordinates); CHECK_EQUAL_RANGE_OF_HINTS(reference_4.hints, result_4->hints); - std::vector> bearings_4 = { - boost::none, + std::vector> bearings_4 = { + std::nullopt, engine::Bearing{200, 10}, engine::Bearing{100, 5}, }; @@ -254,10 +259,10 @@ BOOST_AUTO_TEST_CASE(valid_route_urls) false, RouteParameters::GeometriesType::Polyline, RouteParameters::OverviewType::Simplified, - boost::optional{}, + std::optional{}, coords_1, - std::vector>{}, - std::vector>{}, + std::vector>{}, + std::vector>{}, bearings_4}; auto result_5 = parseParameters("1,2;3,4?steps=false&bearings=;200,10;100,5"); BOOST_CHECK(result_5); @@ -296,8 +301,8 @@ BOOST_AUTO_TEST_CASE(valid_route_urls) auto result_7 = parseParameters("1,2;3,4?radiuses=;unlimited"); RouteParameters reference_7{}; reference_7.coordinates = coords_1; - reference_7.radiuses = {boost::none, - boost::make_optional(std::numeric_limits::infinity())}; + reference_7.radiuses = {std::nullopt, + std::make_optional(std::numeric_limits::infinity())}; BOOST_CHECK(result_7); BOOST_CHECK_EQUAL(reference_7.steps, result_7->steps); BOOST_CHECK_EQUAL(reference_7.alternatives, result_7->alternatives); @@ -314,14 +319,14 @@ BOOST_AUTO_TEST_CASE(valid_route_urls) auto result_8 = parseParameters("1,2;3,4?radiuses=;"); RouteParameters reference_8{}; reference_8.coordinates = coords_1; - reference_8.radiuses = {boost::none, boost::none}; + reference_8.radiuses = {std::nullopt, std::nullopt}; BOOST_CHECK(result_8); CHECK_EQUAL_RANGE(reference_8.radiuses, result_8->radiuses); auto result_9 = parseParameters("1,2?radiuses="); RouteParameters reference_9{}; reference_9.coordinates = coords_1; - reference_9.radiuses = {boost::none}; + reference_9.radiuses = {std::nullopt}; BOOST_CHECK(result_9); CHECK_EQUAL_RANGE(reference_9.radiuses, result_9->radiuses); @@ -335,7 +340,7 @@ BOOST_AUTO_TEST_CASE(valid_route_urls) phantom_3.input_location = coords_3[0]; engine::PhantomNode phantom_4; phantom_4.input_location = coords_3[2]; - std::vector> hints_10 = { + std::vector> hints_10 = { engine::Hint{{engine::SegmentHint{phantom_3, 0x1337}}}, {}, engine::Hint{{engine::SegmentHint{phantom_4, 0x1337}}}, @@ -346,11 +351,11 @@ BOOST_AUTO_TEST_CASE(valid_route_urls) false, RouteParameters::GeometriesType::Polyline, RouteParameters::OverviewType::Simplified, - boost::optional{}, + std::optional{}, coords_3, hints_10, - std::vector>{}, - std::vector>{}}; + std::vector>{}, + std::vector>{}}; auto result_10 = parseParameters( "1,2;3,4;5,6;7,8?steps=false&hints=" + hints_10[0]->ToBase64() + ";;" + hints_10[2]->ToBase64() + ";"); @@ -447,8 +452,8 @@ BOOST_AUTO_TEST_CASE(valid_route_urls) BOOST_CHECK_EQUAL(result_2->annotations_type == RouteParameters::AnnotationsType::All, true); BOOST_CHECK_EQUAL(result_17->annotations, true); - std::vector> approaches_18 = { - boost::none, + std::vector> approaches_18 = { + std::nullopt, engine::Approach::CURB, engine::Approach::UNRESTRICTED, engine::Approach::OPPOSITE, @@ -458,11 +463,11 @@ BOOST_AUTO_TEST_CASE(valid_route_urls) false, RouteParameters::GeometriesType::Polyline, RouteParameters::OverviewType::Simplified, - boost::optional{}, + std::optional{}, coords_3, - std::vector>{}, - std::vector>{}, - std::vector>{}, + std::vector>{}, + std::vector>{}, + std::vector>{}, approaches_18}; auto result_18 = parseParameters( @@ -778,6 +783,7 @@ BOOST_AUTO_TEST_CASE(valid_trip_urls) reference_1.coordinates = coords_1; auto result_1 = parseParameters("1,2;3,4"); BOOST_CHECK(result_1); + CHECK_EQUAL_RANGE(reference_1.radiuses, result_1->radiuses); CHECK_EQUAL_RANGE(reference_1.coordinates, result_1->coordinates); diff --git a/unit_tests/util/binary_heap.cpp b/unit_tests/util/binary_heap.cpp new file mode 100644 index 000000000..354fe7464 --- /dev/null +++ b/unit_tests/util/binary_heap.cpp @@ -0,0 +1,132 @@ +#include "util/binary_heap.hpp" + +#include +#include + +BOOST_AUTO_TEST_SUITE(binary_heap_test) + +BOOST_AUTO_TEST_CASE(empty_heap) +{ + osrm::util::BinaryHeap heap; + BOOST_CHECK(heap.empty()); +} + +BOOST_AUTO_TEST_CASE(push_and_top) +{ + osrm::util::BinaryHeap heap; + heap.emplace(5); + BOOST_CHECK_EQUAL(heap.top(), 5); + BOOST_CHECK(!heap.empty()); +} + +BOOST_AUTO_TEST_CASE(push_multiple_and_order) +{ + osrm::util::BinaryHeap heap; + heap.emplace(5); + heap.emplace(10); + heap.emplace(3); + heap.emplace(8); + BOOST_CHECK_EQUAL(heap.top(), 10); +} + +BOOST_AUTO_TEST_CASE(pop_and_order) +{ + osrm::util::BinaryHeap heap; + heap.emplace(5); + heap.emplace(10); + heap.emplace(3); + heap.emplace(8); + + BOOST_CHECK_EQUAL(heap.top(), 10); + heap.pop(); + BOOST_CHECK_EQUAL(heap.top(), 8); + heap.pop(); + BOOST_CHECK_EQUAL(heap.top(), 5); + heap.pop(); + BOOST_CHECK_EQUAL(heap.top(), 3); + heap.pop(); + BOOST_CHECK(heap.empty()); +} + +BOOST_AUTO_TEST_CASE(clear_heap) +{ + osrm::util::BinaryHeap heap; + heap.emplace(5); + heap.emplace(10); + heap.clear(); + BOOST_CHECK(heap.empty()); +} + +BOOST_AUTO_TEST_CASE(emplace_with_custom_type) +{ + struct CustomType + { + int value; + CustomType(int v) : value(v) {} + bool operator<(const CustomType &other) const { return value < other.value; } + }; + + osrm::util::BinaryHeap heap; + heap.emplace(5); + heap.emplace(10); + heap.emplace(3); + BOOST_CHECK_EQUAL(heap.top().value, 10); +} + +BOOST_AUTO_TEST_CASE(large_number_of_elements) +{ + osrm::util::BinaryHeap heap; + for (int i = 0; i < 1000; ++i) + { + heap.emplace(i); + } + BOOST_CHECK_EQUAL(heap.top(), 999); + + for (int i = 999; i >= 0; --i) + { + BOOST_CHECK_EQUAL(heap.top(), i); + heap.pop(); + } + BOOST_CHECK(heap.empty()); +} + +BOOST_AUTO_TEST_CASE(duplicate_values) +{ + osrm::util::BinaryHeap heap; + heap.emplace(5); + heap.emplace(5); + heap.emplace(5); + + BOOST_CHECK_EQUAL(heap.top(), 5); + heap.pop(); + BOOST_CHECK_EQUAL(heap.top(), 5); + heap.pop(); + BOOST_CHECK_EQUAL(heap.top(), 5); + heap.pop(); + BOOST_CHECK(heap.empty()); +} + +BOOST_AUTO_TEST_CASE(string_type) +{ + osrm::util::BinaryHeap heap; + heap.emplace("apple"); + heap.emplace("banana"); + heap.emplace("cherry"); + + BOOST_CHECK_EQUAL(heap.top(), "cherry"); + heap.pop(); + BOOST_CHECK_EQUAL(heap.top(), "banana"); + heap.pop(); + BOOST_CHECK_EQUAL(heap.top(), "apple"); +} + +BOOST_AUTO_TEST_CASE(emplace_after_clear) +{ + osrm::util::BinaryHeap heap; + heap.emplace(5); + heap.clear(); + heap.emplace(10); + BOOST_CHECK_EQUAL(heap.top(), 10); +} + +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file diff --git a/unit_tests/util/static_rtree.cpp b/unit_tests/util/static_rtree.cpp index d2e29fa2e..06c753432 100644 --- a/unit_tests/util/static_rtree.cpp +++ b/unit_tests/util/static_rtree.cpp @@ -332,13 +332,13 @@ BOOST_AUTO_TEST_CASE(radius_regression_test) { auto results = query.NearestPhantomNodes( - input, osrm::engine::Approach::UNRESTRICTED, 0.01, boost::none, true); + input, osrm::engine::Approach::UNRESTRICTED, 0.01, std::nullopt, true); BOOST_CHECK_EQUAL(results.size(), 0); } { auto results = query.NearestPhantomNodes( - input, osrm::engine::Approach::UNRESTRICTED, 1, 0.01, boost::none, true); + input, osrm::engine::Approach::UNRESTRICTED, 1, 0.01, std::nullopt, true); BOOST_CHECK_EQUAL(results.size(), 0); } } @@ -364,25 +364,25 @@ BOOST_AUTO_TEST_CASE(permissive_edge_snapping) { auto results = query.NearestPhantomNodes( - input, osrm::engine::Approach::UNRESTRICTED, 1000, boost::none, false); + input, osrm::engine::Approach::UNRESTRICTED, 1000, std::nullopt, false); BOOST_CHECK_EQUAL(results.size(), 1); } { auto results = query.NearestPhantomNodes( - input, osrm::engine::Approach::UNRESTRICTED, 1000, boost::none, true); + input, osrm::engine::Approach::UNRESTRICTED, 1000, std::nullopt, true); BOOST_CHECK_EQUAL(results.size(), 2); } { auto results = query.NearestPhantomNodes( - input, osrm::engine::Approach::UNRESTRICTED, 10, 1000, boost::none, false); + input, osrm::engine::Approach::UNRESTRICTED, 10, 1000, std::nullopt, false); BOOST_CHECK_EQUAL(results.size(), 1); } { auto results = query.NearestPhantomNodes( - input, osrm::engine::Approach::UNRESTRICTED, 10, 1000, boost::none, true); + input, osrm::engine::Approach::UNRESTRICTED, 10, 1000, std::nullopt, true); BOOST_CHECK_EQUAL(results.size(), 2); } } @@ -408,7 +408,7 @@ BOOST_AUTO_TEST_CASE(bearing_tests) { auto results = query.NearestPhantomNodes( - input, osrm::engine::Approach::UNRESTRICTED, 5, boost::none, boost::none, false); + input, osrm::engine::Approach::UNRESTRICTED, 5, std::nullopt, std::nullopt, false); BOOST_CHECK_EQUAL(results.size(), 2); BOOST_CHECK_EQUAL(results.back().phantom_node.forward_segment_id.id, 0); BOOST_CHECK_EQUAL(results.back().phantom_node.reverse_segment_id.id, 1); @@ -418,7 +418,7 @@ BOOST_AUTO_TEST_CASE(bearing_tests) auto results = query.NearestPhantomNodes(input, osrm::engine::Approach::UNRESTRICTED, 5, - boost::none, + std::nullopt, engine::Bearing{270, 10}, false); BOOST_CHECK_EQUAL(results.size(), 0); @@ -428,7 +428,7 @@ BOOST_AUTO_TEST_CASE(bearing_tests) auto results = query.NearestPhantomNodes(input, osrm::engine::Approach::UNRESTRICTED, 5, - boost::none, + std::nullopt, engine::Bearing{45, 10}, false); BOOST_CHECK_EQUAL(results.size(), 2); @@ -444,13 +444,13 @@ BOOST_AUTO_TEST_CASE(bearing_tests) { auto results = query.NearestPhantomNodes( - input, osrm::engine::Approach::UNRESTRICTED, 11000, boost::none, true); + input, osrm::engine::Approach::UNRESTRICTED, 11000, std::nullopt, true); BOOST_CHECK_EQUAL(results.size(), 2); } { auto results = query.NearestPhantomNodes( - input, osrm::engine::Approach::UNRESTRICTED, 10, 11000, boost::none, true); + input, osrm::engine::Approach::UNRESTRICTED, 10, 11000, std::nullopt, true); BOOST_CHECK_EQUAL(results.size(), 2); }