Pull in maplibre-native-base repo (#3389)

This commit is contained in:
Bart Louwers
2025-04-16 02:18:42 +02:00
committed by GitHub
parent 48d0691a8a
commit b9f91c1924
62 changed files with 2021 additions and 129 deletions

View File

@@ -97,15 +97,9 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: true
fetch-depth: 0
- name: Setup submodules
shell: bash
run: |
auth_header="$(git config --local --get http.https://github.com/.extraheader)"
git submodule sync --recursive
git -c core.longpaths=true -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive || true
- name: Get OS Architecture
if: runner.os == 'MacOS' || runner.os == 'Linux'
run: uname -m

View File

@@ -109,14 +109,7 @@ jobs:
with:
path: source
fetch-depth: 0
- name: Setup submodules
shell: bash
run: |
cd source
auth_header="$(git config --local --get http.https://github.com/.extraheader)"
git submodule sync --recursive
git -c core.longpaths=true -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1 || true
submodules: true
- name: Install test dependencies
if: runner.os == 'Linux' && matrix.compiler != ''

45
.gitmodules vendored
View File

@@ -22,9 +22,6 @@
[submodule "vendor/eternal"]
path = vendor/eternal
url = https://github.com/mapbox/eternal.git
[submodule "vendor/mapbox-base"]
path = vendor/mapbox-base
url = https://github.com/maplibre/maplibre-native-base.git
[submodule "vendor/googletest"]
path = vendor/googletest
url = https://github.com/google/googletest.git
@@ -58,3 +55,45 @@
[submodule "vendor/PMTiles"]
path = vendor/PMTiles
url = https://github.com/protomaps/PMTiles.git
[submodule "vendor/maplibre-native-base/extras/args"]
path = vendor/maplibre-native-base/extras/args
url = git@github.com:Taywee/args.git
[submodule "vendor/maplibre-native-base/extras/expected-lite"]
path = vendor/maplibre-native-base/extras/expected-lite
url = https://github.com/martinmoene/expected-lite.git
[submodule "vendor/maplibre-native-base/extras/kdbush.hpp"]
path = vendor/maplibre-native-base/extras/kdbush.hpp
url = https://github.com/mourner/kdbush.hpp.git
[submodule "vendor/maplibre-native-base/extras/rapidjson"]
path = vendor/maplibre-native-base/extras/rapidjson
url = https://github.com/Tencent/rapidjson.git
[submodule "vendor/maplibre-native-base/deps/cheap-ruler-cpp"]
path = vendor/maplibre-native-base/deps/cheap-ruler-cpp
url = https://github.com/mapbox/cheap-ruler-cpp.git
[submodule "vendor/maplibre-native-base/deps/geojson-vt-cpp"]
path = vendor/maplibre-native-base/deps/geojson-vt-cpp
url = https://github.com/mapbox/geojson-vt-cpp.git
[submodule "vendor/maplibre-native-base/deps/geojson-cpp"]
path = vendor/maplibre-native-base/deps/geojson-cpp
url = https://github.com/mapbox/geojson-cpp.git
[submodule "vendor/maplibre-native-base/deps/geometry.hpp"]
path = vendor/maplibre-native-base/deps/geometry.hpp
url = https://github.com/mapbox/geometry.hpp.git
[submodule "vendor/maplibre-native-base/deps/jni.hpp"]
path = vendor/maplibre-native-base/deps/jni.hpp
url = https://github.com/mapbox/jni.hpp.git
[submodule "vendor/maplibre-native-base/deps/pixelmatch-cpp"]
path = vendor/maplibre-native-base/deps/pixelmatch-cpp
url = https://github.com/mapbox/pixelmatch-cpp.git
[submodule "vendor/maplibre-native-base/deps/shelf-pack-cpp"]
path = vendor/maplibre-native-base/deps/shelf-pack-cpp
url = https://github.com/mapbox/shelf-pack-cpp.git
[submodule "vendor/maplibre-native-base/deps/supercluster.hpp"]
path = vendor/maplibre-native-base/deps/supercluster.hpp
url = https://github.com/mapbox/supercluster.hpp.git
[submodule "vendor/maplibre-native-base/deps/variant"]
path = vendor/maplibre-native-base/deps/variant
url = https://github.com/mapbox/variant.git
[submodule "vendor/maplibre-native-base/deps/geojson.hpp"]
path = vendor/maplibre-native-base/deps/geojson.hpp
url = https://github.com/mapbox/geojson-cpp.git

View File

@@ -116,7 +116,7 @@ cc_library(
"//vendor:boost",
"//vendor:earcut.hpp",
"//vendor:eternal",
"//vendor:mapbox-base",
"//vendor:maplibre-native-base",
"//vendor:parsedate",
"//vendor:pmtiles",
"//vendor:polylabel",

View File

@@ -1446,7 +1446,7 @@ include(${PROJECT_SOURCE_DIR}/vendor/boost.cmake)
include(${PROJECT_SOURCE_DIR}/vendor/csscolorparser.cmake)
include(${PROJECT_SOURCE_DIR}/vendor/earcut.hpp.cmake)
include(${PROJECT_SOURCE_DIR}/vendor/eternal.cmake)
include(${PROJECT_SOURCE_DIR}/vendor/mapbox-base.cmake)
include(${PROJECT_SOURCE_DIR}/vendor/maplibre-native-base.cmake)
include(${PROJECT_SOURCE_DIR}/vendor/parsedate.cmake)
include(${PROJECT_SOURCE_DIR}/vendor/pmtiles.cmake)
include(${PROJECT_SOURCE_DIR}/vendor/polylabel.cmake)
@@ -1465,11 +1465,11 @@ endif()
target_link_libraries(
mbgl-core
PRIVATE
Mapbox::Base::Extras::kdbush.hpp
Mapbox::Base::supercluster.hpp
Mapbox::Base::shelf-pack-cpp
Mapbox::Base::geojson-vt-cpp
Mapbox::Base::cheap-ruler-cpp
MapLibreNative::Base::Extras::kdbush.hpp
MapLibreNative::Base::supercluster.hpp
MapLibreNative::Base::shelf-pack-cpp
MapLibreNative::Base::geojson-vt-cpp
MapLibreNative::Base::cheap-ruler-cpp
mbgl-compiler-options
mbgl-vendor-boost
mbgl-vendor-earcut.hpp
@@ -1484,31 +1484,31 @@ target_link_libraries(
$<$<BOOL:${MLN_WITH_METAL}>:mbgl-vendor-metal-cpp>
$<IF:$<BOOL:${MLN_USE_RUST}>,mbgl-rustutils,mbgl-vendor-csscolorparser>
PUBLIC
Mapbox::Base
Mapbox::Base::Extras::expected-lite
Mapbox::Base::Extras::rapidjson
Mapbox::Base::geojson.hpp
Mapbox::Base::geometry.hpp
Mapbox::Base::variant
MapLibreNative::Base
MapLibreNative::Base::Extras::expected-lite
MapLibreNative::Base::Extras::rapidjson
MapLibreNative::Base::geojson.hpp
MapLibreNative::Base::geometry.hpp
MapLibreNative::Base::variant
$<$<BOOL:${MLN_USE_TRACY}>:TracyClient>
unordered_dense
)
set(EXPORT_TARGETS
mbgl-core
mapbox-base
mapbox-base-cheap-ruler-cpp
mapbox-base-extras-expected-lite
mapbox-base-extras-kdbush.hpp
mapbox-base-extras-rapidjson
mapbox-base-geojson-vt-cpp
mapbox-base-geojson.hpp
mapbox-base-geometry.hpp
mapbox-base-jni.hpp
mapbox-base-pixelmatch-cpp
mapbox-base-shelf-pack-cpp
mapbox-base-supercluster.hpp
mapbox-base-variant
maplibre-native-base
maplibre-native-base-cheap-ruler-cpp
maplibre-native-base-extras-expected-lite
maplibre-native-base-extras-kdbush.hpp
maplibre-native-base-extras-rapidjson
maplibre-native-base-geojson-vt-cpp
maplibre-native-base-geojson.hpp
maplibre-native-base-geometry.hpp
maplibre-native-base-jni.hpp
maplibre-native-base-pixelmatch-cpp
maplibre-native-base-shelf-pack-cpp
maplibre-native-base-supercluster.hpp
maplibre-native-base-variant
mbgl-compiler-options
mbgl-vendor-boost
mbgl-vendor-earcut.hpp

View File

@@ -6,8 +6,8 @@ add_executable(
target_link_libraries(
mbgl-cache
PRIVATE
Mapbox::Base
Mapbox::Base::Extras::args
MapLibreNative::Base
MapLibreNative::Base::Extras::args
mbgl-compiler-options
mbgl-core
)
@@ -19,7 +19,7 @@ add_executable(
target_link_libraries(
mbgl-offline
PRIVATE Mapbox::Base::Extras::args mbgl-compiler-options mbgl-core
PRIVATE MapLibreNative::Base::Extras::args mbgl-compiler-options mbgl-core
)
add_executable(
@@ -29,7 +29,7 @@ add_executable(
target_link_libraries(
mbgl-render
PRIVATE Mapbox::Base::Extras::args mbgl-compiler-options mbgl-core
PRIVATE MapLibreNative::Base::Extras::args mbgl-compiler-options mbgl-core
)
if(WIN32)

View File

@@ -20,8 +20,8 @@ target_include_directories(
target_link_libraries(
mbgl-expression-test
PRIVATE
Mapbox::Base
Mapbox::Base::Extras::args
MapLibreNative::Base
MapLibreNative::Base::Extras::args
mbgl-core
mbgl-compiler-options
)

View File

@@ -239,7 +239,7 @@ target_link_libraries(maplibre
$<$<CONFIG:Release>:-Wl,--gc-sections>
$<$<CONFIG:Release>:-flto>
$<$<CONFIG:Release>:-fuse-ld=gold>
Mapbox::Base::jni.hpp
MapLibreNative::Base::jni.hpp
mbgl-core
mbgl-vendor-unique_resource)

View File

@@ -101,7 +101,7 @@ target_link_libraries(
PRIVATE
EGL
GLESv3
Mapbox::Base::jni.hpp
MapLibreNative::Base::jni.hpp
android
atomic
jnigraphics
@@ -125,7 +125,7 @@ target_link_libraries(
example-custom-layer
PRIVATE
GLESv3
Mapbox::Base
MapLibreNative::Base
log
mbgl-compiler-options
)
@@ -160,7 +160,7 @@ find_package(curl CONFIG)
target_link_libraries(
mbgl-test-runner
PRIVATE
Mapbox::Base::jni.hpp
MapLibreNative::Base::jni.hpp
mbgl-compiler-options
$<$<BOOL:${curl_FOUND}>:curl::curl_static>
$<LINK_LIBRARY:WHOLE_ARCHIVE,mbgl-test>
@@ -214,7 +214,7 @@ target_include_directories(
target_link_libraries(
mbgl-benchmark-runner
PRIVATE
Mapbox::Base::jni.hpp
MapLibreNative::Base::jni.hpp
mbgl-compiler-options
$<LINK_LIBRARY:WHOLE_ARCHIVE,mbgl-benchmark>
)
@@ -265,7 +265,7 @@ target_include_directories(
target_link_libraries(
mbgl-render-test-runner
PRIVATE
Mapbox::Base::jni.hpp
MapLibreNative::Base::jni.hpp
android
log
mbgl-compiler-options

View File

@@ -128,12 +128,11 @@ endif()
target_link_libraries(
mbgl-glfw
PRIVATE
Mapbox::Base::Extras::args
Mapbox::Base::Extras::filesystem
Mapbox::Base::Extras::rapidjson
MapLibreNative::Base::Extras::args
MapLibreNative::Base::Extras::rapidjson
Mapbox::Map
mbgl-compiler-options
Mapbox::Base::cheap-ruler-cpp
MapLibreNative::Base::cheap-ruler-cpp
)
if(NOT WIN32 AND MLN_WITH_OPENGL)

View File

@@ -3,11 +3,11 @@
#include <rapidjson/prettywriter.h>
#include <rapidjson/stringbuffer.h>
#include <rapidjson/writer.h>
#include <ghc/filesystem.hpp>
#include <cmath>
#include <fstream>
#include <utility>
#include <filesystem>
using Writer = rapidjson::PrettyWriter<rapidjson::StringBuffer>;
@@ -117,7 +117,7 @@ TestWriter& TestWriter::withInitialSize(const mbgl::Size& size) {
}
bool TestWriter::write(const std::string& dir) const {
namespace fs = ghc::filesystem;
namespace fs = std::filesystem;
fs::path rootDir(dir);
if (!fs::exists(rootDir)) {

View File

@@ -43,7 +43,7 @@ target_include_directories(
target_link_libraries(
mbgl-node-loop
PUBLIC
Mapbox::Base
MapLibreNative::Base
)
target_sources(

View File

@@ -54,6 +54,6 @@ cc_test(
deps = [
"render-test-srcs",
"//platform/default:render-test-bin",
"//vendor:mapbox-base",
"//vendor:maplibre-native-base",
],
)

View File

@@ -57,9 +57,8 @@ include(${PROJECT_SOURCE_DIR}/vendor/boost.cmake)
target_link_libraries(
mbgl-render-test
PRIVATE
Mapbox::Base::Extras::args
Mapbox::Base::Extras::filesystem
Mapbox::Base::pixelmatch-cpp
MapLibreNative::Base::Extras::args
MapLibreNative::Base::pixelmatch-cpp
mbgl-compiler-options
mbgl-vendor-boost
PUBLIC mbgl-core

View File

@@ -239,8 +239,8 @@ target_link_libraries(
mbgl-test
PRIVATE
${MLN_CORE_PRIVATE_LIBRARIES}
Mapbox::Base::Extras::args
Mapbox::Base::pixelmatch-cpp
MapLibreNative::Base::Extras::args
MapLibreNative::Base::pixelmatch-cpp
mbgl-compiler-options
mbgl-vendor-cpp-httplib
PUBLIC mbgl-core

63
vendor/BUILD.bazel vendored
View File

@@ -1,48 +1,45 @@
load("@rules_cc//cc:defs.bzl", "cc_library", "objc_library")
load("//bazel:flags.bzl", "CPP_FLAGS")
# vendor/mapbox-base-files.json
cc_library(
name = "mapbox-base",
name = "maplibre-native-base",
hdrs = [
"mapbox-base/extras/args/args.hxx",
"maplibre-native-base/extras/args/args.hxx",
] + glob(
[
"mapbox-base/deps/cheap-ruler-cpp/include/mapbox/*.hpp",
"mapbox-base/deps/geojson-vt-cpp/include/**/*.hpp",
"mapbox-base/deps/geojson.hpp/include/**/*.hpp",
"mapbox-base/deps/geometry.hpp/include/**/*.hpp",
"mapbox-base/deps/jni.hpp/include/jni/*.hpp",
"mapbox-base/deps/pixelmatch-cpp/include/mapbox/*.hpp",
"mapbox-base/deps/shelf-pack-cpp/include/**/*.hpp",
"mapbox-base/deps/supercluster.hpp/include/*.hpp",
"mapbox-base/deps/variant/include/mapbox/*.hpp",
"mapbox-base/extras/expected-lite/include/**/*.hpp",
"mapbox-base/extras/filesystem/include/ghc/*.hpp",
"mapbox-base/extras/kdbush.hpp/include/*.hpp",
"mapbox-base/extras/rapidjson/include/**/*.h",
"mapbox-base/include/mapbox/**/*.hpp",
"maplibre-native-base/deps/cheap-ruler-cpp/include/mapbox/*.hpp",
"maplibre-native-base/deps/geojson-vt-cpp/include/**/*.hpp",
"maplibre-native-base/deps/geojson.hpp/include/**/*.hpp",
"maplibre-native-base/deps/geometry.hpp/include/**/*.hpp",
"maplibre-native-base/deps/jni.hpp/include/jni/*.hpp",
"maplibre-native-base/deps/pixelmatch-cpp/include/mapbox/*.hpp",
"maplibre-native-base/deps/shelf-pack-cpp/include/**/*.hpp",
"maplibre-native-base/deps/supercluster.hpp/include/*.hpp",
"maplibre-native-base/deps/variant/include/mapbox/*.hpp",
"maplibre-native-base/extras/expected-lite/include/**/*.hpp",
"maplibre-native-base/extras/kdbush.hpp/include/*.hpp",
"maplibre-native-base/extras/rapidjson/include/**/*.h",
"maplibre-native-base/include/mapbox/**/*.hpp",
],
exclude = ["mapbox-base/deps/jni.hpp/include/jni/string_conversion.hpp"],
exclude = ["maplibre-native-base/deps/jni.hpp/include/jni/string_conversion.hpp"],
),
copts = CPP_FLAGS,
defines = ["RAPIDJSON_HAS_STDSTRING=1"],
includes = [
"mapbox-base/deps/cheap-ruler-cpp/include",
"mapbox-base/deps/geojson.hpp/include",
"mapbox-base/deps/geojson-vt-cpp/include",
"mapbox-base/deps/geometry.hpp/include",
"mapbox-base/deps/jni.hpp/include",
"mapbox-base/deps/pixelmatch-cpp/include",
"mapbox-base/deps/shelf-pack-cpp/include",
"mapbox-base/deps/supercluster.hpp/include",
"mapbox-base/deps/variant/include",
"mapbox-base/extras/args",
"mapbox-base/extras/expected-lite/include",
"mapbox-base/extras/filesystem/include",
"mapbox-base/extras/kdbush.hpp/include",
"mapbox-base/extras/rapidjson/include",
"mapbox-base/include",
"maplibre-native-base/deps/cheap-ruler-cpp/include",
"maplibre-native-base/deps/geojson.hpp/include",
"maplibre-native-base/deps/geojson-vt-cpp/include",
"maplibre-native-base/deps/geometry.hpp/include",
"maplibre-native-base/deps/jni.hpp/include",
"maplibre-native-base/deps/pixelmatch-cpp/include",
"maplibre-native-base/deps/shelf-pack-cpp/include",
"maplibre-native-base/deps/supercluster.hpp/include",
"maplibre-native-base/deps/variant/include",
"maplibre-native-base/extras/args",
"maplibre-native-base/extras/expected-lite/include",
"maplibre-native-base/extras/kdbush.hpp/include",
"maplibre-native-base/extras/rapidjson/include",
"maplibre-native-base/include",
],
visibility = ["//visibility:public"],
)

1
vendor/mapbox-base vendored

Submodule vendor/mapbox-base deleted from 8990092c30

View File

@@ -1,104 +1,102 @@
# License helper for mapbox-base, should be upstreamed.
if(NOT TARGET mapbox-base)
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/mapbox-base)
if(NOT TARGET maplibre-native)
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/maplibre-native-base)
endif()
set_target_properties(
mapbox-base-extras-kdbush.hpp
maplibre-native-base-extras-kdbush.hpp
PROPERTIES
INTERFACE_MAPLIBRE_NAME "kdbush.hpp"
INTERFACE_MAPLIBRE_URL "https://github.com/mourner/kdbush.hpp"
INTERFACE_MAPLIBRE_AUTHOR "Vladimir Agafonkin"
INTERFACE_MAPLIBRE_LICENSE ${CMAKE_CURRENT_LIST_DIR}/mapbox-base/extras/kdbush.hpp/LICENSE
INTERFACE_MAPLIBRE_LICENSE ${CMAKE_CURRENT_LIST_DIR}/maplibre-native-base/extras/kdbush.hpp/LICENSE
)
set_target_properties(
mapbox-base-extras-expected-lite
maplibre-native-base-extras-expected-lite
PROPERTIES
INTERFACE_MAPLIBRE_NAME "expected-lite"
INTERFACE_MAPLIBRE_URL "https://github.com/martinmoene/expected-lite"
INTERFACE_MAPLIBRE_AUTHOR "Martin Moene"
INTERFACE_MAPLIBRE_LICENSE ${CMAKE_CURRENT_LIST_DIR}/mapbox-base/extras/expected-lite/LICENSE.txt
INTERFACE_MAPLIBRE_LICENSE ${CMAKE_CURRENT_LIST_DIR}/maplibre-native-base/extras/expected-lite/LICENSE.txt
)
set_target_properties(
mapbox-base-supercluster.hpp
maplibre-native-base-supercluster.hpp
PROPERTIES
INTERFACE_MAPLIBRE_NAME "supercluster.hpp"
INTERFACE_MAPLIBRE_URL "https://github.com/mapbox/supercluster.hpp"
INTERFACE_MAPLIBRE_AUTHOR "Mapbox"
INTERFACE_MAPLIBRE_LICENSE ${CMAKE_CURRENT_LIST_DIR}/mapbox-base/deps/supercluster.hpp/LICENSE
INTERFACE_MAPLIBRE_LICENSE ${CMAKE_CURRENT_LIST_DIR}/maplibre-native-base/deps/supercluster.hpp/LICENSE
)
set_target_properties(
mapbox-base-shelf-pack-cpp
maplibre-native-base-shelf-pack-cpp
PROPERTIES
INTERFACE_MAPLIBRE_NAME "shelf-pack-cpp"
INTERFACE_MAPLIBRE_URL "https://github.com/mapbox/shelf-pack-cpp"
INTERFACE_MAPLIBRE_AUTHOR "Mapbox"
INTERFACE_MAPLIBRE_LICENSE ${CMAKE_CURRENT_LIST_DIR}/mapbox-base/deps/shelf-pack-cpp/LICENSE.md
INTERFACE_MAPLIBRE_LICENSE ${CMAKE_CURRENT_LIST_DIR}/maplibre-native-base/deps/shelf-pack-cpp/LICENSE.md
)
set_target_properties(
mapbox-base-geojson-vt-cpp
maplibre-native-base-geojson-vt-cpp
PROPERTIES
INTERFACE_MAPLIBRE_NAME "geojson-vt-cpp"
INTERFACE_MAPLIBRE_URL "https://github.com/mapbox/geojson-vt-cpp"
INTERFACE_MAPLIBRE_AUTHOR "Mapbox"
INTERFACE_MAPLIBRE_LICENSE ${CMAKE_CURRENT_LIST_DIR}/mapbox-base/deps/geojson-vt-cpp/LICENSE
INTERFACE_MAPLIBRE_LICENSE ${CMAKE_CURRENT_LIST_DIR}/maplibre-native-base/deps/geojson-vt-cpp/LICENSE
)
set_target_properties(
mapbox-base-extras-rapidjson
maplibre-native-base-extras-rapidjson
PROPERTIES
INTERFACE_MAPLIBRE_NAME "RapidJSON"
INTERFACE_MAPLIBRE_URL "https://rapidjson.org"
INTERFACE_MAPLIBRE_AUTHOR "THL A29 Limited, a Tencent company, and Milo Yip"
INTERFACE_MAPLIBRE_LICENSE ${CMAKE_CURRENT_LIST_DIR}/mapbox-base/extras/rapidjson/license.txt
INTERFACE_MAPLIBRE_LICENSE ${CMAKE_CURRENT_LIST_DIR}/maplibre-native-base/extras/rapidjson/license.txt
)
set_target_properties(
mapbox-base-geojson.hpp
maplibre-native-base-geojson.hpp
PROPERTIES
INTERFACE_MAPLIBRE_NAME "geojson.hpp"
INTERFACE_MAPLIBRE_URL "https://github.com/mapbox/geojson-cpp"
INTERFACE_MAPLIBRE_AUTHOR "Mapbox"
INTERFACE_MAPLIBRE_LICENSE ${CMAKE_CURRENT_LIST_DIR}/mapbox-base/deps/geojson.hpp/LICENSE
INTERFACE_MAPLIBRE_LICENSE ${CMAKE_CURRENT_LIST_DIR}/maplibre-native-base/deps/geojson.hpp/LICENSE
)
set_target_properties(
mapbox-base-geometry.hpp
maplibre-native-base-geometry.hpp
PROPERTIES
INTERFACE_MAPLIBRE_NAME "geometry.hpp"
INTERFACE_MAPLIBRE_URL "https://github.com/mapbox/geometry.hpp"
INTERFACE_MAPLIBRE_AUTHOR "Mapbox"
INTERFACE_MAPLIBRE_LICENSE ${CMAKE_CURRENT_LIST_DIR}/mapbox-base/deps/geometry.hpp/LICENSE
INTERFACE_MAPLIBRE_LICENSE ${CMAKE_CURRENT_LIST_DIR}/maplibre-native-base/deps/geometry.hpp/LICENSE
)
set_target_properties(
mapbox-base
maplibre-native-base
PROPERTIES
INTERFACE_MAPLIBRE_NAME "mapbox-base"
INTERFACE_MAPLIBRE_URL "https://github.com/mapbox/mapbox-base"
INTERFACE_MAPLIBRE_AUTHOR "Mapbox"
INTERFACE_MAPLIBRE_LICENSE ${CMAKE_CURRENT_LIST_DIR}/mapbox-base/LICENSE
INTERFACE_MAPLIBRE_LICENSE ${CMAKE_CURRENT_LIST_DIR}/maplibre-native-base/LICENSE
)
set_target_properties(
mapbox-base-variant
maplibre-native-base-variant
PROPERTIES
INTERFACE_MAPLIBRE_NAME "variant"
INTERFACE_MAPLIBRE_URL "https://github.com/mapbox/variant"
INTERFACE_MAPLIBRE_AUTHOR "Mapbox"
INTERFACE_MAPLIBRE_LICENSE ${CMAKE_CURRENT_LIST_DIR}/mapbox-base/deps/variant/LICENSE
INTERFACE_MAPLIBRE_LICENSE ${CMAKE_CURRENT_LIST_DIR}/maplibre-native-base/deps/variant/LICENSE
)
set_target_properties(
mapbox-base-cheap-ruler-cpp
maplibre-native-base-cheap-ruler-cpp
PROPERTIES
INTERFACE_MAPLIBRE_NAME "cheap-ruler-cpp"
INTERFACE_MAPLIBRE_URL "https://github.com/mapbox/cheap-ruler-cpp"
INTERFACE_MAPLIBRE_AUTHOR "Mapbox"
INTERFACE_MAPLIBRE_LICENSE ${CMAKE_CURRENT_LIST_DIR}/mapbox-base/deps/cheap-ruler-cpp/LICENSE
INTERFACE_MAPLIBRE_LICENSE ${CMAKE_CURRENT_LIST_DIR}/maplibre-native-base/deps/cheap-ruler-cpp/LICENSE
)

View File

@@ -0,0 +1,10 @@
---
Language: Cpp
BasedOnStyle: Google
AccessModifierOffset: -4
IndentPPDirectives: AfterHash
AllowShortFunctionsOnASingleLine: Inline
ColumnLimit: 120
IndentWidth: 4
SpacesBeforeTrailingComments: 1
...

View File

@@ -0,0 +1,8 @@
Checks: 'bugprone-*,cppcoreguidelines-*,clang-analyzer-*,google-*,misc-*,modernize-*,performance-*,readability-*,-google-runtime-int,-google-readability-todo,-readability-named-parameter,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-cppcoreguidelines-special-member-functions,-cppcoreguidelines-pro-type-vararg,-cppcoreguidelines-pro-bounds-pointer-arithmetic'
WarningsAsErrors: '*'
HeaderFilterRegex: '.*'
CheckOptions:
- key: readability-identifier-naming.PrivateMemberSuffix
value: '_'
- key: readability-identifier-naming.ProtectedMemberSuffix
value: '_'

View File

@@ -0,0 +1,35 @@
name: ci
on:
push:
pull_request:
jobs:
test_debug_build:
strategy:
matrix:
os:
- ubuntu-latest
node_version:
- 16
architecture:
- x64
ccompiler:
- clang
cxxcompiler:
- clang++
release:
- Debug
name: ${{ matrix.os }}
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
- name: Build and run tests
run: |
set -eo pipefail
export CC=${{ matrix.ccompiler }} CXX=${{ matrix.cxxcompiler }}
cmake -B build -S . -DCMAKE_BUILD_TYPE=${{ matrix.release }} -DBUILD_TESTING=ON
cmake --build build
ctest --test-dir build/test

40
vendor/maplibre-native-base/.gitignore vendored Normal file
View File

@@ -0,0 +1,40 @@
# Prerequisites
*.d
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
# CMake build folder
build/
# NPM modules
node_modules
*.user

45
vendor/maplibre-native-base/.gitmodules vendored Normal file
View File

@@ -0,0 +1,45 @@
[submodule "libs/geometry.hpp"]
path = deps/geometry.hpp
url = https://github.com/mapbox/geometry.hpp.git
[submodule "libs/variant"]
path = deps/variant
url = https://github.com/mapbox/variant.git
[submodule "libs/args"]
path = extras/args
url = https://github.com/Taywee/args
[submodule "libs/expected-lite"]
path = extras/expected-lite
url = https://github.com/martinmoene/expected-lite.git
[submodule "libs/filesystem"]
path = extras/filesystem
url = https://github.com/gulrak/filesystem.git
[submodule "libs/pixelmatch-cpp"]
path = deps/pixelmatch-cpp
url = https://github.com/mapbox/pixelmatch-cpp.git
[submodule "libs/rapidjson"]
path = extras/rapidjson
url = https://github.com/Tencent/rapidjson.git
[submodule "mapbox/jni.hpp"]
path = deps/jni.hpp
url = https://github.com/mapbox/jni.hpp.git
[submodule "mapbox/geojson.hpp"]
path = deps/geojson.hpp
url = https://github.com/mapbox/geojson.hpp.git
[submodule "mapbox/supercluster.hpp"]
path = deps/supercluster.hpp
url = https://github.com/mapbox/supercluster.hpp.git
[submodule "extras/kdbush.hpp"]
path = extras/kdbush.hpp
url = https://github.com/mourner/kdbush.hpp.git
[submodule "mapbox/cheap-ruler-cpp"]
path = deps/cheap-ruler-cpp
url = https://github.com/mapbox/cheap-ruler-cpp.git
[submodule "mapbox/shelf-pack-cpp"]
path = deps/shelf-pack-cpp
url = https://github.com/mapbox/shelf-pack-cpp.git
[submodule "mapbox/geojson-vt-cpp"]
path = deps/geojson-vt-cpp
url = https://github.com/mapbox/geojson-vt-cpp.git
[submodule "extras/googletest"]
path = extras/googletest
url = https://github.com/google/googletest.git

139
vendor/maplibre-native-base/CHANGELOG.md vendored Normal file
View File

@@ -0,0 +1,139 @@
# MapLibre Base
## v2.1.1
### 💫️ Features and Improvements
- [variant](https://github.com/mapbox/variant.git) from 1.1.6 to 1.2.0
- [expected-lite](https://github.com/martinmoene/expected-lite) from 0.4.0 to 0.6.2
- [filesystem](https://github.com/gulrak/filesystem.git) from 1.5.10 to 1.5.12
- [googletest](https://github.com/google/googletest) 1.10.0 to 1.12.1
## v2.1.0
### 💫️ Features and Improvements
- Update [args](https://github.com/Taywee/args) from 6.2.3 to 6.4.1
- Update [rapidjson](https://github.com/Tencent/rapidjson) from (28 Jun 2019 - [d87b698d](https://github.com/Tencent/rapidjson/commit/d87b698d)) to (20 Jun 2022 - [27c3a8d](https://github.com/Tencent/rapidjson/commit/27c3a8d))
## v2.0.0
### 💫️ Other
- [base] New fork maintained by MapLibre
- [base] Replace Travis with Github Actions
## v1.9.1
### 💫️ Other
- [deps] Update ghc::filesystem to v1.5.10
## v1.9.0
### 💫️ Other
- [deps] Update ghc::filesystem to v1.5.6
## v1.8.1
### 💫️ Other
- [deps] Update geojson-vt-cpp to v6.6.5
## v1.8.0
### 💫️ Other
- [deps] Update supercluster.hpp to v0.5.0
## v1.7.0
### 💫️ Other
- [deps] Bump supercluster.hpp to v0.4.0
## v1.6.1
### 💫️ Other
- [base] jni.hpp @ 57ca9ed4bbeb22ed8d20a55063dcaa217ba47f42
## v1.6.0
### 💫️ Other
- [base] Update geojson.hpp to v5.1.0
- [base] Update geojson-vt-cpp to v6.6.4
- [ci] Rename master branch to main
- [weak] Introduce WeakPtrFactory::invalidateWeakPtrs()
- [weak] Fix possible WeakPtr locks after WeakPtrFactory gets invalid.
## v1.5.0
### 💫️ Other
- [base] Update geojson.hpp to v0.5.0
## v1.4.0
### ✨ New features
- [extras] Bump googletest to 1.10.0
- Better gmock syntax.
### ⚠️ Breaking changes
- [base] expected-lite @ v0.4.0
### 💫️ Other
- [doc] Add documentation for `mapbox::base::Value`
## v1.3.0
### ✨ New features
- [base] Add platform definitions
### ⚠️ Breaking changes
- [base] jni.hpp @ e2bbae090005ac1ce2a88c51c0cff2d22d957545
### 💫️ Other
- [build] Update LICENSE.thirdparty
## v1.2.1
### 💫️ Other
- Add `MAPBOX_BASE_BUILD_TESTING` option for overriding building tests when building outside of mapbox-base project.
## v1.2.0
### ✨ New features
- Update minimist dependency to v1.2.5
- [base] Added GeoJSON VT and ShelfPack
### ⚠️ Breaking changes
- Move mapbox-base-owned libraries to a single folder
- [base] cheap-ruler-cpp @ 746044cfbb7d254f1d67929eb564a0dcaaa39cc1
- [base] jni.hpp @ 385dede669c843144b9ad68bbb7af3989d76104e
- [base] geometry.hpp @ a5571a3ace5853e0d1e8d5fbdc87163c824ebeb7
### 💫️ Other
- Use googletest framework
## v1.1.0
### ✨ New features
Extras:
- extras/args @ 6.2.2-9-g401663c
- extras/expected-lite @ v0.3.0-6-g6fad61b
- extras/filesystem @ v1.2.4-7-g135015f
- extras/kdbush.hpp @ v0.1.3-1-ge1e847b
- extras/rapidjson @ v1.1.0-490-gd87b698d
New libraries:
- mapbox/io
- mapbox/typewrapper
- mapbox/value
- mapbox/weak
### ⚠️ Breaking changes
- mapbox/geojson.hpp @ v0.4.3
- mapbox/geometry.hpp @ v1.0.0-8-gb3f4bd4
- mapbox/jni.hpp @ v4.0.1
- mapbox/optional @ f6249e7f
- mapbox/supercluster.hpp @ v0.3.2-1-g03c026c
- mapbox/variant @ v1.1.6
## v1.0.0
### ✨ New features
- geometry.hpp @ v1.0.0
- variant @ v1.1.6

View File

@@ -0,0 +1,30 @@
if(TARGET maplibre-native-base)
return()
endif()
cmake_minimum_required(VERSION 3.5.1 FATAL_ERROR)
project(MAPBOX_BASE LANGUAGES CXX C)
option(MAPBOX_BASE_BUILD_TESTING "Bypass project target check and enforce building tests" OFF)
include(CTest)
cmake_policy(SET CMP0063 NEW)
if(NOT CMAKE_VERSION VERSION_LESS 3.13.0)
# Required to allow maplibre-native-base to depend on libraries coming from /deps
cmake_policy(SET CMP0079 NEW)
endif()
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
set(CMAKE_VISIBILITY_INLINES_HIDDEN 1)
add_subdirectory(${PROJECT_SOURCE_DIR}/extras)
add_subdirectory(${PROJECT_SOURCE_DIR}/include)
add_subdirectory(${PROJECT_SOURCE_DIR}/deps)
if ((CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME OR MAPBOX_BASE_BUILD_TESTING) AND BUILD_TESTING)
add_subdirectory(${PROJECT_SOURCE_DIR}/test)
endif()

26
vendor/maplibre-native-base/LICENSE vendored Normal file
View File

@@ -0,0 +1,26 @@
Copyright (c) 2022 MapLibre contributors
Copyright (c) MapBox
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
- Neither the name "MapBox" nor the names of its contributors may be
used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

9
vendor/maplibre-native-base/README.md vendored Normal file
View File

@@ -0,0 +1,9 @@
![MapLibre Logo](https://maplibre.org/img/maplibre-logo-big.svg)
# MapLibre Native Base C++ Libraries
maplibre-native-base
A collection of common static and header-only C++ libraries used among our native SDKs.
Part of the [Maplibre](https://maplibre.org) organization

View File

@@ -0,0 +1,28 @@
function(maplibre_native_base_add_library name include_path)
if(TARGET maplibre-native-base-${name})
return()
endif()
if(NOT EXISTS ${include_path} OR NOT IS_DIRECTORY ${include_path})
message(FATAL_ERROR "Dependency with include path '${include_path}' not found")
endif()
add_library(maplibre-native-base-${name} INTERFACE)
add_library(MapLibreNative::Base::${name} ALIAS maplibre-native-base-${name})
target_include_directories(maplibre-native-base-${name} SYSTEM INTERFACE
${include_path}
)
target_link_libraries(maplibre-native-base INTERFACE maplibre-native-base-${name})
endfunction()
maplibre_native_base_add_library(cheap-ruler-cpp ${CMAKE_CURRENT_LIST_DIR}/cheap-ruler-cpp/include)
maplibre_native_base_add_library(geojson-vt-cpp ${CMAKE_CURRENT_LIST_DIR}/geojson-vt-cpp/include)
maplibre_native_base_add_library(geojson.hpp ${CMAKE_CURRENT_LIST_DIR}/geojson.hpp/include)
maplibre_native_base_add_library(geometry.hpp ${CMAKE_CURRENT_LIST_DIR}/geometry.hpp/include)
maplibre_native_base_add_library(jni.hpp ${CMAKE_CURRENT_LIST_DIR}/jni.hpp/include)
maplibre_native_base_add_library(pixelmatch-cpp ${CMAKE_CURRENT_LIST_DIR}/pixelmatch-cpp/include)
maplibre_native_base_add_library(shelf-pack-cpp ${CMAKE_CURRENT_LIST_DIR}/shelf-pack-cpp/include)
maplibre_native_base_add_library(supercluster.hpp ${CMAKE_CURRENT_LIST_DIR}/supercluster.hpp/include)
maplibre_native_base_add_library(variant ${CMAKE_CURRENT_LIST_DIR}/variant/include)

View File

@@ -0,0 +1,338 @@
# mapbox::base values
*Value* offers a fast, flexible and uncomplicated way to build easy-to-use APIs where strong types are not required.
A mapbox::base::Value holds a value of a type. Supported types are `int`, `uint`, `bool`, `double`, `array`, `object` and `string`. The type and the value of a mapbox::base::Value [can change](#Type).
Values are used widely in Mapbox libraries, for instance when working with geometries or data in JSON format. They can be nested to create complex structures.
- [mapbox::base::Value](#Value)
- [mapbox::base::ValueArray](#ValueArray)
- [mapbox::base::ValueObject](#ValueObject)
- [Introspect Values](#Introspect-Values)
- [Example](#A-real-world-example)
## Value
```C++
mapbox::base::Value num(-20);
mapbox::base::Value pi(3.14159265359);
mapbox::base::Value name("John Smith");
mapbox::base::Value codingIsFun(true);
```
### get
Use `get<T>()` to get a copy.
```C++
double value = pi.get<double>();
```
It throws an exception if the type doesn't match the current type.
```C++
double value;
try {
value = pi.get<double>();
} catch (const std::exception& e) {
std::cout << "Error: " << e.what() << std::endl;
}
std::cout << value << std::endl;
```
If you don't want exceptions, use `get_unchecked<T>()`:
```C++
pi.get_unchecked<std::string>();
```
<!--
or
```C++
double value2 = *pi.getDouble();
std::cout << value << std::endl;
```
//-->
Get a pointer:
```C++
double* value = pi.getDouble();
std::cout << *value << std::endl;
```
outputs 3.14159265359
### set, update
```C++
pi = 0.456;
pi.set<double>(0.123);
std::cout << *pi.getDouble() << std::endl;
```
outputs 0.123
### Type
Assigning a value of an allowed type changes the type of the [mapbox::base::Value](#Value).
You can use `which()` to get the type index.
```C++
mapbox::base::Value val;
val = "a string";
std::cout << val.which() << std::endl;
val = 0.5;
std::cout << val.which() << std::endl;
```
output:
```
5
4
```
To ask for a specific type, use `is<T>()`:
```C++
std::cout << "is double: " << val.is<double>() << ", is string: " << val.is<std::string>() << std::endl;
```
```
is double: 1, is string: 0
```
Use `valid()` to see if the type index is within the allowed range.
## ValueArray
The ValueArray can hold an arbitrary number of [values](#Value) and is based on a [std::vector](https://en.cppreference.com/w/cpp/container/vector). You can use all its methods to work with the array.
```C++
mapbox::base::ValueArray array = {num, pi, name, codingIsFun};
```
or more programatically
```C++
array.push_back(num);
array.push_back(pi);
array.push_back(name);
array.push_back(codingIsFun);
```
Our array is: [-20,3.14159265359,"John Smith",true]
### get an item
```C++
mapbox::base::Value myValue = array[1];
double piV = myValue.get<double>();
std::cout << piV << std::endl;>>
```
### and insert
```C++
auto it = array.begin() + 2;
array.insert(it, "inserting a string");
```
array is now [-20,3.14159265359,"inserting a string","John Smith",true]
### update an item
```C++
array[1].set<double>(0.45);
```
array is now [-20,0.45,"inserting a string","John Smith",true]. Here we can also [change](#Type) the type and assign a value of a different type.
## ValueObject
The ValueObject holds key-value pairs and can be used to model structures similar to json objects.
It is based on an [std::unordered_map](https://de.cppreference.com/w/cpp/container/unordered_map)<std::string, [value](#value)>. You can use their methods to work with ValueObject.
```C++
mapbox::base::ValueObject object;
object.insert({"text-color", "yellow"});
```
### get an item:
```C++
mapbox::base::Value v = object["text-color"];
std::string color = *object["text-color"].getString();
std::cout << color << std::endl;
```
outputs yellow;
### update the value of an item:
```C++
object["text-color"].set<std::string>("green");
std::cout << object["text-color"].get<std::string>() << std::endl;
```
outputs green.
## Introspect Values
Lets assume you get a value from a component and want to peek inside to see whats 'in the box'.
We don't know beforehand how deep the value is nested. Therefor we want to recursively visit the values, and we can use `match()` for the types:
```C++
std::function<void(const mapbox::base::Value&)> visit = [&](const mapbox::base::Value& value) {
value.match([&](const mapbox::base::NullValue) {},
[&](const std::string& str) {},
[&](bool b) {},
[&](uint64_t u64) {},
[&](int64_t i64) {},
[&](double f64) {},
[&](const mapbox::base::ValueArray& array) {
for (const auto& v : array) {
visit(v);
}
},
[&](const mapbox::base::ValueObject& object) {
for (const auto& kv : object) {
visit(kv.second)
}
});
};
visit(value);
```
And now with a bit of extra code to output the value in a json-like fashion:
```C++
std::string toString(const mapbox::base::Value& value) {
std::stringstream buffer;
std::function<void(const mapbox::base::Value&, int)> visit = [&](const mapbox::base::Value& value, int depth) {
std::string indent = "";
for(int i = 0; i < depth; ++i) {
indent += " ";
}
value.match([&](const mapbox::base::NullValue) { buffer << indent << "nullptr"; },
[&](const std::string& str) { buffer << "\"" << str << "\""; },
[&](bool b) { buffer << b; },
[&](uint64_t u64) { buffer << indent << u64; },
[&](int64_t i64) { buffer << i64; },
[&](double f64) { buffer << f64; },
[&](const mapbox::base::ValueArray& array) {
buffer << indent << "[" << std::endl;
for (const auto& v : array) {
buffer << indent << " ";
visit(v, depth+1);
buffer << "," << std::endl;
}
if (array.size() > 1) buffer.seekp(-2, std::ios_base::end);
buffer << std::endl << indent << "]" << std::endl;
},
[&](const mapbox::base::ValueObject& object) {
buffer << indent << "{" << std::endl;
for (const auto& kv : object) {
buffer << indent << " " << kv.first << ": ";
visit(kv.second, depth+1);
buffer << "," << std::endl;
}
if (object.size() > 1) buffer.seekp(-2, std::ios_base::end);
buffer << std::endl << indent << "}" << std::endl;
});
};
visit(value, 0);
return buffer.str();
}
//! lets add our array to our object to create a nested structure:
object.insert({"list", array});
std::cout << toString(object) << std::endl;
```
outputs
```JSON
{
text-color: "green",
list: [
-20,
0.45,
"inserting a string",
"John Smith",
1
]
}
```
## A real world example
Let's assume you want to create a line gradient to be used in MapLibre Native. We can programatically construct the data structure as we would do it if the data comes from a backend data source:
```C++
using A = mapbox::base::ValueArray;
A lineGradient = {"interpolate", A{"linear"}, A{"line-progress"}};
lineGradient.push_back(0);
lineGradient.push_back("blue");
lineGradient.push_back(0.1);
lineGradient.push_back("royalblue");
lineGradient.push_back(0.3);
lineGradient.push_back("cyan");
lineGradient.push_back(0.5);
lineGradient.push_back("lime");
lineGradient.push_back(0.7);
lineGradient.push_back("yellow");
lineGradient.push_back(1);
lineGradient.push_back("red");
//! which we can now give to the map:
map->setStyleLayerProperty("my-line", "line-gradient", lineGradient);
std::cout << toString(lineGradient) << std::endl;
```
results in:
```JSON
[
"interpolate",
["linear"],
["line-progress"],
0,
"blue",
0.1,
"royalblue",
0.3,
"cyan",
0.5,
"lime",
0.7,
"yellow",
1,
"red"
]
```
See https://maplibre.org/maplibre-style-spec/layers/#line-gradient to learn more about line gradients.

View File

@@ -0,0 +1,27 @@
if(TARGET maplibre-native-base-extras)
return()
endif()
function(maplibre_native_base_extras_add_library name include_path)
if(TARGET maplibre-native-base-extras-${name})
return()
endif()
add_library(maplibre-native-base-extras-${name} INTERFACE)
add_library(MapLibreNative::Base::Extras::${name} ALIAS maplibre-native-base-extras-${name})
target_include_directories(maplibre-native-base-extras-${name} SYSTEM INTERFACE
${include_path}
)
target_link_libraries(maplibre-native-base-extras INTERFACE maplibre-native-base-extras-${name})
endfunction()
add_library(maplibre-native-base-extras INTERFACE)
add_library(MapLibreNative::Base::Extras ALIAS maplibre-native-base-extras)
maplibre_native_base_extras_add_library(args ${CMAKE_CURRENT_LIST_DIR}/args)
maplibre_native_base_extras_add_library(expected-lite ${CMAKE_CURRENT_LIST_DIR}/expected-lite/include)
maplibre_native_base_extras_add_library(kdbush.hpp ${CMAKE_CURRENT_LIST_DIR}/kdbush.hpp/include)
include(${PROJECT_SOURCE_DIR}/extras/rapidjson.cmake)

View File

@@ -0,0 +1,17 @@
add_library(gtest_all STATIC
${CMAKE_CURRENT_LIST_DIR}/googletest/googletest/src/gtest_main.cc
${CMAKE_CURRENT_LIST_DIR}/googletest/googletest/src/gtest-all.cc
${CMAKE_CURRENT_LIST_DIR}/googletest/googlemock/src/gmock-all.cc
)
target_include_directories(gtest_all PRIVATE
${CMAKE_CURRENT_LIST_DIR}/googletest/googletest
${CMAKE_CURRENT_LIST_DIR}/googletest/googletest/include
${CMAKE_CURRENT_LIST_DIR}/googletest/googlemock
${CMAKE_CURRENT_LIST_DIR}/googletest/googlemock/include
)
target_include_directories(gtest_all SYSTEM INTERFACE
${CMAKE_CURRENT_LIST_DIR}/googletest/googletest/include
${CMAKE_CURRENT_LIST_DIR}/googletest/googlemock/include
)

View File

@@ -0,0 +1,11 @@
maplibre_native_base_extras_add_library(rapidjson ${CMAKE_CURRENT_LIST_DIR}/rapidjson/include)
target_compile_definitions(maplibre-native-base-extras-rapidjson INTERFACE
RAPIDJSON_HAS_STDSTRING=1
)
if(WIN32)
target_compile_definitions(maplibre-native-base-extras-rapidjson INTERFACE
RAPIDJSON_HAS_CXX11_RVALUE_REFS
)
endif()

View File

@@ -0,0 +1,10 @@
add_library(maplibre-native-base INTERFACE)
add_library(MapLibreNative::Base ALIAS maplibre-native-base)
target_include_directories(maplibre-native-base SYSTEM INTERFACE
"${PROJECT_SOURCE_DIR}/include"
)
target_link_libraries(maplibre-native-base INTERFACE
MapLibreNative::Base::Extras::expected-lite
)

View File

@@ -0,0 +1,14 @@
#pragma once
#include <mapbox/feature.hpp>
namespace mapbox {
namespace base {
using Value = feature::value;
using ValueArray = Value::array_type;
using ValueObject = Value::object_type;
using NullValue = feature::null_value_t;
} // namespace base
} // namespace mapbox

View File

@@ -0,0 +1,57 @@
#pragma once
#include <fstream>
#include <sstream>
#include <string>
#include "mapbox/util/expected.hpp"
namespace mapbox {
namespace base {
namespace io {
using ErrorType = std::string;
inline expected<std::string, ErrorType> readFile(const std::string& filename) {
std::ifstream file(filename, std::ios::binary);
if (!file.good()) {
return make_unexpected(std::string("Failed to read file '") + filename + std::string("'"));
}
std::stringstream data;
data << file.rdbuf();
return expected<std::string, ErrorType>(data.str());
}
inline expected<void, ErrorType> writeFile(const std::string& filename, const std::string& data) {
std::ofstream file(filename, std::ios::binary);
if (!file.good()) {
return make_unexpected(std::string("Failed to write file '") + filename + std::string("'"));
}
file << data;
return expected<void, ErrorType>();
}
inline expected<void, ErrorType> deleteFile(const std::string& filename) {
const int ret = std::remove(filename.c_str());
if (ret != 0) {
return make_unexpected(std::string("Failed to delete file '") + filename + std::string("'"));
}
return expected<void, ErrorType>();
}
inline expected<void, ErrorType> copyFile(const std::string& sourcePath, const std::string& destinationPath) {
auto contents = readFile(sourcePath);
if (!contents) {
return nonstd::make_unexpected(contents.error());
}
return writeFile(destinationPath, *contents);
}
} // namespace io
} // namespace base
} // namespace mapbox

View File

@@ -0,0 +1,70 @@
#pragma once
// Determine compiler
#define MB_COMPILER 0
#define MB_COMPILER_GNU 1
#define MB_COMPILER_CLANG 2
#define MB_COMPILER_MSVC 3
#if defined(__clang__)
# define MB_COMPILER MB_COMPILER_CLANG
#elif defined(__GNUC__) || defined(__GNUG__) // after clang, possible it also has the same defines (need to research)
# define MB_COMPILER MB_COMPILER_GNU
#elif defined(_MSC_VER)
# define MB_COMPILER MB_COMPILER_MSVC
#else
# error "Unsupported compiler"
#endif
// Determine platform
#define MB_PLATFORM 0
#define MB_PLATFORM_WIN32 1
#define MB_PLATFORM_LINUX 2
#define MB_PLATFORM_MAC 3
#define MB_PLATFORM_IOS_EMBEDDED 4
#define MB_PLATFORM_IOS_SIMULATOR 5
#define MB_PLATFORM_ANDROID 6
#define MB_PLATFORM_QNX_NEUTRINO 7
#define MB_PLATFORM_QNX_4 8
#if (defined(__WIN32__) || defined(_WIN32)) && !defined(__ANDROID__)
# define MB_PLATFORM MB_PLATFORM_WIN32
#elif defined(__APPLE_CC__)
# include "TargetConditionals.h"
# if TARGET_OS_IOS && TARGET_OS_EMBEDDED
# define MB_PLATFORM MB_PLATFORM_IOS_EMBEDDED
# elif TARGET_OS_IOS && TARGET_OS_SIMULATOR
# define MB_PLATFORM MB_PLATFORM_IOS_SIMULATOR
# else
# define MB_PLATFORM MB_PLATFORM_MAC
# endif
#elif defined(__ANDROID__)
# define MB_PLATFORM MB_PLATFORM_ANDROID
#elif defined(__QNX__)
# if defined(__QNXNTO__)
# define MB_PLATFORM MB_PLATFORM_QNX_NEUTRINO
# else
# define MB_PLATFORM MB_PLATFORM_QNX_4
# endif
#else // let all other platform right now is a linux platforms
# define MB_PLATFORM MB_PLATFORM_LINUX
#endif
#define MB_PLATFORM_IS_WIN32 (MB_PLATFORM == MB_PLATFORM_WIN32)
#define MB_PLATFORM_IS_LINUX (MB_PLATFORM == MB_PLATFORM_LINUX)
#define MB_PLATFORM_IS_MAC (MB_PLATFORM == MB_PLATFORM_MAC)
#define MB_PLATFORM_IS_IOS_EMBEDDED (MB_PLATFORM == MB_PLATFORM_IOS_EMBEDDED)
#define MB_PLATFORM_IS_IOS_SIMULATOR (MB_PLATFORM == MB_PLATFORM_IOS_SIMULATOR)
#define MB_PLATFORM_IS_IOS (MB_PLATFORM_IS_IOS_EMBEDDED || MB_PLATFORM_IS_IOS_SIMULATOR)
#define MB_PLATFORM_IS_ANDROID (MB_PLATFORM == MB_PLATFORM_ANDROID)
#define MB_PLATFORM_IS_QNX_NEUTRINO (MB_PLATFORM == MB_PLATFORM_QNX_NEUTRINO)
#define MB_PLATFORM_IS_QNX_4 (MB_PLATFORM == MB_PLATFORM_QNX_4)
#define MB_PLATFORM_IS_QNX (MB_PLATFORM_IS_QNX_NEUTRINO || MB_PLATFORM_IS_QNX_4)
#define MB_PLATFORM_IS_DESKTOP (MB_PLATFORM_IS_LINUX || MB_PLATFORM_IS_MAC || MB_PLATFORM_IS_WIN32)
#ifdef NDEBUG
# define MB_IS_DEBUG 0
#else
# define MB_IS_DEBUG 1
#endif

View File

@@ -0,0 +1,384 @@
#pragma once
#include <algorithm>
#include <atomic>
#include <cassert>
#include <functional>
#include <memory>
#include <shared_mutex>
#include <thread>
#include <type_traits>
namespace mapbox {
namespace base {
/// @cond internal
namespace internal {
class WeakPtrSharedData {
public:
WeakPtrSharedData() = default;
void sharedLock() {
std::size_t noLocks = sharedLocks_;
std::size_t incremented;
do {
if (noLocks == kInvalidValue) return;
incremented = noLocks + 1;
// `compare_exchange_weak()` is invoked in a cycle to handle the case,
// if another thread has just modified `sharedLocks_` (so that it is not
// equal to `noLocks` any more). We early return, if `sharedLocks_` became
// equal to `kInvalidValue`.
} while (!sharedLocks_.compare_exchange_weak(noLocks, incremented));
}
void sharedUnlock() {
std::size_t noLocks = sharedLocks_;
std::size_t decremented;
do {
if (noLocks == kInvalidValue) return;
assert(noLocks > 0u);
decremented = noLocks - 1;
} while (!sharedLocks_.compare_exchange_weak(noLocks, decremented));
}
void invalidate() {
assert(valid());
std::size_t noLocks = 0u;
while (!sharedLocks_.compare_exchange_weak(noLocks, kInvalidValue)) {
assert(noLocks != kInvalidValue);
noLocks = 0u;
}
assert(!valid());
}
bool valid() const { return sharedLocks_ != kInvalidValue; }
private:
static constexpr size_t kInvalidValue = std::numeric_limits<std::size_t>::max();
std::atomic_size_t sharedLocks_{0u};
};
using StrongRef = std::shared_ptr<WeakPtrSharedData>;
using WeakRef = std::weak_ptr<WeakPtrSharedData>;
template <typename T>
class WeakPtrBase;
} // namespace internal
/// @endcond
/**
* @brief Scope guard for the WeakPtr-wrapped object
*
* The WeakPtr-wrapped object is guaranteed not to be deleted while
* a WeakPtrGuard instance is present in the scope.
*/
class WeakPtrGuard {
public:
/**
* @brief Default move constructor
*/
WeakPtrGuard(WeakPtrGuard&&) noexcept = default;
~WeakPtrGuard() {
if (strong_) {
strong_->sharedUnlock();
}
}
private:
explicit WeakPtrGuard(internal::StrongRef strong) : strong_(std::move(strong)) {
assert(!strong_ || strong_->valid());
}
internal::StrongRef strong_;
template <typename T>
friend class internal::WeakPtrBase;
};
namespace internal {
/**
* @brief Base type for \c WeakPtr class.
*
* Contains the generic API for weak pointer classes.
*
* This class helps to create a \c WeakPtr template specialization for a
* certain type, enabling the type-specific semantics.
*
* \sa WeakPtr
*
* @tparam T the managed object type
*/
template <typename T>
class WeakPtrBase {
public:
/**
* Gets a lock that protects the managed object, giving
* the guarantee that it will not be deleted (if not
* deleted yet).
*
* Note that it won't make the managed object thread-safe, but
* rather make sure it exists (or not) when the lock
* is being held.
*
* Note: there *MUST* be only one instance of the
* guard referring to the same \a WeakPtrFactory
* available in the scope at a time.
*/
WeakPtrGuard lock() const {
if (StrongRef strong = weak_.lock()) {
strong->sharedLock();
if (strong->valid()) {
return WeakPtrGuard(std::move(strong));
}
strong->sharedUnlock();
}
return WeakPtrGuard(nullptr);
}
/**
* @brief Quick nonblocking check that the managed object still exists.
*
* Checks if the weak pointer is still pointing to a valid
* object. Note that if the WeakPtrFactory lives in a different
* thread, a `false` result cannot be guaranteed to be
* correct since there is an implicit race condition,
* but a `true` result is always correct.
*
* @return given the thread restrictions, true if expired,
* false otherwise.
*/
bool expired() const {
if (StrongRef strong = weak_.lock()) {
return !strong->valid();
}
return true;
}
/**
* @brief Quick nonblocking check that the managed object still exists.
*
* \sa expired()
*
* @return given the thread restrictions, true if the object exists,
* false otherwise.
*/
explicit operator bool() const { return !expired(); }
/**
* Get a raw pointer to the managed object.
*
* In multi-threaded environment, the caller *MUST* call
* lock() and keep locker, before using it.
*
* Usage should be as brief as possible, because it might
* potentially block the thread where the managed object lives.
*
* @return pointer to the object, nullptr if expired.
*/
T* get() const {
if (StrongRef strong = weak_.lock()) {
if (strong->valid()) {
return ptr_;
}
}
return nullptr;
}
protected:
/// @cond internal
WeakPtrBase() = default;
WeakPtrBase(WeakPtrBase&&) noexcept = default;
WeakPtrBase(const WeakPtrBase&) noexcept = default;
template <typename U> // NOLINTNEXTLINE
WeakPtrBase(WeakPtrBase<U>&& other) noexcept : weak_(std::move(other.weak_)), ptr_(static_cast<T*>(other.ptr_)) {}
explicit WeakPtrBase(WeakRef weak, T* ptr) : weak_(std::move(weak)), ptr_(ptr) { assert(ptr_); }
WeakPtrBase& operator=(WeakPtrBase&& other) noexcept = default;
WeakPtrBase& operator=(const WeakPtrBase& other) = default;
~WeakPtrBase() = default;
private:
WeakRef weak_;
T* ptr_{};
template <typename U>
friend class WeakPtrBase;
/// @endcond
};
} // namespace internal
/**
* @brief Default implementation of a weak pointer to an object.
*
* Weak pointers are safe to access even if the
* pointer outlives the object, which this class wraps.
*
* This class will manage only object lifetime
* but will not deal with thread-safeness of the
* objects it is wrapping.
*/
template <typename T>
class WeakPtr final : public internal::WeakPtrBase<T> {
public:
/**
* @brief Default constructor.
*
* Constructs empty \c WeakPtr.
*/
WeakPtr() = default;
/**
* @brief Converting move constructor
*
* \a other becomes empty after the call.
*
* @tparam U a type, which \c T is convertible to
* @param other \c WeakPtr<U> instance
*/
template <typename U> // NOLINTNEXTLINE
WeakPtr(WeakPtr<U>&& other) noexcept : internal::WeakPtrBase<T>(std::move(other)) {}
/**
* @brief Default move constructor.
*/
WeakPtr(WeakPtr&&) noexcept = default;
/**
* @brief Default copy constructor.
*/
WeakPtr(const WeakPtr&) noexcept = default;
/**
* @brief Replaces the managed object with the one managed by \a other.
*
* \a other becomes empty after the call.
*
* @param other
* @return WeakPtr& \c *this
*/
WeakPtr& operator=(WeakPtr&& other) noexcept = default;
/**
* @brief Replaces the managed object with the one managed by \a other.
*
* @param other
* @return WeakPtr& \c *this
*/
WeakPtr& operator=(const WeakPtr& other) = default;
/**
* @brief Dereferences the stored pointer.
*
* Must not be called on empty \c WeakPtr.
*
* @return T* the stored pointer.
*/
T* operator->() const {
T* ptr = this->get();
assert(ptr);
return ptr;
}
private:
explicit WeakPtr(internal::WeakRef weak, T* object) : internal::WeakPtrBase<T>(std::move(weak), object) {}
template <typename U>
friend class WeakPtrFactory;
};
/**
* @brief T wrapper that can create weak pointers.
*
* WARNING: the WeakPtrFactory should all be at the bottom of
* the list of member of the class, making it the first to
* be destroyed and the last to be initialized.
*/
template <typename T>
class WeakPtrFactory final {
public:
WeakPtrFactory(const WeakPtrFactory&) = delete;
WeakPtrFactory& operator=(const WeakPtrFactory&) = delete;
/**
* @brief Construct a new \c WeakPtrFactory object.
*
* @param obj an \c T instance to wrap.
*/
explicit WeakPtrFactory(T* obj) : strong_(std::make_shared<internal::WeakPtrSharedData>()), obj_(obj) {}
/**
* Destroys the factory, invalidating all the
* weak pointers to this object, i.e. makes them empty.
*/
~WeakPtrFactory() { invalidateWeakPtrs(); }
/**
* Make a weak pointer for this WeakPtrFactory. Weak pointer
* can be used for safely accessing the T object and not worry
* about lifetime.
*
* @return a weak pointer.
*/
WeakPtr<T> makeWeakPtr() { return WeakPtr<T>{strong_, obj_}; }
/**
* @brief Makes a weak wrapper for calling a method on the wrapped
* \c T instance.
*
* While the wrapped \c T instance exists, calling the returned wrapper is
* equivalent to invoking \a method on the instance. Note that the instance deletion
* is blocked during the wrapper call.
*
* If the wrapped \c T instance does not exist, calling the returned wrapper
* is ignored.
*
* The example below illustrates creating an \c std::function instance from the
* returned wrapper.
*
* \code
* class T {
* void foo(int);
* std::function<void(int)> makeWeakFoo() {
* return weakFactory.makeWeakMethod(&T::foo);
* }
* mapbox::base::WeakPtrFactory<T> weakFactory{this};
* };
* \endcode
*
* @param method Pointer to an \c T class method.
* @return auto Callable object
*/
template <typename Method>
auto makeWeakMethod(Method method) {
return [weakPtr = makeWeakPtr(), method](auto&&... params) mutable {
WeakPtrGuard guard = weakPtr.lock();
if (T* obj = weakPtr.get()) {
(obj->*method)(std::forward<decltype(params)>(params)...);
}
};
}
/**
* @brief Invalidates all existing weak pointers.
*
* This method is particularly useful, when \c T class has a user-defined destructor,
* that makes the wrapped instance invalid even before entering the \c WeakPtrFactory
* destructor.
* In this case, clients *MUST* explicitly call \c invalidateWeakPtrs() before freeing any resources.
*
* Note: After \c invalidateWeakPtrs() is called, \c makeWeakPtr() returns empty weak pointers.
*/
void invalidateWeakPtrs() {
if (strong_) strong_->invalidate();
strong_.reset();
}
private:
internal::StrongRef strong_;
T* obj_;
};
} // namespace base
} // namespace mapbox

View File

@@ -0,0 +1,17 @@
#pragma once
#include <nonstd/expected.hpp>
namespace mapbox {
namespace base {
template <typename T, typename E>
using expected = nonstd::expected<T, E>;
template <typename E>
auto make_unexpected(E&& value) {
return nonstd::make_unexpected<E>(std::move(value));
}
} // namespace base
} // namespace mapbox

View File

@@ -0,0 +1,41 @@
#pragma once
#include <memory>
#include <type_traits>
#include <utility>
namespace mapbox {
namespace base {
class TypeWrapper {
public:
TypeWrapper() noexcept : storage_(nullptr, noop_deleter) {}
TypeWrapper(TypeWrapper&&) noexcept = default;
TypeWrapper& operator=(TypeWrapper&&) noexcept = default;
template <typename T> // NOLINTNEXTLINE misc-forwarding-reference-overload
TypeWrapper(T&& value) noexcept
: storage_(new std::decay_t<T>(std::forward<T>(value)), cast_deleter<std::decay_t<T>>) {
static_assert(!std::is_same<TypeWrapper, std::decay_t<T>>::value, "TypeWrapper must not wrap itself.");
}
bool has_value() const noexcept { return static_cast<bool>(storage_); }
template <typename T>
T& get() noexcept { // NOLINTNEXTLINE cppcoreguidelines-pro-type-reinterpret-cast
return *reinterpret_cast<T*>(storage_.get());
}
private:
template <typename T>
static void cast_deleter(void* ptr) noexcept {
delete reinterpret_cast<T*>(ptr); // NOLINT cppcoreguidelines-pro-type-reinterpret-cast
}
static void noop_deleter(void*) noexcept {}
using storage_t = std::unique_ptr<void, void (*)(void*)>;
storage_t storage_;
};
} // namespace base
} // namespace mapbox

View File

@@ -0,0 +1 @@
test_defines.hpp

View File

@@ -0,0 +1,31 @@
include(${PROJECT_SOURCE_DIR}/extras/googletest.cmake)
set(TEST_BINARY_PATH ${CMAKE_CURRENT_BINARY_DIR})
configure_file(${PROJECT_SOURCE_DIR}/test/test_defines.hpp.in ${PROJECT_BINARY_DIR}/test_defines.hpp)
function(create_test folder_name)
set (target_name "test_${folder_name}")
set (curr_folder "${PROJECT_SOURCE_DIR}/test/${folder_name}")
file (GLOB_RECURSE test_files "${curr_folder}/*.cpp" "${curr_folder}/*.hpp")
message (STATUS "Adding test ${target_name}")
add_executable(${target_name} ${test_files})
target_link_libraries(${target_name} PRIVATE
MapLibreNative::Base
gtest_all
pthread
)
target_include_directories(${target_name} PRIVATE
${curr_folder}
${PROJECT_BINARY_DIR}
)
add_test(NAME ${target_name} COMMAND ${target_name} ${TEST_ARGUMENTS})
endfunction()
create_test("compatibility")
create_test("io")
create_test("std")
create_test("util")

View File

@@ -0,0 +1,20 @@
#include "mapbox/compatibility/value.hpp"
#include <gtest/gtest.h>
template <typename T>
void unused(T&&) {}
TEST(Compatibility, Dummy) {
mapbox::base::Value v;
EXPECT_FALSE(bool(v));
mapbox::base::ValueArray va;
EXPECT_EQ(va.size(), 0);
mapbox::base::ValueObject vo;
EXPECT_EQ(vo.size(), 0);
mapbox::base::NullValue nv;
unused(nv);
}

View File

@@ -0,0 +1 @@
Hello, World!

View File

@@ -0,0 +1,49 @@
#include "mapbox/io/io.hpp"
#include <gtest/gtest.h>
#include <cassert>
#include <string>
#include "io_delete.hpp"
#include "mapbox/util/expected.hpp"
#include "test_defines.hpp"
TEST(io, ReadWriteFiles) {
const std::string path(std::string(TEST_BINARY_PATH) + "/foo.txt");
const std::string copyPath(std::string(TEST_BINARY_PATH) + "/bar.txt");
const std::string invalidPath("invalid");
const std::string unauthorizedPath("/root/unauthorized");
const std::string bar("bar");
mapbox::base::expected<void, std::string> voidExpected = mapbox::base::io::writeFile(path, bar);
EXPECT_TRUE(voidExpected);
voidExpected = mapbox::base::io::writeFile(unauthorizedPath, bar);
EXPECT_FALSE(voidExpected);
EXPECT_EQ(voidExpected.error(), std::string("Failed to write file '/root/unauthorized'"));
nonstd::expected<std::string, std::string> stringExpected = mapbox::base::io::readFile(path);
EXPECT_TRUE(stringExpected);
EXPECT_EQ(*stringExpected, bar);
stringExpected = mapbox::base::io::readFile(invalidPath);
EXPECT_FALSE(stringExpected);
EXPECT_EQ(stringExpected.error(), std::string("Failed to read file 'invalid'"));
voidExpected = mapbox::base::io::copyFile(path, copyPath);
EXPECT_TRUE(voidExpected);
stringExpected = mapbox::base::io::readFile(copyPath);
EXPECT_EQ(*stringExpected, bar);
voidExpected = mapbox::base::io::copyFile(path, unauthorizedPath);
EXPECT_FALSE(voidExpected);
EXPECT_EQ(voidExpected.error(), std::string("Failed to write file '/root/unauthorized'"));
voidExpected = mapbox::base::io::copyFile(invalidPath, path);
EXPECT_FALSE(voidExpected);
EXPECT_EQ(voidExpected.error(), std::string("Failed to read file 'invalid'"));
deleteTests(path, copyPath, invalidPath);
}

View File

@@ -0,0 +1,21 @@
#include "io_delete.hpp"
#include <gtest/gtest.h>
#include <cassert>
#include <mapbox/io/io.hpp>
#include <string>
void deleteTests(const std::string& path, const std::string& copyPath, const std::string& invalidPath) {
nonstd::expected<void, std::string> voidExpected;
voidExpected = mapbox::base::io::deleteFile(path);
EXPECT_TRUE(voidExpected);
voidExpected = mapbox::base::io::deleteFile(copyPath);
EXPECT_TRUE(voidExpected);
voidExpected = mapbox::base::io::deleteFile(invalidPath);
EXPECT_FALSE(voidExpected);
EXPECT_EQ(voidExpected.error(), std::string("Failed to delete file 'invalid'"));
}

View File

@@ -0,0 +1,5 @@
#pragma once
#include <string>
void deleteTests(const std::string& path, const std::string& copyPath, const std::string& invalidPath);

View File

@@ -0,0 +1,202 @@
#include "mapbox/std/weak.hpp"
#include <gtest/gtest.h>
#include <atomic>
#include <chrono>
#include <ctime>
#include <memory>
#include <thread>
#include <vector>
TEST(WeakPtr, Lock) {
using namespace std::chrono_literals;
static std::atomic_int g_i;
struct TestLock {
void inc() { ++g_i; }
mapbox::base::WeakPtrFactory<TestLock> factory_{this};
};
auto t = std::make_unique<TestLock>();
auto weak1 = t->factory_.makeWeakPtr();
auto weak2 = t->factory_.makeWeakPtr();
auto weak3 = weak2;
std::thread thread1([&] {
auto guard = weak1.lock();
std::this_thread::sleep_for(150ms);
weak1->inc();
});
std::thread thread2([&] {
auto guard = weak2.lock();
std::this_thread::sleep_for(200ms);
weak2->inc();
});
{
auto guard = weak3.lock();
std::this_thread::sleep_for(50ms);
weak3->inc();
}
EXPECT_FALSE(weak1.expired());
EXPECT_FALSE(weak2.expired());
EXPECT_TRUE(weak1);
EXPECT_TRUE(weak2);
ASSERT_NO_THROW(t.reset()); // Should not crash.
thread1.join();
thread2.join();
EXPECT_TRUE(weak1.expired());
EXPECT_TRUE(weak2.expired());
EXPECT_FALSE(weak1);
EXPECT_FALSE(weak2);
EXPECT_EQ(g_i, 3);
}
TEST(WeakPtr, InvalidateWeakPtrs) {
using namespace std::chrono_literals;
static std::atomic_int g_i;
struct TestLock {
void inc() { ++g_i; }
mapbox::base::WeakPtrFactory<TestLock> factory_{this};
};
auto t = std::make_unique<TestLock>();
auto weak1 = t->factory_.makeWeakPtr();
auto weak2 = t->factory_.makeWeakPtr();
auto weak3 = weak2;
std::thread thread1([&] {
auto guard = weak1.lock();
std::this_thread::sleep_for(150ms);
weak1->inc();
});
std::thread thread2([&] {
auto guard = weak2.lock();
std::this_thread::sleep_for(200ms);
weak2->inc();
});
{
auto guard = weak3.lock();
std::this_thread::sleep_for(50ms);
weak3->inc();
}
EXPECT_TRUE(weak1);
EXPECT_TRUE(weak2);
EXPECT_TRUE(weak3);
t->factory_.invalidateWeakPtrs();
// All the existing weak pointer have expired.
EXPECT_FALSE(weak3);
thread1.join();
thread2.join();
EXPECT_FALSE(weak1);
EXPECT_FALSE(weak2);
EXPECT_EQ(g_i, 3);
// The newly created one is empty.
auto weak4 = t->factory_.makeWeakPtr();
EXPECT_FALSE(weak4);
}
TEST(WeakPtr, MultipleLock) {
using namespace std::chrono_literals;
using std::chrono::system_clock;
static std::atomic_int g_i;
struct TestLock {
void inc() { ++g_i; }
mapbox::base::WeakPtrFactory<TestLock> factory_{this};
};
std::time_t now = system_clock::to_time_t(system_clock::now());
struct std::tm* tm = std::localtime(&now);
++tm->tm_sec; // Wait for the next second.
auto nextSecond = system_clock::from_time_t(mktime(tm));
auto t = std::make_unique<TestLock>();
const size_t threadsCount = 50u;
std::vector<std::thread> threads;
threads.reserve(threadsCount);
for (size_t i = 0; i < threadsCount; ++i) {
std::thread thread([nextSecond, weak = t->factory_.makeWeakPtr()] {
auto guard = weak.lock();
std::this_thread::sleep_until(nextSecond);
weak->inc();
});
threads.emplace_back(std::move(thread));
}
t.reset();
for (auto& thread : threads) {
thread.join();
}
EXPECT_EQ(g_i, threadsCount);
}
TEST(WeakPtr, WeakMethod) {
using namespace std::chrono_literals;
static std::atomic_int g_i;
class Test {
public:
void increaseGlobal(int delta) { g_i += delta; }
std::function<void(int)> makeWeakIncreaseGlobal() { return factory_.makeWeakMethod(&Test::increaseGlobal); }
private:
mapbox::base::WeakPtrFactory<Test> factory_{this};
};
auto t = std::make_unique<Test>();
std::function<void(int)> weak1 = t->makeWeakIncreaseGlobal();
std::function<void(int)> weak2 = t->makeWeakIncreaseGlobal();
std::function<void(int)> weak3 = weak2;
std::thread thread1([&] { weak1(1); });
std::thread thread2([&] { weak2(10); });
std::this_thread::sleep_for(50ms);
weak3(100);
t.reset(); // Should not crash.
// The following calls are ignored.
weak1(1);
weak2(2);
weak3(3);
thread1.join();
thread2.join();
EXPECT_EQ(g_i, 111);
}
TEST(WeakPtr, WeakMethodBlock) {
// NOLINTNEXTLINE(google-build-using-namespace)
using namespace std::chrono;
using namespace std::chrono_literals;
static std::atomic_bool g_call_finished{false};
struct Test {
void block(decltype(1ms) duration) {
std::this_thread::sleep_for(duration);
g_call_finished = true;
}
mapbox::base::WeakPtrFactory<Test> factory_{this};
};
auto t = std::make_unique<Test>();
auto weak = t->factory_.makeWeakMethod(&Test::block);
auto first = high_resolution_clock::now();
std::thread thread([&] { weak(100ms); });
std::this_thread::sleep_for(10ms);
t.reset(); // Deletion is blocked until weak(100ms) call returns.
thread.join();
auto totalTime = duration_cast<milliseconds>(high_resolution_clock::now() - first);
EXPECT_TRUE(g_call_finished);
EXPECT_GE(totalTime, 100ms);
}

View File

@@ -0,0 +1 @@
#define TEST_BINARY_PATH "${TEST_BINARY_PATH}"

View File

@@ -0,0 +1,174 @@
#include "mapbox/util/type_wrapper.hpp"
#include <gtest/gtest.h>
using mapbox::base::TypeWrapper;
namespace {
class TestType {
public:
TestType() { str[0] = 'a'; }
// Detect moves
TestType(TestType&& t) noexcept : i1(t.i1 + 1), i2(t.i2 + 2) { str[0] = t.str[0] + 1; }
TestType(const TestType&) = delete;
TestType& operator=(const TestType&) = delete;
int i1 = 0;
int i2 = 1;
char str[256] = {};
};
} // namespace
TEST(TypeWrapper, Empty) {
EXPECT_FALSE(TypeWrapper().has_value());
}
TEST(TypeWrapper, BasicTypes) {
TypeWrapper i = 3;
EXPECT_TRUE(i.has_value());
EXPECT_EQ(i.get<decltype(3)>(), 3);
auto iValue = i.get<decltype(3)>();
EXPECT_EQ(iValue, 3);
EXPECT_TRUE(TypeWrapper(4).has_value());
EXPECT_EQ(TypeWrapper(4).get<decltype(4)>(), 4);
TypeWrapper f = 6.2f;
EXPECT_TRUE(f.has_value());
EXPECT_EQ(f.get<decltype(6.2f)>(), 6.2f);
const float fValue = f.get<decltype(6.2f)>();
EXPECT_EQ(fValue, 6.2f);
EXPECT_TRUE(TypeWrapper(1.0f).has_value());
EXPECT_EQ(TypeWrapper(1.0f).get<decltype(1.0f)>(), 1.0f);
TypeWrapper c = 'z';
EXPECT_TRUE(c.has_value());
EXPECT_EQ(c.get<decltype('z')>(), 'z');
EXPECT_TRUE(TypeWrapper('z').has_value());
EXPECT_EQ(TypeWrapper('z').get<decltype('z')>(), 'z');
}
TEST(TypeWrapper, TypesMove) {
TypeWrapper i = 3;
EXPECT_TRUE(i.has_value());
TypeWrapper f = 6.2f;
EXPECT_TRUE(f.has_value());
f = std::move(i);
EXPECT_FALSE(i.has_value()); // NOLINT(bugprone-use-after-move)
EXPECT_TRUE(f.has_value());
EXPECT_EQ(f.get<decltype(3)>(), 3);
}
TEST(TypeWrapper, SmallType) {
struct T {
explicit T(int32_t* p_) : p(p_) { (*p)++; }
T(T&& t) noexcept : p(t.p) { (*p)++; }
~T() { (*p)--; }
T(const T&) = delete;
T& operator=(const T&) = delete;
int32_t* p;
};
int32_t p = 0;
{
TypeWrapper u1 = TypeWrapper(T(&p));
EXPECT_EQ(p, 1);
auto u2(std::move(u1));
EXPECT_EQ(p, 1);
}
EXPECT_EQ(p, 0);
}
TEST(TypeWrapper, LargeType) {
TestType t1;
TypeWrapper u1 = TypeWrapper(std::move(t1));
EXPECT_TRUE(u1.has_value());
// TestType should be moved into owning TypeWrapper
EXPECT_EQ(u1.get<TestType>().i1, 1);
auto u2(std::move(u1));
EXPECT_FALSE(u1.has_value()); // NOLINT(bugprone-use-after-move)
// TestType should not be moved when owning TypeWrapper is moved;
EXPECT_EQ(u2.get<TestType>().i1, 1);
// TestType should not be moved out of owning TypeWrapper
auto& t2 = u2.get<TestType>();
EXPECT_TRUE(u2.has_value());
EXPECT_EQ(t2.i1, 1);
}
TEST(TypeWrapper, Pointer) {
auto* t1 = new TestType(); // NOLINT cppcoreguidelines-owning-memory
auto u1 = TypeWrapper(t1);
EXPECT_TRUE(u1.has_value());
// Only the pointer should be moved
TestType* t2 = u1.get<TestType*>(); // NOLINT cppcoreguidelines-owning-memory
EXPECT_EQ(t2->i1, 0);
TypeWrapper u2(4);
std::swap(u2, u1);
EXPECT_TRUE(u1.has_value());
EXPECT_TRUE(u2.has_value());
t2 = u2.get<TestType*>();
EXPECT_EQ(t2->i1, 0);
delete t2; // NOLINT cppcoreguidelines-owning-memory
}
TEST(TypeWrapper, UniquePtr) {
auto t1 = std::make_unique<TestType>();
auto u1 = TypeWrapper(std::move(t1));
EXPECT_EQ(t1, nullptr);
EXPECT_TRUE(u1.has_value());
u1 = TypeWrapper();
EXPECT_FALSE(u1.has_value());
TypeWrapper u2;
auto* t3 = new TestType(); // NOLINT cppcoreguidelines-owning-memory
u2 = std::unique_ptr<TestType>(t3);
EXPECT_TRUE(u2.has_value());
}
TEST(TypeWrapper, SharedPtr) {
std::shared_ptr<int> shared(new int(3));
std::weak_ptr<int> weak = shared;
TypeWrapper u1 = 0;
EXPECT_EQ(weak.use_count(), 1);
TypeWrapper u2 = shared;
EXPECT_EQ(weak.use_count(), 2);
u1 = std::move(u2);
EXPECT_EQ(weak.use_count(), 2);
std::swap(u2, u1);
EXPECT_EQ(weak.use_count(), 2);
u2 = 0;
EXPECT_EQ(weak.use_count(), 1);
shared = nullptr;
EXPECT_EQ(weak.use_count(), 0);
}