Merged mapbox-gl-native
This commit is contained in:
11
mapbox-gl-native/.clang-format
Normal file
11
mapbox-gl-native/.clang-format
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
Language: Cpp
|
||||
BasedOnStyle: Google
|
||||
AccessModifierOffset: -4
|
||||
AllowShortFunctionsOnASingleLine: Inline
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
ColumnLimit: 120
|
||||
IndentWidth: 4
|
||||
SpacesBeforeTrailingComments: 1
|
||||
...
|
||||
42
mapbox-gl-native/.clang-tidy
Normal file
42
mapbox-gl-native/.clang-tidy
Normal file
@@ -0,0 +1,42 @@
|
||||
Checks: >
|
||||
-*,
|
||||
android-*,
|
||||
boost-*,
|
||||
bugprone-*,
|
||||
clang-analyzer-core*
|
||||
clang-analyzer-cplusplus*,
|
||||
clang-analyzer-deadcode*,
|
||||
clang-analyzer-optin.cplusplus*,
|
||||
clang-analyzer-optin.performance.Padding,
|
||||
clang-analyzer-security*,
|
||||
clang-diagnostic-*,
|
||||
google-*,
|
||||
misc-*,
|
||||
modernize-*,
|
||||
performance-*,
|
||||
portability-*,
|
||||
readability-*,
|
||||
-bugprone-macro-parentheses,
|
||||
-bugprone-narrowing-conversions,
|
||||
-google-build-using-namespace,
|
||||
-google-explicit-constructor,
|
||||
-google-readability-braces-around-statements,
|
||||
-google-readability-todo,
|
||||
-google-runtime-int,
|
||||
-google-runtime-references,
|
||||
-misc-non-private-member-variables-in-classes,
|
||||
-modernize-avoid-c-arrays,
|
||||
-readability-braces-around-statements,
|
||||
-readability-else-after-return,
|
||||
-readability-implicit-bool-conversion,
|
||||
-readability-magic-numbers,
|
||||
-readability-named-parameter,
|
||||
-readability-uppercase-literal-suffix
|
||||
|
||||
WarningsAsErrors: '*'
|
||||
HeaderFilterRegex: '.*'
|
||||
FormatStyle: file
|
||||
|
||||
CheckOptions:
|
||||
- key: performance-unnecessary-value-param.AllowedTypes
|
||||
value: 'exception_ptr'
|
||||
103
mapbox-gl-native/.cmake-format
Normal file
103
mapbox-gl-native/.cmake-format
Normal file
@@ -0,0 +1,103 @@
|
||||
|
||||
# --------------------------
|
||||
# General Formatting Options
|
||||
# --------------------------
|
||||
# How wide to allow formatted cmake files
|
||||
line_width = 140
|
||||
|
||||
# How many spaces to tab for indent
|
||||
tab_size = 4
|
||||
|
||||
# If arglists are longer than this, break them always
|
||||
max_subargs_per_line = 3
|
||||
|
||||
# If true, separate flow control names from their parentheses with a space
|
||||
separate_ctrl_name_with_space = False
|
||||
|
||||
# If true, separate function names from parentheses with a space
|
||||
separate_fn_name_with_space = False
|
||||
|
||||
# If a statement is wrapped to more than one line, than dangle the closing
|
||||
# parenthesis on it's own line
|
||||
dangle_parens = True
|
||||
|
||||
# If the statement spelling length (including space and parenthesis is larger
|
||||
# than the tab width by more than this amoung, then force reject un-nested
|
||||
# layouts.
|
||||
max_prefix_chars = 2
|
||||
|
||||
# If a candidate layout is wrapped horizontally but it exceeds this many lines,
|
||||
# then reject the layout.
|
||||
max_lines_hwrap = 8
|
||||
|
||||
# What style line endings to use in the output.
|
||||
line_ending = u'unix'
|
||||
|
||||
# Format command names consistently as 'lower' or 'upper' case
|
||||
command_case = u'canonical'
|
||||
|
||||
# Format keywords consistently as 'lower' or 'upper' case
|
||||
keyword_case = u'unchanged'
|
||||
|
||||
# Specify structure for custom cmake functions
|
||||
additional_commands = {
|
||||
"add_node_module": {
|
||||
"kwargs": {
|
||||
"INSTALL_PATH": "*",
|
||||
"NAN_VERSION": "*",
|
||||
"EXCLUDE_NODE_ABIS": "*"
|
||||
}
|
||||
},
|
||||
"target_compile_definitions": {
|
||||
"kwargs": {
|
||||
"PRIVATE": "*",
|
||||
"PUBLIC": "*"
|
||||
}
|
||||
},
|
||||
"set_target_properties": {
|
||||
"kwargs": {
|
||||
"PROPERTIES": {
|
||||
"kwargs": {
|
||||
"INTERFACE_MAPBOX_NAME": "*",
|
||||
"INTERFACE_MAPBOX_URL": "*",
|
||||
"INTERFACE_MAPBOX_AUTHOR": "*",
|
||||
"INTERFACE_MAPBOX_LICENSE": "*"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"target_sources": {
|
||||
"kwargs": {
|
||||
"INTERFACE": "*",
|
||||
"PRIVATE": "*",
|
||||
"PUBLIC": "*"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# A list of command names which should always be wrapped
|
||||
always_wrap = [
|
||||
"add_executable",
|
||||
"add_library",
|
||||
"set_source_files_properties",
|
||||
"target_compile_definitions",
|
||||
"target_include_directories",
|
||||
"target_link_libraries",
|
||||
"target_sources"
|
||||
]
|
||||
|
||||
# Specify the order of wrapping algorithms during successive reflow attempts
|
||||
algorithm_order = [0, 1, 2, 3, 4]
|
||||
|
||||
# If true, the argument lists which are known to be sortable will be sorted
|
||||
# lexicographicall
|
||||
enable_sort = True
|
||||
|
||||
# If true, the parsers may infer whether or not an argument list is sortable
|
||||
# (without annotation).
|
||||
autosort = True
|
||||
|
||||
# If a comment line starts with at least this many consecutive hash characters,
|
||||
# then don't lstrip() them off. This allows for lazy hash rulers where the first
|
||||
# hash char is not separated by space
|
||||
hashruler_min_length = 10
|
||||
6
mapbox-gl-native/.github/CODEOWNERS
vendored
Normal file
6
mapbox-gl-native/.github/CODEOWNERS
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
* @mapbox/gl-native
|
||||
|
||||
# Apple
|
||||
/platform/ios/ @mapbox/maps-ios-reviewers
|
||||
/platform/macos/ @mapbox/maps-ios-reviewers
|
||||
/platform/darwin/ @mapbox/maps-ios-reviewers
|
||||
34
mapbox-gl-native/.github/ISSUE_TEMPLATE/darwin.md
vendored
Normal file
34
mapbox-gl-native/.github/ISSUE_TEMPLATE/darwin.md
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
---
|
||||
name: iOS or macOS
|
||||
about: Mapbox Maps SDK for iOS or macOS
|
||||
|
||||
---
|
||||
<!--
|
||||
Hello and thanks for contributing to the Mapbox Maps SDKs for iOS and macOS! To help us diagnose your problem quickly, please:
|
||||
|
||||
- Include a minimal demonstration of the bug, including code, logs, and screenshots.
|
||||
- Ensure you can reproduce the bug using the latest release.
|
||||
- Only post to report a bug or request a feature; direct all other questions to: https://stackoverflow.com/questions/tagged/mapbox
|
||||
|
||||
Start with a brief description below this line. -->
|
||||
|
||||
### Steps to reproduce
|
||||
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
### Expected behavior
|
||||
|
||||
|
||||
|
||||
### Actual behavior
|
||||
|
||||
|
||||
|
||||
### Configuration
|
||||
|
||||
**Mapbox SDK versions:**
|
||||
**iOS/macOS versions:**
|
||||
**Device/simulator models:**
|
||||
**Xcode version:**
|
||||
25
mapbox-gl-native/.github/ISSUE_TEMPLATE/other.md
vendored
Normal file
25
mapbox-gl-native/.github/ISSUE_TEMPLATE/other.md
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
---
|
||||
name: Other
|
||||
about: Another platform or a cross-platform issue
|
||||
|
||||
---
|
||||
<!--
|
||||
Hello and thanks for contributing to the Mapbox Maps SDK! To help us diagnose your problem quickly, please:
|
||||
|
||||
- Include a minimal demonstration of the bug, including code, logs, and screenshots.
|
||||
- Ensure you can reproduce the bug using the latest release.
|
||||
- Only post to report a bug or request a feature; direct all other questions to: https://stackoverflow.com/questions/tagged/mapbox
|
||||
-->
|
||||
|
||||
**Platform:**
|
||||
**Mapbox SDK version:**
|
||||
|
||||
### Steps to trigger behavior
|
||||
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
### Expected behavior
|
||||
|
||||
### Actual behavior
|
||||
11
mapbox-gl-native/.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
11
mapbox-gl-native/.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
## Launch Checklist
|
||||
|
||||
<!-- Thanks for the PR! Feel free to add or remove items from the checklist. -->
|
||||
|
||||
- [ ] briefly describe the changes in this PR
|
||||
- [ ] include before/after visuals or gifs if this PR includes visual changes
|
||||
- [ ] write tests for all new functionality
|
||||
- [ ] document any changes to public APIs
|
||||
- [ ] tagged `@mapbox/maps-android @mapbox/maps-ios @mapbox/core-sdk` if this PR adds or updates a public API
|
||||
- [ ] tagged `@mapbox/gl-js` if this PR includes shader changes or needs a js port
|
||||
- [ ] apply `needs changelog` label if a changelog is needed (remove label when added)
|
||||
28
mapbox-gl-native/.github/stale.yml
vendored
Normal file
28
mapbox-gl-native/.github/stale.yml
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
# Configuration for probot-stale - https://github.com/probot/stale
|
||||
|
||||
exemptProjects: true
|
||||
exemptMilestones: true
|
||||
|
||||
staleLabel: archived
|
||||
|
||||
limitPerRun: 1
|
||||
|
||||
# SEMVER-MAJOR - @tobrun
|
||||
exemptLabels:
|
||||
- SEMVER-MAJOR
|
||||
|
||||
pulls:
|
||||
daysUntilStale: 60
|
||||
daysUntilClose: -1
|
||||
markComment: false
|
||||
closeComment: >
|
||||
This pull request has been automatically detected as stale because it has not had
|
||||
recent activity and will be archived. Thank you for your contributions.
|
||||
|
||||
issues:
|
||||
daysUntilStale: 180
|
||||
daysUntilClose: -1
|
||||
markComment: false
|
||||
closeComment: >
|
||||
This issue has been automatically detected as stale because it has not had
|
||||
recent activity and will be archived. Thank you for your contributions.
|
||||
67
mapbox-gl-native/.gitignore
vendored
Normal file
67
mapbox-gl-native/.gitignore
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
.DS_Store
|
||||
.transifexrc
|
||||
*.pyc
|
||||
*.gcno
|
||||
*.gcda
|
||||
*~
|
||||
**/actual.png
|
||||
**/diff.png
|
||||
offline.db
|
||||
new_offline.db
|
||||
xcuserdata
|
||||
/platform/node/test/actual
|
||||
/platform/node/test/diff
|
||||
/mason_packages
|
||||
/build
|
||||
/next/build
|
||||
/lib
|
||||
/test/node_modules
|
||||
/test/fixtures/*/*_actual.*
|
||||
/test/fixtures/api/1.png
|
||||
/test/fixtures/api/2.png
|
||||
/test/fixtures/offline_database/offline.db
|
||||
/test/fixtures/offline_database/offline.db-*
|
||||
/test/output
|
||||
/node_modules
|
||||
/platform/ios/benchmark/assets/glyphs/DIN*
|
||||
/platform/ios/benchmark/assets/tiles/mapbox.mapbox-terrain-v2,mapbox.mapbox-streets-v6
|
||||
/platform/darwin/developer.xcconfig
|
||||
/platform/macos/macos.xcworkspace/xcshareddata/macos.xcscmblueprint
|
||||
/platform/ios/ios.xcworkspace/xcshareddata/ios.xcscmblueprint
|
||||
/documentation
|
||||
test/fixtures/api/assets.zip
|
||||
test/fixtures/storage/assets.zip
|
||||
/.circle-week
|
||||
/vendor/.cache
|
||||
buck-out
|
||||
.buckd
|
||||
|
||||
# Generated metrics results
|
||||
metrics/*.html
|
||||
|
||||
# Android RenderTestRunner
|
||||
render-test/android/.*
|
||||
render-test/android/app/build/
|
||||
render-test/android/app/src/main/assets/data.zip
|
||||
render-test/android/local.properties
|
||||
render-test/android/app/.*
|
||||
render-test/android/package.json
|
||||
render-test/android/app/app.iml
|
||||
render-test/android/android.iml
|
||||
|
||||
# IOS RenderTestRunner
|
||||
render-test/ios/codesigning/*.xcent
|
||||
render-test/ios/fastlane/README.md
|
||||
test-data/
|
||||
|
||||
# Generated file from npm/yarn
|
||||
package-lock.json
|
||||
|
||||
# Visual Studio Code
|
||||
.vscode
|
||||
mapbox-gl-native.code-workspace
|
||||
|
||||
# Generated list files from code generation
|
||||
/scripts/generate-file-lists.list
|
||||
/scripts/generate-shaders.list
|
||||
/scripts/generate-style-code.list
|
||||
51
mapbox-gl-native/.gitmodules
vendored
Normal file
51
mapbox-gl-native/.gitmodules
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
[submodule "mapbox-gl-js"]
|
||||
path = mapbox-gl-js
|
||||
url = https://github.com/mapbox/mapbox-gl-js.git
|
||||
[submodule "vendor/nunicode"]
|
||||
path = vendor/nunicode
|
||||
url = https://bitbucket.org/alekseyt/nunicode.git
|
||||
[submodule "vendor/earcut.hpp"]
|
||||
path = vendor/earcut.hpp
|
||||
url = https://github.com/mapbox/earcut.hpp.git
|
||||
[submodule "vendor/polylabel"]
|
||||
path = vendor/polylabel
|
||||
url = https://github.com/mapbox/polylabel.git
|
||||
[submodule "vendor/protozero"]
|
||||
path = vendor/protozero
|
||||
url = https://github.com/mapbox/protozero.git
|
||||
[submodule "vendor/vector-tile"]
|
||||
path = vendor/vector-tile
|
||||
url = https://github.com/mapbox/vector-tile.git
|
||||
[submodule "vendor/wagyu"]
|
||||
path = vendor/wagyu
|
||||
url = https://github.com/mapbox/wagyu.git
|
||||
[submodule "vendor/unique_resource"]
|
||||
path = vendor/unique_resource
|
||||
url = https://github.com/okdshin/unique_resource.git
|
||||
[submodule "vendor/icu"]
|
||||
path = vendor/icu
|
||||
url = https://github.com/unicode-org/icu.git
|
||||
[submodule "vendor/boost"]
|
||||
path = vendor/boost
|
||||
url = https://github.com/mapbox/mapbox-gl-native-boost.git
|
||||
[submodule "vendor/benchmark"]
|
||||
path = vendor/benchmark
|
||||
url = https://github.com/google/benchmark.git
|
||||
[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/mapbox/mapbox-base.git
|
||||
[submodule "vendor/googletest"]
|
||||
path = vendor/googletest
|
||||
url = https://github.com/google/googletest.git
|
||||
[submodule "vendor/zip-archive"]
|
||||
path = vendor/zip-archive
|
||||
url = https://github.com/ZipArchive/ZipArchive.git
|
||||
[submodule "vendor/cpp-httplib"]
|
||||
path = vendor/cpp-httplib
|
||||
url = https://github.com/yhirose/cpp-httplib.git
|
||||
[submodule "vendor/mapbox-gl-native-curl"]
|
||||
path = vendor/mapbox-gl-native-curl
|
||||
url = https://github.com/mapbox/mapbox-gl-native-curl.git
|
||||
32
mapbox-gl-native/.npmignore
Normal file
32
mapbox-gl-native/.npmignore
Normal file
@@ -0,0 +1,32 @@
|
||||
Makefile
|
||||
CmakeLists.txt
|
||||
*yml
|
||||
build
|
||||
cmake
|
||||
misc
|
||||
.*
|
||||
*tgz
|
||||
benchmark
|
||||
expression-test
|
||||
cloudformation
|
||||
bin
|
||||
vendor
|
||||
include
|
||||
mason_packages
|
||||
mapbox-gl-js
|
||||
test
|
||||
lib
|
||||
next
|
||||
src
|
||||
scripts
|
||||
render-test
|
||||
platform/android
|
||||
platform/darwin
|
||||
platform/default
|
||||
platform/glfw
|
||||
platform/ios
|
||||
platform/linux
|
||||
platform/macos
|
||||
platform/qt
|
||||
platform/node/symbol-list
|
||||
platform/node/version-script
|
||||
17
mapbox-gl-native/.topissuesrc
Normal file
17
mapbox-gl-native/.topissuesrc
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"labels": {
|
||||
"release blocker": 25,
|
||||
"beta blocker": 20,
|
||||
"crash": 5,
|
||||
"build": 5,
|
||||
"bug": 2
|
||||
},
|
||||
"reactions": {
|
||||
"+1": 1,
|
||||
"-1": -1,
|
||||
"laugh": 1,
|
||||
"hooray": 1,
|
||||
"confused": 1,
|
||||
"heart": 1
|
||||
}
|
||||
}
|
||||
53
mapbox-gl-native/.tx/config
Normal file
53
mapbox-gl-native/.tx/config
Normal file
@@ -0,0 +1,53 @@
|
||||
[main]
|
||||
host = https://www.transifex.com
|
||||
minimum_perc = 80
|
||||
|
||||
[mapbox-gl-native.foundationstrings-darwin]
|
||||
file_filter = platform/darwin/resources/<lang>.lproj/Foundation.strings
|
||||
lang_map = pt_BR: pt-BR, pt_PT: pt-PT, zh_CN: zh-Hans, zh_TW: zh-Hant
|
||||
source_file = platform/darwin/resources/Base.lproj/Foundation.strings
|
||||
source_lang = en
|
||||
type = STRINGS
|
||||
|
||||
[mapbox-gl-native.foundationstringsdict-darwin]
|
||||
file_filter = platform/darwin/resources/<lang>.lproj/Foundation.stringsdict
|
||||
lang_map = pt_BR: pt-BR, pt_PT: pt-PT, zh_CN: zh-Hans, zh_TW: zh-Hant
|
||||
source_file = platform/darwin/resources/en.lproj/Foundation.stringsdict
|
||||
source_lang = en
|
||||
type = STRINGSDICT
|
||||
|
||||
[mapbox-gl-native.localizablestrings-ios]
|
||||
file_filter = platform/ios/resources/<lang>.lproj/Localizable.strings
|
||||
lang_map = pt_BR: pt-BR, pt_PT: pt-PT, zh_CN: zh-Hans, zh_TW: zh-Hant
|
||||
source_file = platform/ios/resources/Base.lproj/Localizable.strings
|
||||
source_lang = en
|
||||
type = STRINGS
|
||||
|
||||
[mapbox-gl-native.localizablestringsdict-ios]
|
||||
file_filter = platform/ios/resources/<lang>.lproj/Localizable.stringsdict
|
||||
lang_map = pt_BR: pt-BR, pt_PT: pt-PT, zh_CN: zh-Hans, zh_TW: zh-Hant
|
||||
source_file = platform/ios/resources/en.lproj/Localizable.stringsdict
|
||||
source_lang = en
|
||||
type = STRINGSDICT
|
||||
|
||||
[mapbox-gl-native.localizablestrings-macos]
|
||||
file_filter = platform/macos/sdk/<lang>.lproj/Localizable.strings
|
||||
lang_map = pt_BR: pt-BR, pt_PT: pt-PT, zh_CN: zh-Hans, zh_TW: zh-Hant
|
||||
source_file = platform/macos/sdk/Base.lproj/Localizable.strings
|
||||
source_lang = en
|
||||
type = STRINGS
|
||||
|
||||
[mapbox-gl-native.rootstrings-ios]
|
||||
file_filter = platform/ios/app/Settings.bundle/<lang>.lproj/Root.strings
|
||||
lang_map = pt_BR: pt-BR, pt_PT: pt-PT, zh_CN: zh-Hans, zh_TW: zh-Hant
|
||||
source_file = platform/ios/app/Settings.bundle/Base.lproj/Root.strings
|
||||
source_lang = en
|
||||
type = STRINGS
|
||||
|
||||
[mapbox-gl-native.stringsxml-android]
|
||||
file_filter = platform/android/MapboxGLAndroidSDK/src/main/res/values-<lang>/strings.xml
|
||||
lang_map = pt_PT: pt-rPT, zh_CN: zh-rCN, zh_TW: zh-rTW, zh_HK: zh-rHK
|
||||
source_file = platform/android/MapboxGLAndroidSDK/src/main/res/values/strings.xml
|
||||
source_lang = en
|
||||
type = ANDROID
|
||||
|
||||
128
mapbox-gl-native/.ycm_extra_conf.py
Normal file
128
mapbox-gl-native/.ycm_extra_conf.py
Normal file
@@ -0,0 +1,128 @@
|
||||
# Version of .ycm_extra_conf.py sample file adapted
|
||||
# for the Mapbox GL Native project.
|
||||
#
|
||||
# This file is NOT licensed under the GPLv3, which is the license for the rest
|
||||
# of YouCompleteMe.
|
||||
#
|
||||
# Here's the license text for this file:
|
||||
#
|
||||
# This is free and unencumbered software released into the public domain.
|
||||
#
|
||||
# Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
# distribute this software, either in source code form or as a compiled
|
||||
# binary, for any purpose, commercial or non-commercial, and by any
|
||||
# means.
|
||||
#
|
||||
# In jurisdictions that recognize copyright laws, the author or authors
|
||||
# of this software dedicate any and all copyright interest in the
|
||||
# software to the public domain. We make this dedication for the benefit
|
||||
# of the public at large and to the detriment of our heirs and
|
||||
# successors. We intend this dedication to be an overt act of
|
||||
# relinquishment in perpetuity of all present and future rights to this
|
||||
# software under copyright law.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
# OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
# For more information, please refer to <http://unlicense.org/>
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import string
|
||||
import ycm_core
|
||||
|
||||
compilation_database_folders = [
|
||||
'build/linux-x86_64/Debug',
|
||||
'build/qt-linux-x86_64/Debug',
|
||||
'build/qt4-linux-x86_64/Debug',
|
||||
'build/macos/compdb/Debug',
|
||||
]
|
||||
|
||||
subprocess.call(['make compdb'], shell=True)
|
||||
|
||||
for folder in compilation_database_folders:
|
||||
if os.path.exists( folder ):
|
||||
database = ycm_core.CompilationDatabase( folder )
|
||||
|
||||
SOURCE_EXTENSIONS = [ '.cpp', '.cxx', '.cc', '.c', '.m', '.mm' ]
|
||||
|
||||
|
||||
def DirectoryOfThisScript():
|
||||
return os.path.dirname( os.path.abspath( __file__ ) )
|
||||
|
||||
|
||||
def MakeRelativePathsInFlagsAbsolute( flags, working_directory ):
|
||||
if not working_directory:
|
||||
return list( flags )
|
||||
new_flags = []
|
||||
make_next_absolute = False
|
||||
path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ]
|
||||
for flag in flags:
|
||||
new_flag = flag
|
||||
|
||||
if make_next_absolute:
|
||||
make_next_absolute = False
|
||||
if not flag.startswith( '/' ):
|
||||
new_flag = os.path.join( working_directory, flag )
|
||||
|
||||
for path_flag in path_flags:
|
||||
if flag == path_flag:
|
||||
make_next_absolute = True
|
||||
break
|
||||
|
||||
if flag.startswith( path_flag ):
|
||||
path = flag[ len( path_flag ): ]
|
||||
new_flag = path_flag + os.path.join( working_directory, path )
|
||||
break
|
||||
|
||||
if new_flag:
|
||||
new_flags.append( new_flag )
|
||||
return new_flags
|
||||
|
||||
|
||||
def IsHeaderFile( filename ):
|
||||
extension = os.path.splitext( filename )[ 1 ]
|
||||
return extension in [ '.h', '.hxx', '.hpp', '.hh' ]
|
||||
|
||||
|
||||
def GetCompilationInfoForFile( filename ):
|
||||
# The compilation_commands.json file generated by CMake does not have entries
|
||||
# for header files. So we do our best by asking the db for flags for a
|
||||
# corresponding source file, if any. If one exists, the flags for that file
|
||||
# should be good enough.
|
||||
if IsHeaderFile( filename ):
|
||||
basename = os.path.splitext( filename )[ 0 ]
|
||||
for extension in SOURCE_EXTENSIONS:
|
||||
replacement_file = basename + extension
|
||||
if os.path.exists( replacement_file ):
|
||||
compilation_info = database.GetCompilationInfoForFile(
|
||||
replacement_file )
|
||||
if compilation_info.compiler_flags_:
|
||||
return compilation_info
|
||||
return None
|
||||
return database.GetCompilationInfoForFile( filename )
|
||||
|
||||
|
||||
def FlagsForFile( filename, **kwargs ):
|
||||
if not database:
|
||||
return None
|
||||
|
||||
# Bear in mind that compilation_info.compiler_flags_ does NOT return a
|
||||
# python list, but a "list-like" StringVec object
|
||||
compilation_info = GetCompilationInfoForFile( filename )
|
||||
if not compilation_info:
|
||||
return None
|
||||
|
||||
final_flags = MakeRelativePathsInFlagsAbsolute(
|
||||
compilation_info.compiler_flags_,
|
||||
compilation_info.compiler_working_dir_ )
|
||||
|
||||
return {
|
||||
'flags': final_flags,
|
||||
'do_cache': True
|
||||
}
|
||||
121
mapbox-gl-native/ARCHITECTURE.md
Normal file
121
mapbox-gl-native/ARCHITECTURE.md
Normal file
@@ -0,0 +1,121 @@
|
||||
This document aims to outline at a high level the various parts that make up mapbox-gl-native and how they work together.
|
||||
|
||||
# Repository structure
|
||||
|
||||
mapbox-gl-native uses a monolithic that houses both core C++ code and code that wraps the C++ core with SDKs for Android, iOS, macOS, Node.js, and Qt. A "monorepo" allows us to:
|
||||
|
||||
* Make changes to the core API and SDKs simultaneously, ensuring no platform falls behind.
|
||||
* Ensure that core changes do not inadvertently break SDK tests.
|
||||
* Centralize discussions about features and defects that affect multiple platforms.
|
||||
|
||||
In the repository, core C++ code is contained in the `include` and `src` directories. The former includes headers that are considered to make up the "public" core C++ API, while the latter includes `.cpp` implementation files and headers that are private to the implementation. Within both directories, files are nested under an `mbgl` directory, which has various subdirectories based on areas of functionality. Both public and private headers therefore can (and should) always be included with the form `#include <mbgl/___/___.hpp>`.
|
||||
|
||||
Code and build scripts belonging to platform SDKs are contained in the `platform` directory, which has subdirectories for each platform. The `platform/darwin` and `platform/default` directories contain code shared by multiple platform SDKs.
|
||||
|
||||
# Build system
|
||||
|
||||
The mapbox-gl-native build system uses a variety of tools.
|
||||
|
||||
## Make
|
||||
|
||||
GNU Make and a master `Makefile` serves as the coordinating tool for all other build system tools. Most of your interaction with the build system will be via `make` commands. We aim to have a consistent pattern for make targets across platforms: for a given platform, e.g. `ios`, `make ios` builds a reasonable set of end products (though perhaps not all permutations of build options, which can be prohibitively expensive), and `make ios-test` runs a complete test suite for the platform.
|
||||
|
||||
## Git submodules
|
||||
|
||||
Git submodules are used to pull in several dependencies: mason (see below) and several iOS dependencies (though we have plans to phase these out). Initializing these submodules is handled automatically by the necessary `make` targets.
|
||||
|
||||
## npm
|
||||
|
||||
npm is a package manager for Node.js. mapbox-gl-native uses it to pull in several development dependencies that happen to be packaged as node modules -- mainly for testing needs.
|
||||
|
||||
## Mason
|
||||
|
||||
[Mason](https://github.com/mapbox/mason) is Mapbox's own cross platform C/C++ package manager. mapbox-gl-native uses mason packages as a source of precompiled binaries for third-party dependencies such as Boost, RapidJSON, and SQLite, and Mapbox's own C++ modules such as [earcut.hpp](https://github.com/mapbox/earcut.hpp) and [geojson-vt-cpp](https://github.com/mapbox/geojson-vt-cpp). It is also used to obtain a toolchain for Android platform cross-compiliation.
|
||||
|
||||
We track mason dependencies for a given platform in the file `platform/<platform>/scripts/configure.sh`. The `configure` script at the root handles sourcing this file during the build, running the appropriate mason commands, and writing configuration settings for the subsequent build to a `config.gypi` in the build output directory.
|
||||
|
||||
## gyp
|
||||
|
||||
[gyp](https://gyp.gsrc.io/) is a build system originally created for Chromium and since adopted by Node.js. In mapbox-gl-native it's used to build the core C++ static library, the Node.js platform module, and the shared JNI module for Android.
|
||||
|
||||
## Platform-specific subsystems
|
||||
|
||||
Outside of the core C++ static library, platform SDKs typically rely on platform-native build tooling to complete the job.
|
||||
|
||||
* For iOS and macOS this means Xcode and the xcodebuild command line tool.
|
||||
* For Android, Gradle and Android Studio.
|
||||
* For Qt, `qmake`.
|
||||
|
||||
See the relevant platform-specific `README.md` / `INSTALL.md` for details.
|
||||
|
||||
# Major functional components
|
||||
|
||||
## Map
|
||||
## Style
|
||||
|
||||
The "Style" component of mapbox-gl-native contains an implementation of the [Mapbox Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/), defining what data to draw, the order to draw it in, and how to style the data when drawing it.
|
||||
|
||||
In addition to supporting styles loaded from a URL, mapbox-gl-native includes a runtime styling API, which allows users to dynamically modify the current style: add and remove layers, modify layer properties, and so on. As appropriate for a C++ API, the runtime styling API API is _strongly typed_: there are subclasses for each layer type, with correctly-typed accessors for each style property. This results in a large API surface area. Fortunately, this is automated, by generating the API – and the regular portion of the implementation – from the style specification.
|
||||
|
||||
The layers API makes a distinction between public API and internal implementation using [the `Impl` idiom](https://github.com/mapbox/mapbox-gl-native/issues/3254) seen elsewhere in the codebase. Here, it takes the form of parallel class hierarchies:
|
||||
|
||||
* `Layer`, `Source`, and their subclasses form the public API. This is the API consumed by SDK bindings.
|
||||
* `Layer::Impl`, `Source::Impl`, and their subclasses form the internal API. This API is used only by other parts of the core C++ implementation.
|
||||
|
||||
For each subclass of `Layer` or source, there's a corresponding `Impl` subclass. For example, `CircleLayer` and `CircleLayer::Impl`. The base `Layer` class holds a reference to the base `Layer::Impl`, and `CircleLayer` and other subclasses have an `impl()` accessor method that casts this reference to the appropriate subtype.
|
||||
|
||||
## Immutability
|
||||
|
||||
The `Layer::Impl` and `Source::Impl` reference held by `Layer` and `Source` base classes is _immutable_: it's a shared reference to a `const` (read only) pointer. Immutability permits the `Impl` objects to be shared safely between threads when needed -- for example, between the main thread and worker thread that performs computation in the background, or between the main thread and a dedicated renderer thread. See the "Threading" section below for further details on the threading model.
|
||||
|
||||
Immutability is an alternative to several other strategies for safe intra-thread communication. One alternative strategy is to insert locks whenever data is shared between threads and at least one thread may be modifying the data. This strategy is prone to problems such as race conditions (if you forget to use a lock), deadlocks (if locks are acquired in conflicting orders), and poor performance due to lock contention. Another strategy is to copy data whenever it's needed by another thread. For complex structures such as a Mapbox Style, copying can be an expensive operation. With immutability, the approach is to share data without copying, but ensure that any data so shared cannot be modified by any thread, and that the data is not destroyed until the last thread using it relinquishes its reference.
|
||||
|
||||
Immutability is implemented by the `Immutable<T>` template, which acts as a non-nullable shared reference to a `const T`. It has behavior similar to `std::shared_ptr<const T>`, but indicates its intent as an immutable reference that is safe to share between threads.
|
||||
|
||||
Immutability is core to the implementation, and yet one of the defining features of Mapbox GL is the ability to manipulate and mutate the style freely at runtime. How can this be possible if everything is immutable? The answer turns on the distinction mentioned in the previous section between public classes such as `Layer` and private implementations such as `Layer::Impl`. In Mapbox GL, the latter is immutable, but the former is not:
|
||||
|
||||
* **Mutable objects**: `Layer`, `Source`, `Image`, `Light`
|
||||
* **Immutable objects**: `Layer::Impl`, `Source::Impl`, `Image::Impl`, `Light::Impl`
|
||||
|
||||
An instance of a `Layer` subclass such as `CircleLayer` has a reference to an `Immutable<Layer::Impl>`, but is itself mutable -- it has mutating methods such as `setCircleRadius`. Such methods follow a common pattern:
|
||||
|
||||
* Create a new instance of the Impl, copied from the existing Impl. This new instance is temporarily mutable.
|
||||
* Modify this new instance as needed; e.g. set the radius to a new value.
|
||||
* "Freeze" the new instance by making it immutable, and then assign that immutable reference to be the new Impl for the `Layer`.
|
||||
|
||||
Two things to note about this process:
|
||||
|
||||
* No existing Impls are modified -- only the newly created copy.
|
||||
* Only one existing reference to an Impl is modified -- the one held by the `Layer` instance being mutated. Any references to the previous Impl held by other threads remain unchanged. They go on using the previous value for radius until notified by some other means that there has been a change.
|
||||
|
||||
So how do things that are holding references to the previous Impl get notified? The answer is **style diffing**. This is the process by which we determine, from one frame to the next, what parts of the style have changed and therefore what needs to be recalculated in response to those changes in order to draw an updated frame. In parallel to style objects such as `Style`, `Layer`, `Source` and so on, Mapbox GL maintains render objects such as `RenderStyle`, `RenderLayer`, `RenderSource` and so on. These render objects:
|
||||
|
||||
* are mutable
|
||||
* may live on either the main thread or an independent rendering thread, depending on the SDK
|
||||
* contain any and all values calculated from the style objects plus state such as the current zoom level and location -- for example, the set of loaded tiles and the buckets calculated from them
|
||||
|
||||
From one frame to the next, these render objects are updated based on the current state of the style objects. In order to permit the render objects to live on a different thread, this state is communicated as immutable Impl references -- in effect, a snapshot of the style state at the time the frame was requested. And it really is a just snapshot -- we don't communicate things like "the radius of this circle layer was changed", "this layer was removed", etc. Instead, that information is reconstructed by `RenderStyle` by comparing the new snapshot to the old snapshot. Immutability allows us to perform this comparison very efficiently:
|
||||
|
||||
* If the "before" and "after" of two immutable references refer to the same object, we know that it hasn't changed. If they're different, we know it has changed in some way.
|
||||
* We can calculate changes in collections of immutable references (a list of layers or sources) using an efficient [diff algorithm](http://www.xmailserver.org/diff2.pdf). We can further improve this efficiency by making the collections themselves immutable, so that we can avoid running the diff algorithm altogether in the common case where the "before" and "after" collections refer to the same immutable object.
|
||||
|
||||
One final benefit of this approach of diffing immutable objects: we get "smart" updates between two completely independent styles essentially for free. For example, `RenderStyle` doesn't care if the "before" snapshot is from the Mapbox Light style and the "after" snapshot is from the Mapbox Dark style. It will just calculate the difference between the two snapshots, update render data where necessary, and render the next frame. Since those two styles use the same source data and layer IDs, the result will be a fully automatic, seamless transition between light and dark.
|
||||
|
||||
## FileSource
|
||||
## Layout
|
||||
## Rendering
|
||||
## Annotations
|
||||
|
||||
# Threading
|
||||
|
||||
At runtime, mapbox-gl-native uses the following threads:
|
||||
|
||||
* The "main thread" (or other thread on which a `Map` object is created) handles direct `Map` API requests, owns the active `Style` and its associated objects, and renders the map. Since this thread is usually dispatching events triggered by user input, it's important that these duties not require significant computation or perform blocking I/O that would cause UI jank or hangs.
|
||||
* Many of the tasks that require significant computation are associated with layout and styling of map features: parsing vector tiles, computing text layout, and generating data buffers to be consumed by OpenGL. This work happens on "worker threads" that are spawned by the main thread, four per `Style` object. The `Style` and its associated objects handle dispatching tasks to the workers, typically on a tile-by-tile basis.
|
||||
* A "FileSource" thread handles network requests for styles, tiles, and other resources, and I/O on the SQLite database used for offline maps and caching. Requests originate from the main thread, are dispatched by a FileSource internally to its thread, and results are returned to the main thread via an asynchronous callback function. (This is implemented with platform-specific hooks into the native message pump for the requesting thread.)
|
||||
|
||||
To minimize data races and invalid memory access, we aim for zero shared memory state between any two threads. Cross-thread communication occurs via one thread requesting the "invocation" of a task on another thread. The parameters for this task should be passed as value objects, so that they are copied, or as ownership-transferring values such as `std::unique_ptr`. (We're [not entirely there yet](https://github.com/mapbox/mapbox-gl-native/issues/667), but that's the goal.) The result (if any) is likewise passed as a value or ownership-transferring parameter to the callback function.
|
||||
|
||||
Invoking a task on another thread itself creates an ownership obligation: the responsibility for the work happening on the other thread. This ownership is represented by the invocation method returning `std::unique_ptr<AsyncTask>`. Destroying this object indicates that the result of the task is no longer required: the callback is guaranteed not to be called, and the work on the other thread may be aborted (if doing so is convenient).
|
||||
|
||||
All this is implemented by [Thread](https://github.com/mapbox/mapbox-gl-native/blob/master/src/mbgl/util/thread.hpp) and [RunLoop](https://github.com/mapbox/mapbox-gl-native/blob/master/include/mbgl/util/run_loop.hpp).
|
||||
515
mapbox-gl-native/CHANGELOG.md
Normal file
515
mapbox-gl-native/CHANGELOG.md
Normal file
@@ -0,0 +1,515 @@
|
||||
# Changelog
|
||||
|
||||
## master
|
||||
|
||||
## maps-v1.6.0
|
||||
|
||||
### ✨ New features
|
||||
|
||||
- [core] Add support for `Polygon`, `MultiPolygon` geometry types in `distance` expression. ([#16446](https://github.com/mapbox/mapbox-gl-native/pull/16446))
|
||||
|
||||
- [core] Introduce a new API for controlling the camera ([#16419]https://github.com/mapbox/mapbox-gl-native/pull/16419)
|
||||
|
||||
Functions `Map::getFreeCameraOptions()` and `Map::setFreeCameraOptions(options)` provides an alternative way of accessing and modifying properties of the underlying camera entity. The API allows the user to treat the camera as a more traditional 3D object by modifying its position and orientation directly as opposed to setting the state implicitly by using `CameraOptions`. Both APIs are fully compatible with each other.
|
||||
|
||||
### 🐞 Bug fixes
|
||||
|
||||
- [core][tile mode] Labels priority fixes ([#16432](https://github.com/mapbox/mapbox-gl-native/pull/16432))
|
||||
|
||||
This change does the following:
|
||||
|
||||
- strictly arranges all the intersecting labels accordingly to the style-defined priorities
|
||||
- fixes placement order of the variable labels.
|
||||
Before this change, all variable labels that could potentially intersect tile borders were placed first, breaking the style label placement priority order. Now, all the variable labels, which do not actually intersect the tile borders, are placed accordingly to the style-defined priorities
|
||||
|
||||
## maps-v1.6.0-rc.2
|
||||
|
||||
### ✨ New features
|
||||
|
||||
- [core] Introduce Source::setMinimumTileUpdateInterval API ([#16416](https://github.com/mapbox/mapbox-gl-native/pull/16416))
|
||||
|
||||
The `Source::setMinimumTileUpdateInterval(Duration)` method sets the minimum tile update interval, which is used to throttle the tile update network requests.
|
||||
|
||||
The corresponding `Source::getMinimumTileUpdateInterval()` getter is added too.
|
||||
|
||||
Default minimum tile update interval value is `Duration::zero()`.
|
||||
|
||||
- [core] Indroduce `distance` expression. ([#16397](https://github.com/mapbox/mapbox-gl-native/pull/16397))
|
||||
|
||||
The `distance` expression returns the shortest distance between two geometries. The returned value can be consumed as an input into another expression for changing a paint or layout property or filtering features by distance.
|
||||
|
||||
Currently, the `distance` expression supports `Point`, `MultiPoint`, `LineString`, `MultiLineString` geometry types.
|
||||
|
||||
- [core] Introduce style::Source::setVolatile()/isVolatile() API ([#16422](https://github.com/mapbox/mapbox-gl-native/pull/16422))
|
||||
|
||||
The `Source::setVolatile(bool)` method sets a flag defining whether or not the fetched tiles for the given source should be stored in the local cache.
|
||||
|
||||
The corresponding `Source::isVolatile()` getter is added too.
|
||||
|
||||
By default, the source is not volatile.
|
||||
|
||||
- [ios, macos] Allow specifying multiple fonts or font families for local font rendering ([#16253](https://github.com/mapbox/mapbox-gl-native/pull/16253))
|
||||
|
||||
By default, CJK characters are now set in the font specified by the `text-font` layout property. If the named font is not installed on the device or bundled with the application, the characters are set in one of the fallback fonts passed into the `localFontFamily` parameter of `mbgl::Renderer::Renderer()` and `mbgl::MapSnapshotter::MapSnapshotter()`. This parameter can now contain a list of font family names, font display names, and font PostScript names, each name separated by a newline.
|
||||
|
||||
### 🐞 Bug fixes
|
||||
|
||||
- [ios, macos] Fixed error receiving local file URL response ([#16428](https://github.com/mapbox/mapbox-gl-native/pull/16428))
|
||||
|
||||
- [ios, macos] Corrected metrics of locally rendered fonts ([#16253](https://github.com/mapbox/mapbox-gl-native/pull/16253))
|
||||
|
||||
CJK characters are now laid out according to the font, so fonts with nonsquare glyphs have the correct kerning. This also fixes an issue where the baseline for CJK characters was too low compared to non-CJK characters.
|
||||
|
||||
## maps-v1.6.0-rc.1
|
||||
|
||||
### ✨ New features
|
||||
|
||||
- [core] Move logging off the main thread ([#16325](https://github.com/mapbox/mapbox-gl-native/pull/16325))
|
||||
|
||||
- Add source property to limit parent's tile overscale factor ([#16347](https://github.com/mapbox/mapbox-gl-native/pull/16347))
|
||||
|
||||
The new property sets a limit for how much parent tile can be overscaled.
|
||||
|
||||
- [core][tile mode] Introduce API to collect placed symbols data ([#16339](https://github.com/mapbox/mapbox-gl-native/pull/16339))
|
||||
|
||||
The following methods are added to the `Renderer` class in implemented in the Tile map mode:
|
||||
- `collectPlacedSymbolData()`
|
||||
enables or disables collecting of the placed symbols data
|
||||
|
||||
- `getPlacedSymbolsData()`
|
||||
if collecting of the placed symbols data is enabled, returns the reference to the `PlacedSymbolData` vector holding the collected data.
|
||||
|
||||
- [core] Enable circle-sort-key property ([#15875](https://github.com/mapbox/mapbox-gl-native/pull/15875/))
|
||||
|
||||
Adds support for `circle-sort-key` property, consistent with `symbol-sort-key`.
|
||||
|
||||
Sorts drawing order by sort key both within-tile and cross-tile.
|
||||
|
||||
- [core] Add LocationIndicator layer ([#16340](https://github.com/mapbox/mapbox-gl-native/pull/16340))
|
||||
|
||||
Adds a new layer type, `location-indicator`, that can be used to add a source-less indicator to the map, comprising raster images and a precision radius in meters.
|
||||
|
||||
- Add generic setter for Layer's 'source' property ([#16406](https://github.com/mapbox/mapbox-gl-native/pull/16406))
|
||||
|
||||
### 🐞 Bug fixes
|
||||
|
||||
- [core][tile mode] Reduce cut-off labels (part 2) ([#16369](https://github.com/mapbox/mapbox-gl-native/pull/16369))
|
||||
|
||||
Now, the intersecting symbols are placed across all layers _symbol by symbol_ according to the following rules:
|
||||
|
||||
1. First we look, which of the tile border(s) the symbol intersects and prioritize the the symbol placement accordingly (high priority -> low priority): `vertical & horizontal -> vertical -> horizontal`
|
||||
2. For the symbols that intersect the same tile border(s), assuming the tile border split symbol into several sections, we look at the minimal section length. The symbol with a larger minimal section length is placed first.
|
||||
3. For the symbols that intersect the same tile border(s), and have equal minimal section length, we look at the anchor coordinates.
|
||||
4. Finally, if all the previous criteria are the same, we look at the symbol key hashes.
|
||||
|
||||
- [core][tile mode] Fix variable placement for labels with the `icon-text-fit` property set ([#16382](https://github.com/mapbox/mapbox-gl-native/pull/16382))
|
||||
|
||||
The `symbolIntersectsTileEdges()` util in `mbgl::TilePlacement` now considers icon shift for the variable symbols with enabled icon-text-fit setting, thus providing more accurate results.
|
||||
|
||||
- [core] Correctly log a warning instead of crashing when a non-existent image is attempted to be removed. ([#16391](https://github.com/mapbox/mapbox-gl-native/pull/16391))
|
||||
|
||||
- [core] Fix segfault resulting from an invalid geometry ([#16409](https://github.com/mapbox/mapbox-gl-native/pull/16409))
|
||||
|
||||
- [macos] Restored support for macOS 10.11–10.14 ([#16412](https://github.com/mapbox/mapbox-gl-native/pull/16412))
|
||||
|
||||
## maps-v1.5.1
|
||||
|
||||
### 🐞 Bug fixes
|
||||
|
||||
- [core] Fix assert in gfx resources cleanup ([#16349](https://github.com/mapbox/mapbox-gl-native/pull/16349))
|
||||
|
||||
Fix a resource leak assertion in `gl::Context::~Context()` that is evaluating false in scenarios where graphics context has been marked as lost.
|
||||
|
||||
- Hillshade bucket fix for mapbox-gl-native-ios #240 ([#16362](https://github.com/mapbox/mapbox-gl-native/pull/16362))
|
||||
|
||||
When dem tiles are loaded, border in neighboring tiles is updated, too leading to bucket re-upload. if std::move moved indices / vertices previously, they are empty and we get crash. Re-upload requires that only DEM texture is re-uploaded, not the quad vertices and indices.
|
||||
|
||||
## maps-v1.5.0
|
||||
|
||||
### ✨ New features
|
||||
|
||||
- [core] Add Renderer::clearData() ([#16323](https://github.com/mapbox/mapbox-gl-native/pull/16323))
|
||||
|
||||
The newly added `Renderer::clearData()` method allows to clear render data and thus save memory and make sure outdated tiles are not shown. It clears data more agressively than `Renderer::reduceMemoryUse()` does, as it clears not only the cache but all orchestration data, including the data used by the currently rendered frame.
|
||||
|
||||
- [android] Add jni binding for styleable snapshotter ([#16286](https://github.com/mapbox/mapbox-gl-native/pull/16286))
|
||||
|
||||
- [core] Ability to set generic layer properties using setProperty method ([#16324](https://github.com/mapbox/mapbox-gl-native/pull/16324))
|
||||
This change enables the following new keys for the `mbgl::Layer::setProperty()` API:
|
||||
- "filter" invokes `setFilter()`
|
||||
- "minzoom" invokes `setMinZoom()`
|
||||
- "maxzoom" invokes `setMaxZoom()`
|
||||
- "source-layer" invokes `setSourceLayer()`
|
||||
|
||||
The newly-added API is used in the style-conversion code, which made this code much simpler.
|
||||
|
||||
- [android] Expose getLayer, getSource and Observer interface for snapshotter ([#16338](https://github.com/mapbox/mapbox-gl-native/pull/16338))
|
||||
|
||||
### 🐞 Bug fixes
|
||||
|
||||
- [core] Use `TileCoordinates` instead of `LngLat` for `within` expression calculation ([#16319](https://github.com/mapbox/mapbox-gl-native/pull/16319))
|
||||
|
||||
Fix the issue that `within` expression evaluates point features inconsistently across zoom levels if the point lies near the boundary of a GeoJSON object ([#16301](https://github.com/mapbox/mapbox-gl-native/issues/16301))
|
||||
|
||||
- [core][tile mode] Reduce cut-off labels ([#16336](https://github.com/mapbox/mapbox-gl-native/pull/16336))
|
||||
|
||||
Place tile intersecting labels first, across all the layers. Thus we reduce the amount of label cut-offs in Tile mode.
|
||||
|
||||
Before, labels were arranged within one symbol layer (one bucket),which was not enough for several symbol layers being placed at the same time.
|
||||
|
||||
- [core] Fix issue that `within` expression returns incorrect results for geometries crossing the anti-meridian ([#16330](https://github.com/mapbox/mapbox-gl-native/pull/16330))
|
||||
|
||||
## maps-v1.4.1
|
||||
|
||||
### 🐞 Bug fixes
|
||||
|
||||
- [android] Fix wrong method call in map_snapshotter ([#16308](https://github.com/mapbox/mapbox-gl-native/pull/16308))
|
||||
|
||||
In map_snapshotter, a wrong method call will cause Sanpshotter not works with a style url in Android. This change makes it call the right method to let Snapshotter works.
|
||||
|
||||
## maps-v1.4.0
|
||||
|
||||
### ✨ New features
|
||||
|
||||
- [android] Add jni binding for line-sort-key and fill-sort-key ([#16256](https://github.com/mapbox/mapbox-gl-native/pull/16256))
|
||||
|
||||
With this change, android sdk will be able to get sort key for LineLayer and FillLayer.
|
||||
|
||||
- Styleable MapSnapshotter ([#16268](https://github.com/mapbox/mapbox-gl-native/pull/16268))
|
||||
|
||||
New feature provides means of modifying style of a MapSnapshotter. The new API enables several use-cases, such as: adding route overlays, removing extra information (layers) from a base style, adding custom images that are missing from a style.
|
||||
|
||||
- [core] Improve stability of symbol placement when the map is tilted ([#16287](https://github.com/mapbox/mapbox-gl-native/pull/16287))
|
||||
|
||||
These changes improve performance and bring more stability to the symbol placement for the tilted view, which is mainly used for navigation scenarios.
|
||||
|
||||
### 🐞 Bug fixes
|
||||
|
||||
- [core] Fix iterators in addRegularDash() ([#16249](https://github.com/mapbox/mapbox-gl-native/pull/16249))
|
||||
|
||||
Fixes possible crashes when using styles with line patterns.
|
||||
|
||||
- [default] Fix possible crash at RunLoop::wake() ([#16255](https://github.com/mapbox/mapbox-gl-native/pull/16255))
|
||||
|
||||
- [android] Update toGeoJSON in android_conversion.hpp ([#16243](https://github.com/mapbox/mapbox-gl-native/pull/16243))
|
||||
|
||||
Before this chage, `toGeoJSON` method in `android_conversion.hpp` could not convert an Object (Map in android) to GeoJSON object.
|
||||
|
||||
But `within` expression needs to accept an Object and then convert it to the GeoJSON object, now `toGeoJSON` method can convert both string and Object to GeoJSON.
|
||||
|
||||
- [core] Fix `within` expression algorithm so that `false` value will be returned when point is on the boundary. Allow using different GeoJSON formats as arguments of `within` expression.([#16232](https://github.com/mapbox/mapbox-gl-native/pull/16232))
|
||||
|
||||
A valid GeoJSON argument should contain one of the following types: `"Feature"`, `"FeatureCollection"`,`"Polygon"` or `"MultiPolygon"`.
|
||||
|
||||
- [core] [tile mode] placement algorithm must consider icons bounding boxes ([#16277](https://github.com/mapbox/mapbox-gl-native/pull/16277))
|
||||
|
||||
Tile mode placement algorithm now checks if bounding boxes for both label text and icon are intersecting the edges of the tiles.
|
||||
|
||||
Before, it checked only text bounding boxes and thus label icons might have got cut off.
|
||||
|
||||
- [core] Calculate size of an ambient cache without offline region's resources ([#15622](https://github.com/mapbox/mapbox-gl-native/pull/15622))
|
||||
|
||||
Resources that belong to an offline region, should not contribute to the amount of space available in the ambient cache.
|
||||
|
||||
- [core][tile mode] Fix assertion at `line-center` placement handling ([#16293](https://github.com/mapbox/mapbox-gl-native/pull/16293))
|
||||
|
||||
The `Symbol Intersects Tile Edges` placement algorithm should not be applied to the symbols with `line-center` placement.
|
||||
|
||||
- Fixed using of the `in` expression as a layer filter ([#16272](https://github.com/mapbox/mapbox-gl-native/pull/16272))
|
||||
|
||||
The bug was caused by `mbgl::style::conversion::isExpression()` always returning `false` for the `in` expression.
|
||||
|
||||
### 🧩 Architectural changes
|
||||
|
||||
- Changes to `MapSnapshotter` threading model ([#16268](https://github.com/mapbox/mapbox-gl-native/pull/16268))
|
||||
|
||||
Snapshotter's threading model has been changed. Previously, `Map` and `HeadlessFrontend` that is responsible for rendering snapshot, were running on a dedicated thread. After [#16268](https://github.com/mapbox/mapbox-gl-native/pull/16268), `Map` object lives on client thread, so that the client can access `Style` object, while `HeadlessFrontend` lives on a dedicated `Snapshotter` thread.
|
||||
|
||||
##### ⚠️ Breaking changes
|
||||
|
||||
- Signature of a `MapSnapshotter`'s constructor has been changed
|
||||
- Signature for a `MapSnapshotter::snapshot` method has been changed
|
||||
- Size of an offline regions do not affect ambient cache size ([#15622](https://github.com/mapbox/mapbox-gl-native/pull/15622))
|
||||
|
||||
##### 📌 Known issues
|
||||
|
||||
- When feature is exactly on the geometry boundary, `within` expression returns inconsistent values for different zoom levels ([#16301](https://github.com/mapbox/mapbox-gl-native/issues/16301))
|
||||
|
||||
## maps-v1.3.0 (2020.02-relvanillashake)
|
||||
|
||||
### 🐞 Bug fixes
|
||||
|
||||
- [core] Fix offline region download freezing ([#16230](https://github.com/mapbox/mapbox-gl-native/pull/16230))
|
||||
|
||||
Downloaded resources are put in the buffer and inserted in the database in batches.
|
||||
|
||||
Before this change, the buffer was flushed only at the network response callback and thus it never got flushed if the last required resources were present locally and did not initiate network requests - it caused freezing.
|
||||
|
||||
Now the buffer is flushed every time the remaining resources container gets empty.
|
||||
|
||||
### ✨ New features
|
||||
|
||||
- [core] Add Layer::serialize() method ([#16231](https://github.com/mapbox/mapbox-gl-native/pull/16231))
|
||||
|
||||
New method allows serialization of a layer into a Value type, including all modifications done via runtime style API. New method is also an enabler for Style object serialization (sources, layers, etc).
|
||||
|
||||
- [android] Add jni binding for min and max pitch ([#16236](https://github.com/mapbox/mapbox-gl-native/pull/16236))
|
||||
|
||||
- [offline] Offline tool does not hang on 404 error ([#16240](https://github.com/mapbox/mapbox-gl-native/pull/16240))
|
||||
|
||||
The missing resource gets skipped and teh offline region download continues.
|
||||
|
||||
##### ⚠️ Breaking changes
|
||||
|
||||
- Changes to `mbgl::FileSourceManager::getFileSource()` ([#16238](https://github.com/mapbox/mapbox-gl-native/pull/16238))
|
||||
|
||||
It returns now `mbgl::PassRefPtr<FileSource>` (previously was `std::shared_ptr<FileSource>`) in order to enforce keeping the strong reference to the returned object.
|
||||
|
||||
Breaking code example:
|
||||
`auto fs = FileSourceManager::getFileSource(); fs->..`
|
||||
|
||||
Posible fix:
|
||||
`std::shared_ptr<FileSource> fs = `;
|
||||
|
||||
- The `mbgl::OnlineFileSource` class cannot be used directly ([#16238](https://github.com/mapbox/mapbox-gl-native/pull/16238))
|
||||
|
||||
Clients must use the parent `mbgl::FileSource` interface instead.
|
||||
|
||||
Breaking code example:
|
||||
`std::shared_ptr<OnlineFileSource> onlineSource = std::static_pointer_cast<OnlineFileSource>(FileSourceManager::get()->getFileSource(..));`
|
||||
|
||||
Possible fix:
|
||||
`std::shared_ptr<FileSource> onlineSource = FileSourceManager::get()->getFileSource(..);`
|
||||
|
||||
## maps-v1.2.1 (2020.02-release-vanillashake)
|
||||
|
||||
### 🐞 Bug fixes
|
||||
|
||||
- [core] Revert shader changes from [#16189](https://github.com/mapbox/mapbox-gl-native/pull/16189), which will cause incorrect label positioning ([#16235](https://github.com/mapbox/mapbox-gl-native/pull/16235))
|
||||
|
||||
This is a back porting from GL JS [#9333](https://github.com/mapbox/mapbox-gl-js/pull/9333)
|
||||
|
||||
- [ios] Restored support for iOS 9–11 by default ([#16241](https://github.com/mapbox/mapbox-gl-native/pull/16242))
|
||||
|
||||
## maps-v1.2.0 (2020.02-release-vanillashake)
|
||||
|
||||
### ✨ New features
|
||||
|
||||
- [core] Global settings API ([#16174](https://github.com/mapbox/mapbox-gl-native/pull/16174))
|
||||
|
||||
Global settings API provides means of managing non-persistent in-process settings. Initial implementation contains support for experimental option for setting thread priorities.
|
||||
|
||||
- Expose READ_ONLY_MODE_KEY property for DatabaseFileSource ([#16183](https://github.com/mapbox/mapbox-gl-native/pull/16183))
|
||||
|
||||
The `READ_ONLY_MODE_KEY` property is exposed for `DatabaseFileSource`.
|
||||
|
||||
This property allows to re-open the offline database in read-only mode and thus improves the performance for the set-ups that do not require the offline database modifications.
|
||||
|
||||
- [core] Add runtime API for setting tile prefetch delta for a Source ([#16179](https://github.com/mapbox/mapbox-gl-native/pull/16179))
|
||||
|
||||
The new `Source::setPrefetchZoomDelta(optional<uint8_t>)` method allows overriding default tile prefetch setting that is defined by the Map instance.
|
||||
|
||||
- [core] Add support for `within expression`. Implement the use of `within expression` with paint propery and filter expression. ([#16157](https://github.com/mapbox/mapbox-gl-native/pull/16157))
|
||||
|
||||
The `within expression` enables checking whether a feature is inside a pre-defined geometry set/boundary or not. This `within expression` returns a boolean value, `true` indicates that the feature being evaluated is inside the geometry set. The returned value can be then consumed as input by another expression or used directly by a paint/layer property.
|
||||
|
||||
Support for using `within expression` with layout property will be implemented separately.
|
||||
|
||||
- [core] Add support for using `within expression` with layout property. ([#16194](https://github.com/mapbox/mapbox-gl-native/pull/16194))
|
||||
|
||||
- [core] Add support for `in expression`. ([#16162](https://github.com/mapbox/mapbox-gl-native/pull/16162))
|
||||
|
||||
The `in expression` enables checking whether a Number/String/Boolean type item is in a String/Array and returns a boolean value.
|
||||
|
||||
- [core] Add support for using `within expression` with features having `'LineString'` geometry type. ([#16220](https://github.com/mapbox/mapbox-gl-native/pull/16220))
|
||||
|
||||
`within expression` now supports features with geometry types: `'Point'` or `'LineString'`.
|
||||
|
||||
### 🐞 Bug fixes
|
||||
|
||||
- [core] Don't provide multiple responses with the same data for 304 replies ([#16200](https://github.com/mapbox/mapbox-gl-native/pull/16200))
|
||||
|
||||
In cases when cached resource is useable, yet don't have an expiration timestamp, we provided data to the requester from the cache and the same data was returned once 304 response was received from the network.
|
||||
|
||||
- [core] Fix potential visual artifact for line-dasharray ([#16202](https://github.com/mapbox/mapbox-gl-native/pull/16202))
|
||||
|
||||
- Store gfx::DrawScope objects with associated render objects. ([#15395](https://github.com/mapbox/mapbox-gl-native/pull/15395))
|
||||
|
||||
We used some shared SegmentVectors, e.g. for drawing raster or background tiles. In longer running maps, this lead to resource accumulation. By storing the SegmentVectors and the contained gfx::DrawScope objects, we ensure that resources get released when the associated render objects vanish.
|
||||
|
||||
- [core] Fix sprite sheet merging in Style::Impl::onSpriteLoaded ([#16211](https://github.com/mapbox/mapbox-gl-native/pull/16211))
|
||||
|
||||
If we get a new sprite sheet from the server, we need to merge current sprite sheet with a new one, while overwriting duplicates and keeping old unique images in a style.
|
||||
|
||||
### 🏁 Performance improvements
|
||||
|
||||
- [core] Loading images to style optimization ([#16187](https://github.com/mapbox/mapbox-gl-native/pull/16187))
|
||||
|
||||
This change enables attaching images to the style with batches and avoids massive re-allocations. Thus, it improves UI performance especially at start-up time.
|
||||
|
||||
### 🧩 Architectural changes
|
||||
|
||||
##### ⚠️ Breaking changes
|
||||
|
||||
- [core] Loading images to style optimization ([#16187](https://github.com/mapbox/mapbox-gl-native/pull/16187))
|
||||
|
||||
The `style::Style::getImage()` semantics changed - it now returns `optional<style::Image>`.
|
||||
|
||||
## maps-v1.0.1 (2020.01-release-unicorn)
|
||||
|
||||
### 🐞 Bug fixes
|
||||
|
||||
- [core] Use std::list instead of std::map for factory instance ([#16161](https://github.com/mapbox/mapbox-gl-native/pull/16161))
|
||||
|
||||
Factory 'get' method can be invoked recursively and stable iterators are required to guarantee safety.
|
||||
|
||||
- [tile mode] Improvements in symbol placement on tile borders ([#16159](https://github.com/mapbox/mapbox-gl-native/pull/16159))
|
||||
|
||||
In tile mode, the placement order of two symbols crossing a tile border is defined by their anchor Y values.
|
||||
|
||||
Symbols crossing the borders between two neighboring tiles are placed with priority.
|
||||
|
||||
It improves symbol placement stability in the tile map mode.
|
||||
|
||||
## maps-v1.0.0 (2020.01-release-unicorn)
|
||||
|
||||
### ✨ New features
|
||||
|
||||
- [core] Implement stretchable icons ([#16030](https://github.com/mapbox/mapbox-gl-native/pull/16030))
|
||||
|
||||
[Stretchable icons](https://github.com/mapbox/mapbox-gl-js/issues/8917) allow defining certain areas of an icon that may be stretched, leaving the remaining areas of an icon at a fixed size.
|
||||
|
||||
- [core] Port line-sort-key and fill-sort-key ([#15839](https://github.com/mapbox/mapbox-gl-native/pull/15839))
|
||||
|
||||
The new feature allows to sort line and fill layer features. Similar to `symbol-sort-key`.
|
||||
|
||||
- [core] Add image sections to format expression ([#15937](https://github.com/mapbox/mapbox-gl-native/pull/15937))
|
||||
|
||||
The new feature allows to embed images into labels.
|
||||
|
||||
- [core] Introduce OfflineDatabase::runPackDatabaseAutomatically() API ([#15967](https://github.com/mapbox/mapbox-gl-native/pull/15967))
|
||||
|
||||
The new API allows to enable / disable automatic packing of a database.
|
||||
|
||||
- [core] Decouple offline storage vacuum and the deleteRegion API ([#15899](https://github.com/mapbox/mapbox-gl-native/pull/15899))
|
||||
- introduce `OfflineDatabase::pack()` standing for incremental vacuum
|
||||
- make packing optional at offline region deletion
|
||||
|
||||
- [core] Implement image expression (#15877)
|
||||
|
||||
The [image expression](https://docs.mapbox.com/mapbox-gl-js/style-spec/#expressions-types-image) allows determining an image's availability.
|
||||
|
||||
- [core] Add batch conversion of latLngs to/from screenCoords ([#15891](https://github.com/mapbox/mapbox-gl-native/pull/15891))
|
||||
|
||||
This patch introduces batch conversion between LatLng and ScreenCoordinate in Gl-Native core, so for multiple conversions with single point/latLng previously now it can be done with invoking one function call by passing vector of points/latLngs.
|
||||
|
||||
### 🐞 Bug fixes
|
||||
- [tile mode] Fix variable symbols placement ([#16141](https://github.com/mapbox/mapbox-gl-native/pull/16141)
|
||||
|
||||
This change allows the variable symbols to cross the tile border only if their anchor is the first anchor from the `text-variable-anchor` list.
|
||||
|
||||
- [core] Use weak scheduler inside mailbox ([#16136](https://github.com/mapbox/mapbox-gl-native/pull/16136))
|
||||
|
||||
If there are pending requests that are completed after main scheduler is destructed, worker threads may try to push messages to destructed scheduler's queue.
|
||||
|
||||
- [core] Fix a crash in GeoJSON source parsing, caused by `GeoJSONVTData` ownership error ([#16106](https://github.com/mapbox/mapbox-gl-native/pull/16106))
|
||||
|
||||
- [core] Stable position of labels at tile borders in tile mode ([#16040](https://github.com/mapbox/mapbox-gl-native/pull/16040))
|
||||
|
||||
These changes allow to avoid cutting-off labels on tile borders if the variable text placement is enabled.
|
||||
|
||||
- [core] Fix really overscaled lines ([#16045](https://github.com/mapbox/mapbox-gl-native/pull/16045))
|
||||
|
||||
We resample lines after sharp corners in some situations. When tiles were really overscaled, sometimes we didn't have enough precision to represent the resampled vertex because it was too close. Disabling this after a certain point prevents this ([#16018](https://github.com/mapbox/mapbox-gl-native/issues/16018)).
|
||||
|
||||
- [core] Don't use signed int type for anchor segment ([#16008](https://github.com/mapbox/mapbox-gl-native/pull/16008))
|
||||
|
||||
Erroneous signed to unsigned implicit conversion was used when PlacedSymbol(s) were created in SymbolLayout and signed values were used as indexes in a few other places.
|
||||
|
||||
- [core] Increase padding in CollisionIndex for MapMode::Tile ([#15880](https://github.com/mapbox/mapbox-gl-native/pull/15880))
|
||||
|
||||
This increases the padding to 1024 for MapMode::Tile which should be enough to completely include all the data two zoom levels past the data source's max zoom level. Beyond that, 1024 should be enough of a padding to make clipped labels unlikely.
|
||||
|
||||
- [core] Blacklist VAO extension for Adreno (TM) 4xx GPUs ([#15978](https://github.com/mapbox/mapbox-gl-native/pull/15978))
|
||||
|
||||
Blacklist in order to avoid crashes in a driver (Android 5.1.1)
|
||||
|
||||
- [core] Retain thread pool in GeoJSONSource ([#15992](https://github.com/mapbox/mapbox-gl-native/pull/15992))
|
||||
|
||||
Otherwise, the construction of the `Immutable<Source::Impl>` in background thread might never yeld.
|
||||
|
||||
- [core] Fix supercluster lambdas capturing ([#15989](https://github.com/mapbox/mapbox-gl-native/pull/15989))
|
||||
|
||||
Fix wrapping of the parameters in supercluster map/reduce lambdas (Previously, local variables were wrapped by reference).
|
||||
|
||||
- [core] fix rendering of dashed lines with round caps ([#15947](https://github.com/mapbox/mapbox-gl-native/pull/15947))
|
||||
|
||||
In [#15862](https://github.com/mapbox/mapbox-gl-native/pull/15862), we introduced individual textures for line dash patterns to eliminate atlas overflows. Unfortunately, this broke dashed lines that had round caps (dashed lines with straight caps still rendered correctly). Line pattern textures for round caps were now using 256×15 pixel textures.
|
||||
|
||||
- [core] Fix incorrect resizing of TileCache ([#15943](https://github.com/mapbox/mapbox-gl-native/pull/15943))
|
||||
|
||||
- [core] Avoid GeoJSON source flickering on style transitions ([#15907](https://github.com/mapbox/mapbox-gl-native/pull/15907))
|
||||
|
||||
Before this change, all GeoJSON source cleared tile pyramid at the style transition and it caused flickering.
|
||||
|
||||
- [core] Use individual textures for line dash patterns ([#15862](https://github.com/mapbox/mapbox-gl-native/pull/15862))
|
||||
|
||||
This moves the LineAtlas from a shared texture that contained SDF dash patterns to use individual textures.
|
||||
|
||||
- [core] Fix collisions with icon-text-fit and variable placement ([#15828](https://github.com/mapbox/mapbox-gl-native/pull/15828))
|
||||
|
||||
When deciding the placement position it was only checking whether there were text collisions. Now, if icon-text-fit is used it now checks whether the icon fits before accepting a placement position.
|
||||
|
||||
- [core] Fix icon-text-fit ([#15634](https://github.com/mapbox/mapbox-gl-native/pull/15634))
|
||||
|
||||
This fixes rendering by account for the 1px texture padding around icons that were stretched with icon-text-fit.
|
||||
|
||||
### 🏁 Performance improvements
|
||||
|
||||
- [core] Cross tile index performance ([#16127](https://github.com/mapbox/mapbox-gl-native/pull/16127))
|
||||
|
||||
For overscaled tiles, index only the symbols inside the viewport.
|
||||
|
||||
Find matches only among the buckets that have the same leader Id.
|
||||
|
||||
- [core] Calculate GeoJSON tile geometries in a background thread ([#15953](https://github.com/mapbox/mapbox-gl-native/pull/15953))
|
||||
|
||||
Call `mapbox::geojsonvt::GeoJSONVT::getTile()` in a background thread, so that the rendering thread is not blocked.
|
||||
|
||||
- [core] Make requests for expired resources lower priority than requests for new resources ([#15950](https://github.com/mapbox/mapbox-gl-native/pull/15950))
|
||||
|
||||
- [core] Add Scheduler::scheduleAndReplyValue() API ([#15885](https://github.com/mapbox/mapbox-gl-native/pull/15885))
|
||||
|
||||
This change converts GeoJSON features to tiles for the loaded source description in a background thread and thus unblock the UI thread.
|
||||
|
||||
- [core] Enable incremental vacuum for Offline DB ([#15837](https://github.com/mapbox/mapbox-gl-native/pull/15837))
|
||||
|
||||
Thus we avoid re-creating the whole database and keeping the backup file as it happens on calling VACUUM.
|
||||
|
||||
- [core] Fix image requests for already obtained images ([#15825](https://github.com/mapbox/mapbox-gl-native/pull/15825))
|
||||
|
||||
Before this fix, repeated request for an already obtained image was erroneously treated as pending, and it prevented from the tiles load completion.
|
||||
|
||||
### 🧩 Architectural changes
|
||||
|
||||
- [core] Merge style::Layer::set{Layout,Paint}Property ([#15997](https://github.com/mapbox/mapbox-gl-native/pull/15997))
|
||||
|
||||
- [core] Use expected.hpp from mapbox-base ([#15898](https://github.com/mapbox/mapbox-gl-native/pull/15898))
|
||||
|
||||
##### ⚠️ Breaking changes
|
||||
|
||||
- [core] Cross tile index performance (#16127)
|
||||
|
||||
Introduces public [mblg::Renderer::render](https://github.com/mapbox/mapbox-gl-native/pull/16127/files#diff-5a977e0401792825d7fcf522d48df11fR34) API break.
|
||||
|
||||
- [core] Refactor DefaultFileSource codebase ([#15768](https://github.com/mapbox/mapbox-gl-native/pull/15768))
|
||||
- Adds `FileSourceManager` interface that provides access to `FileSource` instances and means of registering / unregistering `FileSource` factories
|
||||
- Splits `DefaultFileSource` into smaller parts
|
||||
- Adds `DatabaseFileSource` interface and it's default implementation
|
||||
- Removes inter-dependencies between concrete `FileSource` classes
|
||||
- All sources operate on dedicated thread, except `MainResourceLoader` that acts as a dispatcher and works on thread that requested it.
|
||||
- Removes `ResourceOptions::withCacheOnlyRequestsSupport` method
|
||||
|
||||
- [core] Remove Map::cycleDebugOptions ([#16005](https://github.com/mapbox/mapbox-gl-native/pull/16005))
|
||||
|
||||
This function was mostly used by the Android API, which is no longer necessary.
|
||||
1053
mapbox-gl-native/CMakeLists.txt
Normal file
1053
mapbox-gl-native/CMakeLists.txt
Normal file
File diff suppressed because it is too large
Load Diff
5
mapbox-gl-native/CODE-OF-CONDUCT.md
Normal file
5
mapbox-gl-native/CODE-OF-CONDUCT.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# Code of conduct
|
||||
|
||||
Everyone is invited to participate in Mapbox’s open source projects and public discussions: we want to create a welcoming and friendly environment. Harassment of participants or other unethical and unprofessional behavior will not be tolerated in our spaces. The [Contributor Covenant](http://contributor-covenant.org) applies to all projects under the Mapbox organization and we ask that you please read [the full text](http://contributor-covenant.org/version/1/2/0/).
|
||||
|
||||
You can learn more about our open source philosophy on [mapbox.com](https://www.mapbox.com/about/open/).
|
||||
36
mapbox-gl-native/CONTRIBUTING.md
Normal file
36
mapbox-gl-native/CONTRIBUTING.md
Normal file
@@ -0,0 +1,36 @@
|
||||
# Contributing
|
||||
|
||||
If you have a usage question for a product built on Mapbox GL (such as our iOS or Android SDKs), please visit https://www.mapbox.com/help/.
|
||||
|
||||
If you want to contribute code:
|
||||
|
||||
1. Please familiarize yourself with the [install process](INSTALL.md).
|
||||
|
||||
1. Ensure that existing [pull requests](https://github.com/mapbox/mapbox-gl-native/pulls) and [issues](https://github.com/mapbox/mapbox-gl-native/issues) don’t already cover your contribution or question.
|
||||
|
||||
1. Pull requests are gladly accepted. If there are any changes that developers using one of the GL SDKs should be aware of, please update the **master** section of the relevant changelog(s):
|
||||
* [Mapbox Maps SDK for Android](platform/android/CHANGELOG.md)
|
||||
* [Mapbox Maps SDK for iOS](platform/ios/CHANGELOG.md)
|
||||
* [Mapbox Maps SDK for macOS](platform/macos/CHANGELOG.md)
|
||||
* [node-mapbox-gl-native](platform/node/CHANGELOG.md)
|
||||
|
||||
1. Prefix your commit messages with the platform(s) your changes affect: `[core]`, `[android]`, `[ios]`, `[macos]`, `[node]`, or `[qt]`.
|
||||
|
||||
Please note the special instructions for contributing new source code files, asset files, or user-facing strings to the [iOS SDK](platform/ios/DEVELOPING.md#contributing) or [macOS SDK](platform/macos/DEVELOPING.md#contributing).
|
||||
|
||||
### Github issue labels
|
||||
|
||||
Our labeling system is:
|
||||
|
||||
* **minimalistic:** Labels’ usefulness are inversely proportional to how many we have.
|
||||
* **objective:** Labels should be objective enough that any two people would agree on a labeling decision.
|
||||
* **useful:** Labels should track state or capture semantic meaning that would otherwise be hard to search for.
|
||||
|
||||
We’ve color-coded our labels by facet to make them easier to use:
|
||||
|
||||
* type (blue)
|
||||
* platform (black)
|
||||
* actionable status (red)
|
||||
* non-actionable status (grey)
|
||||
* importance / urgency (green)
|
||||
* topic / project / misc (yellow)
|
||||
11
mapbox-gl-native/DEVELOPING.md
Normal file
11
mapbox-gl-native/DEVELOPING.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# Developing
|
||||
|
||||
This is been rewritten to include:
|
||||
|
||||
- How to build for the platforms we support.
|
||||
- Acceptance criteria for code contributions (style, static asserts)
|
||||
- How to run the unit tests.
|
||||
- How to run the benchmarks.
|
||||
- How to run the render tests.
|
||||
- How to rebaseline baselines metrics.
|
||||
- How to use GL Native as a 3rd party library in your project.
|
||||
661
mapbox-gl-native/LICENSE.mbgl-core.md
Normal file
661
mapbox-gl-native/LICENSE.mbgl-core.md
Normal file
@@ -0,0 +1,661 @@
|
||||
### [Mapbox GL Native](https://github.com/mapbox/mapbox-gl-native) by Mapbox
|
||||
|
||||
```
|
||||
mapbox-gl-native Copyright (c) 2014-2020 Mapbox.
|
||||
|
||||
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.
|
||||
|
||||
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 OWNER 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.
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### [kdbush.hpp](https://github.com/mourner/kdbush.hpp) by Vladimir Agafonkin
|
||||
|
||||
```
|
||||
Copyright (c) 2016, Vladimir Agafonkin
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### [supercluster.hpp](https://github.com/mapbox/supercluster.hpp) by Mapbox
|
||||
|
||||
```
|
||||
Copyright (c) 2016, Mapbox
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### [shelf-pack-cpp](https://github.com/mapbox/shelf-pack-cpp) by Mapbox
|
||||
|
||||
```
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2017, Mapbox
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose
|
||||
with or without fee is hereby granted, provided that the above copyright notice
|
||||
and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||
THIS SOFTWARE.
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### [geojson-vt-cpp](https://github.com/mapbox/geojson-vt-cpp) by Mapbox
|
||||
|
||||
```
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2015, Mapbox
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose
|
||||
with or without fee is hereby granted, provided that the above copyright notice
|
||||
and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||
THIS SOFTWARE.
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### [cheap-ruler-cpp](https://github.com/mapbox/cheap-ruler-cpp) by Mapbox
|
||||
|
||||
```
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2017, Mapbox
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose
|
||||
with or without fee is hereby granted, provided that the above copyright notice
|
||||
and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||
THIS SOFTWARE.
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### [Boost C++ Libraries](https://www.boost.org) by Boost authors
|
||||
|
||||
```
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### [csscolorparser](https://github.com/mapbox/css-color-parser-cpp) by Dean McNamee and Konstantin Käfer
|
||||
|
||||
```
|
||||
(c) Dean McNamee <dean@gmail.com>, 2012.
|
||||
(c) Konstantin Käfer <mail@kkaefer.com>, 2014.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to
|
||||
deal in the Software without restriction, including without limitation the
|
||||
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
IN THE SOFTWARE.
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### [earcut.hpp](https://github.com/mapbox/earcut.hpp) by Mapbox
|
||||
|
||||
```
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2015, Mapbox
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose
|
||||
with or without fee is hereby granted, provided that the above copyright notice
|
||||
and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||
THIS SOFTWARE.
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### [eternal](https://github.com/mapbox/eternal) by Mapbox
|
||||
|
||||
```
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2018, Mapbox
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose
|
||||
with or without fee is hereby granted, provided that the above copyright notice
|
||||
and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||
THIS SOFTWARE.
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### [parsedate](https://curl.haxx.se) by Daniel Stenberg and others
|
||||
|
||||
```
|
||||
COPYRIGHT AND PERMISSION NOTICE
|
||||
|
||||
Copyright (c) 1996 - 2020, Daniel Stenberg, <daniel@haxx.se>, and many
|
||||
contributors, see the THANKS file.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any purpose
|
||||
with or without fee is hereby granted, provided that the above copyright
|
||||
notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN
|
||||
NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
||||
OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of a copyright holder shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization of the copyright holder.
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### [polylabel](https://github.com/mapbox/polylabel) by Mapbox
|
||||
|
||||
```
|
||||
ISC License
|
||||
Copyright (c) 2016 Mapbox
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose
|
||||
with or without fee is hereby granted, provided that the above copyright notice
|
||||
and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD TO
|
||||
THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
|
||||
IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
|
||||
CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
|
||||
OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||||
ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
SOFTWARE.
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### [protozero](https://github.com/mapbox/protozero) by Mapbox
|
||||
|
||||
```
|
||||
protozero copyright (c) Mapbox.
|
||||
|
||||
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.
|
||||
|
||||
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 OWNER 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.
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### [unique_resource](https://github.com/okdshin/unique_resource) by Shintarou Okada
|
||||
|
||||
```
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### [vector-tile](https://github.com/mapbox/vector-tile) by Mapbox
|
||||
|
||||
```
|
||||
Copyright (c) 2016, Mapbox
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### [wagyu](https://github.com/mapbox/wagyu.git) by Angus Johnson and Mapbox
|
||||
|
||||
```
|
||||
Parts of the code in the Wagyu Library are derived from the version of the
|
||||
Clipper Library by Angus Johnson listed below.
|
||||
|
||||
Author : Angus Johnson
|
||||
Version : 6.4.0
|
||||
Date : 2 July 2015
|
||||
Website : http://www.angusj.com
|
||||
|
||||
Copyright for portions of the derived code in the Wagyu library are held
|
||||
by Angus Johnson, 2010-2015. All other copyright for the Wagyu Library are held by
|
||||
Mapbox, 2016. This code is published in accordance with, and retains the same license
|
||||
as the Clipper Library by Angus Johnson.
|
||||
|
||||
Copyright (c) 2010-2015, Angus Johnson
|
||||
Copyright (c) 2016, Mapbox
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### [mapbox-base](https://github.com/mapbox/mapbox-base) by Mapbox
|
||||
|
||||
```
|
||||
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.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### [expected-lite](https://github.com/martinmoene/expected-lite) by Martin Moene
|
||||
|
||||
```
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### [RapidJSON](https://rapidjson.org) by THL A29 Limited, a Tencent company, and Milo Yip
|
||||
|
||||
```
|
||||
Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
|
||||
Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
|
||||
If you have downloaded a copy of the RapidJSON binary from Tencent, please note that the RapidJSON binary is licensed under the MIT License.
|
||||
If you have downloaded a copy of the RapidJSON source code from Tencent, please note that RapidJSON source code is licensed under the MIT License, except for the third-party components listed below which are subject to different license terms. Your integration of RapidJSON into your own projects may require compliance with the MIT License, as well as the other licenses applicable to the third-party components included within RapidJSON. To avoid the problematic JSON license in your own projects, it's sufficient to exclude the bin/jsonchecker/ directory, as it's the only code under the JSON license.
|
||||
A copy of the MIT License is included in this file.
|
||||
|
||||
Other dependencies and licenses:
|
||||
|
||||
Open Source Software Licensed Under the BSD License:
|
||||
--------------------------------------------------------------------
|
||||
|
||||
The msinttypes r29
|
||||
Copyright (c) 2006-2013 Alexander Chemeris
|
||||
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 of copyright holder 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 REGENTS 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 REGENTS AND 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.
|
||||
|
||||
Open Source Software Licensed Under the JSON License:
|
||||
--------------------------------------------------------------------
|
||||
|
||||
json.org
|
||||
Copyright (c) 2002 JSON.org
|
||||
All Rights Reserved.
|
||||
|
||||
JSON_checker
|
||||
Copyright (c) 2002 JSON.org
|
||||
All Rights Reserved.
|
||||
|
||||
|
||||
Terms of the JSON License:
|
||||
---------------------------------------------------
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
Terms of the MIT License:
|
||||
--------------------------------------------------------------------
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### [geojson.hpp](https://github.com/mapbox/geojson-cpp) by Mapbox
|
||||
|
||||
```
|
||||
Copyright (c) 2016, Mapbox
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### [geometry.hpp](https://github.com/mapbox/geometry.hpp) by Mapbox
|
||||
|
||||
```
|
||||
Copyright (c) 2016, Mapbox
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### [Optional](https://github.com/akrzemi1/Optional) by Andrzej Krzemienski
|
||||
|
||||
```
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### [variant](https://github.com/mapbox/variant) by Mapbox
|
||||
|
||||
```
|
||||
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.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
24
mapbox-gl-native/LICENSE.md
Normal file
24
mapbox-gl-native/LICENSE.md
Normal file
@@ -0,0 +1,24 @@
|
||||
mapbox-gl-native Copyright (c) 2014-2020 Mapbox.
|
||||
|
||||
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.
|
||||
|
||||
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 OWNER 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.
|
||||
34
mapbox-gl-native/README.md
Normal file
34
mapbox-gl-native/README.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# Mapbox GL Native
|
||||
|
||||
[](https://circleci.com/gh/mapbox/workflows/mapbox-gl-native/tree/master) [](https://codecov.io/gh/mapbox/mapbox-gl-native)
|
||||
|
||||
A C++ library that powers customizable vector maps in native applications on multiple platforms by taking stylesheets that conform to the [Mapbox Style Specification](https://docs.mapbox.com/mapbox-gl-js/style-spec/), applying them to vector tiles that conform to the [Mapbox Vector Tile Specification](https://github.com/mapbox/vector-tile-spec/), and rendering them using OpenGL or Metal.
|
||||
|
||||
To embed interactive maps into a native application using a platform-specific language, install the Mapbox Maps SDK:
|
||||
|
||||
* [Mapbox Maps SDK for Android](https://github.com/mapbox/mapbox-gl-native-android/) (Java, Kotlin)
|
||||
* [Mapbox Maps SDK for iOS](https://github.com/mapbox/mapbox-gl-native-ios/blob/master/platform/ios/) (Objective-C, Swift, Interface Builder)
|
||||
* [Mapbox Maps SDK for macOS](https://github.com/mapbox/mapbox-gl-native-ios/tree/master/platform/macos/) (Objective-C, Swift, Interface Builder, AppleScript)
|
||||
|
||||
[Mapbox GL JS](https://github.com/mapbox/mapbox-gl-js) is the WebGL-based counterpart to Mapbox GL Native that is designed for use on the Web.
|
||||
|
||||
## [Developing](DEVELOPING.md)
|
||||
|
||||
We use [CMake](https://cmake.org/cmake/help/latest/) to build Mapbox GL Native
|
||||
for various platforms, including Linux, Android, iOS, macOS and Windows. The
|
||||
following command, executed from the root of this repository tree, will build
|
||||
Mapbox GL Native targeting your host architecture given that you have all the
|
||||
dependencies installed and run the example app.
|
||||
|
||||
```
|
||||
$ git submodule update --init --recursive
|
||||
$ cmake . -B build
|
||||
$ cmake --build build
|
||||
$ MAPBOX_ACCESS_TOKEN=my_access_token_here ./build/platform/glfw/mbgl-glfw
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Mapbox GL Native is licensed under the [2-Clause BSD license](LICENSE.md). The licenses of its dependencies are tracked via [FOSSA](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fmapbox%2Fmapbox-gl-native):
|
||||
|
||||
[](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fmapbox%2Fmapbox-gl-native)
|
||||
88
mapbox-gl-native/appveyor.yml
Normal file
88
mapbox-gl-native/appveyor.yml
Normal file
@@ -0,0 +1,88 @@
|
||||
platform: x64
|
||||
|
||||
image:
|
||||
- Visual Studio 2015
|
||||
- Visual Studio 2017
|
||||
|
||||
environment:
|
||||
PYTHON: C:\python37
|
||||
|
||||
matrix:
|
||||
- configuration: Release
|
||||
- configuration: Debug
|
||||
|
||||
test: off
|
||||
|
||||
clone_depth: 1
|
||||
|
||||
for:
|
||||
-
|
||||
matrix:
|
||||
only:
|
||||
- image: Visual Studio 2015
|
||||
|
||||
environment:
|
||||
LLVM_VERSION: 5.0.1
|
||||
LLVM_HASH: 981543611D719624ACB29A2CFFD6A479CFF36E8AB5EE8A57D8ECA4F9C4C6956F
|
||||
VCVARSALL: 'C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat'
|
||||
QT_PREFIX: 'C:\Qt\latest\msvc2015_64\lib\cmake'
|
||||
|
||||
-
|
||||
matrix:
|
||||
only:
|
||||
- image: Visual Studio 2017
|
||||
|
||||
environment:
|
||||
LLVM_VERSION: 7.0.0
|
||||
LLVM_HASH: 74b197a3959b0408adf0824be01db8dddfa2f9a967f4085af3fad900ed5fdbf6
|
||||
VCVARSALL: 'C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat'
|
||||
QT_PREFIX: 'C:\Qt\latest\msvc2017_64\lib\cmake'
|
||||
|
||||
cache:
|
||||
- '%APPVEYOR_BUILD_FOLDER%\.git\modules'
|
||||
- '%APPVEYOR_BUILD_FOLDER%\LLVM-%LLVM_VERSION%-win64.exe'
|
||||
- '%APPVEYOR_BUILD_FOLDER%\cmake-3.10.1-win64-x64.zip'
|
||||
- C:\clcache
|
||||
|
||||
install:
|
||||
- set PATH=%PYTHON%\Scripts;%PYTHON%;%PATH%
|
||||
- pip install clcache
|
||||
- git config --system core.longpaths true
|
||||
- git submodule sync
|
||||
- git submodule update --init
|
||||
- git submodule foreach git submodule update --init
|
||||
- ps: |
|
||||
if (!(Test-Path "LLVM-$env:LLVM_VERSION-win64.exe")) {
|
||||
appveyor DownloadFile "https://releases.llvm.org/$env:LLVM_VERSION/LLVM-$env:LLVM_VERSION-win64.exe"
|
||||
}
|
||||
scripts\check-sha256.ps1 LLVM-$env:LLVM_VERSION-win64.exe "$env:LLVM_HASH"
|
||||
Start-Process -FilePath "LLVM-$env:LLVM_VERSION-win64.exe" -ArgumentList '/S',"/D=C:\LLVM-$env:LLVM_VERSION" -Wait
|
||||
- ps: |
|
||||
if (!(Test-Path cmake-3.10.1-win64-x64.zip)) {
|
||||
appveyor DownloadFile https://cmake.org/files/v3.10/cmake-3.10.1-win64-x64.zip
|
||||
}
|
||||
scripts\check-sha256.ps1 cmake-3.10.1-win64-x64.zip 8251F70C85B58F3CA1F24E4A3B0637E2D609B5E4A341D00B70E02E89244D5029
|
||||
Start-Process -FilePath '7z' -ArgumentList 'x','cmake-3.10.1-win64-x64.zip','-oC:\' -Wait
|
||||
|
||||
before_build:
|
||||
- set PATH=C:\LLVM-%LLVM_VERSION%\bin;%PATH%
|
||||
- set PATH=C:\cmake-3.10.1-win64-x64\bin;%PATH%
|
||||
- set CLCACHE_DIR=c:\clcache
|
||||
- set CLCACHE_CL=clang-cl
|
||||
- clcache -z
|
||||
- set CC=clcache
|
||||
- set CXX=clcache
|
||||
- set CTEST_OUTPUT_ON_FAILURE=1
|
||||
- mkdir %APPVEYOR_BUILD_FOLDER%\build
|
||||
- cd %APPVEYOR_BUILD_FOLDER%\build
|
||||
|
||||
build_script:
|
||||
- call "%VCVARSALL%" amd64
|
||||
- cmake -G "Ninja"
|
||||
-DCMAKE_BUILD_TYPE=%CONFIGURATION%
|
||||
-DCMAKE_MAKE_PROGRAM="%APPVEYOR_BUILD_FOLDER%\platform\qt\ninja.exe"
|
||||
-DCMAKE_PREFIX_PATH=%QT_PREFIX%
|
||||
-DMBGL_WITH_QT=ON
|
||||
..
|
||||
- cmake --build . --target qmapboxgl -- -j %NUMBER_OF_PROCESSORS%
|
||||
- clcache -s
|
||||
50
mapbox-gl-native/benchmark/CMakeLists.txt
Normal file
50
mapbox-gl-native/benchmark/CMakeLists.txt
Normal file
@@ -0,0 +1,50 @@
|
||||
add_library(
|
||||
mbgl-benchmark STATIC EXCLUDE_FROM_ALL
|
||||
${PROJECT_SOURCE_DIR}/benchmark/api/query.benchmark.cpp
|
||||
${PROJECT_SOURCE_DIR}/benchmark/api/render.benchmark.cpp
|
||||
${PROJECT_SOURCE_DIR}/benchmark/function/camera_function.benchmark.cpp
|
||||
${PROJECT_SOURCE_DIR}/benchmark/function/composite_function.benchmark.cpp
|
||||
${PROJECT_SOURCE_DIR}/benchmark/function/source_function.benchmark.cpp
|
||||
${PROJECT_SOURCE_DIR}/benchmark/parse/filter.benchmark.cpp
|
||||
${PROJECT_SOURCE_DIR}/benchmark/parse/tile_mask.benchmark.cpp
|
||||
${PROJECT_SOURCE_DIR}/benchmark/parse/vector_tile.benchmark.cpp
|
||||
${PROJECT_SOURCE_DIR}/benchmark/src/mbgl/benchmark/benchmark.cpp
|
||||
${PROJECT_SOURCE_DIR}/benchmark/storage/offline_database.benchmark.cpp
|
||||
${PROJECT_SOURCE_DIR}/benchmark/util/dtoa.benchmark.cpp
|
||||
${PROJECT_SOURCE_DIR}/benchmark/util/tilecover.benchmark.cpp
|
||||
)
|
||||
|
||||
target_include_directories(
|
||||
mbgl-benchmark
|
||||
PRIVATE ${PROJECT_SOURCE_DIR}/benchmark/src ${PROJECT_SOURCE_DIR}/platform/default/include ${PROJECT_SOURCE_DIR}/src
|
||||
)
|
||||
|
||||
target_include_directories(
|
||||
mbgl-benchmark
|
||||
PUBLIC ${PROJECT_SOURCE_DIR}/benchmark/include ${PROJECT_SOURCE_DIR}/include
|
||||
)
|
||||
|
||||
include(${PROJECT_SOURCE_DIR}/vendor/benchmark.cmake)
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL iOS)
|
||||
set_target_properties(mbgl-vendor-benchmark PROPERTIES XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET "${IOS_DEPLOYMENT_TARGET}")
|
||||
set_target_properties(mbgl-vendor-benchmark PROPERTIES XCODE_ATTRIBUTE_ENABLE_BITCODE "YES")
|
||||
set_target_properties(mbgl-vendor-benchmark PROPERTIES XCODE_ATTRIBUTE_BITCODE_GENERATION_MODE bitcode)
|
||||
set_target_properties(mbgl-vendor-benchmark PROPERTIES XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH $<$<CONFIG:Debug>:YES>)
|
||||
|
||||
set_target_properties(mbgl-benchmark PROPERTIES XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET "${IOS_DEPLOYMENT_TARGET}")
|
||||
set_target_properties(mbgl-benchmark PROPERTIES XCODE_ATTRIBUTE_ENABLE_BITCODE "YES")
|
||||
set_target_properties(mbgl-benchmark PROPERTIES XCODE_ATTRIBUTE_BITCODE_GENERATION_MODE bitcode)
|
||||
set_target_properties(mbgl-benchmark PROPERTIES XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH $<$<CONFIG:Debug>:YES>)
|
||||
endif()
|
||||
|
||||
# Needed for testing private classes
|
||||
get_target_property(MBGL_CORE_PRIVATE_LIBRARIES mbgl-core LINK_LIBRARIES)
|
||||
|
||||
target_link_libraries(
|
||||
mbgl-benchmark
|
||||
PRIVATE ${MBGL_CORE_PRIVATE_LIBRARIES} mbgl-vendor-benchmark mbgl-compiler-options
|
||||
PUBLIC mbgl-core
|
||||
)
|
||||
|
||||
set_property(TARGET mbgl-benchmark PROPERTY FOLDER Core)
|
||||
3
mapbox-gl-native/benchmark/android/README.md
Normal file
3
mapbox-gl-native/benchmark/android/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# BenchmarkRunner
|
||||
|
||||
This app is a purely native application that can run **mbgl-benchmark-runner** on Android devices.
|
||||
52
mapbox-gl-native/benchmark/android/app/build.gradle
Normal file
52
mapbox-gl-native/benchmark/android/app/build.gradle
Normal file
@@ -0,0 +1,52 @@
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
compileSdkVersion 28
|
||||
|
||||
defaultConfig {
|
||||
applicationId = 'com.mapbox.mapboxsdk.maps.benchmark_runner'
|
||||
minSdkVersion 14
|
||||
targetSdkVersion 28
|
||||
def abi = 'all'
|
||||
if (project.hasProperty('mapbox.abis')) {
|
||||
abi = project.getProperty('mapbox.abis')
|
||||
}
|
||||
ndk {
|
||||
if (abi != 'all') {
|
||||
abiFilters abi.split(' ')
|
||||
} else {
|
||||
abiFilters 'armeabi-v7a', 'x86', 'arm64-v8a', 'x86_64'
|
||||
}
|
||||
}
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
arguments '-DANDROID_CCACHE=ccache'
|
||||
arguments '-DANDROID_STL=c++_static'
|
||||
targets 'mbgl-benchmark-runner'
|
||||
}
|
||||
}
|
||||
android {
|
||||
testBuildType 'release'
|
||||
}
|
||||
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
||||
}
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
version '3.10.2'
|
||||
path '../../../CMakeLists.txt'
|
||||
}
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
signingConfig signingConfigs.debug
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||
androidTestImplementation 'androidx.test:rules:1.2.0'
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package android.app;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.LargeTest;
|
||||
import androidx.test.rule.ActivityTestRule;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.Assert;
|
||||
import org.junit.runner.RunWith;
|
||||
import android.util.Log;
|
||||
|
||||
@LargeTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class NativeActivityTest {
|
||||
|
||||
@Rule
|
||||
public ActivityTestRule<NativeActivity> mActivityTestRule = new ActivityTestRule<>(NativeActivity.class, false, false);
|
||||
|
||||
@Test(timeout = 1200000L)
|
||||
public void runBenchmark() throws Exception {
|
||||
Log.v("Benchmark", "Start the benchmark");
|
||||
mActivityTestRule.launchActivity(null);
|
||||
while (TestState.running) {
|
||||
Log.v("Benchmark", "Benchmark is running...");
|
||||
Thread.sleep(1000L);
|
||||
}
|
||||
Log.v("Benchmark", "All benchmarks are finished!");
|
||||
mActivityTestRule.finishActivity();
|
||||
Assert.assertTrue("Benchmark was successfully finished", TestState.testResult);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package android.app;
|
||||
|
||||
public class TestState {
|
||||
static boolean running = true;
|
||||
static boolean testResult = true;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.mapbox.mapboxsdk.maps.benchmark_runner"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0">
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<application
|
||||
android:allowBackup="false"
|
||||
android:fullBackupContent="false"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:hasCode="true">
|
||||
|
||||
<activity android:name="android.app.NativeActivity"
|
||||
android:label="@string/app_name"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:screenOrientation="portrait">
|
||||
<meta-data android:name="android.app.lib_name"
|
||||
android:value="mbgl-benchmark-runner" />
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@@ -0,0 +1,3 @@
|
||||
benchmark/results/
|
||||
benchmark/fixtures/
|
||||
test/fixtures/api/assets/streets/
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 3.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.2 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 4.7 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 7.5 KiB |
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">BenchmarkRunner</string>
|
||||
</resources>
|
||||
21
mapbox-gl-native/benchmark/android/build.gradle
Normal file
21
mapbox-gl-native/benchmark/android/build.gradle
Normal file
@@ -0,0 +1,21 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
buildscript {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.5.3'
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
||||
1
mapbox-gl-native/benchmark/android/gradle.properties
Normal file
1
mapbox-gl-native/benchmark/android/gradle.properties
Normal file
@@ -0,0 +1 @@
|
||||
org.gradle.jvmargs=-Xmx1536m
|
||||
BIN
mapbox-gl-native/benchmark/android/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
mapbox-gl-native/benchmark/android/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
6
mapbox-gl-native/benchmark/android/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
6
mapbox-gl-native/benchmark/android/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#Sun Feb 05 19:39:12 IST 2017
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
|
||||
164
mapbox-gl-native/benchmark/android/gradlew
vendored
Executable file
164
mapbox-gl-native/benchmark/android/gradlew
vendored
Executable file
@@ -0,0 +1,164 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn ( ) {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die ( ) {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
esac
|
||||
|
||||
# For Cygwin, ensure paths are in UNIX format before anything is touched.
|
||||
if $cygwin ; then
|
||||
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
|
||||
fi
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >&-
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >&-
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
||||
function splitJvmOpts() {
|
||||
JVM_OPTS=("$@")
|
||||
}
|
||||
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
||||
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
||||
|
||||
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
||||
90
mapbox-gl-native/benchmark/android/gradlew.bat
vendored
Normal file
90
mapbox-gl-native/benchmark/android/gradlew.bat
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windowz variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
if "%@eval[2+2]" == "4" goto 4NT_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
goto execute
|
||||
|
||||
:4NT_args
|
||||
@rem Get arguments from the 4NT Shell from JP Software
|
||||
set CMD_LINE_ARGS=%$
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
2
mapbox-gl-native/benchmark/android/settings.gradle
Normal file
2
mapbox-gl-native/benchmark/android/settings.gradle
Normal file
@@ -0,0 +1,2 @@
|
||||
include ':app'
|
||||
|
||||
92
mapbox-gl-native/benchmark/api/query.benchmark.cpp
Normal file
92
mapbox-gl-native/benchmark/api/query.benchmark.cpp
Normal file
@@ -0,0 +1,92 @@
|
||||
#include <benchmark/benchmark.h>
|
||||
|
||||
#include <mbgl/map/map.hpp>
|
||||
#include <mbgl/map/map_options.hpp>
|
||||
#include <mbgl/gfx/headless_frontend.hpp>
|
||||
#include <mbgl/renderer/renderer.hpp>
|
||||
#include <mbgl/style/style.hpp>
|
||||
#include <mbgl/style/image.hpp>
|
||||
#include <mbgl/storage/network_status.hpp>
|
||||
#include <mbgl/util/image.hpp>
|
||||
#include <mbgl/util/io.hpp>
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
namespace {
|
||||
|
||||
class QueryBenchmark {
|
||||
public:
|
||||
QueryBenchmark() {
|
||||
NetworkStatus::Set(NetworkStatus::Status::Offline);
|
||||
|
||||
map.getStyle().loadJSON(util::read_file("benchmark/fixtures/api/style.json"));
|
||||
map.jumpTo(CameraOptions().withCenter(LatLng { 40.726989, -73.992857 }).withZoom(15.0)); // Manhattan
|
||||
map.getStyle().addImage(std::make_unique<style::Image>("test-icon",
|
||||
decodeImage(util::read_file("benchmark/fixtures/api/default_marker.png")), 1.0));
|
||||
|
||||
frontend.render(map);
|
||||
}
|
||||
|
||||
util::RunLoop loop;
|
||||
HeadlessFrontend frontend { { 1000, 1000 }, 1 };
|
||||
Map map { frontend, MapObserver::nullObserver(),
|
||||
MapOptions().withMapMode(MapMode::Static).withSize(frontend.getSize()),
|
||||
ResourceOptions().withCachePath("benchmark/fixtures/api/cache.db").withAssetPath(".").withAccessToken("foobar") };
|
||||
ScreenBox box{{ 0, 0 }, { 1000, 1000 }};
|
||||
};
|
||||
|
||||
} // end namespace
|
||||
|
||||
static void API_queryPixelsForLatLngs(::benchmark::State& state) {
|
||||
std::vector<LatLng> points;
|
||||
int count = 10000;
|
||||
for (int i = 0; i < count; ++i) {
|
||||
points.emplace_back(1, 1);
|
||||
}
|
||||
QueryBenchmark bench;
|
||||
while (state.KeepRunning()) {
|
||||
(void)bench.map.pixelsForLatLngs(points);
|
||||
}
|
||||
}
|
||||
|
||||
static void API_queryLatLngsForPixels(::benchmark::State& state) {
|
||||
std::vector<ScreenCoordinate> points;
|
||||
int count = 10000;
|
||||
for (int i = 0; i < count; ++i) {
|
||||
points.emplace_back(1, 1);
|
||||
}
|
||||
QueryBenchmark bench;
|
||||
while (state.KeepRunning()) {
|
||||
(void)bench.map.latLngsForPixels(points);
|
||||
}
|
||||
}
|
||||
|
||||
static void API_queryRenderedFeaturesAll(::benchmark::State& state) {
|
||||
QueryBenchmark bench;
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
bench.frontend.getRenderer()->queryRenderedFeatures(bench.box, {});
|
||||
}
|
||||
}
|
||||
|
||||
static void API_queryRenderedFeaturesLayerFromLowDensity(::benchmark::State& state) {
|
||||
QueryBenchmark bench;
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
bench.frontend.getRenderer()->queryRenderedFeatures(bench.box, {{{ "testlayer" }}, {}});
|
||||
}
|
||||
}
|
||||
|
||||
static void API_queryRenderedFeaturesLayerFromHighDensity(::benchmark::State& state) {
|
||||
QueryBenchmark bench;
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
bench.frontend.getRenderer()->queryRenderedFeatures(bench.box, {{{"road-street" }}, {}});
|
||||
}
|
||||
}
|
||||
BENCHMARK(API_queryPixelsForLatLngs);
|
||||
BENCHMARK(API_queryLatLngsForPixels);
|
||||
BENCHMARK(API_queryRenderedFeaturesAll)->Iterations(50);
|
||||
BENCHMARK(API_queryRenderedFeaturesLayerFromLowDensity);
|
||||
BENCHMARK(API_queryRenderedFeaturesLayerFromHighDensity);
|
||||
159
mapbox-gl-native/benchmark/api/render.benchmark.cpp
Normal file
159
mapbox-gl-native/benchmark/api/render.benchmark.cpp
Normal file
@@ -0,0 +1,159 @@
|
||||
#include <benchmark/benchmark.h>
|
||||
|
||||
#include <mbgl/gfx/headless_frontend.hpp>
|
||||
#include <mbgl/map/map.hpp>
|
||||
#include <mbgl/map/map_observer.hpp>
|
||||
#include <mbgl/map/map_options.hpp>
|
||||
#include <mbgl/renderer/renderer.hpp>
|
||||
#include <mbgl/storage/network_status.hpp>
|
||||
#include <mbgl/storage/resource_options.hpp>
|
||||
#include <mbgl/style/image.hpp>
|
||||
#include <mbgl/style/layers/symbol_layer.hpp>
|
||||
#include <mbgl/style/sources/geojson_source.hpp>
|
||||
#include <mbgl/style/style.hpp>
|
||||
#include <mbgl/util/image.hpp>
|
||||
#include <mbgl/util/io.hpp>
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
namespace {
|
||||
|
||||
static std::string cachePath { "benchmark/fixtures/api/cache.db" };
|
||||
constexpr double pixelRatio { 1.0 };
|
||||
constexpr Size size { 1000, 1000 };
|
||||
|
||||
class RenderBenchmark {
|
||||
public:
|
||||
RenderBenchmark() {
|
||||
NetworkStatus::Set(NetworkStatus::Status::Offline);
|
||||
}
|
||||
|
||||
util::RunLoop loop;
|
||||
};
|
||||
|
||||
void prepare(Map& map, optional<std::string> json = nullopt) {
|
||||
map.getStyle().loadJSON(json ? *json : util::read_file("benchmark/fixtures/api/style.json"));
|
||||
map.jumpTo(CameraOptions().withCenter(LatLng { 40.726989, -73.992857 }).withZoom(15.0)); // Manhattan
|
||||
|
||||
auto image = decodeImage(util::read_file("benchmark/fixtures/api/default_marker.png"));
|
||||
map.getStyle().addImage(std::make_unique<style::Image>("test-icon", std::move(image), 1.0));
|
||||
}
|
||||
|
||||
void prepare_map2(Map& map, optional<std::string> json = nullopt) {
|
||||
map.getStyle().loadJSON(json ? *json : util::read_file("benchmark/fixtures/api/style.json"));
|
||||
map.jumpTo(CameraOptions().withCenter(LatLng{41.379800, 2.176810}).withZoom(15.0)); // Barcelona
|
||||
|
||||
auto image = decodeImage(util::read_file("benchmark/fixtures/api/default_marker.png"));
|
||||
map.getStyle().addImage(std::make_unique<style::Image>("test-icon", std::move(image), 1.0));
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
|
||||
static void API_renderStill_reuse_map(::benchmark::State& state) {
|
||||
RenderBenchmark bench;
|
||||
HeadlessFrontend frontend { size, pixelRatio };
|
||||
Map map { frontend, MapObserver::nullObserver(),
|
||||
MapOptions().withMapMode(MapMode::Static).withSize(size).withPixelRatio(pixelRatio),
|
||||
ResourceOptions().withCachePath(cachePath).withAccessToken("foobar") };
|
||||
prepare(map);
|
||||
|
||||
for (auto _ : state) {
|
||||
frontend.render(map);
|
||||
}
|
||||
}
|
||||
|
||||
static void API_renderStill_reuse_map_formatted_labels(::benchmark::State& state) {
|
||||
RenderBenchmark bench;
|
||||
HeadlessFrontend frontend { size, pixelRatio };
|
||||
Map map { frontend, MapObserver::nullObserver(),
|
||||
MapOptions().withMapMode(MapMode::Static).withSize(size).withPixelRatio(pixelRatio),
|
||||
ResourceOptions().withCachePath(cachePath).withAccessToken("foobar") };
|
||||
prepare(map, util::read_file("benchmark/fixtures/api/style_formatted_labels.json"));
|
||||
|
||||
for (auto _ : state) {
|
||||
frontend.render(map);
|
||||
}
|
||||
}
|
||||
|
||||
static void API_renderStill_reuse_map_switch_styles(::benchmark::State& state) {
|
||||
RenderBenchmark bench;
|
||||
HeadlessFrontend frontend { size, pixelRatio };
|
||||
Map map { frontend, MapObserver::nullObserver(),
|
||||
MapOptions().withMapMode(MapMode::Static).withSize(size).withPixelRatio(pixelRatio),
|
||||
ResourceOptions().withCachePath(cachePath).withAccessToken("foobar") };
|
||||
|
||||
for (auto _ : state) {
|
||||
prepare(map, { "{}" });
|
||||
frontend.render(map);
|
||||
prepare(map);
|
||||
frontend.render(map);
|
||||
}
|
||||
}
|
||||
|
||||
static void API_renderStill_recreate_map(::benchmark::State& state) {
|
||||
RenderBenchmark bench;
|
||||
|
||||
for (auto _ : state) {
|
||||
HeadlessFrontend frontend { size, pixelRatio };
|
||||
Map map { frontend, MapObserver::nullObserver(),
|
||||
MapOptions().withMapMode(MapMode::Static).withSize(size).withPixelRatio(pixelRatio),
|
||||
ResourceOptions().withCachePath(cachePath).withAccessToken("foobar") };
|
||||
prepare(map);
|
||||
frontend.render(map);
|
||||
}
|
||||
}
|
||||
|
||||
static void API_renderStill_recreate_map_2(::benchmark::State& state) {
|
||||
RenderBenchmark bench;
|
||||
|
||||
for (auto _ : state) {
|
||||
HeadlessFrontend frontend{size, pixelRatio};
|
||||
Map map{frontend,
|
||||
MapObserver::nullObserver(),
|
||||
MapOptions().withMapMode(MapMode::Static).withSize(size).withPixelRatio(pixelRatio),
|
||||
ResourceOptions().withCachePath(cachePath).withAccessToken("foobar")};
|
||||
prepare_map2(map);
|
||||
frontend.render(map);
|
||||
}
|
||||
}
|
||||
|
||||
static void API_renderStill_multiple_sources(::benchmark::State& state) {
|
||||
using namespace mbgl::style;
|
||||
RenderBenchmark bench;
|
||||
HeadlessFrontend frontend{size, pixelRatio};
|
||||
Map map{frontend,
|
||||
MapObserver::nullObserver(),
|
||||
MapOptions().withMapMode(MapMode::Static).withSize(size).withPixelRatio(pixelRatio),
|
||||
ResourceOptions().withCachePath(cachePath).withAccessToken("foobar")};
|
||||
prepare(map);
|
||||
auto& style = map.getStyle();
|
||||
const int kSourcesCount = 50;
|
||||
const int kLayersCount = 50;
|
||||
for (int i = 0; i < kSourcesCount; ++i) {
|
||||
std::ostringstream sourceOss;
|
||||
sourceOss << "GeoJSONSource" << i;
|
||||
std::string sourceId{sourceOss.str()};
|
||||
auto source = std::make_unique<GeoJSONSource>(sourceId);
|
||||
style.addSource(std::move(source));
|
||||
for (int j = 0; j < kLayersCount; ++j) {
|
||||
std::ostringstream layerOss;
|
||||
layerOss << sourceId << '#' << j;
|
||||
auto layer = std::make_unique<SymbolLayer>(layerOss.str(), sourceId);
|
||||
style.addLayer(std::move(layer));
|
||||
}
|
||||
}
|
||||
|
||||
for (auto _ : state) {
|
||||
frontend.render(map);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK(API_renderStill_reuse_map)->Unit(benchmark::kMillisecond)->Iterations(50);
|
||||
BENCHMARK(API_renderStill_reuse_map_formatted_labels)->Unit(benchmark::kMillisecond)->Iterations(50);
|
||||
BENCHMARK(API_renderStill_reuse_map_switch_styles)->Unit(benchmark::kMillisecond)->Iterations(50);
|
||||
BENCHMARK(API_renderStill_recreate_map)->Unit(benchmark::kMillisecond)->Iterations(50);
|
||||
BENCHMARK(API_renderStill_recreate_map_2)->Unit(benchmark::kMillisecond)->Iterations(50);
|
||||
BENCHMARK(API_renderStill_multiple_sources)->Unit(benchmark::kMillisecond)->Iterations(50);
|
||||
BIN
mapbox-gl-native/benchmark/fixtures/api/cache.db
Normal file
BIN
mapbox-gl-native/benchmark/fixtures/api/cache.db
Normal file
Binary file not shown.
BIN
mapbox-gl-native/benchmark/fixtures/api/default_marker.png
Normal file
BIN
mapbox-gl-native/benchmark/fixtures/api/default_marker.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1010 B |
3993
mapbox-gl-native/benchmark/fixtures/api/style.json
Normal file
3993
mapbox-gl-native/benchmark/fixtures/api/style.json
Normal file
File diff suppressed because it is too large
Load Diff
3993
mapbox-gl-native/benchmark/fixtures/api/style_formatted_labels.json
Normal file
3993
mapbox-gl-native/benchmark/fixtures/api/style_formatted_labels.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,61 @@
|
||||
#include <benchmark/benchmark.h>
|
||||
|
||||
#include <mbgl/style/conversion/json.hpp>
|
||||
#include <mbgl/style/conversion/function.hpp>
|
||||
#include <mbgl/style/conversion/property_value.hpp>
|
||||
#include <mbgl/style/conversion_impl.hpp>
|
||||
|
||||
using namespace mbgl;
|
||||
using namespace mbgl::style;
|
||||
|
||||
static std::string createFunctionJSON(size_t stopCount) {
|
||||
std::string stops = "[";
|
||||
for (size_t i = 0; i < stopCount; i++) {
|
||||
std::string value = std::to_string(24.0f / stopCount * i);
|
||||
if (stops.size() > 1) stops += ",";
|
||||
stops += "[" + value + ", " + value + "]";
|
||||
}
|
||||
stops += "]";
|
||||
return R"({"type": "exponential", "base": 2, "stops": )" + stops + "}";
|
||||
}
|
||||
|
||||
static void Parse_CameraFunction(benchmark::State& state) {
|
||||
size_t stopCount = state.range(0);
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
conversion::Error error;
|
||||
state.PauseTiming();
|
||||
auto doc = createFunctionJSON(stopCount);
|
||||
state.ResumeTiming();
|
||||
optional<PropertyValue<float>> result = conversion::convertJSON<PropertyValue<float>>(doc, error, false, false);
|
||||
if (!result) {
|
||||
state.SkipWithError(error.message.c_str());
|
||||
}
|
||||
}
|
||||
state.SetLabel(std::to_string(stopCount).c_str());
|
||||
}
|
||||
|
||||
static void Evaluate_CameraFunction(benchmark::State& state) {
|
||||
size_t stopCount = state.range(0);
|
||||
auto doc = createFunctionJSON(stopCount);
|
||||
conversion::Error error;
|
||||
optional<PropertyValue<float>> function = conversion::convertJSON<PropertyValue<float>>(doc, error, false, false);
|
||||
if (!function) {
|
||||
state.SkipWithError(error.message.c_str());
|
||||
}
|
||||
|
||||
while(state.KeepRunning()) {
|
||||
float z = 24.0f * static_cast<float>(rand() % 100) / 100;
|
||||
function->asExpression().evaluate(z);
|
||||
}
|
||||
|
||||
state.SetLabel(std::to_string(stopCount).c_str());
|
||||
}
|
||||
|
||||
BENCHMARK(Parse_CameraFunction)
|
||||
->Arg(1)->Arg(2)->Arg(4)->Arg(6)->Arg(8)->Arg(10)->Arg(12);
|
||||
|
||||
BENCHMARK(Evaluate_CameraFunction)
|
||||
->Arg(1)->Arg(2)->Arg(4)->Arg(6)->Arg(8)->Arg(10)->Arg(12);
|
||||
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
#include <benchmark/benchmark.h>
|
||||
|
||||
#include <mbgl/benchmark/stub_geometry_tile_feature.hpp>
|
||||
|
||||
#include <mbgl/style/conversion/json.hpp>
|
||||
#include <mbgl/style/conversion/function.hpp>
|
||||
#include <mbgl/style/conversion/property_value.hpp>
|
||||
#include <mbgl/style/conversion_impl.hpp>
|
||||
|
||||
using namespace mbgl;
|
||||
using namespace mbgl::style;
|
||||
|
||||
static std::string createFunctionJSON(size_t stopCount) {
|
||||
std::string stops = "[";
|
||||
for (size_t outerStop = 0; outerStop < stopCount; outerStop++) {
|
||||
for (size_t innerStop = 0; innerStop < stopCount; innerStop++) {
|
||||
std::string zoom = std::to_string(24.0f / stopCount * outerStop);
|
||||
std::string value = std::to_string(100.0f / stopCount * innerStop);
|
||||
|
||||
if (stops.size() > 1) stops += ",";
|
||||
stops += R"([{"zoom":)" + zoom + R"(,"value":)" + value + "}, " + value + "]";
|
||||
}
|
||||
}
|
||||
stops += "]";
|
||||
return R"({"type": "exponential", "base": 2, "stops": )" + stops + R"(, "property": "x"})";
|
||||
}
|
||||
|
||||
static void Parse_CompositeFunction(benchmark::State& state) {
|
||||
size_t stopCount = state.range(0);
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
conversion::Error error;
|
||||
state.PauseTiming();
|
||||
auto doc = createFunctionJSON(stopCount);
|
||||
state.ResumeTiming();
|
||||
optional<PropertyValue<float>> result = conversion::convertJSON<PropertyValue<float>>(doc, error, true, false);
|
||||
if (!result) {
|
||||
state.SkipWithError(error.message.c_str());
|
||||
}
|
||||
}
|
||||
state.SetLabel(std::to_string(stopCount).c_str());
|
||||
}
|
||||
|
||||
static void Evaluate_CompositeFunction(benchmark::State& state) {
|
||||
size_t stopCount = state.range(0);
|
||||
auto doc = createFunctionJSON(stopCount);
|
||||
conversion::Error error;
|
||||
optional<PropertyValue<float>> function = conversion::convertJSON<PropertyValue<float>>(doc, error, true, false);
|
||||
if (!function) {
|
||||
state.SkipWithError(error.message.c_str());
|
||||
}
|
||||
|
||||
while(state.KeepRunning()) {
|
||||
float z = 24.0f * static_cast<float>(rand() % 100) / 100;
|
||||
function->asExpression().evaluate(z, StubGeometryTileFeature(PropertyMap { { "x", static_cast<int64_t>(rand() % 100) } }), -1.0f);
|
||||
}
|
||||
|
||||
state.SetLabel(std::to_string(stopCount).c_str());
|
||||
}
|
||||
|
||||
BENCHMARK(Parse_CompositeFunction)
|
||||
->Arg(1)->Arg(2)->Arg(4)->Arg(6)->Arg(8)->Arg(10)->Arg(12);
|
||||
|
||||
BENCHMARK(Evaluate_CompositeFunction)
|
||||
->Arg(1)->Arg(2)->Arg(4)->Arg(6)->Arg(8)->Arg(10)->Arg(12);
|
||||
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
#include <benchmark/benchmark.h>
|
||||
|
||||
#include <mbgl/benchmark/stub_geometry_tile_feature.hpp>
|
||||
|
||||
#include <mbgl/style/conversion/json.hpp>
|
||||
#include <mbgl/style/conversion/property_value.hpp>
|
||||
#include <mbgl/style/conversion_impl.hpp>
|
||||
|
||||
using namespace mbgl;
|
||||
using namespace mbgl::style;
|
||||
|
||||
static std::string createFunctionJSON(size_t stopCount) {
|
||||
std::string stops = "[";
|
||||
for (size_t i = 0; i < stopCount; i++) {
|
||||
std::string value = std::to_string(100.0f / stopCount * i);
|
||||
if (stops.size() > 1) stops += ",";
|
||||
stops += "[" + value + ", " + value + "]";
|
||||
}
|
||||
stops += "]";
|
||||
return R"({"type": "exponential", "base": 2, "stops": )" + stops + R"(, "property": "x"})";
|
||||
}
|
||||
|
||||
static void Parse_SourceFunction(benchmark::State& state) {
|
||||
size_t stopCount = state.range(0);
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
conversion::Error error;
|
||||
state.PauseTiming();
|
||||
auto doc = createFunctionJSON(stopCount);
|
||||
state.ResumeTiming();
|
||||
optional<PropertyValue<float>> result = conversion::convertJSON<PropertyValue<float>>(doc, error, true, false);
|
||||
if (!result) {
|
||||
state.SkipWithError(error.message.c_str());
|
||||
}
|
||||
}
|
||||
state.SetLabel(std::to_string(stopCount).c_str());
|
||||
}
|
||||
|
||||
static void Evaluate_SourceFunction(benchmark::State& state) {
|
||||
size_t stopCount = state.range(0);
|
||||
auto doc = createFunctionJSON(stopCount);
|
||||
conversion::Error error;
|
||||
optional<PropertyValue<float>> function = conversion::convertJSON<PropertyValue<float>>(doc, error, true, false);
|
||||
if (!function) {
|
||||
state.SkipWithError(error.message.c_str());
|
||||
}
|
||||
|
||||
while(state.KeepRunning()) {
|
||||
function->asExpression().evaluate(StubGeometryTileFeature(PropertyMap { { "x", static_cast<int64_t>(rand() % 100) } }), -1.0f);
|
||||
}
|
||||
|
||||
state.SetLabel(std::to_string(stopCount).c_str());
|
||||
}
|
||||
|
||||
BENCHMARK(Parse_SourceFunction)
|
||||
->Arg(1)->Arg(2)->Arg(4)->Arg(6)->Arg(8)->Arg(10)->Arg(12);
|
||||
|
||||
BENCHMARK(Evaluate_SourceFunction)
|
||||
->Arg(1)->Arg(2)->Arg(4)->Arg(6)->Arg(8)->Arg(10)->Arg(12);
|
||||
|
||||
|
||||
7
mapbox-gl-native/benchmark/include/mbgl/benchmark.hpp
Normal file
7
mapbox-gl-native/benchmark/include/mbgl/benchmark.hpp
Normal file
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
int runBenchmark(int argc, char* argv[]);
|
||||
|
||||
} // namespace mbgl
|
||||
@@ -0,0 +1,68 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>BenchmarkAppTests</key>
|
||||
<dict>
|
||||
<key>BlueprintName</key>
|
||||
<string>BenchmarkAppTests</string>
|
||||
<key>BundleIdentifiersForCrashReportEmphasis</key>
|
||||
<array>
|
||||
<string>com.mapbox.BenchmarkApp</string>
|
||||
<string>com.mapbox.BenchmarkAppTests</string>
|
||||
</array>
|
||||
<key>CommandLineArguments</key>
|
||||
<array/>
|
||||
<key>DependentProductPaths</key>
|
||||
<array>
|
||||
<string>__TESTROOT__/Debug-iphoneos/BenchmarkApp.app</string>
|
||||
<string>__TESTROOT__/Debug-iphoneos/BenchmarkApp.app/PlugIns/BenchmarkAppTests.xctest</string>
|
||||
</array>
|
||||
<key>EnvironmentVariables</key>
|
||||
<dict>
|
||||
<key>OS_ACTIVITY_DT_MODE</key>
|
||||
<string>YES</string>
|
||||
<key>SQLITE_ENABLE_THREAD_ASSERTIONS</key>
|
||||
<string>1</string>
|
||||
</dict>
|
||||
<key>IsAppHostedTestBundle</key>
|
||||
<true/>
|
||||
<key>ProductModuleName</key>
|
||||
<string>BenchmarkAppTests</string>
|
||||
<key>RunOrder</key>
|
||||
<integer>0</integer>
|
||||
<key>SystemAttachmentLifetime</key>
|
||||
<string>deleteOnSuccess</string>
|
||||
<key>TestBundlePath</key>
|
||||
<string>__TESTHOST__/PlugIns/BenchmarkAppTests.xctest</string>
|
||||
<key>TestHostBundleIdentifier</key>
|
||||
<string>com.mapbox.BenchmarkApp</string>
|
||||
<key>TestHostPath</key>
|
||||
<string>__TESTROOT__/Debug-iphoneos/BenchmarkApp.app</string>
|
||||
<key>TestLanguage</key>
|
||||
<string></string>
|
||||
<key>TestRegion</key>
|
||||
<string></string>
|
||||
<key>TestingEnvironmentVariables</key>
|
||||
<dict>
|
||||
<key>DYLD_FALLBACK_FRAMEWORK_PATH</key>
|
||||
<string></string>
|
||||
<key>DYLD_INSERT_LIBRARIES</key>
|
||||
<string>__PLATFORMS__/iPhoneOS.platform/Developer/usr/lib/libXCTestBundleInject.dylib</string>
|
||||
<key>XCInjectBundleInto</key>
|
||||
<string>unused</string>
|
||||
</dict>
|
||||
<key>ToolchainsSettingValue</key>
|
||||
<array/>
|
||||
<key>UITargetAppCommandLineArguments</key>
|
||||
<array/>
|
||||
<key>UserAttachmentLifetime</key>
|
||||
<string>deleteOnSuccess</string>
|
||||
</dict>
|
||||
<key>__xctestrun_metadata__</key>
|
||||
<dict>
|
||||
<key>FormatVersion</key>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,68 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>BenchmarkAppTests</key>
|
||||
<dict>
|
||||
<key>BlueprintName</key>
|
||||
<string>BenchmarkAppTests</string>
|
||||
<key>BundleIdentifiersForCrashReportEmphasis</key>
|
||||
<array>
|
||||
<string>com.mapbox.BenchmarkApp</string>
|
||||
<string>com.mapbox.BenchmarkAppTests</string>
|
||||
</array>
|
||||
<key>CommandLineArguments</key>
|
||||
<array/>
|
||||
<key>DependentProductPaths</key>
|
||||
<array>
|
||||
<string>__TESTROOT__/Release-iphoneos/BenchmarkApp.app</string>
|
||||
<string>__TESTROOT__/Release-iphoneos/BenchmarkApp.app/PlugIns/BenchmarkAppTests.xctest</string>
|
||||
</array>
|
||||
<key>EnvironmentVariables</key>
|
||||
<dict>
|
||||
<key>OS_ACTIVITY_DT_MODE</key>
|
||||
<string>YES</string>
|
||||
<key>SQLITE_ENABLE_THREAD_ASSERTIONS</key>
|
||||
<string>1</string>
|
||||
</dict>
|
||||
<key>IsAppHostedTestBundle</key>
|
||||
<true/>
|
||||
<key>ProductModuleName</key>
|
||||
<string>BenchmarkAppTests</string>
|
||||
<key>RunOrder</key>
|
||||
<integer>0</integer>
|
||||
<key>SystemAttachmentLifetime</key>
|
||||
<string>deleteOnSuccess</string>
|
||||
<key>TestBundlePath</key>
|
||||
<string>__TESTHOST__/PlugIns/BenchmarkAppTests.xctest</string>
|
||||
<key>TestHostBundleIdentifier</key>
|
||||
<string>com.mapbox.BenchmarkApp</string>
|
||||
<key>TestHostPath</key>
|
||||
<string>__TESTROOT__/Release-iphoneos/BenchmarkApp.app</string>
|
||||
<key>TestLanguage</key>
|
||||
<string></string>
|
||||
<key>TestRegion</key>
|
||||
<string></string>
|
||||
<key>TestingEnvironmentVariables</key>
|
||||
<dict>
|
||||
<key>DYLD_FALLBACK_FRAMEWORK_PATH</key>
|
||||
<string></string>
|
||||
<key>DYLD_INSERT_LIBRARIES</key>
|
||||
<string>__PLATFORMS__/iPhoneOS.platform/Developer/usr/lib/libXCTestBundleInject.dylib</string>
|
||||
<key>XCInjectBundleInto</key>
|
||||
<string>unused</string>
|
||||
</dict>
|
||||
<key>ToolchainsSettingValue</key>
|
||||
<array/>
|
||||
<key>UITargetAppCommandLineArguments</key>
|
||||
<array/>
|
||||
<key>UserAttachmentLifetime</key>
|
||||
<string>deleteOnSuccess</string>
|
||||
</dict>
|
||||
<key>__xctestrun_metadata__</key>
|
||||
<dict>
|
||||
<key>FormatVersion</key>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
62
mapbox-gl-native/benchmark/ios/Info.plist
Normal file
62
mapbox-gl-native/benchmark/ios/Info.plist
Normal file
@@ -0,0 +1,62 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN""http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>BenchmarkApp</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.mapbox.BenchmarkApp</string>
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string>com.mapbox.BenchmarkApp</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleLongVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>com.mapbox.BenchmarkApp</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>MBGL</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>7877</string>
|
||||
<key>CSResourcesFileMapped</key>
|
||||
<true/>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>© 2014–2020 Mapbox</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>${MACOSX_DEPLOYMENT_TARGET}</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>UIBackgroundModes</key>
|
||||
<array>
|
||||
<string>fetch</string>
|
||||
<string>remote-notification</string>
|
||||
</array>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
7
mapbox-gl-native/benchmark/ios/README.md
Normal file
7
mapbox-gl-native/benchmark/ios/README.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# iOS BenchmarkRunner App
|
||||
|
||||
This is a blank single-view-controller iOS app, linked against to a C++ static libraries, plus a a simple unit xctest. We use CMake to create an Xcode-friendly out-of-source build system. In another word, the build system is maintained by `CMakeLists` file,instead of a configured `.xcodeproj` file.
|
||||
|
||||
This CMake project can build the executable BenchmarkApp which is linked to the static C++ library 'mbgl-benchmark'. CMakeLists.txt files are the only build configuration kept in source control. This is in contrast to committing the `.xcodeproj` directory which includes the backing XML, which is nonsensically hard to edit by hand.
|
||||
|
||||
The test instantiates ObjC object of class `IosTestRunner` from the app, the class will instantiates a C++ object from the linked library `mbgl-benchmark` and calls running benchmark function on it. It subsequently deletes the C++ object pointer. In the end, the test will check the existence of test report, which is a json file that attach to xctest result.
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>application-identifier</key>
|
||||
<string>$TEAM_ID.com.mapbox.BenchmarkApp</string>
|
||||
<key>com.apple.developer.team-identifier</key>
|
||||
<string>$TEAM_ID</string>
|
||||
<key>get-task-allow</key>
|
||||
<true/>
|
||||
<key>keychain-access-groups</key>
|
||||
<array>
|
||||
<string>$TEAM_ID.com.mapbox.BenchmarkApp</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>application-identifier</key>
|
||||
<string>$TEAM_ID.com.mapbox.BenchmarkAppTests</string>
|
||||
<key>com.apple.developer.team-identifier</key>
|
||||
<string>$TEAM_ID</string>
|
||||
<key>get-task-allow</key>
|
||||
<true/>
|
||||
<key>keychain-access-groups</key>
|
||||
<array>
|
||||
<string>$TEAM_ID.com.mapbox.BenchmarkAppTests</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>application-identifier</key>
|
||||
<string>$TEAM_ID.com.mapbox.BenchmarkAppTests</string>
|
||||
<key>com.apple.developer.team-identifier</key>
|
||||
<string>$TEAM_ID</string>
|
||||
<key>get-task-allow</key>
|
||||
<true/>
|
||||
<key>keychain-access-groups</key>
|
||||
<array>
|
||||
<string>$TEAM_ID.com.mapbox.BenchmarkAppTests</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>application-identifier</key>
|
||||
<string>$TEAM_ID.com.mapbox.BenchmarkAppTests</string>
|
||||
<key>com.apple.developer.team-identifier</key>
|
||||
<string>$TEAM_ID</string>
|
||||
<key>get-task-allow</key>
|
||||
<true/>
|
||||
<key>keychain-access-groups</key>
|
||||
<array>
|
||||
<string>$TEAM_ID.com.mapbox.BenchmarkAppTests</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
11
mapbox-gl-native/benchmark/ios/codesigning/codesign_all.sh
Executable file
11
mapbox-gl-native/benchmark/ios/codesigning/codesign_all.sh
Executable file
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
identity=$(/usr/bin/env xcrun security find-identity -v -p codesigning)
|
||||
var=${identity#*1)\ }
|
||||
CODE_SIGN_IDENTITY=${var%\ \"Apple\ Development*}
|
||||
|
||||
codesign --force --sign $CODE_SIGN_IDENTITY --entitlements codesigning/BenchmarkApp.app.xcent --timestamp=none ./Release-iphoneos/BenchmarkApp.app
|
||||
codesign --force --sign $CODE_SIGN_IDENTITY --deep --preserve-metadata=identifier,entitlements,flags --timestamp=none ./Release-iphoneos/BenchmarkApp.app/Frameworks/libXCTestSwiftSupport.dylib
|
||||
codesign --force --sign $CODE_SIGN_IDENTITY --deep --preserve-metadata=identifier,entitlements,flags --timestamp=none ./Release-iphoneos/BenchmarkApp.app/Frameworks/libXCTestBundleInject.dylib
|
||||
codesign --force --sign $CODE_SIGN_IDENTITY --deep --preserve-metadata=identifier,entitlements,flags --timestamp=none ./Release-iphoneos/BenchmarkApp.app/Frameworks/XCTAutomationSupport.framework
|
||||
codesign --force --sign $CODE_SIGN_IDENTITY --deep --preserve-metadata=identifier,entitlements,flags --timestamp=none ./Release-iphoneos/BenchmarkApp.app/Frameworks/XCTest.framework
|
||||
codesign --force --sign $CODE_SIGN_IDENTITY --deep --entitlements codesigning/BenchmarkAppTests.xctest.xcent --timestamp=none ./Release-iphoneos/BenchmarkApp.app/PlugIns/BenchmarkAppTests.xctest
|
||||
40
mapbox-gl-native/benchmark/ios/codesigning/generate-entitlements.swift
Executable file
40
mapbox-gl-native/benchmark/ios/codesigning/generate-entitlements.swift
Executable file
@@ -0,0 +1,40 @@
|
||||
#!/usr/bin/swift
|
||||
|
||||
/// Generates Entitlement files .xcent for codesigning, containing the correct team id
|
||||
import Swift
|
||||
import Foundation
|
||||
|
||||
let fileManager = FileManager.default
|
||||
|
||||
let contentsOfCurrentWorkingDirectory = try FileManager.default.contentsOfDirectory(at: URL(fileURLWithPath: "./codesigning/"), includingPropertiesForKeys: nil, options: [])
|
||||
|
||||
guard let rawTeamIdEnv = getenv("IOS_DEVELOPMENT_TEAM") else {
|
||||
print("Please add a IOS_DEVELOPMENT_TEAM environment variable.")
|
||||
exit(1)
|
||||
}
|
||||
|
||||
let teamId2 = String(utf8String: rawTeamIdEnv)
|
||||
|
||||
for file in contentsOfCurrentWorkingDirectory {
|
||||
if (file.pathExtension == "template") {
|
||||
var content = ""
|
||||
do {
|
||||
content = try String(contentsOf: file, encoding: .utf8)
|
||||
}
|
||||
catch {
|
||||
print("Error reading xcent file: \(error).")
|
||||
}
|
||||
|
||||
content = content.replacingOccurrences(of: "$TEAM_ID", with: teamId2!)
|
||||
|
||||
var targetFile = file
|
||||
targetFile.deletePathExtension()
|
||||
do {
|
||||
try content.write(to: targetFile, atomically: false, encoding: .utf8)
|
||||
print("Entitlement " + targetFile.absoluteString + " generated.")
|
||||
}
|
||||
catch {
|
||||
print("Error writing xcent file: \(error).")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>application-identifier</key>
|
||||
<string>$TEAM_ID.com.mapbox.BenchmarkAppTests</string>
|
||||
<key>com.apple.developer.team-identifier</key>
|
||||
<string>$TEAM_ID</string>
|
||||
<key>get-task-allow</key>
|
||||
<true/>
|
||||
<key>keychain-access-groups</key>
|
||||
<array>
|
||||
<string>$TEAM_ID.com.mapbox.BenchmarkAppTests</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
3
mapbox-gl-native/benchmark/ios/fastlane/Appfile
Normal file
3
mapbox-gl-native/benchmark/ios/fastlane/Appfile
Normal file
@@ -0,0 +1,3 @@
|
||||
app_identifier("com.mapbox.BenchmarkApp") # The bundle identifier of your app
|
||||
apple_id ENV['MAPBOX_APPLE_ID']
|
||||
team_id ENV['MAPBOX_APPLE_TEAM_ID'] # Developer Portal Team ID
|
||||
5
mapbox-gl-native/benchmark/ios/fastlane/Matchfile
Normal file
5
mapbox-gl-native/benchmark/ios/fastlane/Matchfile
Normal file
@@ -0,0 +1,5 @@
|
||||
git_url("git@github.com:mapbox/apple-certificates.git")
|
||||
type("development") # The default type, can be: appstore, adhoc, enterprise or development
|
||||
app_identifier(["com.mapbox.BenchmarkApp", "com.mapbox.BenchmarkAppTests"])
|
||||
username ENV['MAPBOX_APPLE_ID']
|
||||
keychain_name("fastlane_keychain")
|
||||
12
mapbox-gl-native/benchmark/ios/iosTestRunner.h
Normal file
12
mapbox-gl-native/benchmark/ios/iosTestRunner.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NSString *dataDir = @"benchmark-data";
|
||||
NSString *resultFilePath = @"benchmark/results.json";
|
||||
|
||||
__attribute__((visibility ("default")))
|
||||
@interface IosTestRunner : NSObject
|
||||
|
||||
- (NSString*) getResultPath;
|
||||
- (BOOL) getTestStatus;
|
||||
|
||||
@end
|
||||
34
mapbox-gl-native/benchmark/ios/ios_test_runner.cpp
Normal file
34
mapbox-gl-native/benchmark/ios/ios_test_runner.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
#include <ios_test_runner.hpp>
|
||||
|
||||
#include <mbgl/benchmark.hpp>
|
||||
|
||||
#include <mbgl/util/logging.hpp>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <vector>
|
||||
|
||||
#define EXPORT __attribute__((visibility("default")))
|
||||
|
||||
EXPORT
|
||||
bool TestRunner::startTest(const std::string& basePath) {
|
||||
std::vector<std::string> arguments = {"mbgl-benchmark-runner",
|
||||
"--benchmark_repetitions=10",
|
||||
"--benchmark_format=json",
|
||||
"--benchmark_out=" + basePath + "/benchmark/results.json"};
|
||||
std::vector<char*> argv;
|
||||
for (const auto& arg : arguments) {
|
||||
argv.push_back(const_cast<char*>(arg.data()));
|
||||
}
|
||||
argv.push_back(nullptr);
|
||||
|
||||
if (chdir(basePath.c_str())) {
|
||||
mbgl::Log::Error(mbgl::Event::General, "Failed to change the directory to " + basePath);
|
||||
return false;
|
||||
}
|
||||
|
||||
mbgl::Log::Info(mbgl::Event::General, "Start BenchmarkRunner");
|
||||
int status = mbgl::runBenchmark(static_cast<uint32_t>(argv.size()), argv.data());
|
||||
mbgl::Log::Info(mbgl::Event::General, "BenchmarkRunner finished with status: '%d'", status);
|
||||
|
||||
return status == 0;
|
||||
}
|
||||
22
mapbox-gl-native/benchmark/ios/tests/Info.plist
Normal file
22
mapbox-gl-native/benchmark/ios/tests/Info.plist
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>BenchmarkAppTests</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.mapbox.BenchmarkAppTests</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>BenchmarkAppTests</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
</dict>
|
||||
</plist>
|
||||
34
mapbox-gl-native/benchmark/parse/filter.benchmark.cpp
Normal file
34
mapbox-gl-native/benchmark/parse/filter.benchmark.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
#include <benchmark/benchmark.h>
|
||||
|
||||
#include <mbgl/style/filter.hpp>
|
||||
#include <mbgl/style/conversion/json.hpp>
|
||||
#include <mbgl/style/conversion/filter.hpp>
|
||||
#include <mbgl/style/conversion_impl.hpp>
|
||||
#include <mbgl/tile/geometry_tile_data.hpp>
|
||||
#include <mbgl/benchmark/stub_geometry_tile_feature.hpp>
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
style::Filter parse(const char* expression) {
|
||||
style::conversion::Error error;
|
||||
return *style::conversion::convertJSON<style::Filter>(expression, error);
|
||||
}
|
||||
|
||||
static void Parse_Filter(benchmark::State& state) {
|
||||
while (state.KeepRunning()) {
|
||||
parse(R"FILTER(["==", "foo", "bar"])FILTER");
|
||||
}
|
||||
}
|
||||
|
||||
static void Parse_EvaluateFilter(benchmark::State& state) {
|
||||
const style::Filter filter = parse(R"FILTER(["==", "foo", "bar"])FILTER");
|
||||
const StubGeometryTileFeature feature = { {}, FeatureType::Unknown , {}, {{ "foo", std::string("bar") }} };
|
||||
const style::expression::EvaluationContext context(&feature);
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
filter(context);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK(Parse_Filter);
|
||||
BENCHMARK(Parse_EvaluateFilter);
|
||||
36
mapbox-gl-native/benchmark/parse/tile_mask.benchmark.cpp
Normal file
36
mapbox-gl-native/benchmark/parse/tile_mask.benchmark.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
#include <benchmark/benchmark.h>
|
||||
|
||||
#include <mbgl/algorithm/update_tile_masks.hpp>
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
class FakeTile {
|
||||
public:
|
||||
FakeTile(TileMask mask_)
|
||||
: mask(std::move(mask_)) {
|
||||
}
|
||||
void setMask(TileMask mask_) {
|
||||
mask = std::move(mask_);
|
||||
}
|
||||
|
||||
const bool usedByRenderedLayers = true;
|
||||
TileMask mask;
|
||||
};
|
||||
|
||||
static void TileMaskGeneration(benchmark::State& state) {
|
||||
std::map<UnwrappedTileID, FakeTile> renderables = {
|
||||
{ UnwrappedTileID{ 12, 1028, 1456 }, TileMask{} },
|
||||
{ UnwrappedTileID{ 13, 2056, 2912 }, TileMask{} },
|
||||
{ UnwrappedTileID{ 13, 2056, 2913 }, TileMask{} },
|
||||
{ UnwrappedTileID{ 14, 4112, 5824 }, TileMask{} },
|
||||
{ UnwrappedTileID{ 14, 4112, 5827 }, TileMask{} },
|
||||
{ UnwrappedTileID{ 14, 4114, 5824 }, TileMask{} },
|
||||
{ UnwrappedTileID{ 14, 4114, 5825 }, TileMask{} },
|
||||
};
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
algorithm::updateTileMasks(renderables);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK(TileMaskGeneration);
|
||||
28
mapbox-gl-native/benchmark/parse/vector_tile.benchmark.cpp
Normal file
28
mapbox-gl-native/benchmark/parse/vector_tile.benchmark.cpp
Normal file
@@ -0,0 +1,28 @@
|
||||
#include <benchmark/benchmark.h>
|
||||
|
||||
#include <mbgl/tile/vector_tile_data.hpp>
|
||||
#include <mbgl/util/io.hpp>
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
static void Parse_VectorTile(benchmark::State& state) {
|
||||
auto data = std::make_shared<std::string>(util::read_file("test/fixtures/api/assets/streets/10-163-395.vector.pbf"));
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
std::size_t length = 0;
|
||||
VectorTileData tile(data);
|
||||
for (const auto& name : tile.layerNames()) {
|
||||
if (auto layer = tile.getLayer(name)) {
|
||||
const std::size_t count = layer->featureCount();
|
||||
for (std::size_t i = 0; i < count; i++) {
|
||||
if (auto feature = layer->getFeature(i)) {
|
||||
length += feature->getGeometries().size();
|
||||
length += feature->getProperties().size();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK(Parse_VectorTile);
|
||||
13
mapbox-gl-native/benchmark/src/mbgl/benchmark/benchmark.cpp
Normal file
13
mapbox-gl-native/benchmark/src/mbgl/benchmark/benchmark.cpp
Normal file
@@ -0,0 +1,13 @@
|
||||
#include <mbgl/benchmark.hpp>
|
||||
|
||||
#include <benchmark/benchmark.h>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
int runBenchmark(int argc, char* argv[]) {
|
||||
::benchmark::Initialize(&argc, argv);
|
||||
::benchmark::RunSpecifiedBenchmarks();
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace mbgl
|
||||
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/tile/geometry_tile_data.hpp>
|
||||
#include <mbgl/util/feature.hpp>
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
class StubGeometryTileFeature : public GeometryTileFeature {
|
||||
public:
|
||||
StubGeometryTileFeature(PropertyMap properties_)
|
||||
: properties(std::move(properties_)) {
|
||||
}
|
||||
|
||||
StubGeometryTileFeature(FeatureIdentifier id_, FeatureType type_, GeometryCollection geometry_, PropertyMap properties_)
|
||||
: properties(std::move(properties_)),
|
||||
id(std::move(id_)),
|
||||
type(type_),
|
||||
geometry(std::move(geometry_)) {
|
||||
}
|
||||
|
||||
PropertyMap properties;
|
||||
FeatureIdentifier id;
|
||||
FeatureType type = FeatureType::Point;
|
||||
GeometryCollection geometry;
|
||||
|
||||
FeatureType getType() const override {
|
||||
return type;
|
||||
}
|
||||
|
||||
FeatureIdentifier getID() const override {
|
||||
return id;
|
||||
}
|
||||
|
||||
optional<Value> getValue(const std::string& key) const override {
|
||||
return properties.count(key) ? properties.at(key) : optional<Value>();
|
||||
}
|
||||
|
||||
const GeometryCollection& getGeometries() const override {
|
||||
return geometry;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,196 @@
|
||||
#include <benchmark/benchmark.h>
|
||||
|
||||
#include <mbgl/storage/offline_database.hpp>
|
||||
#include <mbgl/storage/resource.hpp>
|
||||
#include <mbgl/storage/response.hpp>
|
||||
#include <mbgl/storage/sqlite3.hpp>
|
||||
#include <mbgl/util/string.hpp>
|
||||
#include <mbgl/util/logging.hpp>
|
||||
|
||||
#include <random>
|
||||
|
||||
class OfflineDatabase : public benchmark::Fixture {
|
||||
public:
|
||||
void SetUp(const ::benchmark::State&) override {
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
db.setOfflineMapboxTileCountLimit(100000);
|
||||
|
||||
response.data = std::make_shared<std::string>(50 * 1024, 0);
|
||||
response.mustRevalidate = false;
|
||||
response.expires = mbgl::util::now() + 1h;
|
||||
|
||||
resetAmbientTiles();
|
||||
resetRegion();
|
||||
}
|
||||
|
||||
void resetAmbientTiles() {
|
||||
using namespace mbgl;
|
||||
|
||||
db.clearAmbientCache();
|
||||
|
||||
for (unsigned i = 0; i < tileCount; ++i) {
|
||||
const Resource ambient = Resource::tile("mapbox://tile_ambient" + util::toString(i), 1, 0, 0, 0, Tileset::Scheme::XYZ);
|
||||
db.put(ambient, response);
|
||||
}
|
||||
}
|
||||
|
||||
void resetRegion() {
|
||||
using namespace mbgl;
|
||||
|
||||
auto regions = db.listRegions().value();
|
||||
if (!regions.empty()) {
|
||||
db.deleteRegion(std::move(regions[0]));
|
||||
}
|
||||
|
||||
OfflineTilePyramidRegionDefinition definition{ "mapbox://style", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 2.0, true };
|
||||
OfflineRegionMetadata metadata{{ 1, 2, 3 }};
|
||||
|
||||
auto region = db.createRegion(definition, metadata);
|
||||
regionID = region->getID();
|
||||
|
||||
for (unsigned i = 0; i < tileCount; ++i) {
|
||||
const Resource offline = Resource::tile("mapbox://tile_offline_region" + util::toString(i), 1.0, 0, 0, 0, Tileset::Scheme::XYZ);
|
||||
db.putRegionResource(regionID, offline, response);
|
||||
}
|
||||
}
|
||||
|
||||
mbgl::Response response;
|
||||
mbgl::OfflineDatabase db{":memory:"};
|
||||
|
||||
const unsigned tileCount = 100;
|
||||
int64_t regionID = 0;
|
||||
};
|
||||
|
||||
BENCHMARK_F(OfflineDatabase, InvalidateRegion)(benchmark::State& state) {
|
||||
while (state.KeepRunning()) {
|
||||
db.invalidateRegion(regionID);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_F(OfflineDatabase, DeleteRegion)(benchmark::State& state) {
|
||||
while (state.KeepRunning()) {
|
||||
resetRegion();
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_F(OfflineDatabase, InsertTileRegion)(benchmark::State& state) {
|
||||
using namespace mbgl;
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
const Resource offline = Resource::tile("mapbox://InsertTileRegion" +
|
||||
util::toString(state.iterations()), 1, 0, 0, 0, Tileset::Scheme::XYZ);
|
||||
db.putRegionResource(regionID, offline, response);
|
||||
}
|
||||
}
|
||||
BENCHMARK_F(OfflineDatabase, InvalidateAmbientCache)(benchmark::State& state) {
|
||||
while (state.KeepRunning()) {
|
||||
db.invalidateAmbientCache();
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_F(OfflineDatabase, ClearAmbientCache)(benchmark::State& state) {
|
||||
while (state.KeepRunning()) {
|
||||
resetAmbientTiles();
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_F(OfflineDatabase, InsertTileCache)(benchmark::State& state) {
|
||||
using namespace mbgl;
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
const Resource ambient = Resource::tile("mapbox://InsertTileCache" +
|
||||
util::toString(state.iterations()), 1, 0, 0, 0, Tileset::Scheme::XYZ);
|
||||
db.put(ambient, response);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_F(OfflineDatabase, InsertBigTileCache)(benchmark::State& state) {
|
||||
using namespace mbgl;
|
||||
|
||||
Response big;
|
||||
big.data = std::make_shared<std::string>(util::DEFAULT_MAX_CACHE_SIZE / 100, 0);
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
const Resource ambient = Resource::tile("mapbox://InsertTileCache" +
|
||||
util::toString(state.iterations()), 1, 0, 0, 0, Tileset::Scheme::XYZ);
|
||||
db.put(ambient, big);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_F(OfflineDatabase, GetTile)(benchmark::State& state) {
|
||||
using namespace mbgl;
|
||||
|
||||
std::random_device rd;
|
||||
std::mt19937 gen(rd());
|
||||
std::uniform_int_distribution<> dis(0, tileCount - 1);
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
auto res = db.get(Resource::tile("mapbox://tile_ambient" + util::toString(dis(gen)), 1, 0, 0, 0, Tileset::Scheme::XYZ));
|
||||
assert(res != nullopt);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_F(OfflineDatabase, AddTilesToFullDatabase)(benchmark::State& state) {
|
||||
using namespace mbgl;
|
||||
|
||||
Log::setObserver(std::make_unique<Log::NullObserver>());
|
||||
db.setMaximumAmbientCacheSize(50 * 1024 * 5);
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
const Resource ambient = Resource::tile("mapbox://AddTilesToFullDatabase" +
|
||||
util::toString(state.iterations()), 1, 0, 0, 0, Tileset::Scheme::XYZ);
|
||||
db.put(ambient, response);
|
||||
}
|
||||
|
||||
Log::removeObserver();
|
||||
}
|
||||
|
||||
BENCHMARK_F(OfflineDatabase, AddTilesToDisabledDatabase)(benchmark::State& state) {
|
||||
using namespace mbgl;
|
||||
|
||||
auto regions = db.listRegions().value();
|
||||
if (!regions.empty()) {
|
||||
db.deleteRegion(std::move(regions[0]));
|
||||
}
|
||||
|
||||
// Disables the ambient cache.
|
||||
db.setMaximumAmbientCacheSize(0);
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
const Resource ambient = Resource::tile("mapbox://AddTilesToFullDatabase" +
|
||||
util::toString(state.iterations()), 1, 0, 0, 0, Tileset::Scheme::XYZ);
|
||||
db.put(ambient, response);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_F(OfflineDatabase, GetTileFromDisabledDatabase)(benchmark::State& state) {
|
||||
using namespace mbgl;
|
||||
|
||||
auto regions = db.listRegions().value();
|
||||
if (!regions.empty()) {
|
||||
db.deleteRegion(std::move(regions[0]));
|
||||
}
|
||||
|
||||
// Disables the ambient cache.
|
||||
db.setMaximumAmbientCacheSize(0);
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
auto res = db.get(Resource::tile("mapbox://tile_ambient", 1, 0, 0, 0, Tileset::Scheme::XYZ));
|
||||
assert(res == nullopt);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_F(OfflineDatabase, ResizeDatabase)(benchmark::State& state) {
|
||||
uint64_t size = 25 * 1024 * 1024;
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
db.setMaximumAmbientCacheSize(size);
|
||||
|
||||
size -= response.data->size();
|
||||
|
||||
if (size < response.data->size()) {
|
||||
size = 25 * 1024 * 1024;
|
||||
}
|
||||
}
|
||||
}
|
||||
66
mapbox-gl-native/benchmark/util/dtoa.benchmark.cpp
Normal file
66
mapbox-gl-native/benchmark/util/dtoa.benchmark.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
#include <benchmark/benchmark.h>
|
||||
|
||||
#include <mbgl/util/dtoa.hpp>
|
||||
|
||||
#include <cfloat>
|
||||
#include <cmath>
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
static void Util_dtoa(::benchmark::State& state) {
|
||||
while (state.KeepRunning()) {
|
||||
util::dtoa(0.);
|
||||
util::dtoa(M_E);
|
||||
util::dtoa(M_LOG2E);
|
||||
util::dtoa(M_LOG10E);
|
||||
util::dtoa(M_LN2);
|
||||
util::dtoa(M_LN10);
|
||||
util::dtoa(M_PI);
|
||||
util::dtoa(M_PI_2);
|
||||
util::dtoa(M_PI_4);
|
||||
util::dtoa(M_1_PI);
|
||||
util::dtoa(M_2_PI);
|
||||
util::dtoa(M_2_SQRTPI);
|
||||
util::dtoa(M_SQRT2);
|
||||
util::dtoa(M_SQRT1_2);
|
||||
}
|
||||
}
|
||||
|
||||
static void Util_standardDtoa(::benchmark::State& state) {
|
||||
while (state.KeepRunning()) {
|
||||
std::to_string(0.);
|
||||
std::to_string(M_E);
|
||||
std::to_string(M_LOG2E);
|
||||
std::to_string(M_LOG10E);
|
||||
std::to_string(M_LN2);
|
||||
std::to_string(M_LN10);
|
||||
std::to_string(M_PI);
|
||||
std::to_string(M_PI_2);
|
||||
std::to_string(M_PI_4);
|
||||
std::to_string(M_1_PI);
|
||||
std::to_string(M_2_PI);
|
||||
std::to_string(M_2_SQRTPI);
|
||||
std::to_string(M_SQRT2);
|
||||
std::to_string(M_SQRT1_2);
|
||||
}
|
||||
}
|
||||
|
||||
static void Util_dtoaLimits(::benchmark::State& state) {
|
||||
while (state.KeepRunning()) {
|
||||
util::dtoa(DBL_MIN);
|
||||
util::dtoa(DBL_MAX);
|
||||
}
|
||||
}
|
||||
|
||||
static void Util_standardDtoaLimits(::benchmark::State& state) {
|
||||
while (state.KeepRunning()) {
|
||||
std::to_string(DBL_MIN);
|
||||
std::to_string(DBL_MAX);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK(Util_dtoa);
|
||||
BENCHMARK(Util_standardDtoa);
|
||||
|
||||
BENCHMARK(Util_dtoaLimits);
|
||||
BENCHMARK(Util_standardDtoaLimits);
|
||||
93
mapbox-gl-native/benchmark/util/tilecover.benchmark.cpp
Normal file
93
mapbox-gl-native/benchmark/util/tilecover.benchmark.cpp
Normal file
@@ -0,0 +1,93 @@
|
||||
#include <benchmark/benchmark.h>
|
||||
#include <mbgl/util/geo.hpp>
|
||||
#include <mbgl/util/geometry.hpp>
|
||||
#include <mbgl/util/tile_coordinate.hpp>
|
||||
#include <mbgl/util/tile_cover.hpp>
|
||||
#include <mbgl/map/transform.hpp>
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
static const LatLngBounds sanFrancisco =
|
||||
LatLngBounds::hull({ 37.6609, -122.5744 }, { 37.8271, -122.3204 });
|
||||
|
||||
static void TileCountBounds(benchmark::State& state) {
|
||||
std::size_t length = 0;
|
||||
while (state.KeepRunning()) {
|
||||
auto count = util::tileCount(sanFrancisco, 10);
|
||||
length += count;
|
||||
}
|
||||
}
|
||||
|
||||
static void TileCoverPitchedViewport(benchmark::State& state) {
|
||||
Transform transform;
|
||||
transform.resize({ 512, 512 });
|
||||
// slightly offset center so that tile order is better defined
|
||||
transform.jumpTo(CameraOptions().withCenter(LatLng { 0.1, -0.1 }).withZoom(8.0).withBearing(5.0).withPitch(40.0));
|
||||
|
||||
std::size_t length = 0;
|
||||
while (state.KeepRunning()) {
|
||||
auto tiles = util::tileCover(transform.getState(), 8);
|
||||
length += tiles.size();
|
||||
}
|
||||
}
|
||||
|
||||
static void TileCoverBounds(benchmark::State& state) {
|
||||
std::size_t length = 0;
|
||||
while (state.KeepRunning()) {
|
||||
auto tiles = util::tileCover(sanFrancisco, 8);
|
||||
length += tiles.size();
|
||||
}
|
||||
}
|
||||
|
||||
static const auto geomPolygon = Polygon<double>{
|
||||
{
|
||||
{-122.5143814086914,37.779127216982424},
|
||||
{-122.50811576843262,37.72721239056709},
|
||||
{-122.50313758850099,37.70820178063929},
|
||||
{-122.3938751220703,37.707454835665274},
|
||||
{-122.37567901611328,37.70663997801684},
|
||||
{-122.36297607421874,37.71343018466285},
|
||||
{-122.354736328125,37.727280276860036},
|
||||
{-122.36469268798828,37.73868429065797},
|
||||
{-122.38014221191408,37.75442980295571},
|
||||
{-122.38391876220702,37.78753873820529},
|
||||
{-122.35919952392578,37.8065289741725},
|
||||
{-122.35679626464844,37.820632846207864},
|
||||
{-122.3712158203125,37.835276322922695},
|
||||
{-122.3818588256836,37.82958198283902},
|
||||
{-122.37190246582031,37.80788523279169},
|
||||
{-122.38735198974608,37.791337175930686},
|
||||
{-122.40966796874999,37.812767557570204},
|
||||
{-122.46425628662108,37.807071480609274},
|
||||
{-122.46803283691405,37.810326435534755},
|
||||
{-122.47901916503906,37.81168262440736},
|
||||
{-122.48966217041016,37.78916666399649},
|
||||
{-122.50579833984375,37.78781006166096},
|
||||
{-122.5143814086914,37.779127216982424}
|
||||
}
|
||||
};
|
||||
|
||||
static void TileCoverPolygon(benchmark::State& state) {
|
||||
std::size_t length = 0;
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
auto tiles = util::tileCover(geomPolygon, 8);
|
||||
length += tiles.size();
|
||||
}
|
||||
}
|
||||
|
||||
static void TileCountPolygon(benchmark::State& state) {
|
||||
std::size_t length = 0;
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
auto tiles = util::tileCount(geomPolygon, 16);
|
||||
length += tiles;
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK(TileCountBounds);
|
||||
BENCHMARK(TileCountPolygon);
|
||||
BENCHMARK(TileCoverPitchedViewport);
|
||||
BENCHMARK(TileCoverBounds);
|
||||
BENCHMARK(TileCoverPolygon);
|
||||
|
||||
42
mapbox-gl-native/bin/CMakeLists.txt
Normal file
42
mapbox-gl-native/bin/CMakeLists.txt
Normal file
@@ -0,0 +1,42 @@
|
||||
add_executable(
|
||||
mbgl-cache
|
||||
${PROJECT_SOURCE_DIR}/bin/cache.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
mbgl-cache
|
||||
PRIVATE
|
||||
Mapbox::Base
|
||||
Mapbox::Base::Extras::args
|
||||
mbgl-compiler-options
|
||||
mbgl-core
|
||||
)
|
||||
|
||||
add_executable(
|
||||
mbgl-offline
|
||||
${PROJECT_SOURCE_DIR}/bin/offline.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
mbgl-offline
|
||||
PRIVATE Mapbox::Base::Extras::args mbgl-compiler-options mbgl-core
|
||||
)
|
||||
|
||||
add_executable(
|
||||
mbgl-render
|
||||
${PROJECT_SOURCE_DIR}/bin/render.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
mbgl-render
|
||||
PRIVATE Mapbox::Base::Extras::args mbgl-compiler-options mbgl-core
|
||||
)
|
||||
|
||||
install(TARGETS mbgl-offline mbgl-render RUNTIME DESTINATION bin)
|
||||
|
||||
# FIXME: CI must have a valid token
|
||||
#
|
||||
# add_test(NAME mbgl-offline-tool-test COMMAND mbgl-offline -s mapbox://styles/mapbox/satellite-v9 --maxZoom=0 WORKING_DIRECTORY
|
||||
# ${PROJECT_SOURCE_DIR} )
|
||||
#
|
||||
# add_test(NAME mbgl-render-tool-test COMMAND mbgl-render WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} )
|
||||
98
mapbox-gl-native/bin/cache.cpp
Normal file
98
mapbox-gl-native/bin/cache.cpp
Normal file
@@ -0,0 +1,98 @@
|
||||
#include <mbgl/storage/file_source_manager.hpp>
|
||||
#include <mbgl/storage/resource.hpp>
|
||||
#include <mbgl/storage/resource_options.hpp>
|
||||
#include <mbgl/util/chrono.hpp>
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
|
||||
#include <args.hxx>
|
||||
#include <mapbox/io/io.hpp>
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
args::ArgumentParser p("Mapbox GL cache tool", "");
|
||||
args::HelpFlag helpFlag(p, "help", "Display this help menu", {'h'});
|
||||
|
||||
args::ValueFlag<std::string> urlValue(p, "URL", "Resource URL (required)", {'u'}, args::Options::Required);
|
||||
args::ValueFlag<std::string> cacheValue(
|
||||
p, "cache", "Path to the cache database (required)", {'c'}, args::Options::Required);
|
||||
args::ValueFlag<std::string> dataValue(
|
||||
p, "data", "Path to the resource data (required)", {'d'}, args::Options::Required);
|
||||
args::ValueFlag<std::string> etagValue(p, "etag", "Cache eTag, none otherwise", {'t'});
|
||||
args::ValueFlag<unsigned long> expiresValue(p, "expires", "Expires date, will use 'now' otherwise", {'e'});
|
||||
args::ValueFlag<unsigned long> modifiedValue(p, "modified", "Modified date, will use 'now' otherwise", {'m'});
|
||||
|
||||
std::unordered_map<std::string, mbgl::Resource::Kind> typeMap{{"glyphs", mbgl::Resource::Glyphs},
|
||||
{"image", mbgl::Resource::Image},
|
||||
{"source", mbgl::Resource::Source},
|
||||
{"sprite-image", mbgl::Resource::SpriteImage},
|
||||
{"sprite-json", mbgl::Resource::SpriteJSON},
|
||||
{"style", mbgl::Resource::Style},
|
||||
{"tile", mbgl::Resource::Tile}};
|
||||
|
||||
std::string typeHelp("One of the following (required):");
|
||||
for (auto key : typeMap) {
|
||||
typeHelp += " " + key.first;
|
||||
}
|
||||
|
||||
args::MapFlag<std::string, mbgl::Resource::Kind> typeFlag(
|
||||
p, "type", typeHelp, {"type"}, typeMap, args::Options::Required);
|
||||
|
||||
args::Group tileIdGroup(p, "Coordinates (required for 'tile')", args::Group::Validators::AllOrNone);
|
||||
args::ValueFlag<int32_t> xValueFlag(tileIdGroup, "x", "Tile x coordinate", {'x'});
|
||||
args::ValueFlag<int32_t> yValueFlag(tileIdGroup, "y", "Tile y coordinate", {'y'});
|
||||
args::ValueFlag<int32_t> zValueFlag(tileIdGroup, "z", "The zoom level", {'z'});
|
||||
|
||||
try {
|
||||
p.ParseCLI(argc, argv);
|
||||
} catch (const args::Help&) {
|
||||
std::cout << p;
|
||||
exit(0);
|
||||
} catch (const args::ParseError& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
std::cerr << p;
|
||||
exit(1);
|
||||
} catch (const args::ValidationError& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
std::cerr << p;
|
||||
exit(2);
|
||||
}
|
||||
|
||||
auto file = mapbox::base::io::readFile(args::get(dataValue));
|
||||
if (!file) {
|
||||
std::cerr << file.error() << std::endl;
|
||||
exit(3);
|
||||
}
|
||||
|
||||
mbgl::Response response;
|
||||
response.data = std::make_shared<std::string>(*file);
|
||||
response.etag = etagValue ? args::get(etagValue) : std::string();
|
||||
response.expires = expiresValue ? mbgl::Timestamp(mbgl::Seconds(args::get(expiresValue))) : mbgl::util::now();
|
||||
response.modified = modifiedValue ? mbgl::Timestamp(mbgl::Seconds(args::get(modifiedValue))) : mbgl::util::now();
|
||||
|
||||
mbgl::Resource resource(args::get(typeFlag), args::get(urlValue));
|
||||
|
||||
if (args::get(typeFlag) == mbgl::Resource::Tile) {
|
||||
if (!xValueFlag || !yValueFlag || !zValueFlag) {
|
||||
std::cerr << "Error: -x, -y and -z must be provided for tiles" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
resource.tileData = {{args::get(urlValue),
|
||||
1,
|
||||
args::get(xValueFlag),
|
||||
args::get(yValueFlag),
|
||||
static_cast<int8_t>(args::get(zValueFlag))}};
|
||||
}
|
||||
|
||||
mbgl::util::RunLoop loop;
|
||||
std::shared_ptr<mbgl::FileSource> dbfs = mbgl::FileSourceManager::get()->getFileSource(
|
||||
mbgl::FileSourceType::Database, mbgl::ResourceOptions().withCachePath(args::get(cacheValue)));
|
||||
dbfs->forward(resource, response, [&loop] { loop.stop(); });
|
||||
loop.run();
|
||||
return 0;
|
||||
}
|
||||
274
mapbox-gl-native/bin/offline.cpp
Normal file
274
mapbox-gl-native/bin/offline.cpp
Normal file
@@ -0,0 +1,274 @@
|
||||
#include <mbgl/util/default_styles.hpp>
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
#include <mbgl/util/string.hpp>
|
||||
#include <mbgl/util/geojson.hpp>
|
||||
|
||||
#include <mbgl/storage/database_file_source.hpp>
|
||||
#include <mbgl/storage/file_source_manager.hpp>
|
||||
#include <mbgl/storage/resource_options.hpp>
|
||||
|
||||
#include <args.hxx>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <csignal>
|
||||
#include <atomic>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
|
||||
using namespace std::literals::chrono_literals;
|
||||
|
||||
std::string readFile(const std::string& fileName) {
|
||||
std::ifstream stream(fileName.c_str());
|
||||
if (!stream.good()) {
|
||||
throw std::runtime_error("Cannot read file: " + fileName);
|
||||
}
|
||||
|
||||
std::stringstream buffer;
|
||||
buffer << stream.rdbuf();
|
||||
stream.close();
|
||||
|
||||
return buffer.str();
|
||||
}
|
||||
|
||||
mapbox::geometry::geometry<double> parseGeometry(const std::string& json) {
|
||||
using namespace mapbox::geojson;
|
||||
auto geojson = parse(json);
|
||||
return geojson.match(
|
||||
[](const geometry& geom) {
|
||||
return geom;
|
||||
},
|
||||
[](const feature& feature) {
|
||||
return feature.geometry;
|
||||
},
|
||||
[](const feature_collection& featureCollection) {
|
||||
if (featureCollection.size() < 1) {
|
||||
throw std::runtime_error("No features in feature collection");
|
||||
}
|
||||
geometry_collection geometries;
|
||||
|
||||
for (auto feature : featureCollection) {
|
||||
geometries.push_back(feature.geometry);
|
||||
}
|
||||
|
||||
return geometries;
|
||||
});
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, mbgl::Response::Error::Reason r) {
|
||||
switch (r) {
|
||||
case mbgl::Response::Error::Reason::Success:
|
||||
return os << "Response::Error::Reason::Success";
|
||||
case mbgl::Response::Error::Reason::NotFound:
|
||||
return os << "Response::Error::Reason::NotFound";
|
||||
case mbgl::Response::Error::Reason::Server:
|
||||
return os << "Response::Error::Reason::Server";
|
||||
case mbgl::Response::Error::Reason::Connection:
|
||||
return os << "Response::Error::Reason::Connection";
|
||||
case mbgl::Response::Error::Reason::RateLimit:
|
||||
return os << "Response::Error::Reason::RateLimit";
|
||||
case mbgl::Response::Error::Reason::Other:
|
||||
return os << "Response::Error::Reason::Other";
|
||||
}
|
||||
|
||||
// The above switch is exhaustive, but placate GCC nonetheless:
|
||||
assert(false);
|
||||
return os;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
args::ArgumentParser argumentParser("Mapbox GL offline tool");
|
||||
args::HelpFlag helpFlag(argumentParser, "help", "Display this help menu", {'h', "help"});
|
||||
|
||||
args::ValueFlag<std::string> tokenValue(argumentParser, "key", "Mapbox access token", {'t', "token"});
|
||||
args::ValueFlag<std::string> styleValue(argumentParser, "URL", "Map stylesheet", {'s', "style"});
|
||||
args::ValueFlag<std::string> outputValue(argumentParser, "file", "Output database file name", {'o', "output"});
|
||||
args::ValueFlag<std::string> apiBaseValue(argumentParser, "URL", "API Base URL", {'a', "apiBaseURL"});
|
||||
|
||||
args::Group mergeGroup(argumentParser, "Merge databases:", args::Group::Validators::AllOrNone);
|
||||
args::ValueFlag<std::string> mergePathValue(mergeGroup, "merge", "Database to merge from", {'m', "merge"});
|
||||
args::ValueFlag<std::string> inputValue(mergeGroup, "input", "Database to merge into. Use with --merge option.", {'i', "input"});
|
||||
|
||||
// LatLngBounds
|
||||
args::Group latLngBoundsGroup(argumentParser, "LatLng bounds:", args::Group::Validators::AllOrNone);
|
||||
args::ValueFlag<double> northValue(latLngBoundsGroup, "degrees", "North latitude", {"north"});
|
||||
args::ValueFlag<double> westValue(latLngBoundsGroup, "degrees", "West longitude", {"west"});
|
||||
args::ValueFlag<double> southValue(latLngBoundsGroup, "degrees", "South latitude", {"south"});
|
||||
args::ValueFlag<double> eastValue(latLngBoundsGroup, "degrees", "East longitude", {"east"});
|
||||
|
||||
// Geometry
|
||||
args::Group geoJSONGroup(argumentParser, "GeoJson geometry:", args::Group::Validators::AllOrNone);
|
||||
args::ValueFlag<std::string> geometryValue(geoJSONGroup, "file", "GeoJSON Feature file containing the region geometry (can't be a FeatureCollection)", {"geojson"});
|
||||
|
||||
args::ValueFlag<double> minZoomValue(argumentParser, "number", "Min zoom level", {"minZoom"});
|
||||
args::ValueFlag<double> maxZoomValue(argumentParser, "number", "Max zoom level", {"maxZoom"});
|
||||
args::ValueFlag<double> pixelRatioValue(argumentParser, "number", "Pixel ratio", {"pixelRatio"});
|
||||
args::ValueFlag<bool> includeIdeographsValue(argumentParser, "boolean", "Include CJK glyphs", {"includeIdeographs"});
|
||||
|
||||
try {
|
||||
argumentParser.ParseCLI(argc, argv);
|
||||
} catch (const args::Help&) {
|
||||
std::cout << argumentParser;
|
||||
exit(0);
|
||||
} catch (const args::ParseError& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
std::cerr << argumentParser;
|
||||
exit(1);
|
||||
} catch (const args::ValidationError& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
std::cerr << argumentParser;
|
||||
exit(2);
|
||||
}
|
||||
|
||||
std::string style = styleValue ? args::get(styleValue) : mbgl::util::default_styles::streets.url;
|
||||
|
||||
mbgl::optional<std::string> mergePath = {};
|
||||
if (mergePathValue) mergePath = args::get(mergePathValue);
|
||||
mbgl::optional<std::string> inputDb = {};
|
||||
if (inputValue) inputDb = args::get(inputValue);
|
||||
|
||||
const double minZoom = minZoomValue ? args::get(minZoomValue) : 0.0;
|
||||
const double maxZoom = maxZoomValue ? args::get(maxZoomValue) : 15.0;
|
||||
const double pixelRatio = pixelRatioValue ? args::get(pixelRatioValue) : 1.0;
|
||||
const bool includeIdeographs = includeIdeographsValue ? args::get(includeIdeographsValue) : false;
|
||||
const std::string output = outputValue ? args::get(outputValue) : "offline.db";
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
OfflineRegionDefinition definition = [&]() {
|
||||
if (geometryValue) {
|
||||
try {
|
||||
std::string json = readFile(geometryValue.Get());
|
||||
auto geometry = parseGeometry(json);
|
||||
return OfflineRegionDefinition{ OfflineGeometryRegionDefinition(style, geometry, minZoom, maxZoom, pixelRatio, includeIdeographs) };
|
||||
} catch(const std::runtime_error& e) {
|
||||
std::cerr << "Could not parse geojson file " << geometryValue.Get() << ": " << e.what() << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
// Bay area
|
||||
const double north = northValue ? args::get(northValue) : 37.2;
|
||||
const double west = westValue ? args::get(westValue) : -122.8;
|
||||
const double south = southValue ? args::get(southValue) : 38.1;
|
||||
const double east = eastValue ? args::get(eastValue) : -121.7;
|
||||
LatLngBounds boundingBox = LatLngBounds::hull(LatLng(north, west), LatLng(south, east));
|
||||
return OfflineRegionDefinition{ OfflineTilePyramidRegionDefinition(style, boundingBox, minZoom, maxZoom, pixelRatio, includeIdeographs) };
|
||||
}
|
||||
}();
|
||||
|
||||
const char* tokenEnv = getenv("MAPBOX_ACCESS_TOKEN");
|
||||
const std::string token = tokenValue ? args::get(tokenValue) : (tokenEnv ? tokenEnv : std::string());
|
||||
|
||||
const std::string apiBaseURL = apiBaseValue ? args::get(apiBaseValue) : mbgl::util::API_BASE_URL;
|
||||
|
||||
|
||||
util::RunLoop loop;
|
||||
std::shared_ptr<DatabaseFileSource> fileSource = std::static_pointer_cast<DatabaseFileSource>(
|
||||
std::shared_ptr<FileSource>(FileSourceManager::get()->getFileSource(
|
||||
FileSourceType::Database,
|
||||
ResourceOptions().withAccessToken(token).withBaseURL(apiBaseURL).withCachePath(output))));
|
||||
|
||||
std::unique_ptr<OfflineRegion> region;
|
||||
|
||||
if (inputDb && mergePath) {
|
||||
DatabaseFileSource inputSource(ResourceOptions().withCachePath(*inputDb));
|
||||
|
||||
int retCode = 0;
|
||||
std::cout << "Start Merge" << std::endl;
|
||||
inputSource.mergeOfflineRegions(*mergePath, [&] (mbgl::expected<std::vector<OfflineRegion>, std::exception_ptr> result) {
|
||||
|
||||
if (!result) {
|
||||
std::cerr << "Error merging database: " << util::toString(result.error()) << std::endl;
|
||||
retCode = 1;
|
||||
} else {
|
||||
std::cout << " Added " << result->size() << " Regions" << std::endl;
|
||||
std::cout << "Finished Merge" << std::endl;
|
||||
}
|
||||
loop.stop();
|
||||
});
|
||||
loop.run();
|
||||
return retCode;
|
||||
}
|
||||
|
||||
OfflineRegionMetadata metadata;
|
||||
|
||||
class Observer : public OfflineRegionObserver {
|
||||
public:
|
||||
Observer(OfflineRegion& region_,
|
||||
std::shared_ptr<DatabaseFileSource> fileSource_,
|
||||
util::RunLoop& loop_,
|
||||
mbgl::optional<std::string> mergePath_)
|
||||
: region(region_),
|
||||
fileSource(std::move(fileSource_)),
|
||||
loop(loop_),
|
||||
mergePath(std::move(mergePath_)),
|
||||
start(util::now()) {}
|
||||
|
||||
void statusChanged(OfflineRegionStatus status) override {
|
||||
if (status.downloadState == OfflineRegionDownloadState::Inactive) {
|
||||
std::cout << "stopped" << std::endl;
|
||||
loop.stop();
|
||||
return;
|
||||
}
|
||||
|
||||
std::string bytesPerSecond = "-";
|
||||
|
||||
auto elapsedSeconds = (util::now() - start) / 1s;
|
||||
if (elapsedSeconds != 0) {
|
||||
bytesPerSecond = util::toString(status.completedResourceSize / elapsedSeconds);
|
||||
}
|
||||
|
||||
std::cout << status.completedResourceCount << " / " << status.requiredResourceCount << " resources | "
|
||||
<< status.completedTileCount << " / " << status.requiredTileCount << " tiles"
|
||||
<< (status.requiredResourceCountIsPrecise ? " | " : " (indeterminate); ")
|
||||
<< status.completedResourceSize << " bytes downloaded"
|
||||
<< " (" << bytesPerSecond << " bytes/sec)" << std::endl;
|
||||
|
||||
if (status.complete()) {
|
||||
std::cout << "Finished Download" << std::endl;
|
||||
loop.stop();
|
||||
}
|
||||
}
|
||||
|
||||
void responseError(Response::Error error) override {
|
||||
std::cerr << error.reason << " downloading resource: " << error.message << std::endl;
|
||||
}
|
||||
|
||||
void mapboxTileCountLimitExceeded(uint64_t limit) override {
|
||||
std::cerr << "Error: reached limit of " << limit << " offline tiles" << std::endl;
|
||||
}
|
||||
|
||||
OfflineRegion& region;
|
||||
std::shared_ptr<DatabaseFileSource> fileSource;
|
||||
util::RunLoop& loop;
|
||||
mbgl::optional<std::string> mergePath;
|
||||
Timestamp start;
|
||||
};
|
||||
|
||||
static auto stop = [&] {
|
||||
if (region) {
|
||||
std::cout << "Stopping download... ";
|
||||
fileSource->setOfflineRegionDownloadState(*region, OfflineRegionDownloadState::Inactive);
|
||||
}
|
||||
};
|
||||
|
||||
std::signal(SIGINT, [] (int) { stop(); });
|
||||
|
||||
fileSource->createOfflineRegion(
|
||||
definition, metadata, [&](mbgl::expected<OfflineRegion, std::exception_ptr> region_) {
|
||||
if (!region_) {
|
||||
std::cerr << "Error creating region: " << util::toString(region_.error()) << std::endl;
|
||||
loop.stop();
|
||||
exit(1);
|
||||
} else {
|
||||
assert(region_);
|
||||
region = std::make_unique<OfflineRegion>(std::move(*region_));
|
||||
fileSource->setOfflineRegionObserver(*region,
|
||||
std::make_unique<Observer>(*region, fileSource, loop, mergePath));
|
||||
fileSource->setOfflineRegionDownloadState(*region, OfflineRegionDownloadState::Active);
|
||||
}
|
||||
});
|
||||
|
||||
loop.run();
|
||||
return 0;
|
||||
}
|
||||
18
mapbox-gl-native/bin/offline.sh
Executable file
18
mapbox-gl-native/bin/offline.sh
Executable file
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
set -o pipefail
|
||||
|
||||
OFFLINE=./build/macos/Release/mbgl-offline
|
||||
|
||||
# Barcelona
|
||||
$OFFLINE --north 41.4664 --west 2.0407 --south 41.2724 --east 2.2680 --output barcelona.db
|
||||
$OFFLINE --north 41.4664 --west 2.0407 --south 41.2724 --east 2.2680 --output barcelona_sat.db --style mapbox://styles/mapbox/satellite-v8
|
||||
|
||||
# Greater London within the M25 at zoom levels 0–15
|
||||
$OFFLINE --north 51.6777 --west -0.5026 --south 51.3237 --east 0.2527 --maxZoom 15 --output london.db
|
||||
$OFFLINE --north 51.6777 --west -0.5026 --south 51.3237 --east 0.2527 --maxZoom 15 --output london_sat.db --style mapbox://styles/mapbox/satellite-v8
|
||||
|
||||
# The contiguous United States at zoom levels 0–9
|
||||
$OFFLINE --north 49.6107 --west -125.5078 --south 24.2870 --east -66.3574 --maxZoom 9 --output us.db
|
||||
$OFFLINE --north 49.6107 --west -125.5078 --south 24.2870 --east -66.3574 --maxZoom 9 --output us_sat.db --style mapbox://styles/mapbox/satellite-v8
|
||||
110
mapbox-gl-native/bin/render.cpp
Normal file
110
mapbox-gl-native/bin/render.cpp
Normal file
@@ -0,0 +1,110 @@
|
||||
#include <mbgl/map/map.hpp>
|
||||
#include <mbgl/map/map_options.hpp>
|
||||
#include <mbgl/util/image.hpp>
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
#include <mbgl/util/default_styles.hpp>
|
||||
|
||||
#include <mbgl/gfx/backend.hpp>
|
||||
#include <mbgl/gfx/headless_frontend.hpp>
|
||||
#include <mbgl/style/style.hpp>
|
||||
|
||||
#include <args.hxx>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
args::ArgumentParser argumentParser("Mapbox GL render tool");
|
||||
args::HelpFlag helpFlag(argumentParser, "help", "Display this help menu", {"help"});
|
||||
|
||||
args::ValueFlag<std::string> backendValue(argumentParser, "Backend", "Rendering backend", {"backend"});
|
||||
args::ValueFlag<std::string> tokenValue(argumentParser, "key", "Mapbox access token", {'t', "token"});
|
||||
args::ValueFlag<std::string> styleValue(argumentParser, "URL", "Map stylesheet", {'s', "style"});
|
||||
args::ValueFlag<std::string> outputValue(argumentParser, "file", "Output file name", {'o', "output"});
|
||||
args::ValueFlag<std::string> cacheValue(argumentParser, "file", "Cache database file name", {'c', "cache"});
|
||||
args::ValueFlag<std::string> assetsValue(argumentParser, "file", "Directory to which asset:// URLs will resolve", {'a', "assets"});
|
||||
|
||||
args::Flag debugFlag(argumentParser, "debug", "Debug mode", {"debug"});
|
||||
|
||||
args::ValueFlag<double> pixelRatioValue(argumentParser, "number", "Image scale factor", {'r', "ratio"});
|
||||
|
||||
args::ValueFlag<double> zoomValue(argumentParser, "number", "Zoom level", {'z', "zoom"});
|
||||
|
||||
args::ValueFlag<double> lonValue(argumentParser, "degrees", "Longitude", {'x', "lon"});
|
||||
args::ValueFlag<double> latValue(argumentParser, "degrees", "Latitude", {'y', "lat"});
|
||||
args::ValueFlag<double> bearingValue(argumentParser, "degrees", "Bearing", {'b', "bearing"});
|
||||
args::ValueFlag<double> pitchValue(argumentParser, "degrees", "Pitch", {'p', "pitch"});
|
||||
args::ValueFlag<uint32_t> widthValue(argumentParser, "pixels", "Image width", {'w', "width"});
|
||||
args::ValueFlag<uint32_t> heightValue(argumentParser, "pixels", "Image height", {'h', "height"});
|
||||
|
||||
try {
|
||||
argumentParser.ParseCLI(argc, argv);
|
||||
} catch (const args::Help&) {
|
||||
std::cout << argumentParser;
|
||||
exit(0);
|
||||
} catch (const args::ParseError& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
std::cerr << argumentParser;
|
||||
exit(1);
|
||||
} catch (const args::ValidationError& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
std::cerr << argumentParser;
|
||||
exit(2);
|
||||
}
|
||||
|
||||
std::string style = styleValue ? args::get(styleValue) : mbgl::util::default_styles::streets.url;
|
||||
const double lat = latValue ? args::get(latValue) : 0;
|
||||
const double lon = lonValue ? args::get(lonValue) : 0;
|
||||
const double zoom = zoomValue ? args::get(zoomValue) : 0;
|
||||
const double bearing = bearingValue ? args::get(bearingValue) : 0;
|
||||
const double pitch = pitchValue ? args::get(pitchValue) : 0;
|
||||
const double pixelRatio = pixelRatioValue ? args::get(pixelRatioValue) : 1;
|
||||
|
||||
const uint32_t width = widthValue ? args::get(widthValue) : 512;
|
||||
const uint32_t height = heightValue ? args::get(heightValue) : 512;
|
||||
const std::string output = outputValue ? args::get(outputValue) : "out.png";
|
||||
const std::string cache_file = cacheValue ? args::get(cacheValue) : "cache.sqlite";
|
||||
const std::string asset_root = assetsValue ? args::get(assetsValue) : ".";
|
||||
|
||||
// Try to load the token from the environment.
|
||||
const char* tokenEnv = getenv("MAPBOX_ACCESS_TOKEN");
|
||||
const std::string token = tokenValue ? args::get(tokenValue) : (tokenEnv ? tokenEnv : std::string());
|
||||
|
||||
const bool debug = debugFlag ? args::get(debugFlag) : false;
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
util::RunLoop loop;
|
||||
|
||||
HeadlessFrontend frontend({ width, height }, pixelRatio);
|
||||
Map map(frontend, MapObserver::nullObserver(),
|
||||
MapOptions().withMapMode(MapMode::Static).withSize(frontend.getSize()).withPixelRatio(pixelRatio),
|
||||
ResourceOptions().withCachePath(cache_file).withAssetPath(asset_root).withAccessToken(std::string(token)));
|
||||
|
||||
if (style.find("://") == std::string::npos) {
|
||||
style = std::string("file://") + style;
|
||||
}
|
||||
|
||||
map.getStyle().loadURL(style);
|
||||
map.jumpTo(CameraOptions()
|
||||
.withCenter(LatLng { lat, lon })
|
||||
.withZoom(zoom)
|
||||
.withBearing(bearing)
|
||||
.withPitch(pitch));
|
||||
|
||||
if (debug) {
|
||||
map.setDebug(debug ? mbgl::MapDebugOptions::TileBorders | mbgl::MapDebugOptions::ParseStatus : mbgl::MapDebugOptions::NoDebug);
|
||||
}
|
||||
|
||||
try {
|
||||
std::ofstream out(output, std::ios::binary);
|
||||
out << encodePNG(frontend.render(map).image);
|
||||
out.close();
|
||||
} catch(std::exception& e) {
|
||||
std::cout << "Error: " << e.what() << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
766
mapbox-gl-native/circle.yml
Normal file
766
mapbox-gl-native/circle.yml
Normal file
@@ -0,0 +1,766 @@
|
||||
version: 2.1
|
||||
|
||||
#
|
||||
# This CI configuration heavily relies on templates and CMake. Most of the
|
||||
# jobs will have the following steps (usually configurable via parameters):
|
||||
# prepare, build and test.
|
||||
#
|
||||
# 'sanity-checks' and 'baselines' are special. The former will run a series
|
||||
# of checks to see if the patch has the minimum requirements for landing in
|
||||
# our repository and the latter will generate new baselines for the tests
|
||||
# in case the PR changes the baselines.
|
||||
#
|
||||
workflows:
|
||||
version: 2
|
||||
development:
|
||||
jobs:
|
||||
- sanity-checks
|
||||
- build-template:
|
||||
name: android-armeabi-v7a-release
|
||||
executor_name: ubuntu-eoan
|
||||
target_is_android: true
|
||||
requires:
|
||||
- sanity-checks
|
||||
config_params: '-G Ninja -DCMAKE_INSTALL_PREFIX=/tmp/workspace/install/$CIRCLE_JOB -DCMAKE_TOOLCHAIN_FILE=/opt/android/ndk-bundle/build/cmake/android.toolchain.cmake -DANDROID_CCACHE=/usr/bin/ccache -DANDROID_ABI=armeabi-v7a'
|
||||
install: true
|
||||
- build-template:
|
||||
name: android-arm64-v8a-release
|
||||
executor_name: ubuntu-eoan
|
||||
target_is_android: true
|
||||
requires:
|
||||
- sanity-checks
|
||||
config_params: '-G Ninja -DCMAKE_INSTALL_PREFIX=/tmp/workspace/install/$CIRCLE_JOB -DCMAKE_TOOLCHAIN_FILE=/opt/android/ndk-bundle/build/cmake/android.toolchain.cmake -DANDROID_CCACHE=/usr/bin/ccache -DANDROID_ABI=arm64-v8a'
|
||||
build_params: '--target libmbgl-render-test-runner.so'
|
||||
install: true
|
||||
- build-template:
|
||||
name: android-x86-release
|
||||
executor_name: ubuntu-eoan
|
||||
target_is_android: true
|
||||
requires:
|
||||
- sanity-checks
|
||||
config_params: '-G Ninja -DCMAKE_INSTALL_PREFIX=/tmp/workspace/install/$CIRCLE_JOB -DCMAKE_TOOLCHAIN_FILE=/opt/android/ndk-bundle/build/cmake/android.toolchain.cmake -DANDROID_CCACHE=/usr/bin/ccache -DANDROID_ABI=x86'
|
||||
build_params: '--target libmbgl-render-test-runner.so'
|
||||
install: true
|
||||
- build-template:
|
||||
name: android-x86_64-release
|
||||
executor_name: ubuntu-eoan
|
||||
target_is_android: true
|
||||
requires:
|
||||
- sanity-checks
|
||||
config_params: '-G Ninja -DCMAKE_INSTALL_PREFIX=/tmp/workspace/install/$CIRCLE_JOB -DCMAKE_TOOLCHAIN_FILE=/opt/android/ndk-bundle/build/cmake/android.toolchain.cmake -DANDROID_CCACHE=/usr/bin/ccache -DANDROID_ABI=x86_64'
|
||||
build_params: '--target libmbgl-render-test-runner.so'
|
||||
install: true
|
||||
- build-template:
|
||||
name: linux-gcc8-release
|
||||
executor_name: ubuntu-eoan
|
||||
target_is_linux: true
|
||||
requires:
|
||||
- sanity-checks
|
||||
config_params: '-G Ninja -DCMAKE_INSTALL_PREFIX=/tmp/workspace/install/$CIRCLE_JOB -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER=gcc-8 -DCMAKE_CXX_COMPILER=g++-8'
|
||||
install: true
|
||||
metrics: true
|
||||
style_tests: true
|
||||
- build-template:
|
||||
name: linux-gcc5-release
|
||||
executor_name: ubuntu-eoan
|
||||
target_is_linux: true
|
||||
requires:
|
||||
- linux-gcc8-release
|
||||
config_params: '-G Ninja -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER=gcc-5 -DCMAKE_CXX_COMPILER=g++-5'
|
||||
build_params: '--target mbgl-glfw'
|
||||
test_params: '-N -Q'
|
||||
- build-template:
|
||||
name: linux-gcc8-debug-coverage
|
||||
executor_name: ubuntu-eoan
|
||||
target_is_linux: true
|
||||
requires:
|
||||
- linux-gcc8-release
|
||||
config_params: '-G Ninja -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER=gcc-8 -DCMAKE_CXX_COMPILER=g++-8 -DCMAKE_BUILD_TYPE=Debug -DMBGL_WITH_COVERAGE=ON'
|
||||
style_tests: true
|
||||
upload_coverage: true
|
||||
- build-template:
|
||||
name: linux-clang8-release
|
||||
executor_name: ubuntu-eoan
|
||||
target_is_linux: true
|
||||
requires:
|
||||
- sanity-checks
|
||||
config_params: '-G Ninja -DCMAKE_INSTALL_PREFIX=/tmp/workspace/install/$CIRCLE_JOB -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER=clang-8 -DCMAKE_CXX_COMPILER=clang++-8'
|
||||
install: true
|
||||
metrics: true
|
||||
style_tests: true
|
||||
- build-template:
|
||||
name: FIXME-linux-asan
|
||||
executor_name: ubuntu-eoan
|
||||
target_is_linux: true
|
||||
requires:
|
||||
- sanity-checks
|
||||
config_params: '-G Ninja -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER=clang-8 -DCMAKE_CXX_COMPILER=clang++-8 -DMBGL_WITH_SANITIZER=address'
|
||||
test_params: '|| true'
|
||||
style_tests: true
|
||||
- build-template:
|
||||
name: linux-tsan
|
||||
executor_name: ubuntu-eoan
|
||||
target_is_linux: true
|
||||
requires:
|
||||
- sanity-checks
|
||||
config_params: '-G Ninja -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER=clang-8 -DCMAKE_CXX_COMPILER=clang++-8 -DMBGL_WITH_SANITIZER=thread'
|
||||
style_tests: true
|
||||
- build-template:
|
||||
name: FIXME-linux-valgrind
|
||||
executor_name: ubuntu-eoan
|
||||
target_is_linux: true
|
||||
requires:
|
||||
- sanity-checks
|
||||
config_params: '-G Ninja -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER=clang-8 -DCMAKE_CXX_COMPILER=clang++-8 -DCMAKE_CXX_FLAGS=-DSANITIZE'
|
||||
test_params: '-j 4 -E "mbgl-node|gl-benchmark" -D ExperimentalMemCheck || true'
|
||||
- build-template:
|
||||
name: linux-ubsan
|
||||
executor_name: ubuntu-eoan
|
||||
target_is_linux: true
|
||||
requires:
|
||||
- sanity-checks
|
||||
config_params: '-G Ninja -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER=clang-8 -DCMAKE_CXX_COMPILER=clang++-8 -DMBGL_WITH_SANITIZER=undefined'
|
||||
style_tests: true
|
||||
- build-template:
|
||||
name: qt5-linux-gcc5-release
|
||||
executor_name: ubuntu-eoan
|
||||
target_is_linux: true
|
||||
requires:
|
||||
- sanity-checks
|
||||
config_params: '-G Ninja -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER=gcc-5 -DCMAKE_CXX_COMPILER=g++-5 -DMBGL_WITH_QT=ON'
|
||||
- build-template:
|
||||
name: qt5-macos-gcc5-release
|
||||
executor_name: macos-11_1_0
|
||||
target_is_macos: true
|
||||
requires:
|
||||
- linux-gcc8-release
|
||||
config_params: '-G Ninja -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DMBGL_WITH_QT=ON -DCMAKE_PREFIX_PATH=$(echo /usr/local/Cellar/qt/5.*/lib/cmake)'
|
||||
- build-template:
|
||||
name: macos-xcode11-release
|
||||
executor_name: macos-11_1_0
|
||||
target_is_macos: true
|
||||
requires:
|
||||
- linux-gcc8-release
|
||||
config_params: '-G Ninja -DCMAKE_INSTALL_PREFIX=/tmp/workspace/install/$CIRCLE_JOB -DCMAKE_CXX_COMPILER_LAUNCHER=ccache'
|
||||
install: true
|
||||
metrics: true
|
||||
style_tests: true
|
||||
- build-template:
|
||||
name: macos-xcode11-debug
|
||||
executor_name: macos-11_1_0
|
||||
target_is_macos: true
|
||||
requires:
|
||||
- macos-xcode11-release
|
||||
config_params: '-G Ninja -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_BUILD_TYPE=Debug -DMBGL_WITH_COVERAGE=ON'
|
||||
style_tests: true
|
||||
upload_coverage: true
|
||||
- build-template:
|
||||
name: ios-xcode11-release
|
||||
executor_name: macos-11_3_1
|
||||
target_is_macos: true
|
||||
requires:
|
||||
- linux-gcc8-release
|
||||
config_params: '-G Xcode -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_ARCHITECTURES=arm64e -DCMAKE_OSX_SYSROOT=iphoneos -DMBGL_WITH_IOS_CCACHE=ON'
|
||||
build_params: '--config Release'
|
||||
- android-render-test-runner:
|
||||
requires:
|
||||
- linux-gcc8-release
|
||||
# - android-unit-test-runner:
|
||||
# requires:
|
||||
# - linux-gcc8-release
|
||||
- ios-render-test-runner:
|
||||
requires:
|
||||
- linux-gcc8-release
|
||||
- ios-unit-test-runner:
|
||||
requires:
|
||||
- linux-gcc8-release
|
||||
- baselines:
|
||||
requires:
|
||||
- android-arm64-v8a-release
|
||||
- android-armeabi-v7a-release
|
||||
- android-render-test-runner
|
||||
- android-x86-release
|
||||
- android-x86_64-release
|
||||
- linux-clang8-release
|
||||
- linux-gcc8-release
|
||||
- macos-xcode11-release
|
||||
- ios-render-test-runner
|
||||
- trigger-pipeline:
|
||||
requires:
|
||||
- baselines
|
||||
name: mapboxci
|
||||
slug: mapbox/mapbox-gl-native-internal
|
||||
- android-api-breakage:
|
||||
requires:
|
||||
- baselines
|
||||
nightly:
|
||||
triggers:
|
||||
- schedule:
|
||||
cron: "0 5 * * *"
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
jobs:
|
||||
- build-template:
|
||||
name: linux-gcc8-debug-coverage-nightly
|
||||
executor_name: ubuntu-eoan
|
||||
target_is_linux: true
|
||||
config_params: '-G Ninja -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER=gcc-8 -DCMAKE_CXX_COMPILER=g++-8 -DCMAKE_BUILD_TYPE=Debug -DMBGL_WITH_COVERAGE=ON'
|
||||
style_tests: true
|
||||
upload_coverage: true
|
||||
- build-template:
|
||||
name: macos-xcode11-debug-coverage-nightly
|
||||
executor_name: macos-11_1_0
|
||||
target_is_macos: true
|
||||
requires:
|
||||
- linux-gcc8-debug-coverage-nightly
|
||||
config_params: '-G Ninja -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_BUILD_TYPE=Debug -DMBGL_WITH_COVERAGE=ON'
|
||||
style_tests: true
|
||||
upload_coverage: true
|
||||
publish_coverage: true
|
||||
|
||||
#
|
||||
# Executors: we currently support two executors, one based on Ubuntu 19.04 aka Disco
|
||||
# and another based on macOS + Xcode 11.1.0. The Ubuntu executor is a lot more stable
|
||||
# and will produce reproduceable builds completely offline because it uses a docker
|
||||
# image with all the build dependencies preinstalled, whereas the macOS is managed
|
||||
# by CircleCI and will install dependencies on build time. Build results from the macOS
|
||||
# bots might differ if in meantime the macOS image gets updated. :-(
|
||||
#
|
||||
executors:
|
||||
ubuntu-eoan:
|
||||
docker:
|
||||
# FIXME: Move the image to mbgl/
|
||||
- image: tmpsantos/mbgl_ci:1.9
|
||||
resource_class: xlarge
|
||||
working_directory: /src
|
||||
environment:
|
||||
DISPLAY: :99
|
||||
UBSAN_OPTIONS: print_stacktrace=1:halt_on_error=1:report_error_type=1
|
||||
ASAN_OPTIONS: strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1:halt_on_error=0
|
||||
QT_INSTALL_DOCS: /usr/share/qt5/doc
|
||||
QT_VERSION: 5
|
||||
TSAN_OPTIONS: suppressions=/src/platform/linux/tsan_suppress.txt
|
||||
macos-11_1_0:
|
||||
macos:
|
||||
xcode: '11.1.0'
|
||||
environment:
|
||||
HOMEBREW_NO_AUTO_UPDATE: 1
|
||||
HOMEBREW_NO_INSTALL_CLEANUP: 1
|
||||
macos-11_3_1:
|
||||
macos:
|
||||
xcode: '11.3.1'
|
||||
environment:
|
||||
HOMEBREW_NO_AUTO_UPDATE: 1
|
||||
HOMEBREW_NO_INSTALL_CLEANUP: 1
|
||||
|
||||
commands:
|
||||
prepare:
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- 'ccache-v1-{{ .Environment.CIRCLE_JOB }}-{{ .Branch }}-{{ .Revision }}'
|
||||
- 'ccache-v1-{{ .Environment.CIRCLE_JOB }}-{{ .Branch }}-'
|
||||
- 'ccache-v1-{{ .Environment.CIRCLE_JOB }}-master'
|
||||
- run:
|
||||
name: Prepare
|
||||
command: |
|
||||
git submodule sync
|
||||
git submodule update --init --recursive
|
||||
git gc
|
||||
npm install --ignore-scripts
|
||||
ulimit -c unlimited
|
||||
prepare-linux:
|
||||
steps:
|
||||
- run:
|
||||
name: Prepare Linux
|
||||
background: true
|
||||
command: |
|
||||
Xvfb :99 -noreset -screen 0 1280x1024x24
|
||||
prepare-macos:
|
||||
steps:
|
||||
- run:
|
||||
name: Prepare macOS
|
||||
command: |
|
||||
brew install cmake ccache glfw ninja pkgconfig qt chargepoint/xcparse/xcparse
|
||||
brew cask install google-cloud-sdk
|
||||
pip install ansi2html scipy
|
||||
config:
|
||||
parameters:
|
||||
config_params:
|
||||
type: string
|
||||
steps:
|
||||
- run:
|
||||
name: Configure
|
||||
command: |
|
||||
cmake . -B build << parameters.config_params >>
|
||||
build:
|
||||
parameters:
|
||||
build_params:
|
||||
type: string
|
||||
steps:
|
||||
- run:
|
||||
name: Build
|
||||
command: |
|
||||
ccache --zero-stats --max-size=2G
|
||||
cmake --build build -j $(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null) << parameters.build_params >>
|
||||
ccache --show-stats
|
||||
install:
|
||||
steps:
|
||||
- run:
|
||||
name: Install
|
||||
command: |
|
||||
cmake --build build --target install/strip
|
||||
test:
|
||||
parameters:
|
||||
test_params:
|
||||
type: string
|
||||
steps:
|
||||
- run:
|
||||
name: Test
|
||||
command: |
|
||||
cd build
|
||||
ctest -V << parameters.test_params >>
|
||||
metrics:
|
||||
parameters:
|
||||
step_name:
|
||||
type: string
|
||||
metrics_params:
|
||||
type: string
|
||||
steps:
|
||||
- run:
|
||||
name: << parameters.step_name >>
|
||||
command: |
|
||||
build/mbgl-render-test-runner << parameters.metrics_params >>
|
||||
save:
|
||||
steps:
|
||||
- save_cache:
|
||||
key: 'ccache-v1-{{ .Environment.CIRCLE_JOB }}-{{ .Branch }}-{{ .Revision }}'
|
||||
paths:
|
||||
- .git/modules
|
||||
- /Users/distiller/Library/Caches/Homebrew
|
||||
- node_modules
|
||||
- ~/.ccache
|
||||
- ~/.gradle
|
||||
- run:
|
||||
name: Collecting results
|
||||
when: always
|
||||
command: |
|
||||
mkdir -p /tmp/workspace/metrics && touch /tmp/workspace/.$CIRCLE_JOB
|
||||
if [ -d metrics/$CIRCLE_JOB ]; then cp -r metrics/$CIRCLE_JOB /tmp/workspace/metrics; fi
|
||||
mkdir -p /tmp/tests/baselines
|
||||
if [ -f baselines.patch ]; then cp baselines.patch /tmp/tests/baselines; fi
|
||||
mkdir -p /tmp/tests/nitpick
|
||||
if [ -f nitpick.patch ]; then cp nitpick.patch /tmp/tests/nitpick; fi
|
||||
mkdir -p /tmp/tests/render
|
||||
if [ -f clang-tidy.log ]; then cp clang-tidy.log /tmp/tests/clang-tidy; fi
|
||||
mkdir -p /tmp/tests/render
|
||||
if ls render-test/*.html 1> /dev/null 2>&1; then cp render-test/*.html /tmp/tests/render; fi
|
||||
mkdir -p /tmp/tests/metrics
|
||||
if ls metrics/*.html 1> /dev/null 2>&1; then cp metrics/*.html /tmp/tests/metrics; fi
|
||||
mkdir -p /tmp/tests/coredumps
|
||||
if ls core* 1> /dev/null 2>&1; then cp core* /tmp/tests/coredumps; fi
|
||||
mkdir -p /tmp/tests/valgrind
|
||||
if ls build/Testing/Temporary/MemoryChecker.*.log 1> /dev/null 2>&1; then cp build/Testing/Temporary/MemoryChecker.*.log /tmp/tests/valgrind; fi
|
||||
- persist_to_workspace:
|
||||
root: /tmp/workspace
|
||||
paths:
|
||||
- '*'
|
||||
- store_artifacts:
|
||||
path: /tmp/tests
|
||||
destination: tests
|
||||
login-google-cloud-platform:
|
||||
steps:
|
||||
- run:
|
||||
name: Login Google Cloud Platform
|
||||
command: |
|
||||
echo "${GCLOUD_SERVICE_ACCOUNT_JSON}" > secret.json
|
||||
gcloud auth activate-service-account --key-file secret.json --project android-gl-native
|
||||
rm secret.json
|
||||
login-google-cloud-platform-ios:
|
||||
steps:
|
||||
- run:
|
||||
name: Login to IOS Google Cloud Platform
|
||||
command: |
|
||||
if [[ -n "${GCLOUD_SERVICE_ACCOUNT_JSON_IOS}" ]]; then
|
||||
echo "${GCLOUD_SERVICE_ACCOUNT_JSON_IOS}" > iosAccount.json
|
||||
gcloud auth activate-service-account --key-file iosAccount.json --project ios-mapbox-gl-native
|
||||
rm iosAccount.json
|
||||
fi
|
||||
prepare-ios-codesign-keychain:
|
||||
parameters:
|
||||
directory:
|
||||
type: string
|
||||
steps:
|
||||
- run:
|
||||
name: Prepare codesign keychain
|
||||
command: |
|
||||
cd << parameters.directory >>
|
||||
fastlane run create_keychain name:fastlane_keychain password:$FASTLANE_PASSWORD timeout:false unlock:true
|
||||
fastlane match
|
||||
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k $FASTLANE_PASSWORD fastlane_keychain
|
||||
codesign-ios-test-runner:
|
||||
parameters:
|
||||
directory:
|
||||
type: string
|
||||
steps:
|
||||
- run:
|
||||
name: Codesign iOS TestApp for running on a physical device
|
||||
command: |
|
||||
cp -r << parameters.directory >>/codesigning build
|
||||
cd build
|
||||
./codesigning/generate-entitlements.swift
|
||||
./codesigning/codesign_all.sh
|
||||
codesign -dv --verbose=4 Release-iphoneos/*.app # for debugging that app is signed or not
|
||||
run-ios-test-app:
|
||||
parameters:
|
||||
directory:
|
||||
type: string
|
||||
steps:
|
||||
- run:
|
||||
name: Run iOS Test App on Firebase
|
||||
no_output_timeout: 30m
|
||||
command: |
|
||||
if [[ -n "${GCLOUD_SERVICE_ACCOUNT_JSON_IOS}" ]]; then
|
||||
# arrange files in a way Firebase expects it, and package them in a zip file
|
||||
cp << parameters.directory >>/*_iphoneos13.2-arm64e-release.xctestrun build
|
||||
cd build
|
||||
zip testapp.zip -r Release-iphoneos/*.app --quiet
|
||||
zip testapp.zip *_iphoneos13.2-arm64e-release.xctestrun
|
||||
gcloud firebase test ios models list
|
||||
gcloud firebase test ios run \
|
||||
--test testapp.zip \
|
||||
--device model=iphone11,version=13.3,locale=en,orientation=portrait --xcode-version=11.3.1 --timeout 30m \
|
||||
--verbosity=debug --no-record-video --results-dir ios-test-app-${CIRCLE_BUILD_NUM}
|
||||
fi
|
||||
upload-coverage-results:
|
||||
steps:
|
||||
- run:
|
||||
name: Get coverage results
|
||||
command: |
|
||||
cd build
|
||||
find . -type f -iname *.gcda -exec gcov -p -b {} \;
|
||||
- run:
|
||||
name: Upload coverage results to codecov.io
|
||||
command: |
|
||||
bash <(curl -sSfL https://codecov.io/bash) -X gcov || echo 'Codecov failed to upload'
|
||||
publish-coverage-metrics:
|
||||
steps:
|
||||
- run:
|
||||
name: Upload coverage metrics to s3
|
||||
command: |
|
||||
if [[ $CIRCLE_BRANCH == master ]]; then
|
||||
scripts/publish_core_codecoverage.js -p Linux -s Core
|
||||
fi
|
||||
|
||||
jobs:
|
||||
ios-render-test-runner:
|
||||
executor: macos-11_3_1
|
||||
steps:
|
||||
- checkout
|
||||
- prepare
|
||||
- prepare-macos
|
||||
- prepare-ios-codesign-keychain:
|
||||
directory: render-test/ios
|
||||
- config:
|
||||
config_params: '-G Xcode -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_SYSROOT=iphoneos -DMBGL_IOS_RENDER_TEST=ON -DCMAKE_OSX_ARCHITECTURES=arm64e -DMBGL_WITH_IOS_CCACHE=ON'
|
||||
- build:
|
||||
build_params: '--config Release'
|
||||
- codesign-ios-test-runner:
|
||||
directory: render-test/ios
|
||||
- login-google-cloud-platform-ios
|
||||
- run-ios-test-app:
|
||||
directory: render-test/ios
|
||||
- run:
|
||||
name: Retrieve Test Result from gcloud
|
||||
when: always
|
||||
command: |
|
||||
if [[ -n "${GCLOUD_SERVICE_ACCOUNT_JSON_IOS}" ]]; then
|
||||
testResult=$(gsutil ls -d gs://test-lab-hn7kwqcz3108z-hjm4qtbqqkymk/ios-test-app-${CIRCLE_BUILD_NUM}/iphone11-13.3-en-portrait/TestLogs/)
|
||||
mkdir -p render-test-app
|
||||
gsutil -m cp -r $testResult render-test-app
|
||||
cd render-test-app/TestLogs
|
||||
xcparse attachments *.xcresult && ls
|
||||
cd ../.. && mkdir -p /tmp/tests/ios-render-test
|
||||
if ls render-test-app/TestLogs/*.html 1> /dev/null 2>&1; then cp render-test-app/TestLogs/*.html /tmp/tests/ios-render-test; fi
|
||||
if [[ -n $(ls render-test-app/TestLogs/*.zip 2>/dev/null) ]]; then
|
||||
cp render-test-app/TestLogs/*.zip metrics/ios-render-test-runner/
|
||||
cp render-test-app/TestLogs/*.zip /tmp/tests/ios-render-test
|
||||
cd metrics/ios-render-test-runner/
|
||||
unzip -o *.zip
|
||||
rm -rf *.zip
|
||||
fi
|
||||
fi
|
||||
- save
|
||||
ios-unit-test-runner:
|
||||
executor: macos-11_3_1
|
||||
steps:
|
||||
- checkout
|
||||
- prepare
|
||||
- prepare-macos
|
||||
- prepare-ios-codesign-keychain:
|
||||
directory: test/ios
|
||||
- config:
|
||||
config_params: '-G Xcode -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_SYSROOT=iphoneos -DMBGL_IOS_UNIT_TEST=ON -DCMAKE_OSX_ARCHITECTURES=arm64e -DMBGL_WITH_IOS_CCACHE=ON'
|
||||
- build:
|
||||
build_params: '--config Release'
|
||||
- codesign-ios-test-runner:
|
||||
directory: test/ios
|
||||
- login-google-cloud-platform-ios
|
||||
- run-ios-test-app:
|
||||
directory: test/ios
|
||||
- run:
|
||||
name: Retrieve Test Result from gcloud
|
||||
when: always
|
||||
command: |
|
||||
if [[ -n "${GCLOUD_SERVICE_ACCOUNT_JSON_IOS}" ]]; then
|
||||
testResult=$(gsutil ls -d gs://test-lab-hn7kwqcz3108z-hjm4qtbqqkymk/ios-test-app-${CIRCLE_BUILD_NUM}/iphone11-13.3-en-portrait/TestLogs/)
|
||||
mkdir -p unit-test-app
|
||||
gsutil -m cp -r $testResult unit-test-app
|
||||
cd unit-test-app/TestLogs
|
||||
xcparse attachments *.xcresult && ls
|
||||
cd ../.. && mkdir -p /tmp/tests/unit-test
|
||||
if ls unit-test-app/TestLogs/*.xml 1> /dev/null 2>&1; then cp unit-test-app/TestLogs/*.xml /tmp/tests/unit-test/results.xml; fi
|
||||
fi
|
||||
- save
|
||||
android-api-breakage:
|
||||
executor: ubuntu-eoan
|
||||
steps:
|
||||
- run:
|
||||
name: Clone mapbox-gl-native-android in working directory
|
||||
command: git clone https://github.com/mapbox/mapbox-gl-native-android.git .
|
||||
- prepare
|
||||
- run:
|
||||
name: Update mapbox-gl-native to match PR
|
||||
command: cd vendor/mapbox-gl-native && git fetch origin $CIRCLE_SHA1 && git checkout $CIRCLE_SHA1 && git submodule update --init --recursive
|
||||
- run:
|
||||
name: Build SDK
|
||||
command: BUILDTYPE=Release make android-arm-v8
|
||||
- save
|
||||
android-unit-test-runner:
|
||||
executor: ubuntu-eoan
|
||||
steps:
|
||||
- checkout
|
||||
- prepare
|
||||
- run:
|
||||
name: Build UnitTestRunner APK
|
||||
command: |
|
||||
cd test/android
|
||||
./gradlew --parallel --max-workers=8 -Pmapbox.abis=arm64-v8a app:assembleRelease app:assembleAndroidTest
|
||||
- login-google-cloud-platform
|
||||
- run:
|
||||
name: Run UnitTestRunner on Firebase
|
||||
no_output_timeout: 20m
|
||||
command: |
|
||||
gcloud firebase test android models list
|
||||
gcloud firebase test android run --type instrumentation \
|
||||
--app test/android/app/build/outputs/apk/release/app-release.apk \
|
||||
--test test/android/app/build/outputs/apk/androidTest/release/app-release-androidTest.apk \
|
||||
--device-ids flame --os-version-ids 29 --locales en --orientations portrait --timeout 20m \
|
||||
--directories-to-pull /sdcard/test/results --results-dir unit-test-${CIRCLE_BUILD_NUM} \
|
||||
--no-record-video --no-performance-metrics
|
||||
- run:
|
||||
name: Retrieve Test Result from gcloud
|
||||
when: always
|
||||
command: |
|
||||
testResult=$(gsutil ls gs://test-lab-186672a0qp5bq-ycr70axads3nc/unit-test-${CIRCLE_BUILD_NUM}/**/results/results.xml)
|
||||
mkdir -p /tmp/tests/unit-test
|
||||
gsutil cp $testResult /tmp/tests/unit-test
|
||||
- save
|
||||
android-render-test-runner:
|
||||
executor: ubuntu-eoan
|
||||
steps:
|
||||
- checkout
|
||||
- prepare
|
||||
- run:
|
||||
name: Build RenderTestRunner APK
|
||||
command: |
|
||||
cd render-test/android
|
||||
./gradlew --parallel --max-workers=8 -Pmapbox.abis=arm64-v8a app:assembleRelease app:assembleAndroidTest
|
||||
- login-google-cloud-platform
|
||||
- run:
|
||||
name: Run RenderTestRunner Instrumentation Test on Firebase
|
||||
no_output_timeout: 20m
|
||||
command: |
|
||||
gcloud firebase test android models list
|
||||
gcloud firebase test android run --type instrumentation \
|
||||
--app render-test/android/app/build/outputs/apk/release/app-release.apk \
|
||||
--test render-test/android/app/build/outputs/apk/androidTest/release/app-release-androidTest.apk \
|
||||
--device-ids flame --os-version-ids 29 --locales en --orientations portrait --timeout 20m \
|
||||
--directories-to-pull /sdcard --results-dir render-test-app-${CIRCLE_BUILD_NUM} \
|
||||
--no-record-video --no-performance-metrics
|
||||
- run:
|
||||
name: Retrieve TestResult from gcloud
|
||||
when: always
|
||||
command: |
|
||||
testResult=$(gsutil ls gs://test-lab-186672a0qp5bq-ycr70axads3nc/render-test-app-${CIRCLE_BUILD_NUM}/**/*.html)
|
||||
mkdir -p /tmp/tests/render-test-app
|
||||
gsutil cp $testResult /tmp/tests/render-test-app
|
||||
- run:
|
||||
name: Retrieve Rebaselined Metrics from gcloud
|
||||
command: |
|
||||
metricsResult=$(gsutil ls -d gs://test-lab-186672a0qp5bq-ycr70axads3nc/render-test-app-${CIRCLE_BUILD_NUM}/*/*/sdcard/baselines/*) || true
|
||||
gsutil -m cp -r $metricsResult metrics/android-render-test-runner/ || true
|
||||
mkdir -p /tmp/tests/render-test-app/rebaselined_metrics
|
||||
gsutil -m cp -r $metricsResult /tmp/tests/render-test-app/rebaselined_metrics || true
|
||||
- save
|
||||
trigger-pipeline:
|
||||
executor: ubuntu-eoan
|
||||
parameters:
|
||||
slug:
|
||||
type: string
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Trigger Pipeline
|
||||
command: |
|
||||
scripts/ci-circleci-start-pipeline.py --target-slug << parameters.slug >>
|
||||
sanity-checks:
|
||||
executor: ubuntu-eoan
|
||||
steps:
|
||||
- checkout
|
||||
- prepare
|
||||
- config:
|
||||
config_params: '-G Ninja -DCMAKE_C_COMPILER=clang-8 -DCMAKE_CXX_COMPILER=clang++-8'
|
||||
- run:
|
||||
name: Code Generators
|
||||
command: |
|
||||
cp build/mbgl-core.license LICENSE.mbgl-core.md
|
||||
platform/default/include/mbgl/storage/offline_schema.js
|
||||
scripts/generate-shaders.js
|
||||
scripts/generate-style-code.js
|
||||
git add -A && git diff --staged --exit-code | tee nitpick.patch
|
||||
- run:
|
||||
name: Validation Scripts
|
||||
command: |
|
||||
scripts/nitpick/submodule-pin.js
|
||||
- run:
|
||||
name: CMake Format
|
||||
command: |
|
||||
cmake-format -i $(find -name '*.cmake' -and -not -path './vendor/*/*' -and -not -path './build/*')
|
||||
cmake-format -i $(find -name CMakeLists.txt -and -not -path './vendor/*/*' -and -not -path './build/*')
|
||||
git diff --exit-code | tee nitpick.patch
|
||||
- run:
|
||||
name: Clang Format
|
||||
command: |
|
||||
git diff -U0 --ignore-submodules=all --no-color origin/master... *.cpp *.hpp | clang-format-diff-8 -p1 -i
|
||||
git diff --exit-code | tee nitpick.patch
|
||||
- run:
|
||||
name: Clang Tidy
|
||||
command: |
|
||||
run-clang-tidy-8 -quiet -j $(nproc) -header-filter='.*' -p build $PWD/src/.*cpp $PWD/platform/.*cpp
|
||||
- save
|
||||
baselines:
|
||||
executor: ubuntu-eoan
|
||||
steps:
|
||||
- checkout
|
||||
- prepare
|
||||
- prepare-linux
|
||||
- attach_workspace:
|
||||
at: /tmp/attach
|
||||
- run:
|
||||
name: 'Binary Size'
|
||||
command: |
|
||||
/tmp/attach/install/linux-gcc8-release/bin/mbgl-render-test-runner -u rebaseline -p metrics/binary-size.json
|
||||
- run:
|
||||
name: 'Metrics Baselines'
|
||||
command: |
|
||||
cp -r /tmp/attach/metrics .
|
||||
git add -A && git diff --staged --exit-code | tee baselines.patch
|
||||
- save
|
||||
build-template:
|
||||
parameters:
|
||||
config_params:
|
||||
type: string
|
||||
default: ''
|
||||
build_params:
|
||||
type: string
|
||||
default: ''
|
||||
test_params:
|
||||
type: string
|
||||
default: ''
|
||||
executor_name:
|
||||
type: string
|
||||
target_is_android:
|
||||
type: boolean
|
||||
default: false
|
||||
target_is_linux:
|
||||
type: boolean
|
||||
default: false
|
||||
target_is_macos:
|
||||
type: boolean
|
||||
default: false
|
||||
install:
|
||||
type: boolean
|
||||
default: false
|
||||
metrics:
|
||||
type: boolean
|
||||
default: false
|
||||
style_tests:
|
||||
type: boolean
|
||||
default: false
|
||||
upload_coverage:
|
||||
type: boolean
|
||||
default: false
|
||||
publish_coverage:
|
||||
type: boolean
|
||||
default: false
|
||||
executor: << parameters.executor_name >>
|
||||
steps:
|
||||
- checkout
|
||||
- when:
|
||||
condition: << parameters.target_is_android >>
|
||||
steps:
|
||||
- prepare
|
||||
- config:
|
||||
config_params: << parameters.config_params >>
|
||||
- build:
|
||||
build_params: << parameters.build_params >>
|
||||
- when:
|
||||
condition: << parameters.target_is_linux >>
|
||||
steps:
|
||||
- prepare
|
||||
- prepare-linux
|
||||
- config:
|
||||
config_params: << parameters.config_params >>
|
||||
- build:
|
||||
build_params: << parameters.build_params >>
|
||||
- test:
|
||||
test_params: << parameters.test_params >>
|
||||
- when:
|
||||
condition: << parameters.target_is_macos >>
|
||||
steps:
|
||||
- prepare
|
||||
- prepare-macos
|
||||
- config:
|
||||
config_params: << parameters.config_params >>
|
||||
- build:
|
||||
build_params: << parameters.build_params >>
|
||||
- test:
|
||||
test_params: << parameters.test_params >>
|
||||
- when:
|
||||
condition: << parameters.install >>
|
||||
steps:
|
||||
- install
|
||||
- when:
|
||||
condition: << parameters.style_tests >>
|
||||
steps:
|
||||
- metrics:
|
||||
step_name: 'Style Tests'
|
||||
metrics_params: '-u rebaseline -p metrics/$CIRCLE_JOB-style.json'
|
||||
- when:
|
||||
condition: << parameters.metrics >>
|
||||
steps:
|
||||
- metrics:
|
||||
step_name: 'Metrics'
|
||||
metrics_params: '-u rebaseline -p metrics/$CIRCLE_JOB-metrics.json'
|
||||
- when:
|
||||
condition: << parameters.upload_coverage >>
|
||||
steps:
|
||||
- upload-coverage-results
|
||||
- when:
|
||||
condition: << parameters.publish_coverage >>
|
||||
steps:
|
||||
- publish-coverage-metrics
|
||||
- save
|
||||
117
mapbox-gl-native/cloudformation/ci.template.js
Normal file
117
mapbox-gl-native/cloudformation/ci.template.js
Normal file
@@ -0,0 +1,117 @@
|
||||
'use strict';
|
||||
|
||||
const template = {
|
||||
AWSTemplateFormatVersion: '2010-09-09',
|
||||
Description: 'mapbox-gl-native travis resources',
|
||||
Resources: {
|
||||
BuildUser: {
|
||||
Type: 'AWS::IAM::User',
|
||||
Properties: {
|
||||
Policies: [
|
||||
{
|
||||
PolicyName: 'listBuckets',
|
||||
PolicyDocument: {
|
||||
Statement: [
|
||||
{
|
||||
Action: [ 's3:ListBucket' ],
|
||||
Effect: 'Allow',
|
||||
Resource: [ 'arn:aws:s3:::mapbox' ],
|
||||
Condition: { StringLike: { 's3:prefix': 'mapbox-gl-native/*' } }
|
||||
},
|
||||
{
|
||||
Action: [ 's3:ListBucket' ],
|
||||
Resource: [ 'arn:aws:s3:::mapbox-node-binary' ],
|
||||
Effect: 'Allow'
|
||||
},
|
||||
{
|
||||
Action: [ 's3:ListBucket' ],
|
||||
Resource: [ 'arn:aws:s3:::mapbox-loading-dock' ],
|
||||
Effect: 'Allow'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
PolicyName: 'build-testing',
|
||||
PolicyDocument: {
|
||||
Statement: [
|
||||
{
|
||||
Action: [
|
||||
's3:GetObject',
|
||||
's3:GetObjectAcl',
|
||||
's3:PutObject',
|
||||
's3:PutObjectAcl'
|
||||
],
|
||||
Effect: 'Allow',
|
||||
Resource: [
|
||||
'arn:aws:s3:::mapbox/mapbox-gl-native/*',
|
||||
'arn:aws:s3:::mapbox-node-binary/@mapbox/mapbox-gl-native/*',
|
||||
'arn:aws:s3:::mapbox/mapbox-gl-native/ios/builds/*'
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
PolicyName: 'cloudwatch-metrics',
|
||||
PolicyDocument: {
|
||||
Statement: [
|
||||
{
|
||||
Action: [
|
||||
'cloudwatch:PutMetricData',
|
||||
'cloudwatch:GetMetricData',
|
||||
'cloudwatch:GetMetricStatistics'
|
||||
],
|
||||
Effect: 'Allow',
|
||||
Resource: [ '*' ]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
PolicyName: 'get-signing-key',
|
||||
PolicyDocument: {
|
||||
Statement: [
|
||||
{
|
||||
Action: [ 's3:GetObject' ],
|
||||
Effect: 'Allow',
|
||||
Resource: [
|
||||
'arn:aws:s3:::mapbox/android/signing-credentials/secring.gpg'
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
PolicyName: 'publish-metrics',
|
||||
PolicyDocument: {
|
||||
Statement: [
|
||||
{
|
||||
Action: [ 's3:PutObject', 's3:GetObject', 's3:GetObjectAcl' ],
|
||||
Effect: 'Allow',
|
||||
Resource: [
|
||||
'arn:aws:s3:::mapbox-loading-dock/raw/mobile.binarysize/*',
|
||||
'arn:aws:s3:::mapbox-loading-dock/raw/mobile.codecoverage/*',
|
||||
'arn:aws:s3:::mapbox-loading-dock/raw/mobile_staging.docs_coverage/*',
|
||||
'arn:aws:s3:::mapbox-loading-dock/raw/mobile_staging.codecoverage/*',
|
||||
'arn:aws:s3:::mapbox-loading-dock/raw/mobile_staging.github_stats/*'
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
BuildUserKey: {
|
||||
Type: 'AWS::IAM::AccessKey',
|
||||
Properties: { UserName: { Ref: 'BuildUser' } }
|
||||
}
|
||||
},
|
||||
Outputs: {
|
||||
AccessKeyId: { Value: { Ref: 'BuildUserKey' } },
|
||||
SecretAccessKey: { Value: { 'Fn::GetAtt': [ 'BuildUserKey', 'SecretAccessKey' ] } }
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = template;
|
||||
12
mapbox-gl-native/codecov.yml
Normal file
12
mapbox-gl-native/codecov.yml
Normal file
@@ -0,0 +1,12 @@
|
||||
ignore:
|
||||
- "benchmark/"
|
||||
- "expression-test/"
|
||||
- "render-test/"
|
||||
- "test/"
|
||||
- "vendor/"
|
||||
|
||||
coverage:
|
||||
status:
|
||||
project:
|
||||
default:
|
||||
threshold: 1%
|
||||
42
mapbox-gl-native/expression-test/CMakeLists.txt
Normal file
42
mapbox-gl-native/expression-test/CMakeLists.txt
Normal file
@@ -0,0 +1,42 @@
|
||||
add_executable(
|
||||
mbgl-expression-test
|
||||
${PROJECT_SOURCE_DIR}/expression-test/expression_test_logger.cpp
|
||||
${PROJECT_SOURCE_DIR}/expression-test/expression_test_logger.hpp
|
||||
${PROJECT_SOURCE_DIR}/expression-test/expression_test_parser.cpp
|
||||
${PROJECT_SOURCE_DIR}/expression-test/expression_test_parser.hpp
|
||||
${PROJECT_SOURCE_DIR}/expression-test/expression_test_runner.cpp
|
||||
${PROJECT_SOURCE_DIR}/expression-test/expression_test_runner.hpp
|
||||
${PROJECT_SOURCE_DIR}/expression-test/test_runner_common.cpp
|
||||
${PROJECT_SOURCE_DIR}/expression-test/test_runner_common.hpp
|
||||
${PROJECT_SOURCE_DIR}/expression-test/main.cpp
|
||||
)
|
||||
|
||||
target_compile_definitions(
|
||||
mbgl-expression-test
|
||||
PRIVATE TEST_RUNNER_ROOT_PATH="${PROJECT_SOURCE_DIR}"
|
||||
)
|
||||
|
||||
# FIXME: Should not use core private interface
|
||||
target_include_directories(
|
||||
mbgl-expression-test
|
||||
PRIVATE ${PROJECT_SOURCE_DIR}/src
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
mbgl-expression-test
|
||||
PRIVATE
|
||||
Mapbox::Base
|
||||
Mapbox::Base::Extras::args
|
||||
Mapbox::Base::Extras::filesystem
|
||||
mbgl-core
|
||||
)
|
||||
|
||||
set_property(TARGET mbgl-expression-test PROPERTY FOLDER Executables)
|
||||
|
||||
string(RANDOM LENGTH 5 ALPHABET 0123456789 MBGL_EXPRESSION_TEST_SEED)
|
||||
|
||||
add_test(
|
||||
NAME mbgl-expression-test
|
||||
COMMAND mbgl-expression-test -s --seed=${MBGL_EXPRESSION_TEST_SEED}
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
||||
)
|
||||
177
mapbox-gl-native/expression-test/expression_test_logger.cpp
Normal file
177
mapbox-gl-native/expression-test/expression_test_logger.cpp
Normal file
@@ -0,0 +1,177 @@
|
||||
#include "expression_test_logger.hpp"
|
||||
#include "expression_test_runner.hpp"
|
||||
#include "filesystem.hpp"
|
||||
|
||||
#include <mbgl/util/io.hpp>
|
||||
#include <mbgl/util/string.hpp>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
using namespace mbgl;
|
||||
using namespace std::literals;
|
||||
|
||||
namespace {
|
||||
|
||||
const char* resultsStyle = R"HTML(
|
||||
<style>
|
||||
body { font: 18px/1.2 -apple-system, BlinkMacSystemFont, "Helvetica Neue", Helvetica, Arial, sans-serif; padding: 10px; }
|
||||
h1 { font-size: 32px; margin-bottom: 0; }
|
||||
button { vertical-align: middle; }
|
||||
h2 { font-size: 24px; font-weight: normal; margin: 10px 0 10px; line-height: 1; }
|
||||
.test { border-bottom: 1px dotted #bbb; padding-bottom: 5px; }
|
||||
.tests { border-top: 1px dotted #bbb; margin-top: 10px; }
|
||||
.test p, .test pre { margin: 0 0 10px; }
|
||||
.test pre { font-size: 14px; }
|
||||
.label { color: white; font-size: 18px; padding: 2px 6px 3px; border-radius: 3px; margin-right: 3px; vertical-align: bottom; display: inline-block; }
|
||||
.hide { display: none; }
|
||||
.test.failed > h2 > span { background: red; }
|
||||
.test.passed > h2 > span { background: green; }
|
||||
.test.ignored > h2 > span { background: grey; }
|
||||
.test.errored > h2 > span { background: #ff006f; }
|
||||
.test.ignored.passed > h2 > span { background: #E8A408; }
|
||||
</style>
|
||||
)HTML";
|
||||
|
||||
const char* resultsHeaderButtons = R"HTML(
|
||||
<button id='toggle-sequence'>Toggle test sequence</button>
|
||||
<button id='toggle-passed'>Toggle passed tests</button>
|
||||
<button id='toggle-ignored'>Toggle ignored tests</button>
|
||||
</h1>
|
||||
)HTML";
|
||||
|
||||
const char* resultsScript = R"HTML(
|
||||
<script>
|
||||
document.getElementById('toggle-passed').addEventListener('click', function (e) {
|
||||
for (const row of document.querySelectorAll('.test.passed')) {
|
||||
row.classList.toggle('hide');
|
||||
}
|
||||
});
|
||||
document.getElementById('toggle-ignored').addEventListener('click', function (e) {
|
||||
for (const row of document.querySelectorAll('.test.ignored')) {
|
||||
row.classList.toggle('hide');
|
||||
}
|
||||
});
|
||||
document.getElementById('toggle-sequence').addEventListener('click', function (e) {
|
||||
document.getElementById('test-sequence').classList.toggle('hide');
|
||||
});
|
||||
</script>
|
||||
)HTML";
|
||||
|
||||
std::string createResultItem(const TestRunOutput& result, const std::string& status, bool shouldHide) {
|
||||
std::ostringstream html;
|
||||
html << "<div class=\"test " << status << (shouldHide ? " hide" : "") << "\">\n";
|
||||
html << R"(<h2><span class="label">)" << status << "</span> " << result.id << "</h2>\n";
|
||||
|
||||
html << "<p><pre>"s << result.expression << "</pre></p>\n"s;
|
||||
if (result.passed) {
|
||||
html << "<strong>Serialized:</strong><p><pre>"s << result.serialized << "</pre></p>\n"s;
|
||||
} else {
|
||||
html << "<p><strong>Difference:</strong><pre>" << result.text << "</pre></p>\n";
|
||||
}
|
||||
html << "</div>\n";
|
||||
|
||||
return html.str();
|
||||
}
|
||||
|
||||
std::string createResultPage(const TestStats& stats, bool shuffle, uint32_t seed) {
|
||||
const std::size_t unsuccessfulCount = stats.errored.size() + stats.failed.size();
|
||||
const bool unsuccessful = unsuccessfulCount > 0;
|
||||
std::ostringstream resultsPage;
|
||||
|
||||
// Style
|
||||
resultsPage << resultsStyle;
|
||||
|
||||
// Header with buttons
|
||||
if (unsuccessful) {
|
||||
resultsPage << R"HTML(<h1 style="color: red;">)HTML";
|
||||
resultsPage << util::toString(unsuccessfulCount) << " tests failed.";
|
||||
} else {
|
||||
resultsPage << R"HTML(<h1 style="color: green;">)HTML";
|
||||
resultsPage << "All tests passed!";
|
||||
}
|
||||
|
||||
resultsPage << resultsHeaderButtons;
|
||||
|
||||
// Test sequence
|
||||
{
|
||||
resultsPage << "<div id='test-sequence' class='hide'>\n";
|
||||
|
||||
// Failed tests
|
||||
if (unsuccessful) {
|
||||
resultsPage << "<p><strong>Failed tests:</strong>";
|
||||
for (const auto& failed : stats.failed) {
|
||||
resultsPage << failed.id << " ";
|
||||
}
|
||||
resultsPage << "<p><strong>Errored tests:</strong>";
|
||||
for (const auto& errored : stats.errored) {
|
||||
resultsPage << errored.id << " ";
|
||||
}
|
||||
resultsPage << "</p>\n";
|
||||
}
|
||||
|
||||
// Test sequence
|
||||
resultsPage << "<p><strong>Test sequence: </strong>";
|
||||
for (const auto& id : stats.ids) {
|
||||
resultsPage << id << " ";
|
||||
}
|
||||
resultsPage << "</p>\n";
|
||||
|
||||
// Shuffle
|
||||
if (shuffle) {
|
||||
resultsPage << "<p><strong>Shuffle seed</strong>: " << util::toString(seed) << "</p>\n";
|
||||
}
|
||||
|
||||
resultsPage << "</div>\n";
|
||||
}
|
||||
|
||||
// Script
|
||||
resultsPage << resultsScript;
|
||||
|
||||
// Tests
|
||||
resultsPage << "<div class=\"tests\">\n";
|
||||
const auto appendResult = [&] (const auto& results, const std::string& status, bool hide = false) {
|
||||
for (const auto& result : results) {
|
||||
resultsPage << createResultItem(result, status, hide);
|
||||
}
|
||||
};
|
||||
|
||||
appendResult(stats.passed, "passed"s, unsuccessful);
|
||||
appendResult(stats.failed, "failed"s);
|
||||
appendResult(stats.errored, "errored"s);
|
||||
appendResult(stats.ignorePassed, "ignored passed"s, unsuccessful);
|
||||
appendResult(stats.ignoreFailed, "ignored"s, true);
|
||||
resultsPage << "</div>\n";
|
||||
|
||||
return resultsPage.str();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void printStats(const TestStats& stats) {
|
||||
const std::size_t count = stats.testCount();
|
||||
if (std::size_t passedTests = stats.passed.size()) {
|
||||
printf(ANSI_COLOR_GREEN "%zu passed (%.1lf%%)" ANSI_COLOR_RESET "\n", passedTests, 100.0 * passedTests / count);
|
||||
}
|
||||
if (std::size_t ignorePassedTests = stats.ignorePassed.size()) {
|
||||
printf(ANSI_COLOR_YELLOW "%zu passed but were ignored (%.1lf%%)" ANSI_COLOR_RESET "\n", ignorePassedTests, 100.0 * ignorePassedTests / count);
|
||||
}
|
||||
if (std::size_t ignoreFailedTests = stats.ignoreFailed.size()) {
|
||||
printf(ANSI_COLOR_LIGHT_GRAY "%zu ignored (%.1lf%%)" ANSI_COLOR_RESET "\n", ignoreFailedTests, 100.0 * ignoreFailedTests / count);
|
||||
}
|
||||
if (std::size_t failedTests = stats.failed.size()) {
|
||||
printf(ANSI_COLOR_RED "%zu failed (%.1lf%%)" ANSI_COLOR_RESET "\n", failedTests, 100.0 * failedTests / count);
|
||||
}
|
||||
if (std::size_t erroredTests = stats.errored.size()) {
|
||||
printf(ANSI_COLOR_RED "%zu errored (%.1lf%%)" ANSI_COLOR_RESET "\n", erroredTests, 100.0 * erroredTests / count);
|
||||
}
|
||||
}
|
||||
|
||||
void writeHTMLResults(const TestStats& stats, const std::string& rootPath, bool shuffle, uint32_t seed) {
|
||||
filesystem::path path = filesystem::path(rootPath) / "index.html"s;
|
||||
try {
|
||||
util::write_file(path.string(), createResultPage(stats, shuffle, seed));
|
||||
printf("Results at: %s\n", path.string().c_str());
|
||||
} catch (std::exception&) {
|
||||
printf(ANSI_COLOR_RED "* ERROR can't write result page %s" ANSI_COLOR_RESET "\n", path.string().c_str());
|
||||
}
|
||||
}
|
||||
14
mapbox-gl-native/expression-test/expression_test_logger.hpp
Normal file
14
mapbox-gl-native/expression-test/expression_test_logger.hpp
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#define ANSI_COLOR_RED "\x1b[31m"
|
||||
#define ANSI_COLOR_GREEN "\x1b[32m"
|
||||
#define ANSI_COLOR_YELLOW "\x1b[33m"
|
||||
#define ANSI_COLOR_LIGHT_GRAY "\x1b[90m"
|
||||
#define ANSI_COLOR_RESET "\x1b[0m"
|
||||
|
||||
class TestStats;
|
||||
|
||||
void printStats(const TestStats&);
|
||||
void writeHTMLResults(const TestStats&, const std::string&, bool, uint32_t);
|
||||
544
mapbox-gl-native/expression-test/expression_test_parser.cpp
Normal file
544
mapbox-gl-native/expression-test/expression_test_parser.cpp
Normal file
@@ -0,0 +1,544 @@
|
||||
#include "expression_test_parser.hpp"
|
||||
|
||||
#include <mbgl/util/io.hpp>
|
||||
#include <mbgl/util/logging.hpp>
|
||||
#include <mbgl/util/variant.hpp>
|
||||
#include <mbgl/style/conversion/function.hpp>
|
||||
#include <mbgl/style/rapidjson_conversion.hpp>
|
||||
#include <mbgl/style/expression/parsing_context.hpp>
|
||||
|
||||
#include <mapbox/geojson/rapidjson.hpp>
|
||||
#include <rapidjson/writer.h>
|
||||
#include <rapidjson/prettywriter.h>
|
||||
#include <rapidjson/stringbuffer.h>
|
||||
|
||||
#include <args.hxx>
|
||||
|
||||
#include <regex>
|
||||
|
||||
using namespace mbgl;
|
||||
using namespace mbgl::style;
|
||||
using namespace mbgl::style::conversion;
|
||||
using namespace std::literals;
|
||||
|
||||
namespace {
|
||||
|
||||
void writeJSON(rapidjson::PrettyWriter<rapidjson::StringBuffer>& writer, const Value& value) {
|
||||
value.match(
|
||||
[&] (const NullValue&) { writer.Null(); },
|
||||
[&] (bool b) { writer.Bool(b); },
|
||||
[&] (uint64_t u) { writer.Uint64(u); },
|
||||
[&] (int64_t i) { writer.Int64(i); },
|
||||
[&] (double d) { d == std::floor(d) ? writer.Int64(d) : writer.Double(d); },
|
||||
[&] (const std::string& s) { writer.String(s); },
|
||||
[&] (const std::vector<Value>& arr) {
|
||||
writer.StartArray();
|
||||
for(const auto& item : arr) {
|
||||
writeJSON(writer, item);
|
||||
}
|
||||
writer.EndArray();
|
||||
},
|
||||
[&] (const std::unordered_map<std::string, Value>& obj) {
|
||||
writer.StartObject();
|
||||
for(const auto& entry : obj) {
|
||||
writer.Key(entry.first.c_str());
|
||||
writeJSON(writer, entry.second);
|
||||
}
|
||||
writer.EndObject();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
using ErrorMessage = std::string;
|
||||
using JSONReply = variant<JSDocument, ErrorMessage>;
|
||||
JSONReply readJson(const filesystem::path& jsonPath) {
|
||||
auto maybeJSON = util::readFile(jsonPath);
|
||||
if (!maybeJSON) {
|
||||
return { "Unable to open file "s + jsonPath.string() };
|
||||
}
|
||||
|
||||
JSDocument document;
|
||||
document.Parse<rapidjson::kParseFullPrecisionFlag>(*maybeJSON);
|
||||
if (document.HasParseError()) {
|
||||
return { formatJSONParseError(document) };
|
||||
}
|
||||
|
||||
return { std::move(document) };
|
||||
}
|
||||
|
||||
std::string toString(const JSValue& value) {
|
||||
assert(value.IsString());
|
||||
return { value.GetString(), value.GetStringLength() };
|
||||
}
|
||||
|
||||
optional<Value> toValue(const JSValue& jsvalue) {
|
||||
if (jsvalue.IsNull()) {
|
||||
return Value{};
|
||||
}
|
||||
|
||||
if (jsvalue.IsArray()) {
|
||||
std::vector<Value> values;
|
||||
values.reserve(jsvalue.GetArray().Size());
|
||||
for (const auto& v : jsvalue.GetArray()) {
|
||||
if (auto value = toValue(v)) {
|
||||
values.emplace_back(std::move(*value));
|
||||
}
|
||||
}
|
||||
return {std::move(values)};
|
||||
}
|
||||
|
||||
if (jsvalue.IsObject()) {
|
||||
std::unordered_map<std::string, Value> value_map;
|
||||
for (const auto& pair : jsvalue.GetObject()) {
|
||||
if (auto value = toValue(pair.value)) {
|
||||
value_map.emplace(toString(pair.name), std::move(*value));
|
||||
}
|
||||
}
|
||||
return {std::move(value_map)};
|
||||
}
|
||||
|
||||
if (!jsvalue.IsArray() && !jsvalue.IsObject()) {
|
||||
return toValue(Convertible(&jsvalue));
|
||||
}
|
||||
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
style::expression::type::Type stringToType(const std::string& type) {
|
||||
using namespace style::expression;
|
||||
if (type == "string"s || type == "number-format"s) {
|
||||
return type::String;
|
||||
} else if (type == "number"s) {
|
||||
return type::Number;
|
||||
} else if (type == "boolean"s) {
|
||||
return type::Boolean;
|
||||
} else if (type == "object"s) {
|
||||
return type::Object;
|
||||
} else if (type == "color"s) {
|
||||
return type::Color;
|
||||
} else if (type == "value"s) {
|
||||
return type::Value;
|
||||
} else if (type == "formatted"s) {
|
||||
return type::Formatted;
|
||||
} else if (type == "resolvedImage"s) {
|
||||
return type::Image;
|
||||
}
|
||||
|
||||
// Should not reach.
|
||||
assert(false);
|
||||
return type::Null;
|
||||
}
|
||||
|
||||
optional<style::expression::type::Type> toExpressionType(const PropertySpec& spec) {
|
||||
using namespace style::expression;
|
||||
if (spec.type == "array") {
|
||||
type::Type itemType = spec.value.empty() ? type::Value : stringToType(spec.value);
|
||||
if (spec.length) {
|
||||
return {type::Array(itemType, spec.length)};
|
||||
}
|
||||
return {type::Array(itemType)};
|
||||
}
|
||||
|
||||
if (spec.type == "enum") {
|
||||
return {type::String};
|
||||
}
|
||||
|
||||
return spec.type.empty() ? nullopt : optional<type::Type>{stringToType(spec.type)};
|
||||
}
|
||||
|
||||
void parseCompiled(const JSValue& compiledValue, TestData& data) {
|
||||
const auto& compiled = compiledValue.GetObject();
|
||||
assert(compiled.HasMember("result"));
|
||||
assert(compiled["result"].IsString());
|
||||
const std::string& result = toString(compiled["result"]);
|
||||
data.expected.compiled.success = result == "success";
|
||||
|
||||
if (compiled.HasMember("isFeatureConstant")) {
|
||||
assert(compiled["isFeatureConstant"].IsBool());
|
||||
data.expected.compiled.isFeatureConstant = compiled["isFeatureConstant"].GetBool();
|
||||
}
|
||||
|
||||
if (compiled.HasMember("isZoomConstant")) {
|
||||
assert(compiled["isZoomConstant"].IsBool());
|
||||
data.expected.compiled.isZoomConstant = compiled["isZoomConstant"].GetBool();
|
||||
}
|
||||
|
||||
if (compiled.HasMember("type")) {
|
||||
assert(compiled["type"].IsString());
|
||||
data.expected.compiled.serializedType = toString(compiled["type"]);
|
||||
}
|
||||
|
||||
if (compiled.HasMember("errors")) {
|
||||
assert(compiled["errors"].IsArray());
|
||||
for (const auto& errorVal : compiled["errors"].GetArray()) {
|
||||
assert(errorVal.IsObject());
|
||||
const auto& errorObject = errorVal.GetObject();
|
||||
assert(errorObject.HasMember("key"));
|
||||
assert(errorObject.HasMember("error"));
|
||||
|
||||
std::unordered_map<std::string, Value> errorMap;
|
||||
errorMap.emplace("key"s, Value{toString(errorObject["key"])});
|
||||
errorMap.emplace("error"s, Value{toString(errorObject["error"])});
|
||||
data.expected.compiled.errors.emplace_back(Value{std::move(errorMap)});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void parseExpected(const JSValue& expectedValue, TestData& data) {
|
||||
assert(expectedValue.IsObject());
|
||||
const auto& expected = expectedValue.GetObject();
|
||||
assert(expected.HasMember("compiled"));
|
||||
parseCompiled(expected["compiled"], data);
|
||||
|
||||
// set outputs
|
||||
if (expected.HasMember("outputs")) {
|
||||
data.expected.outputs = toValue(expected["outputs"]);
|
||||
}
|
||||
|
||||
// set serialized
|
||||
if (expected.HasMember("serialized")) {
|
||||
data.expected.serialized = toValue(expected["serialized"]);
|
||||
}
|
||||
}
|
||||
|
||||
void parsePropertySpec(const JSValue& value, TestData& data) {
|
||||
const auto& propertySpec = value.GetObject();
|
||||
PropertySpec spec;
|
||||
|
||||
if (propertySpec.HasMember("type")) {
|
||||
assert(propertySpec["type"].IsString());
|
||||
spec.type = toString(propertySpec["type"]);
|
||||
}
|
||||
|
||||
if (propertySpec.HasMember("value")) {
|
||||
assert(propertySpec["value"].IsString());
|
||||
spec.value = toString(propertySpec["value"]);
|
||||
}
|
||||
|
||||
if (propertySpec.HasMember("length")) {
|
||||
assert(propertySpec["length"].IsNumber());
|
||||
spec.length = propertySpec["length"].GetDouble();
|
||||
}
|
||||
|
||||
if (propertySpec.HasMember("property-type")) {
|
||||
assert(propertySpec["property-type"].IsString());
|
||||
spec.isDataDriven = true;
|
||||
}
|
||||
|
||||
if (propertySpec.HasMember("expression")) {
|
||||
assert(propertySpec["expression"].IsObject());
|
||||
spec.expression = toValue(propertySpec["expression"]);
|
||||
}
|
||||
|
||||
data.spec = std::move(spec);
|
||||
}
|
||||
|
||||
bool parseInputs(const JSValue& inputsValue, TestData& data) {
|
||||
assert(inputsValue.IsArray());
|
||||
for (const auto& input : inputsValue.GetArray()) {
|
||||
assert(input.IsArray());
|
||||
assert(input.Size() == 2);
|
||||
assert(input[0].IsObject());
|
||||
assert(input[1].IsObject());
|
||||
|
||||
// Parse evaluation context, zoom.
|
||||
optional<float> zoom;
|
||||
const auto& evaluationContext = input[0].GetObject();
|
||||
if (evaluationContext.HasMember("zoom")) {
|
||||
assert(evaluationContext["zoom"].IsNumber());
|
||||
zoom = evaluationContext["zoom"].GetDouble();
|
||||
}
|
||||
|
||||
// Parse heatmap density
|
||||
optional<double> heatmapDensity;
|
||||
if (evaluationContext.HasMember("heatmapDensity")) {
|
||||
assert(evaluationContext["heatmapDensity"].IsNumber());
|
||||
heatmapDensity = evaluationContext["heatmapDensity"].GetDouble();
|
||||
}
|
||||
|
||||
// Parse canonicalID
|
||||
optional<CanonicalTileID> canonical;
|
||||
if (evaluationContext.HasMember("canonicalID")) {
|
||||
const auto& canonicalIDObject = evaluationContext["canonicalID"];
|
||||
assert(canonicalIDObject.IsObject());
|
||||
assert(canonicalIDObject.HasMember("z") && canonicalIDObject["z"].IsNumber());
|
||||
assert(canonicalIDObject.HasMember("x") && canonicalIDObject["x"].IsNumber());
|
||||
assert(canonicalIDObject.HasMember("y") && canonicalIDObject["y"].IsNumber());
|
||||
canonical = CanonicalTileID(
|
||||
canonicalIDObject["z"].GetUint(), canonicalIDObject["x"].GetUint(), canonicalIDObject["y"].GetUint());
|
||||
}
|
||||
|
||||
// Parse availableImages
|
||||
std::set<std::string> availableImages;
|
||||
if (evaluationContext.HasMember("availableImages")) {
|
||||
assert(evaluationContext["availableImages"].IsArray());
|
||||
for (const auto& image : evaluationContext["availableImages"].GetArray()) {
|
||||
assert(image.IsString());
|
||||
availableImages.emplace(toString(image));
|
||||
}
|
||||
}
|
||||
|
||||
// Parse feature properties
|
||||
Feature feature(mapbox::geometry::point<double>(0.0, 0.0));
|
||||
const auto& featureObject = input[1].GetObject();
|
||||
if (featureObject.HasMember("properties")) {
|
||||
assert(featureObject["properties"].IsObject());
|
||||
feature.properties = mapbox::geojson::convert<PropertyMap>(featureObject["properties"]);
|
||||
}
|
||||
|
||||
if (featureObject.HasMember("geometry")) {
|
||||
assert(featureObject["geometry"].IsObject());
|
||||
feature.geometry = mapbox::geojson::convert<mapbox::geometry::geometry<double>>(featureObject["geometry"]);
|
||||
}
|
||||
|
||||
if (featureObject.HasMember("id")) {
|
||||
assert(featureObject["id"].IsNumber() || featureObject["id"].IsString());
|
||||
feature.id = mapbox::geojson::convert<mapbox::feature::identifier>(featureObject["id"]);
|
||||
}
|
||||
|
||||
data.inputs.emplace_back(std::move(zoom),
|
||||
std::move(heatmapDensity),
|
||||
std::move(canonical),
|
||||
std::move(availableImages),
|
||||
std::move(feature));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::tuple<filesystem::path, std::vector<filesystem::path>, bool, uint32_t> parseArguments(int argc, char** argv) {
|
||||
args::ArgumentParser argumentParser("Mapbox GL Expression Test Runner");
|
||||
|
||||
args::HelpFlag helpFlag(argumentParser, "help", "Display this help menu", { 'h', "help" });
|
||||
args::Flag shuffleFlag(argumentParser, "shuffle", "Toggle shuffling the tests order", {'s', "shuffle"});
|
||||
args::ValueFlag<uint32_t> seedValue(argumentParser, "seed", "Shuffle seed (default: random)",
|
||||
{ "seed" });
|
||||
args::PositionalList<std::string> testNameValues(argumentParser, "URL", "Test name(s)");
|
||||
args::ValueFlag<std::string> testFilterValue(argumentParser, "filter", "Test filter regex", {'f', "filter"});
|
||||
|
||||
try {
|
||||
argumentParser.ParseCLI(argc, argv);
|
||||
} catch (const args::Help&) {
|
||||
std::ostringstream stream;
|
||||
stream << argumentParser;
|
||||
Log::Info(Event::General, stream.str());
|
||||
exit(0);
|
||||
} catch (const args::ParseError& e) {
|
||||
std::ostringstream stream;
|
||||
stream << argumentParser;
|
||||
Log::Info(Event::General, stream.str());
|
||||
Log::Error(Event::General, e.what());
|
||||
exit(1);
|
||||
} catch (const args::ValidationError& e) {
|
||||
std::ostringstream stream;
|
||||
stream << argumentParser;
|
||||
Log::Info(Event::General, stream.str());
|
||||
Log::Error(Event::General, e.what());
|
||||
exit(2);
|
||||
}
|
||||
|
||||
filesystem::path rootPath {std::string(TEST_RUNNER_ROOT_PATH).append("/mapbox-gl-js/test/integration/expression-tests")};
|
||||
if (!filesystem::exists(rootPath)) {
|
||||
Log::Error(Event::General, "Test path '%s' does not exist.", rootPath.string().c_str());
|
||||
exit(3);
|
||||
}
|
||||
|
||||
std::vector<filesystem::path> paths;
|
||||
for (const auto& testName : args::get(testNameValues)) {
|
||||
paths.emplace_back(rootPath.string() + "/" + testName);
|
||||
}
|
||||
|
||||
if (paths.empty()) {
|
||||
paths.emplace_back(rootPath);
|
||||
}
|
||||
|
||||
auto testFilter = testFilterValue ? args::get(testFilterValue) : std::string{};
|
||||
// Recursively traverse through the test paths and collect test directories containing "test.json".
|
||||
std::vector<filesystem::path> testPaths;
|
||||
testPaths.reserve(paths.size());
|
||||
for (const auto& path : paths) {
|
||||
if (!filesystem::exists(path)) {
|
||||
Log::Warning(Event::General, "Provided test folder '%s' does not exist.", path.string().c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto& testPath : filesystem::recursive_directory_iterator(path)) {
|
||||
if (!testFilter.empty() && !std::regex_search(testPath.path().string(), std::regex(testFilter))) {
|
||||
continue;
|
||||
}
|
||||
if (testPath.path().filename() == "test.json") {
|
||||
testPaths.emplace_back(testPath.path());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Arguments{ std::move(rootPath),
|
||||
std::move(testPaths),
|
||||
shuffleFlag ? args::get(shuffleFlag) : false,
|
||||
seedValue ? args::get(seedValue) : 1u };
|
||||
}
|
||||
|
||||
Ignores parseExpressionIgnores() {
|
||||
Ignores ignores;
|
||||
const auto mainIgnoresPath = filesystem::path(TEST_RUNNER_ROOT_PATH).append("metrics/ignores/platform-all.json");
|
||||
auto maybeIgnores = readJson(mainIgnoresPath);
|
||||
if (!maybeIgnores.is<JSDocument>()) { // NOLINT
|
||||
return {};
|
||||
}
|
||||
|
||||
for (const auto& property : maybeIgnores.get<JSDocument>().GetObject()) {
|
||||
std::string id{ toString(property.name) };
|
||||
// Keep only expression-test ignores
|
||||
if (id.rfind("expression-tests", 0) != 0) {
|
||||
continue;
|
||||
}
|
||||
std::string reason{ toString(property.value) };
|
||||
ignores.emplace_back(std::move(id), std::move(reason));
|
||||
}
|
||||
|
||||
return ignores;
|
||||
}
|
||||
|
||||
optional<TestData> parseTestData(const filesystem::path& path) {
|
||||
TestData data;
|
||||
auto maybeJson = readJson(path.string());
|
||||
if (!maybeJson.is<JSDocument>()) { // NOLINT
|
||||
Log::Error(Event::General, "Cannot parse test '%s'.", path.string().c_str());
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
data.document = std::move(maybeJson.get<JSDocument>());
|
||||
|
||||
// Check that mandatory test data members are present.
|
||||
if (!data.document.HasMember("expression") || !data.document.HasMember("expected")) {
|
||||
Log::Error(Event::General, "Test fixture '%s' does not contain required data.", path.string().c_str());
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
// Parse propertySpec
|
||||
if (data.document.HasMember("propertySpec")) {
|
||||
assert(data.document["propertySpec"].IsObject());
|
||||
parsePropertySpec(data.document["propertySpec"], data);
|
||||
}
|
||||
|
||||
// Parse expected
|
||||
parseExpected(data.document["expected"], data);
|
||||
|
||||
// Parse inputs
|
||||
if (data.document.HasMember("inputs") && !parseInputs(data.document["inputs"], data)) {
|
||||
Log::Error(Event::General,"Can't convert inputs value for '%s'", path.string().c_str());
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
return {std::move(data)};
|
||||
}
|
||||
|
||||
std::string toJSON(const Value& value, unsigned indent, bool singleLine) {
|
||||
rapidjson::StringBuffer buffer;
|
||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer);
|
||||
if (singleLine) {
|
||||
writer.SetFormatOptions(rapidjson::kFormatSingleLineArray);
|
||||
}
|
||||
writer.SetIndent(' ', indent);
|
||||
writeJSON(writer, value);
|
||||
return buffer.GetString();
|
||||
}
|
||||
|
||||
JSDocument toDocument(const Value& value) {
|
||||
JSDocument document;
|
||||
document.Parse<rapidjson::kParseFullPrecisionFlag>(toJSON(value));
|
||||
return document;
|
||||
}
|
||||
|
||||
Value toValue(const Compiled& compiled) {
|
||||
std::unordered_map<std::string, Value> compiledObject;
|
||||
compiledObject.emplace("result", compiled.success ? "success"s : "error"s);
|
||||
if (compiled.success) {
|
||||
compiledObject.emplace("isFeatureConstant", compiled.isFeatureConstant);
|
||||
compiledObject.emplace("isZoomConstant", compiled.isZoomConstant);
|
||||
compiledObject.emplace("type", compiled.serializedType);
|
||||
} else {
|
||||
compiledObject.emplace("errors", compiled.errors);
|
||||
}
|
||||
return {std::move(compiledObject)};
|
||||
}
|
||||
|
||||
// Serializes native expression types to JS format.
|
||||
// Color and Formatted are exceptions.
|
||||
// TODO: harmonize serialized format to remove this conversion.
|
||||
optional<Value> toValue(const expression::Value& exprValue) {
|
||||
return exprValue.match(
|
||||
[](const Color& c) -> optional<Value> {
|
||||
std::vector<Value> color { double(c.r), double(c.g), double(c.b), double(c.a) };
|
||||
return {Value{std::move(color)}};
|
||||
},
|
||||
[](const expression::Formatted& formatted) -> optional<Value> { return {formatted.toObject()}; },
|
||||
[](const std::vector<expression::Value>& values) -> optional<Value> {
|
||||
std::vector<Value> mbglValues;
|
||||
for (const auto& value : values) {
|
||||
if (auto converted = expression::fromExpressionValue<Value>(value)) {
|
||||
mbglValues.emplace_back(std::move(*converted));
|
||||
}
|
||||
}
|
||||
return {Value{std::move(mbglValues)}};
|
||||
},
|
||||
[](const std::unordered_map<std::string, expression::Value>& valueMap) -> optional<Value> {
|
||||
std::unordered_map<std::string, Value> mbglValueMap;
|
||||
for (const auto& pair : valueMap) {
|
||||
if (auto converted = expression::fromExpressionValue<Value>(pair.second)) {
|
||||
mbglValueMap.emplace(pair.first, std::move(*converted));
|
||||
}
|
||||
}
|
||||
return {Value{std::move(mbglValueMap)}};
|
||||
},
|
||||
[](const auto& v) { return expression::fromExpressionValue<Value>(v); });
|
||||
}
|
||||
|
||||
std::unique_ptr<style::expression::Expression> parseExpression(const JSValue& value,
|
||||
optional<PropertySpec>& spec,
|
||||
TestResult& result) {
|
||||
optional<style::expression::type::Type> expected = spec ? toExpressionType(*spec) : nullopt;
|
||||
expression::ParsingContext ctx = expected ? expression::ParsingContext(*expected) :
|
||||
expression::ParsingContext();
|
||||
Convertible convertible(&value);
|
||||
expression::ParseResult parsed;
|
||||
if (value.IsObject() && !value.IsArray() && expected){
|
||||
Error error;
|
||||
parsed = convertFunctionToExpression(*expected, convertible, error, false /*convert tokens*/);
|
||||
if (!parsed) {
|
||||
// TODO: should the error message be checked for function conversion?
|
||||
}
|
||||
} else {
|
||||
parsed = ctx.parseLayerPropertyExpression(convertible);
|
||||
if (!parsed) {
|
||||
for (const auto& parsingError : ctx.getErrors()) {
|
||||
std::unordered_map<std::string, Value> errorMap;
|
||||
errorMap.emplace("key"s, Value{parsingError.key});
|
||||
errorMap.emplace("error"s, Value{parsingError.message});
|
||||
result.compiled.errors.emplace_back(Value{std::move(errorMap)});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result.expression = toValue(value);
|
||||
result.compiled.success = bool(parsed);
|
||||
if (parsed) {
|
||||
result.compiled.isFeatureConstant = expression::isFeatureConstant(**parsed);
|
||||
result.compiled.isZoomConstant = expression::isZoomConstant(**parsed);
|
||||
result.compiled.serializedType = style::expression::type::toString((*parsed)->getType());
|
||||
result.serialized = (*parsed)->serialize();
|
||||
return std::move(*parsed);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<style::expression::Expression> parseExpression(const optional<Value>& value,
|
||||
optional<PropertySpec>& spec,
|
||||
TestResult& result) {
|
||||
assert(value);
|
||||
auto document = toDocument(*value);
|
||||
assert(!document.HasParseError());
|
||||
return parseExpression(document, spec, result);
|
||||
}
|
||||
103
mapbox-gl-native/expression-test/expression_test_parser.hpp
Normal file
103
mapbox-gl-native/expression-test/expression_test_parser.hpp
Normal file
@@ -0,0 +1,103 @@
|
||||
#pragma once
|
||||
|
||||
#include "filesystem.hpp"
|
||||
|
||||
#include <mbgl/style/expression/expression.hpp>
|
||||
#include <mbgl/util/feature.hpp>
|
||||
#include <mbgl/util/optional.hpp>
|
||||
#include <mbgl/util/rapidjson.hpp>
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
struct Input {
|
||||
Input(optional<float> zoom_,
|
||||
optional<double> heatmapDensity_,
|
||||
optional<CanonicalTileID> canonical_,
|
||||
std::set<std::string> availableImages_,
|
||||
Feature feature_)
|
||||
: zoom(std::move(zoom_)),
|
||||
heatmapDensity(std::move(heatmapDensity_)),
|
||||
canonical(std::move(canonical_)),
|
||||
availableImages(std::move(availableImages_)),
|
||||
feature(std::move(feature_)) {}
|
||||
optional<float> zoom;
|
||||
optional<double> heatmapDensity;
|
||||
optional<CanonicalTileID> canonical;
|
||||
std::set<std::string> availableImages;
|
||||
Feature feature;
|
||||
};
|
||||
|
||||
struct Compiled {
|
||||
bool operator==(const Compiled& other) const {
|
||||
bool typeEqual = success == other.success &&
|
||||
isFeatureConstant == other.isFeatureConstant &&
|
||||
isZoomConstant == other.isZoomConstant &&
|
||||
serializedType == other.serializedType &&
|
||||
errors == other.errors;
|
||||
return typeEqual;
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
bool isFeatureConstant = false;
|
||||
bool isZoomConstant = false;
|
||||
std::string serializedType;
|
||||
std::vector<Value> errors;
|
||||
};
|
||||
|
||||
struct TestResult {
|
||||
Compiled compiled;
|
||||
optional<Value> expression;
|
||||
optional<Value> outputs;
|
||||
optional<Value> serialized;
|
||||
};
|
||||
|
||||
struct PropertySpec {
|
||||
std::string type;
|
||||
std::string value;
|
||||
std::size_t length = 0;
|
||||
bool isDataDriven = false;
|
||||
optional<Value> expression;
|
||||
};
|
||||
|
||||
class TestData {
|
||||
public:
|
||||
std::vector<Input> inputs;
|
||||
TestResult expected;
|
||||
TestResult result;
|
||||
TestResult recompiled;
|
||||
optional<PropertySpec> spec;
|
||||
JSDocument document;
|
||||
};
|
||||
|
||||
struct Ignore {
|
||||
Ignore(std::string id_, std::string reason_)
|
||||
: id(std::move(id_)),
|
||||
reason(std::move(reason_)) {}
|
||||
|
||||
std::string id;
|
||||
std::string reason;
|
||||
};
|
||||
|
||||
using Arguments = std::tuple<filesystem::path, std::vector<filesystem::path>, bool, uint32_t>;
|
||||
Arguments parseArguments(int argc, char** argv);
|
||||
|
||||
using Ignores = std::vector<Ignore>;
|
||||
Ignores parseExpressionIgnores();
|
||||
optional<TestData> parseTestData(const filesystem::path&);
|
||||
|
||||
std::string toJSON(const Value& value, unsigned indent = 0, bool singleLine = false);
|
||||
JSDocument toDocument(const Value&);
|
||||
Value toValue(const Compiled&);
|
||||
optional<Value> toValue(const style::expression::Value&);
|
||||
|
||||
std::unique_ptr<style::expression::Expression> parseExpression(const JSValue&,
|
||||
optional<PropertySpec>&,
|
||||
TestResult&);
|
||||
std::unique_ptr<style::expression::Expression> parseExpression(const optional<Value>&,
|
||||
optional<PropertySpec>&,
|
||||
TestResult&);
|
||||
|
||||
204
mapbox-gl-native/expression-test/expression_test_runner.cpp
Normal file
204
mapbox-gl-native/expression-test/expression_test_runner.cpp
Normal file
@@ -0,0 +1,204 @@
|
||||
#include "expression_test_runner.hpp"
|
||||
#include "expression_test_logger.hpp"
|
||||
#include "expression_test_parser.hpp"
|
||||
#include "filesystem.hpp"
|
||||
#include "test_runner_common.hpp"
|
||||
|
||||
#include <mbgl/util/io.hpp>
|
||||
|
||||
#include <rapidjson/writer.h>
|
||||
#include <rapidjson/prettywriter.h>
|
||||
#include <rapidjson/stringbuffer.h>
|
||||
|
||||
#include <sstream>
|
||||
#include <regex>
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
namespace {
|
||||
|
||||
std::string simpleDiff(const Value& result, const Value& expected) {
|
||||
std::vector<std::string> resultTokens {tokenize(toJSON(result, 2, true))};
|
||||
std::vector<std::string> expectedTokens {tokenize(toJSON(expected, 2, true))};
|
||||
std::size_t maxLength = std::max(resultTokens.size(), expectedTokens.size());
|
||||
std::ostringstream diff;
|
||||
const auto flush = [] (const std::vector<std::string>& vec, std::size_t pos, std::ostringstream& out, std::string separator) {
|
||||
for (std::size_t j = pos; j < vec.size(); ++j) {
|
||||
out << separator << vec[j] << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
for (std::size_t i = 0; i < maxLength; ++i) {
|
||||
if (resultTokens.size() <= i) {
|
||||
flush(expectedTokens, i, diff, "-"s);
|
||||
break;
|
||||
}
|
||||
|
||||
if (expectedTokens.size() <= i) {
|
||||
flush(resultTokens, i, diff, "+"s);
|
||||
break;
|
||||
}
|
||||
|
||||
if (resultTokens[i] != expectedTokens[i]) {
|
||||
diff << "-"s << expectedTokens[i] << std::endl;
|
||||
diff << "+"s << resultTokens[i] << std::endl;
|
||||
} else {
|
||||
diff << resultTokens[i] << std::endl;
|
||||
}
|
||||
}
|
||||
return diff.str();
|
||||
}
|
||||
|
||||
void rewriteRoundtrippedType(const std::string& expected, std::string& actual) {
|
||||
if (!expected.rfind("array", 0) && !actual.rfind("array", 0)) {
|
||||
actual = expected;
|
||||
}
|
||||
}
|
||||
|
||||
void updateTest(TestData& data) {
|
||||
assert(data.document["expected"].IsObject());
|
||||
auto& expected = data.document["expected"];
|
||||
auto compiled = toDocument(toValue(data.result.compiled));
|
||||
assert(!compiled.HasParseError());
|
||||
expected["compiled"].Swap(compiled);
|
||||
|
||||
if (data.result.outputs) {
|
||||
auto outputs = toDocument(stripPrecision(data.result.outputs.value_or(Value{})));
|
||||
assert(!outputs.HasParseError());
|
||||
expected["outputs"].Swap(outputs);
|
||||
} else {
|
||||
expected.RemoveMember("outputs");
|
||||
}
|
||||
|
||||
if (data.result.serialized) {
|
||||
auto serialized = toDocument(*data.result.serialized);
|
||||
assert(!serialized.HasParseError());
|
||||
expected["serialized"].Swap(serialized);
|
||||
} else {
|
||||
expected.RemoveMember("serialized");
|
||||
}
|
||||
}
|
||||
|
||||
void writeTestData(const JSDocument& document, const std::string& rootPath, const std::string& id) {
|
||||
rapidjson::StringBuffer buffer;
|
||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer);
|
||||
writer.SetFormatOptions(rapidjson::kFormatSingleLineArray);
|
||||
writer.SetIndent(' ', 2);
|
||||
document.Accept(writer);
|
||||
buffer.Put('\n');
|
||||
filesystem::path path = filesystem::path(rootPath) / id / "test.json"s;
|
||||
try {
|
||||
util::write_file(path.string(), {buffer.GetString(), buffer.GetSize()});
|
||||
} catch (std::exception&) {
|
||||
printf(ANSI_COLOR_RED "* ERROR can't update '%s' test" ANSI_COLOR_RESET "\n", id.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TestRunOutput runExpressionTest(TestData& data, const std::string& rootPath, const std::string& id) {
|
||||
TestRunOutput output(id);
|
||||
const auto evaluateExpression = [&data](std::unique_ptr<style::expression::Expression>& expression,
|
||||
TestResult& result) {
|
||||
assert(expression);
|
||||
std::vector<Value> outputs;
|
||||
if (!data.inputs.empty()) {
|
||||
for (const auto& input : data.inputs) {
|
||||
mbgl::style::expression::EvaluationResult evaluationResult;
|
||||
if (input.canonical) {
|
||||
evaluationResult = expression->evaluate(
|
||||
input.zoom, input.feature, input.heatmapDensity, input.availableImages, *input.canonical);
|
||||
} else {
|
||||
evaluationResult =
|
||||
expression->evaluate(input.zoom, input.feature, input.heatmapDensity, input.availableImages);
|
||||
}
|
||||
if (!evaluationResult) {
|
||||
std::unordered_map<std::string, Value> error{{"error", Value{evaluationResult.error().message}}};
|
||||
outputs.emplace_back(Value{std::move(error)});
|
||||
} else {
|
||||
auto value = toValue(*evaluationResult);
|
||||
assert(value);
|
||||
outputs.emplace_back(Value{*value});
|
||||
}
|
||||
}
|
||||
}
|
||||
result.outputs = {Value{std::move(outputs)}};
|
||||
};
|
||||
|
||||
// Parse expression
|
||||
auto parsedExpression = parseExpression(data.document["expression"], data.spec, data.result);
|
||||
output.expression = toJSON(data.result.expression.value_or(Value{}), 2, true);
|
||||
|
||||
// Evaluate expression
|
||||
if (parsedExpression) {
|
||||
evaluateExpression(parsedExpression, data.result);
|
||||
output.serialized = toJSON(data.result.serialized.value_or(Value{}), 2, true);
|
||||
|
||||
// round trip
|
||||
auto recompiledExpression = parseExpression(data.result.serialized, data.spec, data.recompiled);
|
||||
if (recompiledExpression) {
|
||||
evaluateExpression(recompiledExpression, data.recompiled);
|
||||
rewriteRoundtrippedType(data.expected.compiled.serializedType,
|
||||
data.recompiled.compiled.serializedType);
|
||||
}
|
||||
}
|
||||
|
||||
if (getenv("UPDATE")) {
|
||||
output.passed = true;
|
||||
updateTest(data);
|
||||
writeTestData(data.document, rootPath, id);
|
||||
return output;
|
||||
}
|
||||
|
||||
bool compileOk = data.result.compiled == data.expected.compiled;
|
||||
bool evalOk = compileOk && deepEqual(data.result.outputs, data.expected.outputs);
|
||||
|
||||
bool recompileOk = true;
|
||||
bool roundTripOk = true;
|
||||
bool serializationOk = true;
|
||||
|
||||
if (data.expected.compiled.success) {
|
||||
serializationOk = compileOk && deepEqual(data.result.serialized, data.expected.serialized);
|
||||
recompileOk = compileOk && data.recompiled.compiled == data.expected.compiled;
|
||||
roundTripOk = recompileOk && deepEqual(data.recompiled.outputs, data.expected.outputs);
|
||||
}
|
||||
|
||||
output.passed = compileOk && evalOk && recompileOk && roundTripOk && serializationOk;
|
||||
|
||||
if (!compileOk) {
|
||||
auto resultValue = toValue(data.result.compiled);
|
||||
auto expectedValue = toValue(data.expected.compiled);
|
||||
output.text += "Compiled expression difference:\n"s +
|
||||
simpleDiff(resultValue, expectedValue) +
|
||||
"\n"s;
|
||||
}
|
||||
|
||||
if (compileOk && !serializationOk) {
|
||||
auto diff = simpleDiff(data.expected.serialized.value_or(Value{}),
|
||||
data.result.serialized.value_or(Value{}));
|
||||
output.text += "Serialized expression difference:\n"s + diff + "\n"s;
|
||||
}
|
||||
|
||||
if (compileOk && !recompileOk) {
|
||||
auto recompiledValue = toValue(data.recompiled.compiled);
|
||||
auto expectedValue = toValue(data.expected.compiled);
|
||||
output.text += "Recompiled expression difference:\n"s +
|
||||
simpleDiff(recompiledValue, expectedValue) +
|
||||
"\n"s;
|
||||
}
|
||||
|
||||
if (compileOk && !evalOk) {
|
||||
auto diff = simpleDiff(data.expected.outputs.value_or(Value{}),
|
||||
data.result.outputs.value_or(Value{}));
|
||||
output.text += "Expression outputs difference:\n"s + diff + "\n"s;
|
||||
}
|
||||
|
||||
if (recompileOk && !roundTripOk) {
|
||||
auto diff = simpleDiff(data.expected.outputs.value_or(Value{}),
|
||||
data.recompiled.outputs.value_or(Value{}));
|
||||
output.text += "Roundtripped through serialize expression outputs difference:\n"s +
|
||||
diff + "\n"s;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
32
mapbox-gl-native/expression-test/expression_test_runner.hpp
Normal file
32
mapbox-gl-native/expression-test/expression_test_runner.hpp
Normal file
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
class TestData;
|
||||
|
||||
struct TestRunOutput {
|
||||
TestRunOutput(std::string id_) : id(std::move(id_)) {}
|
||||
std::string id;
|
||||
bool passed = false;
|
||||
std::string text;
|
||||
std::string expression;
|
||||
std::string serialized;
|
||||
};
|
||||
|
||||
class TestStats {
|
||||
public:
|
||||
std::size_t testCount() const {
|
||||
return passed.size() + failed.size() + errored.size() +
|
||||
ignorePassed.size() + ignoreFailed.size();
|
||||
}
|
||||
|
||||
std::vector<TestRunOutput> passed;
|
||||
std::vector<TestRunOutput> failed;
|
||||
std::vector<TestRunOutput> errored;
|
||||
std::vector<TestRunOutput> ignorePassed;
|
||||
std::vector<TestRunOutput> ignoreFailed;
|
||||
std::vector<std::string> ids;
|
||||
};
|
||||
|
||||
TestRunOutput runExpressionTest(TestData&, const std::string& rootPath, const std::string& id);
|
||||
9
mapbox-gl-native/expression-test/filesystem.hpp
Normal file
9
mapbox-gl-native/expression-test/filesystem.hpp
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <ghc/filesystem.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
namespace filesystem = ghc::filesystem;
|
||||
|
||||
} // namespace mbgl
|
||||
75
mapbox-gl-native/expression-test/main.cpp
Normal file
75
mapbox-gl-native/expression-test/main.cpp
Normal file
@@ -0,0 +1,75 @@
|
||||
#include "expression_test_parser.hpp"
|
||||
#include "expression_test_runner.hpp"
|
||||
#include "expression_test_logger.hpp"
|
||||
|
||||
#include <random>
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
// Parse args
|
||||
std::vector<mbgl::filesystem::path> testPaths;
|
||||
mbgl::filesystem::path rootPath;
|
||||
bool shuffle;
|
||||
uint32_t seed;
|
||||
std::tie(rootPath, testPaths, shuffle, seed) = parseArguments(argc, argv);
|
||||
|
||||
// Parse ignores
|
||||
const auto ignores = parseExpressionIgnores();
|
||||
|
||||
if (shuffle) {
|
||||
printf(ANSI_COLOR_YELLOW "Shuffle seed: %d" ANSI_COLOR_RESET "\n", seed);
|
||||
std::seed_seq sequence { seed };
|
||||
std::mt19937 shuffler(sequence);
|
||||
std::shuffle(testPaths.begin(), testPaths.end(), shuffler);
|
||||
}
|
||||
|
||||
// Run tests, collect stats and output of each run.
|
||||
TestStats stats;
|
||||
for (const auto& path : testPaths) {
|
||||
const auto& expectation = path.parent_path().string();
|
||||
std::string id = expectation.substr(rootPath.string().length() + 1, expectation.length() - rootPath.string().length());
|
||||
stats.ids.emplace_back(id);
|
||||
|
||||
bool shouldIgnore = false;
|
||||
std::string ignoreReason;
|
||||
const std::string ignoreName = "expression-tests/" + id;
|
||||
const auto it = std::find_if(ignores.cbegin(), ignores.cend(), [&ignoreName] (const auto& ignore) { return ignore.id == ignoreName; });
|
||||
if (it != ignores.end()) {
|
||||
shouldIgnore = true;
|
||||
ignoreReason = (*it).reason;
|
||||
}
|
||||
|
||||
optional<TestRunOutput> testRun;
|
||||
if (auto testData = parseTestData(path)) {
|
||||
testRun = runExpressionTest(*testData, rootPath.string(), id);
|
||||
}
|
||||
|
||||
if (!testRun) {
|
||||
stats.errored.emplace_back(id);
|
||||
printf(ANSI_COLOR_RED "* ERROR can't parse '%s' test" ANSI_COLOR_RESET "\n", id.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (shouldIgnore) {
|
||||
if (testRun->passed) {
|
||||
stats.ignorePassed.emplace_back(std::move(*testRun));
|
||||
printf(ANSI_COLOR_YELLOW "* PASSED ignored test %s (%s)" ANSI_COLOR_RESET "\n", id.c_str(), ignoreReason.c_str());
|
||||
} else {
|
||||
stats.ignoreFailed.emplace_back(std::move(*testRun));
|
||||
printf(ANSI_COLOR_LIGHT_GRAY "* FAILED ignored test %s (%s)" ANSI_COLOR_RESET "\n", id.c_str(), ignoreReason.c_str());
|
||||
}
|
||||
} else {
|
||||
if (testRun->passed) {
|
||||
stats.passed.emplace_back(std::move(*testRun));
|
||||
printf(ANSI_COLOR_GREEN "* PASSED %s" ANSI_COLOR_RESET "\n", id.c_str());
|
||||
} else {
|
||||
printf(ANSI_COLOR_RED "* FAILED %s\n%s" ANSI_COLOR_RESET, id.c_str(), testRun->text.c_str());
|
||||
stats.failed.emplace_back(std::move(*testRun));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printStats(stats);
|
||||
writeHTMLResults(stats, rootPath.string(), shuffle, seed);
|
||||
|
||||
return stats.errored.size() + stats.failed.size() == 0 ? 0 : 1;
|
||||
}
|
||||
131
mapbox-gl-native/expression-test/test_runner_common.cpp
Normal file
131
mapbox-gl-native/expression-test/test_runner_common.cpp
Normal file
@@ -0,0 +1,131 @@
|
||||
#include "test_runner_common.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include <regex>
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
// Strip precision for numbers, so that we can compare evaluated results with fixtures.
|
||||
// Copied from JS expression harness.
|
||||
Value stripPrecision(const Value& value) {
|
||||
const double decimalSigFigs = 6;
|
||||
if (auto num = numericValue<double>(value)) {
|
||||
if (*num == 0) {
|
||||
return *num;
|
||||
}
|
||||
|
||||
const double multiplier = std::pow(10, std::max(0.0, decimalSigFigs - std::ceil(std::log10(std::fabs(*num)))));
|
||||
|
||||
// We strip precision twice in a row here to avoid cases where
|
||||
// stripping an already stripped number will modify its value
|
||||
// due to bad floating point precision luck
|
||||
// eg `Math.floor(8.16598 * 100000) / 100000` -> 8.16597
|
||||
const double firstStrip = std::floor(*num * multiplier) / multiplier;
|
||||
return std::floor(firstStrip * multiplier) / multiplier;
|
||||
}
|
||||
|
||||
if (value.is<std::vector<Value>>()) {
|
||||
std::vector<Value> stripped;
|
||||
const auto& vec = value.get<std::vector<Value>>();
|
||||
stripped.reserve(vec.size());
|
||||
for (const auto& val : vec) {
|
||||
stripped.emplace_back(stripPrecision(val));
|
||||
}
|
||||
return stripped;
|
||||
} else if (value.is<std::unordered_map<std::string, Value>>()) {
|
||||
std::unordered_map<std::string, Value> stripped;
|
||||
const auto& map = value.get<std::unordered_map<std::string, Value>>();
|
||||
for (const auto& pair : map) {
|
||||
stripped.emplace(pair.first, stripPrecision(pair.second));
|
||||
}
|
||||
return stripped;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
std::vector<std::string> tokenize(std::string str) {
|
||||
std::vector<std::string> tokens;
|
||||
std::regex re("\n");
|
||||
std::copy(std::regex_token_iterator<std::string::iterator>(str.begin(), str.end(), re, -1),
|
||||
std::regex_token_iterator<std::string::iterator>(),
|
||||
std::back_inserter(tokens));
|
||||
return tokens;
|
||||
}
|
||||
|
||||
bool deepEqual(const Value& a, const Value& b) {
|
||||
const auto& anum = numericValue<double>(a);
|
||||
const auto& bnum = numericValue<double>(b);
|
||||
if (anum && bnum) {
|
||||
return stripPrecision(*anum) == stripPrecision(*bnum);
|
||||
}
|
||||
|
||||
if (a.which() != b.which()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a.getArray() && b.getArray()) {
|
||||
const auto& avec = *a.getArray();
|
||||
const auto& bvec = *b.getArray();
|
||||
if (avec.size() != bvec.size()) {
|
||||
return false;
|
||||
}
|
||||
for (std::size_t i = 0; i < avec.size(); ++i) {
|
||||
if (!deepEqual(avec[i], bvec[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (a.getObject() && b.getObject()) {
|
||||
const auto& amap = *a.getObject();
|
||||
const auto& bmap = *b.getObject();
|
||||
if (amap.size() != bmap.size()) {
|
||||
return false;
|
||||
}
|
||||
for (const auto& pair : amap) {
|
||||
auto it = bmap.find(pair.first);
|
||||
if (it == bmap.end()) {
|
||||
return false;
|
||||
}
|
||||
if (!deepEqual(pair.second, it->second)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (a == b) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (a.getString() && b.getString()) {
|
||||
const auto& strA = *a.getString();
|
||||
const auto& strB = *b.getString();
|
||||
if (strA == strB) {
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
double numA = std::stod(strA);
|
||||
double numB = std::stod(strB);
|
||||
return stripPrecision(numA) == stripPrecision(numB);
|
||||
} catch (...) {
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool deepEqual(const optional<Value>& a, const optional<Value>& b) {
|
||||
if ((a && !b) || (!a && b)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a && b) {
|
||||
return deepEqual(*a, *b);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
13
mapbox-gl-native/expression-test/test_runner_common.hpp
Normal file
13
mapbox-gl-native/expression-test/test_runner_common.hpp
Normal file
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/util/feature.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
Value stripPrecision(const Value& value);
|
||||
std::vector<std::string> tokenize(std::string str);
|
||||
bool deepEqual(const Value& a, const Value& b);
|
||||
bool deepEqual(const optional<Value>& a, const optional<Value>& b);
|
||||
74
mapbox-gl-native/include/mbgl/actor/actor.hpp
Normal file
74
mapbox-gl-native/include/mbgl/actor/actor.hpp
Normal file
@@ -0,0 +1,74 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/actor/aspiring_actor.hpp>
|
||||
#include <mbgl/actor/established_actor.hpp>
|
||||
#include <mbgl/actor/mailbox.hpp>
|
||||
#include <mbgl/actor/message.hpp>
|
||||
#include <mbgl/actor/actor_ref.hpp>
|
||||
#include <mbgl/util/noncopyable.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <future>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
/*
|
||||
An `Actor<O>` is an owning reference to an asynchronous object of type `O`: an "actor".
|
||||
Communication with an actor happens via message passing: you send a message to the object
|
||||
(using `invoke`), passing a pointer to the member function to call and arguments which
|
||||
are then forwarded to the actor.
|
||||
|
||||
The actor receives messages sent to it asynchronously, in a manner defined its `Scheduler`.
|
||||
To store incoming messages before their receipt, each actor has a `Mailbox`, which acts as
|
||||
a FIFO queue. Messages sent from actor S to actor R are guaranteed to be processed in the
|
||||
order sent. However, relative order of messages sent by two *different* actors S1 and S2
|
||||
to R is *not* guaranteed (and can't be: S1 and S2 may be acting asynchronously with respect
|
||||
to each other).
|
||||
|
||||
An `Actor<O>` can be converted to an `ActorRef<O>`, a non-owning value object representing
|
||||
a (weak) reference to the actor. Messages can be sent via the `Ref` as well.
|
||||
|
||||
It's safe -- and encouraged -- to pass `Ref`s between actors via messages. This is how two-way
|
||||
communication and other forms of collaboration between multiple actors is accomplished.
|
||||
|
||||
It's safe for a `Ref` to outlive its `Actor` -- the reference is "weak", and does not extend
|
||||
the lifetime of the owning Actor, and sending a message to a `Ref` whose `Actor` has died is
|
||||
a no-op. (In the future, a dead-letters queue or log may be implemented.)
|
||||
|
||||
Construction and destruction of an Actor is synchronous: the corresponding `O`
|
||||
object is constructed synchronously by the `Actor` constructor, and destructed synchronously
|
||||
by the `~Actor` destructor, after ensuring that the `O` is not currently receiving an
|
||||
asynchronous message. The constructor of `O` is passed an `ActorRef<O>` referring to itself
|
||||
(which it can use to self-send messages), followed by the forwarded arguments passed to
|
||||
`Actor<O>`. Asynchronous object construction can be accomplished by directly using the
|
||||
lower-level types, `AspiringActor<O>` and `EstablishedActor<O>`.
|
||||
|
||||
Please don't send messages that contain shared pointers or references. That subverts the
|
||||
purpose of the actor model: prohibiting direct concurrent access to shared state.
|
||||
*/
|
||||
template <class Object>
|
||||
class Actor {
|
||||
public:
|
||||
template <class... Args>
|
||||
Actor(Scheduler& scheduler, Args&&... args)
|
||||
: target(scheduler, parent, std::forward<Args>(args)...) {}
|
||||
|
||||
template <class... Args>
|
||||
Actor(std::shared_ptr<Scheduler> scheduler, Args&&... args)
|
||||
: retainer(std::move(scheduler)), target(*retainer, parent, std::forward<Args>(args)...) {}
|
||||
|
||||
Actor(const Actor&) = delete;
|
||||
|
||||
ActorRef<std::decay_t<Object>> self() {
|
||||
return parent.self();
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<Scheduler> retainer;
|
||||
AspiringActor<Object> parent;
|
||||
EstablishedActor<Object> target;
|
||||
};
|
||||
|
||||
} // namespace mbgl
|
||||
64
mapbox-gl-native/include/mbgl/actor/actor_ref.hpp
Normal file
64
mapbox-gl-native/include/mbgl/actor/actor_ref.hpp
Normal file
@@ -0,0 +1,64 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/actor/mailbox.hpp>
|
||||
#include <mbgl/actor/message.hpp>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
/*
|
||||
An `ActorRef<O>` is a *non*-owning, weak reference to an actor of type `O`. You can send it
|
||||
messages just like an `Actor<O>`. It's a value object: safe to copy and pass between actors
|
||||
via messages.
|
||||
|
||||
An `ActorRef<O>` does not extend the lifetime of the corresponding `Actor<O>`. That's determined
|
||||
entirely by whichever object owns the `Actor<O>` -- the actor's "supervisor".
|
||||
|
||||
It's safe for a `Ref` to outlive its `Actor` -- the reference is "weak", and does not extend
|
||||
the lifetime of the owning Actor, and sending a message to a `Ref` whose `Actor` has died is
|
||||
a no-op. (In the future, a dead-letters queue or log may be implemented.)
|
||||
*/
|
||||
|
||||
template <class Object>
|
||||
class ActorRef {
|
||||
public:
|
||||
ActorRef(Object& object_, std::weak_ptr<Mailbox> weakMailbox_)
|
||||
: object(&object_),
|
||||
weakMailbox(std::move(weakMailbox_)) {
|
||||
}
|
||||
|
||||
template <typename Fn, class... Args>
|
||||
void invoke(Fn fn, Args&&... args) const {
|
||||
if (auto mailbox = weakMailbox.lock()) {
|
||||
mailbox->push(actor::makeMessage(*object, fn, std::forward<Args>(args)...));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Fn, class... Args>
|
||||
auto ask(Fn fn, Args&&... args) const {
|
||||
// Result type is deduced from the function's return type
|
||||
using ResultType = typename std::result_of<decltype(fn)(Object, Args...)>::type;
|
||||
|
||||
std::promise<ResultType> promise;
|
||||
auto future = promise.get_future();
|
||||
|
||||
if (auto mailbox = weakMailbox.lock()) {
|
||||
mailbox->push(
|
||||
actor::makeMessage(
|
||||
std::move(promise), *object, fn, std::forward<Args>(args)...
|
||||
)
|
||||
);
|
||||
} else {
|
||||
promise.set_exception(std::make_exception_ptr(std::runtime_error("Actor has gone away")));
|
||||
}
|
||||
|
||||
return future;
|
||||
}
|
||||
|
||||
private:
|
||||
Object* object;
|
||||
std::weak_ptr<Mailbox> weakMailbox;
|
||||
};
|
||||
|
||||
} // namespace mbgl
|
||||
60
mapbox-gl-native/include/mbgl/actor/aspiring_actor.hpp
Normal file
60
mapbox-gl-native/include/mbgl/actor/aspiring_actor.hpp
Normal file
@@ -0,0 +1,60 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/actor/mailbox.hpp>
|
||||
#include <mbgl/actor/message.hpp>
|
||||
#include <mbgl/actor/actor_ref.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <future>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
template <class Object>
|
||||
class EstablishedActor;
|
||||
|
||||
template <class Object>
|
||||
class Actor;
|
||||
|
||||
/*
|
||||
An `AspiringActor<O>` is one half of the pair of types that comprise an actor (see `Actor<O>`),
|
||||
the other half being `EstablishedActor<O>`. It is responsible for:
|
||||
- ownership of the actor's `Mailbox`
|
||||
- allocating the memory for (but *not* constructing) the target object `O`
|
||||
|
||||
Using these two pieces--the mailbox and a stable address for `O`--an `AspiringActor<O>` can
|
||||
accept messages for the target object, or provide `ActorRef<O>`s that do so, before the object
|
||||
has actually been constructed by the corresponding `EstablishedActor<O>`. (Such messages are
|
||||
queued in the mailbox until after the object is constructed.)
|
||||
|
||||
This allows for an `AspiringActor<O>` to be created and safely used by a thread other than the
|
||||
one on which the target object will (eventually) live.
|
||||
*/
|
||||
template <class Object>
|
||||
class AspiringActor {
|
||||
public:
|
||||
AspiringActor() : mailbox(std::make_shared<Mailbox>()) {
|
||||
// mailbox starts closed because the `Object` hasn't yet been constructed
|
||||
assert(!mailbox->isOpen());
|
||||
}
|
||||
|
||||
AspiringActor(const AspiringActor&) = delete;
|
||||
|
||||
ActorRef<std::decay_t<Object>> self() {
|
||||
return ActorRef<std::decay_t<Object>>(object(), mailbox);
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<Mailbox> mailbox;
|
||||
std::aligned_storage_t<sizeof(Object)> objectStorage;
|
||||
|
||||
Object& object() {
|
||||
return *reinterpret_cast<Object *>(&objectStorage);
|
||||
}
|
||||
|
||||
friend class EstablishedActor<Object>;
|
||||
friend class Actor<Object>;
|
||||
};
|
||||
|
||||
} // namespace mbgl
|
||||
80
mapbox-gl-native/include/mbgl/actor/established_actor.hpp
Normal file
80
mapbox-gl-native/include/mbgl/actor/established_actor.hpp
Normal file
@@ -0,0 +1,80 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/actor/aspiring_actor.hpp>
|
||||
#include <mbgl/actor/mailbox.hpp>
|
||||
#include <mbgl/actor/message.hpp>
|
||||
#include <mbgl/actor/actor_ref.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <future>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
/*
|
||||
An `EstablishedActor<O>` is one half of the pair of types that comprise an actor (see `Actor<O>`),
|
||||
the other half being `AspiringActor<O>`. It is responsible for managing the lifetime of the
|
||||
target object `O` and the open/closed state of the parent's `mailbox`.
|
||||
|
||||
The `O` object's lifetime is contained by that of its owning `EstablishedActor<O>`: the
|
||||
`EstablishedActor` constructor executes the `O` constructor via "placement new", constructing
|
||||
it at the address provided by the parent `AspiringActor`, and the `~EstablishedActor` destructor
|
||||
similarly executes the `~O` destructor (after closing the mailbox). `EstablishedActor` should
|
||||
therefore live entirely on the thread intended to own `O`.
|
||||
*/
|
||||
|
||||
template <class Object>
|
||||
class EstablishedActor {
|
||||
public:
|
||||
// Construct the Object from a parameter pack `args` (i.e. `Object(args...)`)
|
||||
template <typename U = Object, class... Args, typename std::enable_if<
|
||||
std::is_constructible<U, Args...>::value ||
|
||||
std::is_constructible<U, ActorRef<U>, Args...>::value
|
||||
>::type * = nullptr>
|
||||
EstablishedActor(Scheduler& scheduler, AspiringActor<Object>& parent_, Args&& ... args)
|
||||
: parent(parent_) {
|
||||
emplaceObject(std::forward<Args>(args)...);
|
||||
parent.mailbox->open(scheduler);
|
||||
}
|
||||
|
||||
// Construct the `Object` from a tuple containing the constructor arguments (i.e.
|
||||
// `Object(std::get<0>(args), std::get<1>(args), ...)`)
|
||||
template <class ArgsTuple, std::size_t ArgCount = std::tuple_size<std::decay_t<ArgsTuple>>::value>
|
||||
EstablishedActor(Scheduler& scheduler, AspiringActor<Object>& parent_, ArgsTuple&& args)
|
||||
: parent(parent_) {
|
||||
emplaceObject(std::forward<ArgsTuple>(args), std::make_index_sequence<ArgCount>{});
|
||||
parent.mailbox->open(scheduler);
|
||||
}
|
||||
|
||||
EstablishedActor(const EstablishedActor&) = delete;
|
||||
|
||||
~EstablishedActor() {
|
||||
parent.mailbox->close();
|
||||
parent.object().~Object();
|
||||
}
|
||||
|
||||
private:
|
||||
// Enabled for Objects with a constructor taking ActorRef<Object> as the first parameter
|
||||
template <typename U = Object, class... Args, typename std::enable_if<std::is_constructible<U, ActorRef<U>, Args...>::value>::type * = nullptr>
|
||||
void emplaceObject(Args&&... args_) {
|
||||
new (&parent.objectStorage) Object(parent.self(), std::forward<Args>(args_)...);
|
||||
}
|
||||
|
||||
// Enabled for plain Objects
|
||||
template <typename U = Object, class... Args, typename std::enable_if<std::is_constructible<U, Args...>::value>::type * = nullptr>
|
||||
void emplaceObject(Args&&... args_) {
|
||||
new (&parent.objectStorage) Object(std::forward<Args>(args_)...);
|
||||
}
|
||||
|
||||
// Used to expand a tuple holding the constructor arguments
|
||||
template <class ArgsTuple, std::size_t... I>
|
||||
void emplaceObject(ArgsTuple&& args, std::index_sequence<I...>) {
|
||||
emplaceObject(std::move(std::get<I>(std::forward<ArgsTuple>(args)))...);
|
||||
(void) args; // mark args as used: if it's empty tuple, it's not actually used above.
|
||||
}
|
||||
|
||||
AspiringActor<Object>& parent;
|
||||
};
|
||||
|
||||
} // namespace mbgl
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user