Add dependencies locally
1
deps/GSL
vendored
@ -1 +0,0 @@
|
||||
Subproject commit f1a494cfd2ce55fe88b5134eab985f5852667b8d
|
34
deps/GSL/.clang-format
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
ColumnLimit: 100
|
||||
|
||||
UseTab: Never
|
||||
IndentWidth: 4
|
||||
AccessModifierOffset: -4
|
||||
NamespaceIndentation: Inner
|
||||
|
||||
BreakBeforeBraces: Custom
|
||||
BraceWrapping:
|
||||
AfterNamespace: true
|
||||
AfterEnum: true
|
||||
AfterStruct: true
|
||||
AfterClass: true
|
||||
SplitEmptyFunction: false
|
||||
AfterControlStatement: true
|
||||
AfterFunction: true
|
||||
AfterUnion: true
|
||||
BeforeElse: true
|
||||
|
||||
|
||||
AlwaysBreakTemplateDeclarations: true
|
||||
BreakConstructorInitializersBeforeComma: true
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
AllowShortBlocksOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: true
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
|
||||
PointerAlignment: Left
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignTrailingComments: true
|
||||
|
||||
SpaceAfterCStyleCast: true
|
||||
CommentPragmas: '^ NO-FORMAT:'
|
1
deps/GSL/.gitattributes
vendored
Normal file
@ -0,0 +1 @@
|
||||
include/gsl/* linguist-language=C++
|
50
deps/GSL/.github/workflows/android.yml
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
name: CI_Android
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
|
||||
jobs:
|
||||
Android:
|
||||
runs-on: macos-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: build
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Create build directory
|
||||
run: mkdir -p build
|
||||
working-directory: .
|
||||
|
||||
- name: Start emulator
|
||||
run: |
|
||||
echo "y" | $ANDROID_HOME/tools/bin/sdkmanager --install 'system-images;android-24;default;x86_64'
|
||||
echo "no" | $ANDROID_HOME/tools/bin/avdmanager create avd -n xamarin_android_emulator -k 'system-images;android-24;default;x86_64' --force
|
||||
$ANDROID_HOME/emulator/emulator -list-avds
|
||||
echo "Starting emulator"
|
||||
# Start emulator in background
|
||||
nohup $ANDROID_HOME/emulator/emulator -avd xamarin_android_emulator -no-snapshot > /dev/null 2>&1 &
|
||||
echo "Emulator starting"
|
||||
|
||||
- name: Configure
|
||||
run: cmake -Werror=dev -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK_LATEST_HOME/build/cmake/android.toolchain.cmake -DANDROID_PLATFORM=16 -DANDROID_ABI=x86_64 -DCMAKE_BUILD_TYPE=Debug ..
|
||||
|
||||
- name: Build
|
||||
run: cmake --build . --parallel
|
||||
|
||||
- name: Wait for emulator ready
|
||||
run: |
|
||||
$ANDROID_HOME/platform-tools/adb wait-for-device shell 'while [[ -z $(getprop sys.boot_completed | tr -d '\r') ]]; do sleep 10; done; input keyevent 82'
|
||||
$ANDROID_HOME/platform-tools/adb devices
|
||||
$ANDROID_HOME/platform-tools/adb shell getprop ro.product.cpu.abi
|
||||
echo "Emulator started"
|
||||
|
||||
- name: Deploy tests
|
||||
run: |
|
||||
adb push tests /data/local/tmp
|
||||
adb shell find /data/local/tmp/tests -maxdepth 1 -exec chmod +x {} \\\;
|
||||
|
||||
- name: Test
|
||||
run: adb shell find /data/local/tmp/tests -name "*_tests" -maxdepth 1 -exec {} \\\;
|
25
deps/GSL/.github/workflows/cmake_find_package.yml
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
name: cmake_find_package
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
|
||||
jobs:
|
||||
cmake-find-package:
|
||||
name: Build ${{ matrix.os }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ ubuntu-latest, macos-latest ]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: lukka/get-cmake@latest
|
||||
with:
|
||||
cmakeVersion: 3.14.0
|
||||
- name: Configure GSL
|
||||
run: cmake -S . -B build -G "Ninja" -D GSL_TEST=OFF -D CMAKE_INSTALL_PREFIX=${GITHUB_WORKSPACE}/build/install
|
||||
- name: Install GSL
|
||||
run: cmake --build build --target install
|
||||
- name: Test GSL find_package support
|
||||
run: cmake -S tests/ -B build/tests_find_package -G "Ninja" -D CMAKE_PREFIX_PATH=${GITHUB_WORKSPACE}/build/install -D CMAKE_BUILD_TYPE=Release
|
52
deps/GSL/.github/workflows/ios.yml
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
name: CI_iOS
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
|
||||
jobs:
|
||||
iOS:
|
||||
runs-on: macos-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: build
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Create build directory
|
||||
run: mkdir -p build
|
||||
working-directory: .
|
||||
|
||||
- name: Configure
|
||||
run: |
|
||||
cmake \
|
||||
-Werror=dev \
|
||||
-GXcode \
|
||||
-DCMAKE_SYSTEM_NAME=iOS \
|
||||
"-DCMAKE_OSX_ARCHITECTURES=arm64;x86_64" \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=9 \
|
||||
-DCMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY \
|
||||
"-DMACOSX_BUNDLE_GUI_IDENTIFIER=GSL.\$(EXECUTABLE_NAME)" \
|
||||
-DMACOSX_BUNDLE_BUNDLE_VERSION=3.1.0 \
|
||||
-DMACOSX_BUNDLE_SHORT_VERSION_STRING=3.1.0 \
|
||||
..
|
||||
|
||||
- name: Build
|
||||
run: cmake --build . --parallel `sysctl -n hw.ncpu` --config Release -- -sdk iphonesimulator
|
||||
|
||||
- name: Start simulator
|
||||
run: |
|
||||
RUNTIME=`xcrun simctl list runtimes iOS -j|jq '.runtimes|last.identifier'`
|
||||
UDID=`xcrun simctl list devices iPhone available -j|jq -r ".devices[$RUNTIME]|last.udid"`
|
||||
xcrun simctl bootstatus $UDID -b
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
for TEST in `find tests/Release-iphonesimulator -depth 1 -name "*.app"`
|
||||
do
|
||||
xcrun simctl install booted $TEST
|
||||
TEST_ID=`plutil -convert json -o - $TEST/Info.plist|jq -r ".CFBundleIdentifier"`
|
||||
xcrun simctl launch --console booted $TEST_ID
|
||||
xcrun simctl uninstall booted $TEST_ID
|
||||
done
|
16
deps/GSL/.gitignore
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
CMakeFiles
|
||||
build
|
||||
tests/CMakeFiles
|
||||
tests/Debug
|
||||
*.opensdf
|
||||
*.sdf
|
||||
tests/*tests.dir
|
||||
*.vcxproj
|
||||
*.vcxproj.filters
|
||||
*.sln
|
||||
*.tlog
|
||||
Testing/Temporary/*.*
|
||||
CMakeCache.txt
|
||||
*.suo
|
||||
.vs/
|
||||
.vscode/
|
48
deps/GSL/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
cmake_minimum_required(VERSION 3.14...3.16)
|
||||
|
||||
project(GSL VERSION 4.0.0 LANGUAGES CXX)
|
||||
|
||||
add_library(GSL INTERFACE)
|
||||
add_library(Microsoft.GSL::GSL ALIAS GSL)
|
||||
|
||||
# https://cmake.org/cmake/help/latest/variable/PROJECT_IS_TOP_LEVEL.html
|
||||
string(COMPARE EQUAL ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR} PROJECT_IS_TOP_LEVEL)
|
||||
|
||||
option(GSL_INSTALL "Generate and install GSL target" ${PROJECT_IS_TOP_LEVEL})
|
||||
option(GSL_TEST "Build and perform GSL tests" ${PROJECT_IS_TOP_LEVEL})
|
||||
|
||||
# The implementation generally assumes a platform that implements C++14 support
|
||||
target_compile_features(GSL INTERFACE "cxx_std_14")
|
||||
|
||||
# Setup include directory
|
||||
add_subdirectory(include)
|
||||
|
||||
target_sources(GSL INTERFACE $<BUILD_INTERFACE:${GSL_SOURCE_DIR}/GSL.natvis>)
|
||||
|
||||
if (GSL_TEST)
|
||||
enable_testing()
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
||||
if (GSL_INSTALL)
|
||||
include(GNUInstallDirs)
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
||||
install(DIRECTORY "${PROJECT_SOURCE_DIR}/include/gsl" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
|
||||
set(export_name "Microsoft.GSLConfig")
|
||||
set(namespace "Microsoft.GSL::")
|
||||
set(cmake_files_install_dir ${CMAKE_INSTALL_DATADIR}/cmake/Microsoft.GSL)
|
||||
|
||||
install(TARGETS GSL EXPORT ${export_name} INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
install(EXPORT ${export_name} NAMESPACE ${namespace} DESTINATION ${cmake_files_install_dir})
|
||||
export(TARGETS GSL NAMESPACE ${namespace} FILE ${export_name}.cmake)
|
||||
|
||||
set(gls_config_version "${CMAKE_CURRENT_BINARY_DIR}/Microsoft.GSLConfigVersion.cmake")
|
||||
|
||||
write_basic_package_version_file(${gls_config_version} COMPATIBILITY SameMajorVersion ARCH_INDEPENDENT)
|
||||
|
||||
install(FILES ${gls_config_version} DESTINATION ${cmake_files_install_dir})
|
||||
|
||||
install(FILES GSL.natvis DESTINATION ${cmake_files_install_dir})
|
||||
endif()
|
18
deps/GSL/CMakeSettings.json
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "x64-Debug",
|
||||
"generator": "Ninja",
|
||||
"configurationType": "Debug",
|
||||
"inheritEnvironments": [
|
||||
"msvc_x64_x64"
|
||||
],
|
||||
"buildRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\build\\${name}",
|
||||
"installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}",
|
||||
"cmakeCommandArgs": "-DGSL_CXX_STANDARD=17",
|
||||
"buildCommandArgs": "-v",
|
||||
"ctestCommandArgs": "",
|
||||
"codeAnalysisRuleset": "CppCoreCheckRules.ruleset"
|
||||
}
|
||||
]
|
||||
}
|
29
deps/GSL/CONTRIBUTING.md
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
## Contributing to the Guidelines Support Library
|
||||
|
||||
The Guidelines Support Library (GSL) contains functions and types that are suggested for use by the
|
||||
[C++ Core Guidelines](https://github.com/isocpp/CppCoreGuidelines). GSL design changes are made only as a result of modifications to the Guidelines.
|
||||
|
||||
GSL is accepting contributions that improve or refine any of the types in this library as well as ports to other platforms. Changes should have an issue
|
||||
tracking the suggestion that has been approved by the maintainers. Your pull request should include a link to the bug that you are fixing. If you've submitted
|
||||
a PR, please post a comment in the associated issue to avoid duplication of effort.
|
||||
|
||||
## Legal
|
||||
You will need to complete a Contributor License Agreement (CLA). Briefly, this agreement testifies that you are granting us and the community permission to
|
||||
use the submitted change according to the terms of the project's license, and that the work being submitted is under appropriate copyright.
|
||||
|
||||
Please submit a Contributor License Agreement (CLA) before submitting a pull request. You may visit https://cla.microsoft.com to sign digitally.
|
||||
|
||||
## Housekeeping
|
||||
Your pull request should:
|
||||
|
||||
* Include a description of what your change intends to do
|
||||
* Be a child commit of a reasonably recent commit in the **main** branch
|
||||
* Requests need not be a single commit, but should be a linear sequence of commits (i.e. no merge commits in your PR)
|
||||
* It is desirable, but not necessary, for the tests to pass at each commit. Please see [README.md](./README.md) for instructions to build the test suite.
|
||||
* Have clear commit messages
|
||||
* e.g. "Fix issue", "Add tests for type", etc.
|
||||
* Include appropriate tests
|
||||
* Tests should include reasonable permutations of the target fix/change
|
||||
* Include baseline changes with your change
|
||||
* All changed code must have 100% code coverage
|
||||
* To avoid line ending issues, set `autocrlf = input` and `whitespace = cr-at-eol` in your git configuration
|
32
deps/GSL/GSL.natvis
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
This will make GitHub and some editors recognize this code as XML:
|
||||
vim: syntax=xml
|
||||
-->
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
<!-- These types are from the util header. -->
|
||||
<Type Name="gsl::final_action<*>">
|
||||
<DisplayString>{{ invoke = {invoke_}, action = {f_} }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[invoke]">invoke_</Item>
|
||||
<Item Name="[callback]">f_</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<!-- These types are from the span header. -->
|
||||
<Type Name="gsl::span<*, *>">
|
||||
<DisplayString>{{ extent = {storage_.size_} }}</DisplayString>
|
||||
<Expand>
|
||||
<ArrayItems>
|
||||
<Size>storage_.size_</Size>
|
||||
<ValuePointer>storage_.data_</ValuePointer>
|
||||
</ArrayItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<!-- These types are from the pointers header. -->
|
||||
<Type Name="gsl::not_null<*>">
|
||||
<!-- We can always dereference this since it's an invariant. -->
|
||||
<DisplayString>value = {*ptr_}</DisplayString>
|
||||
</Type>
|
||||
</AutoVisualizer>
|
21
deps/GSL/LICENSE
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
|
||||
This code is licensed under the MIT License (MIT).
|
||||
|
||||
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.
|
218
deps/GSL/README.md
vendored
Normal file
@ -0,0 +1,218 @@
|
||||
# GSL: Guidelines Support Library
|
||||
[![Build Status](https://dev.azure.com/cppstat/GSL/_apis/build/status/microsoft.GSL?branchName=main)](https://dev.azure.com/cppstat/GSL/_build/latest?definitionId=1&branchName=main)
|
||||
|
||||
The Guidelines Support Library (GSL) contains functions and types that are suggested for use by the
|
||||
[C++ Core Guidelines](https://github.com/isocpp/CppCoreGuidelines) maintained by the [Standard C++ Foundation](https://isocpp.org).
|
||||
This repo contains Microsoft's implementation of GSL.
|
||||
|
||||
The entire implementation is provided inline in the headers under the [gsl](./include/gsl) directory. The implementation generally assumes a platform that implements C++14 support.
|
||||
|
||||
While some types have been broken out into their own headers (e.g. [gsl/span](./include/gsl/span)),
|
||||
it is simplest to just include [gsl/gsl](./include/gsl/gsl) and gain access to the entire library.
|
||||
|
||||
> NOTE: We encourage contributions that improve or refine any of the types in this library as well as ports to
|
||||
other platforms. Please see [CONTRIBUTING.md](./CONTRIBUTING.md) for more information about contributing.
|
||||
|
||||
# Project Code of Conduct
|
||||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
||||
|
||||
# Usage of Third Party Libraries
|
||||
This project makes use of the [Google Test](https://github.com/google/googletest) testing library. Please see the [ThirdPartyNotices.txt](./ThirdPartyNotices.txt) file for details regarding the licensing of Google Test.
|
||||
|
||||
# Supported features
|
||||
## Microsoft GSL implements the following from the C++ Core Guidelines:
|
||||
|
||||
Feature | Supported? | Description
|
||||
-------------------------------------------------------------------------|:----------:|-------------
|
||||
[**1. Views**][cg-views] | |
|
||||
[owner](docs/headers.md#user-content-H-pointers-owner) | ☑ | An alias for a raw pointer
|
||||
[not_null](docs/headers.md#user-content-H-pointers-not_null) | ☑ | Restricts a pointer/smart pointer to hold non-null values
|
||||
[span](docs/headers.md#user-content-H-span-span) | ☑ | A view over a contiguous sequence of memory. Based on the standardized version of `std::span`, however `gsl::span` enforces bounds checking.
|
||||
span_p | ☐ | Spans a range starting from a pointer to the first place for which the predicate is true
|
||||
[basic_zstring](docs/headers.md#user-content-H-zstring) | ☑ | A pointer to a C-string (zero-terminated array) with a templated char type
|
||||
[zstring](docs/headers.md#user-content-H-zstring) | ☑ | An alias to `basic_zstring` with dynamic extent and a char type of `char`
|
||||
[czstring](docs/headers.md#user-content-H-zstring) | ☑ | An alias to `basic_zstring` with dynamic extent and a char type of `const char`
|
||||
[wzstring](docs/headers.md#user-content-H-zstring) | ☑ | An alias to `basic_zstring` with dynamic extent and a char type of `wchar_t`
|
||||
[cwzstring](docs/headers.md#user-content-H-zstring) | ☑ | An alias to `basic_zstring` with dynamic extent and a char type of `const wchar_t`
|
||||
[u16zstring](docs/headers.md#user-content-H-zstring) | ☑ | An alias to `basic_zstring` with dynamic extent and a char type of `char16_t`
|
||||
[cu16zstring](docs/headers.md#user-content-H-zstring) | ☑ | An alias to `basic_zstring` with dynamic extent and a char type of `const char16_t`
|
||||
[u32zstring](docs/headers.md#user-content-H-zstring) | ☑ | An alias to `basic_zstring` with dynamic extent and a char type of `char32_t`
|
||||
[cu32zstring](docs/headers.md#user-content-H-zstring) | ☑ | An alias to `basic_zstring` with dynamic extent and a char type of `const char32_t`
|
||||
[**2. Owners**][cg-owners] | |
|
||||
[unique_ptr](docs/headers.md#user-content-H-pointers-unique_ptr) | ☑ | An alias to `std::unique_ptr`
|
||||
[shared_ptr](docs/headers.md#user-content-H-pointers-shared_ptr) | ☑ | An alias to `std::shared_ptr`
|
||||
stack_array | ☐ | A stack-allocated array
|
||||
dyn_array | ☐ | A heap-allocated array
|
||||
[**3. Assertions**][cg-assertions] | |
|
||||
[Expects](docs/headers.md#user-content-H-assert-expects) | ☑ | A precondition assertion; on failure it terminates
|
||||
[Ensures](docs/headers.md#user-content-H-assert-ensures) | ☑ | A postcondition assertion; on failure it terminates
|
||||
[**4. Utilities**][cg-utilities] | |
|
||||
move_owner | ☐ | A helper function that moves one `owner` to the other
|
||||
[byte](docs/headers.md#user-content-H-byte-byte) | ☑ | Either an alias to `std::byte` or a byte type
|
||||
[final_action](docs/headers.md#user-content-H-util-final_action) | ☑ | A RAII style class that invokes a functor on its destruction
|
||||
[finally](docs/headers.md#user-content-H-util-finally) | ☑ | A helper function instantiating [final_action](docs/headers.md#user-content-H-util-final_action)
|
||||
[GSL_SUPPRESS](docs/headers.md#user-content-H-assert-gsl_suppress) | ☑ | A macro that takes an argument and turns it into `[[gsl::suppress(x)]]` or `[[gsl::suppress("x")]]`
|
||||
[[implicit]] | ☐ | A "marker" to put on single-argument constructors to explicitly make them non-explicit
|
||||
[index](docs/headers.md#user-content-H-util-index) | ☑ | A type to use for all container and array indexing (currently an alias for `std::ptrdiff_t`)
|
||||
joining_thread | ☐ | A RAII style version of `std::thread` that joins
|
||||
[narrow](docs/headers.md#user-content-H-narrow-narrow) | ☑ | A checked version of `narrow_cast`; it can throw [narrowing_error](docs/headers.md#user-content-H-narrow-narrowing_error)
|
||||
[narrow_cast](docs/headers.md#user-content-H-util-narrow_cast) | ☑ | A narrowing cast for values and a synonym for `static_cast`
|
||||
[narrowing_error](docs/headers.md#user-content-H-narrow-narrowing_error) | ☑ | A custom exception type thrown by [narrow](docs/headers.md#user-content-H-narrow-narrow)
|
||||
[**5. Concepts**][cg-concepts] | ☐ |
|
||||
|
||||
## The following features do not exist in or have been removed from the C++ Core Guidelines:
|
||||
Feature | Supported? | Description
|
||||
-----------------------------------|:----------:|-------------
|
||||
[strict_not_null](docs/headers.md#user-content-H-pointers-strict_not_null) | ☑ | A stricter version of [not_null](docs/headers.md#user-content-H-pointers-not_null) with explicit constructors
|
||||
multi_span | ☐ | Deprecated. Multi-dimensional span.
|
||||
strided_span | ☐ | Deprecated. Support for this type has been discontinued.
|
||||
basic_string_span | ☐ | Deprecated. Like `span` but for strings with a templated char type
|
||||
string_span | ☐ | Deprecated. An alias to `basic_string_span` with a char type of `char`
|
||||
cstring_span | ☐ | Deprecated. An alias to `basic_string_span` with a char type of `const char`
|
||||
wstring_span | ☐ | Deprecated. An alias to `basic_string_span` with a char type of `wchar_t`
|
||||
cwstring_span | ☐ | Deprecated. An alias to `basic_string_span` with a char type of `const wchar_t`
|
||||
u16string_span | ☐ | Deprecated. An alias to `basic_string_span` with a char type of `char16_t`
|
||||
cu16string_span | ☐ | Deprecated. An alias to `basic_string_span` with a char type of `const char16_t`
|
||||
u32string_span | ☐ | Deprecated. An alias to `basic_string_span` with a char type of `char32_t`
|
||||
cu32string_span | ☐ | Deprecated. An alias to `basic_string_span` with a char type of `const char32_t`
|
||||
|
||||
This is based on [CppCoreGuidelines semi-specification](https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#gsl-guidelines-support-library).
|
||||
|
||||
[cg-views]: https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#gslview-views
|
||||
[cg-owners]: https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#gslowner-ownership-pointers
|
||||
[cg-assertions]: https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#gslassert-assertions
|
||||
[cg-utilities]: https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#gslutil-utilities
|
||||
[cg-concepts]: https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#gslconcept-concepts
|
||||
|
||||
# Quick Start
|
||||
## Supported Compilers / Toolsets
|
||||
The GSL officially supports the latest and previous major versions of VS with MSVC & LLVM, GCC, Clang, and XCode with Apple-Clang.
|
||||
Within these two major versions, we try to target the latest minor updates / revisions (although this may be affected by
|
||||
delays between a toolchain's release and when it becomes widely available for use).
|
||||
Below is a table showing the versions currently being tested.
|
||||
|
||||
Compiler |Toolset Versions Currently Tested
|
||||
:------- |--:
|
||||
XCode | 13.2.1 & 12.5.1
|
||||
GCC | 11[^1] & 10[^2]
|
||||
Clang | 12[^2] & 11[^2]
|
||||
Visual Studio with MSVC | VS2022[^3] & VS2019[^4]
|
||||
Visual Studio with LLVM | VS2022[^3] & VS2019[^4]
|
||||
|
||||
|
||||
[^1]: Precise version may be found in the [latest CI results](https://dev.azure.com/cppstat/GSL/_build?definitionId=1&branchFilter=26).
|
||||
[^2]: Precise version may be found in the [latest CI results](https://dev.azure.com/cppstat/GSL/_build?definitionId=1&branchFilter=26). Should be the version specified [here](https://github.com/actions/virtual-environments/blob/main/images/linux/Ubuntu2004-Readme.md#language-and-runtime).
|
||||
[^3]: Precise version may be found in the [latest CI results](https://dev.azure.com/cppstat/GSL/_build?definitionId=1&branchFilter=26). Should be the version specified [here](https://github.com/actions/virtual-environments/blob/main/images/win/Windows2022-Readme.md#visual-studio-enterprise-2022).
|
||||
[^4]: Precise version may be found in the [latest CI results](https://dev.azure.com/cppstat/GSL/_build?definitionId=1&branchFilter=26). Should be the version specified [here](https://github.com/actions/virtual-environments/blob/main/images/win/Windows2019-Readme.md#visual-studio-enterprise-2019).
|
||||
|
||||
---
|
||||
If you successfully port GSL to another platform, we would love to hear from you!
|
||||
- Submit an issue specifying the platform and target.
|
||||
- Consider contributing your changes by filing a pull request with any necessary changes.
|
||||
- If at all possible, add a CI/CD step and add the button to the table below!
|
||||
|
||||
Target | CI/CD Status
|
||||
:------- | -----------:
|
||||
iOS | ![CI_iOS](https://github.com/microsoft/GSL/workflows/CI_iOS/badge.svg)
|
||||
Android | ![CI_Android](https://github.com/microsoft/GSL/workflows/CI_Android/badge.svg)
|
||||
|
||||
Note: These CI/CD steps are run with each pull request, however failures in them are non-blocking.
|
||||
|
||||
## Building the tests
|
||||
To build the tests, you will require the following:
|
||||
|
||||
* [CMake](http://cmake.org), version 3.14 or later to be installed and in your PATH.
|
||||
|
||||
These steps assume the source code of this repository has been cloned into a directory named `c:\GSL`.
|
||||
|
||||
1. Create a directory to contain the build outputs for a particular architecture (we name it `c:\GSL\build-x86` in this example).
|
||||
|
||||
cd GSL
|
||||
md build-x86
|
||||
cd build-x86
|
||||
|
||||
2. Configure CMake to use the compiler of your choice (you can see a list by running `cmake --help`).
|
||||
|
||||
cmake -G "Visual Studio 15 2017" c:\GSL
|
||||
|
||||
3. Build the test suite (in this case, in the Debug configuration, Release is another good choice).
|
||||
|
||||
cmake --build . --config Debug
|
||||
|
||||
4. Run the test suite.
|
||||
|
||||
ctest -C Debug
|
||||
|
||||
All tests should pass - indicating your platform is fully supported and you are ready to use the GSL types!
|
||||
|
||||
## Building GSL - Using vcpkg
|
||||
|
||||
You can download and install GSL using the [vcpkg](https://github.com/Microsoft/vcpkg) dependency manager:
|
||||
|
||||
git clone https://github.com/Microsoft/vcpkg.git
|
||||
cd vcpkg
|
||||
./bootstrap-vcpkg.sh
|
||||
./vcpkg integrate install
|
||||
vcpkg install ms-gsl
|
||||
|
||||
The GSL port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository.
|
||||
|
||||
## Using the libraries
|
||||
As the types are entirely implemented inline in headers, there are no linking requirements.
|
||||
|
||||
You can copy the [gsl](./include/gsl) directory into your source tree so it is available
|
||||
to your compiler, then include the appropriate headers in your program.
|
||||
|
||||
Alternatively set your compiler's *include path* flag to point to the GSL development folder (`c:\GSL\include` in the example above) or installation folder (after running the install). Eg.
|
||||
|
||||
MSVC++
|
||||
|
||||
/I c:\GSL\include
|
||||
|
||||
GCC/clang
|
||||
|
||||
-I$HOME/dev/GSL/include
|
||||
|
||||
Include the library using:
|
||||
|
||||
#include <gsl/gsl>
|
||||
|
||||
## Usage in CMake
|
||||
|
||||
The library provides a Config file for CMake, once installed it can be found via `find_package`.
|
||||
|
||||
Which, when successful, will add library target called `Microsoft.GSL::GSL` which you can use via the usual
|
||||
`target_link_libraries` mechanism.
|
||||
|
||||
```cmake
|
||||
find_package(Microsoft.GSL CONFIG REQUIRED)
|
||||
|
||||
target_link_libraries(foobar PRIVATE Microsoft.GSL::GSL)
|
||||
```
|
||||
|
||||
### FetchContent
|
||||
|
||||
If you are using CMake version 3.11+ you can use the offical [FetchContent module](https://cmake.org/cmake/help/latest/module/FetchContent.html).
|
||||
This allows you to easily incorporate GSL into your project.
|
||||
|
||||
```cmake
|
||||
# NOTE: This example uses CMake version 3.14 (FetchContent_MakeAvailable).
|
||||
# Since it streamlines the FetchContent process
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
|
||||
include(FetchContent)
|
||||
|
||||
FetchContent_Declare(GSL
|
||||
GIT_REPOSITORY "https://github.com/microsoft/GSL"
|
||||
GIT_TAG "v4.0.0"
|
||||
GIT_SHALLOW ON
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(GSL)
|
||||
|
||||
target_link_libraries(foobar PRIVATE Microsoft.GSL::GSL)
|
||||
```
|
||||
|
||||
## Debugging visualization support
|
||||
|
||||
For Visual Studio users, the file [GSL.natvis](./GSL.natvis) in the root directory of the repository can be added to your project if you would like more helpful visualization of GSL types in the Visual Studio debugger than would be offered by default.
|
41
deps/GSL/SECURITY.md
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
<!-- BEGIN MICROSOFT SECURITY.MD V0.0.7 BLOCK -->
|
||||
|
||||
## Security
|
||||
|
||||
Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
|
||||
|
||||
If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below.
|
||||
|
||||
## Reporting Security Issues
|
||||
|
||||
**Please do not report security vulnerabilities through public GitHub issues.**
|
||||
|
||||
Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report).
|
||||
|
||||
If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey).
|
||||
|
||||
You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc).
|
||||
|
||||
Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
|
||||
|
||||
* Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
|
||||
* Full paths of source file(s) related to the manifestation of the issue
|
||||
* The location of the affected source code (tag/branch/commit or direct URL)
|
||||
* Any special configuration required to reproduce the issue
|
||||
* Step-by-step instructions to reproduce the issue
|
||||
* Proof-of-concept or exploit code (if possible)
|
||||
* Impact of the issue, including how an attacker might exploit the issue
|
||||
|
||||
This information will help us triage your report more quickly.
|
||||
|
||||
If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs.
|
||||
|
||||
## Preferred Languages
|
||||
|
||||
We prefer all communications to be in English.
|
||||
|
||||
## Policy
|
||||
|
||||
Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd).
|
||||
|
||||
<!-- END MICROSOFT SECURITY.MD BLOCK -->
|
41
deps/GSL/ThirdPartyNotices.txt
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
|
||||
THIRD-PARTY SOFTWARE NOTICES AND INFORMATION
|
||||
Do Not Translate or Localize
|
||||
|
||||
GSL: Guidelines Support Library incorporates third party material from the projects listed below.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Software: Google Test
|
||||
Owner: Google Inc.
|
||||
Source URL: github.com/google/googletest
|
||||
License: BSD 3 - Clause
|
||||
Text:
|
||||
Copyright 2008, Google Inc.
|
||||
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 Google Inc. 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
|
||||
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.
|
||||
-------------------------------------------------------------------------------
|
66
deps/GSL/azure-pipelines.yml
vendored
Normal file
@ -0,0 +1,66 @@
|
||||
trigger:
|
||||
- main
|
||||
|
||||
pr:
|
||||
autoCancel: true
|
||||
|
||||
stages:
|
||||
- stage: GCC
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: ./pipelines/jobs.yml
|
||||
parameters:
|
||||
compiler: gcc
|
||||
image: ubuntu-20.04
|
||||
compilerVersions: [ 11, 10 ]
|
||||
setupfile: 'setup_gcc.yml'
|
||||
|
||||
- stage: Clang
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: ./pipelines/jobs.yml
|
||||
parameters:
|
||||
compiler: clang
|
||||
image: ubuntu-20.04
|
||||
compilerVersions: [ 12, 11 ]
|
||||
setupfile: 'setup_clang.yml'
|
||||
|
||||
- stage: Xcode
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: ./pipelines/jobs.yml
|
||||
parameters:
|
||||
compiler: 'Xcode'
|
||||
image: macOS-11
|
||||
compilerVersions: [ '12.5.1', '13.2.1' ]
|
||||
setupfile: 'setup_apple.yml'
|
||||
|
||||
- stage: VS_MSVC
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: ./pipelines/jobs.yml
|
||||
parameters:
|
||||
compiler: 'VS2019 (MSVC)'
|
||||
compilerVersions: [ 'default' ]
|
||||
image: windows-2019
|
||||
- template: ./pipelines/jobs.yml
|
||||
parameters:
|
||||
compiler: 'VS2022 (MSVC)'
|
||||
compilerVersions: [ 'default' ]
|
||||
image: windows-2022
|
||||
|
||||
- stage: VS_LLVM
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: ./pipelines/jobs.yml
|
||||
parameters:
|
||||
compiler: 'VS2019 (LLVM)'
|
||||
compilerVersions: [ 'default' ]
|
||||
image: windows-2019
|
||||
extraCmakeArgs: '-T ClangCL'
|
||||
- template: ./pipelines/jobs.yml
|
||||
parameters:
|
||||
compiler: 'VS2022 (LLVM)'
|
||||
compilerVersions: [ 'default' ]
|
||||
image: windows-2022
|
||||
extraCmakeArgs: '-T ClangCL'
|
853
deps/GSL/docs/headers.md
vendored
Normal file
@ -0,0 +1,853 @@
|
||||
The Guidelines Support Library (GSL) interface is very lightweight and exposed via a header-only library. This document attempts to document all of the headers and their exposed classes and functions.
|
||||
|
||||
Types and functions are exported in the namespace `gsl`.
|
||||
|
||||
See [GSL: Guidelines support library](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#S-gsl)
|
||||
|
||||
# <a name="H" />Headers
|
||||
|
||||
- [`<algorithms>`](#user-content-H-algorithms)
|
||||
- [`<assert>`](#user-content-H-assert)
|
||||
- [`<byte>`](#user-content-H-byte)
|
||||
- [`<gsl>`](#user-content-H-gsl)
|
||||
- [`<narrow>`](#user-content-H-narrow)
|
||||
- [`<pointers>`](#user-content-H-pointers)
|
||||
- [`<span>`](#user-content-H-span)
|
||||
- [`<span_ext>`](#user-content-H-span_ext)
|
||||
- [`<zstring>`](#user-content-H-zstring)
|
||||
- [`<util>`](#user-content-H-util)
|
||||
|
||||
## <a name="H-algorithms" />`<algorithms>`
|
||||
|
||||
This header contains some common algorithms that have been wrapped in GSL safety features.
|
||||
|
||||
- [`gsl::copy`](#user-content-H-algorithms-copy)
|
||||
|
||||
### <a name="H-algorithms-copy" />`gsl::copy`
|
||||
|
||||
```cpp
|
||||
template <class SrcElementType, std::size_t SrcExtent, class DestElementType,
|
||||
std::size_t DestExtent>
|
||||
void copy(span<SrcElementType, SrcExtent> src, span<DestElementType, DestExtent> dest);
|
||||
```
|
||||
|
||||
This function copies the content from the `src` [`span`](#user-content-H-span-span) to the `dest` [`span`](#user-content-H-span-span). It [`Expects`](#user-content-H-assert-expects)
|
||||
that the destination `span` is at least as large as the source `span`.
|
||||
|
||||
## <a name="H-assert" />`<assert>`
|
||||
|
||||
This header contains some macros used for contract checking and suppressing code analysis warnings.
|
||||
|
||||
See [GSL.assert: Assertions](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#SS-assertions)
|
||||
|
||||
- [`GSL_SUPPRESS`](#user-content-H-assert-gsl_suppress)
|
||||
- [`Expects`](#user-content-H-assert-expects)
|
||||
- [`Ensures`](#user-content-H-assert-ensures)
|
||||
|
||||
### <a name="H-assert-gsl_suppress" />`GSL_SUPPRESS`
|
||||
|
||||
This macro can be used to suppress a code analysis warning.
|
||||
|
||||
The core guidelines request tools that check for the rules to respect suppressing a rule by writing
|
||||
`[[gsl::suppress(tag)]]` or `[[gsl::suppress(tag, justification: "message")]]`.
|
||||
|
||||
Clang does not use exactly that syntax, but requires `tag` to be put in double quotes `[[gsl::suppress("tag")]]`.
|
||||
|
||||
For portable code you can use `GSL_SUPPRESS(tag)`.
|
||||
|
||||
See [In.force: Enforcement](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#inforce-enforcement).
|
||||
|
||||
### <a name="H-assert-expects" />`Expects`
|
||||
|
||||
This macro can be used for expressing a precondition. If the precondition is not held, then `std::terminate` will be called.
|
||||
|
||||
See [I.6: Prefer `Expects()` for expressing preconditions](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#i6-prefer-expects-for-expressing-preconditions)
|
||||
|
||||
### <a name="H-assert-ensures" />`Ensures`
|
||||
|
||||
This macro can be used for expressing a postcondition. If the postcondition is not held, then `std::terminate` will be called.
|
||||
|
||||
See [I.8: Prefer `Ensures()` for expressing postconditions](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#i8-prefer-ensures-for-expressing-postconditions)
|
||||
|
||||
## <a name="H-byte" />`<byte>`
|
||||
|
||||
This header contains the definition of a byte type, implementing `std::byte` before it was standardized into C++17.
|
||||
|
||||
- [`gsl::byte`](#user-content-H-byte-byte)
|
||||
|
||||
### <a name="H-byte-byte" />`gsl::byte`
|
||||
|
||||
If `GSL_USE_STD_BYTE` is defined to be `1`, then `gsl::byte` will be an alias to `std::byte`.
|
||||
If `GSL_USE_STD_BYTE` is defined to be `0`, then `gsl::byte` will be a distinct type that implements the concept of byte.
|
||||
If `GSL_USE_STD_BYTE` is not defined, then the header file will check if `std::byte` is available (C\+\+17 or higher). If yes,
|
||||
`gsl::byte` will be an alias to `std::byte`, otherwise `gsl::byte` will be a distinct type that implements the concept of byte.
|
||||
|
||||
⚠ Take care when linking projects that were compiled with different language standards (before C\+\+17 and C\+\+17 or higher).
|
||||
If you do so, you might want to `#define GSL_USE_STD_BYTE 0` to a fixed value to be sure that both projects use exactly
|
||||
the same type. Otherwise you might get linker errors.
|
||||
|
||||
See [SL.str.5: Use `std::byte` to refer to byte values that do not necessarily represent characters](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rstr-byte)
|
||||
|
||||
### Non-member functions
|
||||
|
||||
```cpp
|
||||
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
|
||||
constexpr byte& operator<<=(byte& b, IntegerType shift) noexcept;
|
||||
|
||||
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
|
||||
constexpr byte operator<<(byte b, IntegerType shift) noexcept;
|
||||
|
||||
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
|
||||
constexpr byte& operator>>=(byte& b, IntegerType shift) noexcept;
|
||||
|
||||
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
|
||||
constexpr byte operator>>(byte b, IntegerType shift) noexcept;
|
||||
```
|
||||
|
||||
Left or right shift a `byte` by a given number of bits.
|
||||
|
||||
```cpp
|
||||
constexpr byte& operator|=(byte& l, byte r) noexcept;
|
||||
constexpr byte operator|(byte l, byte r) noexcept;
|
||||
```
|
||||
|
||||
Bitwise "or" of two `byte`s.
|
||||
|
||||
```cpp
|
||||
constexpr byte& operator&=(byte& l, byte r) noexcept;
|
||||
constexpr byte operator&(byte l, byte r) noexcept;
|
||||
```
|
||||
|
||||
Bitwise "and" of two `byte`s.
|
||||
|
||||
```cpp
|
||||
constexpr byte& operator^=(byte& l, byte r) noexcept;
|
||||
constexpr byte operator^(byte l, byte r) noexcept;
|
||||
```
|
||||
|
||||
Bitwise xor of two `byte`s.
|
||||
|
||||
```cpp
|
||||
constexpr byte operator~(byte b) noexcept;
|
||||
```
|
||||
|
||||
Bitwise negation of a `byte`. Flips all bits. Zeroes become ones, ones become zeroes.
|
||||
|
||||
```cpp
|
||||
template <typename T>
|
||||
constexpr byte to_byte(T t) noexcept;
|
||||
```
|
||||
|
||||
Convert the given value to a `byte`. The template requires `T` to be an `unsigned char` so that no data loss can occur.
|
||||
If you want to convert an integer constant to a `byte` you probably want to call `to_byte<integer constant>()`.
|
||||
|
||||
```cpp
|
||||
template <int I>
|
||||
constexpr byte to_byte() noexcept;
|
||||
```
|
||||
|
||||
Convert the given value `I` to a `byte`. The template requires `I` to be in the valid range 0..255 for a `gsl::byte`.
|
||||
|
||||
## <a name="H-gsl" />`<gsl>`
|
||||
|
||||
This header is a convenience header that includes all other [GSL headers](#user-content-H).
|
||||
Since `<narrow>` requires exceptions, it will only be included if exceptions are enabled.
|
||||
|
||||
## <a name="H-narrow" />`<narrow>`
|
||||
|
||||
This header contains utility functions and classes, for narrowing casts, which require exceptions. The narrowing-related utilities that don't require exceptions are found inside [util](#user-content-H-util).
|
||||
|
||||
See [GSL.util: Utilities](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#SS-utilities)
|
||||
|
||||
- [`gsl::narrowing_error`](#user-content-H-narrow-narrowing_error)
|
||||
- [`gsl::narrow`](#user-content-H-narrow-narrow)
|
||||
|
||||
### <a name="H-narrow-narrowing_error" />`gsl::narrowing_error`
|
||||
|
||||
`gsl::narrowing_error` is the exception thrown by [`gsl::narrow`](#user-content-H-narrow-narrow) when a narrowing conversion fails. It is derived from `std::exception`.
|
||||
|
||||
### <a name="H-narrow-narrow" />`gsl::narrow`
|
||||
|
||||
`gsl::narrow<T>(x)` is a named cast that does a `static_cast<T>(x)` for narrowing conversions with no signedness promotions.
|
||||
If the argument `x` cannot be represented in the target type `T`, then the function throws a [`gsl::narrowing_error`](#user-content-H-narrow-narrowing_error) (e.g., `narrow<unsigned>(-42)` and `narrow<char>(300)` throw).
|
||||
|
||||
Note: compare [`gsl::narrow_cast`](#user-content-H-util-narrow_cast) in header [util](#user-content-H-util).
|
||||
|
||||
See [ES.46: Avoid lossy (narrowing, truncating) arithmetic conversions](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-narrowing) and [ES.49: If you must use a cast, use a named cast](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-casts-named)
|
||||
|
||||
## <a name="H-pointers" />`<pointers>`
|
||||
|
||||
This header contains some pointer types.
|
||||
|
||||
See [GSL.view](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#SS-views)
|
||||
|
||||
- [`gsl::unique_ptr`](#user-content-H-pointers-unique_ptr)
|
||||
- [`gsl::shared_ptr`](#user-content-H-pointers-shared_ptr)
|
||||
- [`gsl::owner`](#user-content-H-pointers-owner)
|
||||
- [`gsl::not_null`](#user-content-H-pointers-not_null)
|
||||
- [`gsl::strict_not_null`](#user-content-H-pointers-strict_not_null)
|
||||
|
||||
### <a name="H-pointers-unique_ptr" />`gsl::unique_ptr`
|
||||
|
||||
`gsl::unique_ptr` is an alias to `std::unique_ptr`.
|
||||
|
||||
See [GSL.owner: Ownership pointers](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#SS-ownership)
|
||||
|
||||
### <a name="H-pointers-shared_ptr" />`gsl::shared_ptr`
|
||||
|
||||
`gsl::shared_ptr` is an alias to `std::shared_ptr`.
|
||||
|
||||
See [GSL.owner: Ownership pointers](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#SS-ownership)
|
||||
|
||||
### <a name="H-pointers-owner" />`gsl::owner`
|
||||
|
||||
`gsl::owner<T>` is designed as a safety mechanism for code that must deal directly with raw pointers that own memory. Ideally such code should be restricted to the implementation of low-level abstractions. `gsl::owner` can also be used as a stepping point in converting legacy code to use more modern RAII constructs such as smart pointers.
|
||||
`T` must be a pointer type (`std::is_pointer<T>`).
|
||||
|
||||
A `gsl::owner<T>` is a typedef to `T`. It adds no runtime overhead whatsoever, as it is purely syntactic and does not add any runtime checks. Instead, it serves as an annotation for static analysis tools which check for memory safety, and as a code comprehension guide for human readers.
|
||||
|
||||
See Enforcement section of [C.31: All resources acquired by a class must be released by the class’s destructor](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rc-dtor-release).
|
||||
|
||||
### <a name="H-pointers-not_null" />`gsl::not_null`
|
||||
|
||||
`gsl::not_null<T>` restricts a pointer or smart pointer to only hold non-null values. It has no size overhead over `T`.
|
||||
|
||||
The checks for ensuring that the pointer is not null are done in the constructor. There is no overhead when retrieving or dereferencing the checked pointer.
|
||||
When a nullptr check fails, `std::terminate` is called.
|
||||
|
||||
See [F.23: Use a `not_null<T>` to indicate that “null” is not a valid value](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rf-nullptr)
|
||||
|
||||
#### Member functions
|
||||
|
||||
##### Construct/Copy
|
||||
|
||||
```cpp
|
||||
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
|
||||
constexpr not_null(U&& u);
|
||||
|
||||
template <typename = std::enable_if_t<!std::is_same<std::nullptr_t, T>::value>>
|
||||
constexpr not_null(T u);
|
||||
```
|
||||
|
||||
Constructs a `gsl_owner<T>` from a pointer that is convertible to `T` or that is a `T`. It [`Expects`](#user-content-H-assert-expects) that the provided pointer is not `== nullptr`.
|
||||
|
||||
```cpp
|
||||
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
|
||||
constexpr not_null(const not_null<U>& other);
|
||||
```
|
||||
|
||||
Constructs a `gsl_owner<T>` from another `gsl_owner` where the other pointer is convertible to `T`. It [`Expects`](#user-content-H-assert-expects) that the provided pointer is not `== nullptr`.
|
||||
|
||||
```cpp
|
||||
not_null(const not_null& other) = default;
|
||||
not_null& operator=(const not_null& other) = default;
|
||||
```
|
||||
|
||||
Copy construction and assignment.
|
||||
|
||||
```cpp
|
||||
not_null(std::nullptr_t) = delete;
|
||||
not_null& operator=(std::nullptr_t) = delete;
|
||||
```
|
||||
|
||||
Construction from `std::nullptr_t` and assignment of `std::nullptr_t` are explicitly deleted.
|
||||
|
||||
##### Modifiers
|
||||
|
||||
```cpp
|
||||
not_null& operator++() = delete;
|
||||
not_null& operator--() = delete;
|
||||
not_null operator++(int) = delete;
|
||||
not_null operator--(int) = delete;
|
||||
not_null& operator+=(std::ptrdiff_t) = delete;
|
||||
not_null& operator-=(std::ptrdiff_t) = delete;
|
||||
```
|
||||
|
||||
Explicitly deleted operators. Pointers point to single objects ([I.13: Do not pass an array as a single pointer](http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Ri-array)), so don't allow these operators.
|
||||
|
||||
##### Observers
|
||||
|
||||
```cpp
|
||||
constexpr details::value_or_reference_return_t<T> get() const;
|
||||
constexpr operator T() const { return get(); }
|
||||
```
|
||||
|
||||
Get the underlying pointer.
|
||||
|
||||
```cpp
|
||||
constexpr decltype(auto) operator->() const { return get(); }
|
||||
constexpr decltype(auto) operator*() const { return *get(); }
|
||||
```
|
||||
|
||||
Dereference the underlying pointer.
|
||||
|
||||
```cpp
|
||||
void operator[](std::ptrdiff_t) const = delete;
|
||||
```
|
||||
|
||||
Array index operator is explicitly deleted. Pointers point to single objects ([I.13: Do not pass an array as a single pointer](http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Ri-array)), so don't allow treating them as an array.
|
||||
|
||||
#### Non-member functions
|
||||
|
||||
```cpp
|
||||
template <class T>
|
||||
auto make_not_null(T&& t) noexcept;
|
||||
```
|
||||
|
||||
Creates a `gsl::not_null` object, deducing the target type from the type of the argument.
|
||||
|
||||
```cpp
|
||||
template <class T, class U>
|
||||
auto operator==(const not_null<T>& lhs,
|
||||
const not_null<U>& rhs) noexcept(noexcept(lhs.get() == rhs.get()))
|
||||
-> decltype(lhs.get() == rhs.get());
|
||||
template <class T, class U>
|
||||
auto operator!=(const not_null<T>& lhs,
|
||||
const not_null<U>& rhs) noexcept(noexcept(lhs.get() != rhs.get()))
|
||||
-> decltype(lhs.get() != rhs.get());
|
||||
template <class T, class U>
|
||||
auto operator<(const not_null<T>& lhs,
|
||||
const not_null<U>& rhs) noexcept(noexcept(lhs.get() < rhs.get()))
|
||||
-> decltype(lhs.get() < rhs.get());
|
||||
template <class T, class U>
|
||||
auto operator<=(const not_null<T>& lhs,
|
||||
const not_null<U>& rhs) noexcept(noexcept(lhs.get() <= rhs.get()))
|
||||
-> decltype(lhs.get() <= rhs.get());
|
||||
template <class T, class U>
|
||||
auto operator>(const not_null<T>& lhs,
|
||||
const not_null<U>& rhs) noexcept(noexcept(lhs.get() > rhs.get()))
|
||||
-> decltype(lhs.get() > rhs.get());
|
||||
template <class T, class U>
|
||||
auto operator>=(const not_null<T>& lhs,
|
||||
const not_null<U>& rhs) noexcept(noexcept(lhs.get() >= rhs.get()))
|
||||
-> decltype(lhs.get() >= rhs.get());
|
||||
```
|
||||
|
||||
Comparison of pointers that are convertible to each other.
|
||||
|
||||
##### Input/Output
|
||||
|
||||
```cpp
|
||||
template <class T>
|
||||
std::ostream& operator<<(std::ostream& os, const not_null<T>& val);
|
||||
```
|
||||
|
||||
Performs stream output on a `not_null` pointer, invoking `os << val.get()`. This function is only available when `GSL_NO_IOSTREAMS` is not defined.
|
||||
|
||||
##### Modifiers
|
||||
|
||||
```cpp
|
||||
template <class T, class U>
|
||||
std::ptrdiff_t operator-(const not_null<T>&, const not_null<U>&) = delete;
|
||||
template <class T>
|
||||
not_null<T> operator-(const not_null<T>&, std::ptrdiff_t) = delete;
|
||||
template <class T>
|
||||
not_null<T> operator+(const not_null<T>&, std::ptrdiff_t) = delete;
|
||||
template <class T>
|
||||
not_null<T> operator+(std::ptrdiff_t, const not_null<T>&) = delete;
|
||||
```
|
||||
|
||||
Addition and subtraction are explicitly deleted. Pointers point to single objects ([I.13: Do not pass an array as a single pointer](http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Ri-array)), so don't allow these operators.
|
||||
|
||||
##### STL integration
|
||||
|
||||
```cpp
|
||||
template <class T>
|
||||
struct std::hash<gsl::not_null<T>> { ... };
|
||||
```
|
||||
|
||||
Specialization of `std::hash` for `gsl::not_null`.
|
||||
|
||||
### <a name="H-pointers-strict_not_null" />`gsl::strict_not_null`
|
||||
|
||||
`strict_not_null` is the same as [`not_null`](#user-content-H-pointers-not_null) except that the constructors are `explicit`.
|
||||
|
||||
The free function that deduces the target type from the type of the argument and creates a `gsl::strict_not_null` object is `gsl::make_strict_not_null`.
|
||||
|
||||
## <a name="H-span" />`<span>`
|
||||
|
||||
This header file exports the class `gsl::span`, a bounds-checked implementation of `std::span`.
|
||||
|
||||
- [`gsl::span`](#user-content-H-span-span)
|
||||
|
||||
### <a name="H-span-span" />`gsl::span`
|
||||
|
||||
```cpp
|
||||
template <class ElementType, std::size_t Extent>
|
||||
class span;
|
||||
```
|
||||
|
||||
`gsl::span` is a view over memory. It does not own the memory and is only a way to access contiguous sequences of objects.
|
||||
The extent can be either a fixed size or [`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent).
|
||||
|
||||
The `gsl::span` is based on the standardized version of `std::span` which was added to C++20. Originally, the plan was to
|
||||
deprecate `gsl::span` when `std::span` finished standardization, however that plan changed when the runtime bounds checking
|
||||
was removed from `std::span`'s design.
|
||||
|
||||
The only difference between `gsl::span` and `std::span` is that `gsl::span` strictly enforces runtime bounds checking.
|
||||
Any violations of the bounds check results in termination of the program.
|
||||
Like `gsl::span`, `gsl::span`'s iterators also differ from `std::span`'s iterator in that all access operations are bounds checked.
|
||||
|
||||
#### Which version of span should I use?
|
||||
|
||||
##### Use `gsl::span` if
|
||||
|
||||
- you want to guarantee bounds safety in your project.
|
||||
- All data accessing operations use bounds checking to ensure you are only accessing valid memory.
|
||||
- your project uses C++14 or C++17.
|
||||
- `std::span` is not available as it was not introduced into the STL until C++20.
|
||||
|
||||
##### Use `std::span` if
|
||||
|
||||
- your project is C++20 and you need the performance offered by `std::span`.
|
||||
|
||||
#### Types
|
||||
|
||||
```cpp
|
||||
using element_type = ElementType;
|
||||
using value_type = std::remove_cv_t<ElementType>;
|
||||
using size_type = std::size_t;
|
||||
using pointer = element_type*;
|
||||
using const_pointer = const element_type*;
|
||||
using reference = element_type&;
|
||||
using const_reference = const element_type&;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
|
||||
using iterator = details::span_iterator<ElementType>;
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
```
|
||||
|
||||
#### Member functions
|
||||
|
||||
```cpp
|
||||
constexpr span() noexcept;
|
||||
```
|
||||
|
||||
Constructs an empty `span`. This constructor is only available if `Extent` is 0 or [`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent).
|
||||
`span::data()` will return `nullptr`.
|
||||
|
||||
```cpp
|
||||
constexpr explicit(Extent != gsl::dynamic_extent) span(pointer ptr, size_type count) noexcept;
|
||||
```
|
||||
|
||||
Constructs a `span` from a pointer and a size. If `Extent` is not [`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent),
|
||||
then the constructor [`Expects`](#user-content-H-assert-expects) that `count == Extent`.
|
||||
|
||||
```cpp
|
||||
constexpr explicit(Extent != gsl::dynamic_extent) span(pointer firstElem, pointer lastElem) noexcept;
|
||||
```
|
||||
|
||||
Constructs a `span` from a pointer to the begin and the end of the data. If `Extent` is not [`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent),
|
||||
then the constructor [`Expects`](#user-content-H-assert-expects) that `lastElem - firstElem == Extent`.
|
||||
|
||||
```cpp
|
||||
template <std::size_t N>
|
||||
constexpr span(element_type (&arr)[N]) noexcept;
|
||||
```
|
||||
|
||||
Constructs a `span` from a C style array. This overload is available if `Extent ==`[`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent)
|
||||
or `N == Extent`.
|
||||
|
||||
```cpp
|
||||
template <class T, std::size_t N>
|
||||
constexpr span(std::array<T, N>& arr) noexcept;
|
||||
|
||||
template <class T, std::size_t N>
|
||||
constexpr span(const std::array<T, N>& arr) noexcept;
|
||||
```
|
||||
|
||||
Constructs a `span` from a `std::array`. These overloads are available if `Extent ==`[`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent)
|
||||
or `N == Extent`, and if the array can be interpreted as a `ElementType` array.
|
||||
|
||||
```cpp
|
||||
template <class Container>
|
||||
constexpr explicit(Extent != gsl::dynamic_extent) span(Container& cont) noexcept;
|
||||
|
||||
template <class Container>
|
||||
constexpr explicit(Extent != gsl::dynamic_extent) span(const Container& cont) noexcept;
|
||||
```
|
||||
|
||||
Constructs a `span` from a container. These overloads are available if `Extent ==`[`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent)
|
||||
or `N == Extent`, and if the container can be interpreted as a contiguous `ElementType` array.
|
||||
|
||||
```cpp
|
||||
constexpr span(const span& other) noexcept = default;
|
||||
```
|
||||
|
||||
Copy constructor.
|
||||
|
||||
```cpp
|
||||
template <class OtherElementType, std::size_t OtherExtent>
|
||||
explicit(Extent != gsl::dynamic_extent && OtherExtent == dynamic_extent)
|
||||
constexpr span(const span<OtherElementType, OtherExtent>& other) noexcept;
|
||||
```
|
||||
|
||||
Constructs a `span` from another `span`. This constructor is available if `OtherExtent == Extent || Extent ==`[`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent)` || OtherExtent ==`[`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent)
|
||||
and if `ElementType` and `OtherElementType` are compatible.
|
||||
|
||||
If `Extent !=`[`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent) and `OtherExtent ==`[`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent),
|
||||
then the constructor [`Expects`](#user-content-H-assert-expects) that `other.size() == Extent`.
|
||||
|
||||
```cpp
|
||||
constexpr span& operator=(const span& other) noexcept = default;
|
||||
```
|
||||
|
||||
Copy assignment
|
||||
|
||||
```cpp
|
||||
template <std::size_t Count>
|
||||
constexpr span<element_type, Count> first() const noexcept;
|
||||
|
||||
constexpr span<element_type, dynamic_extent> first(size_type count) const noexcept;
|
||||
|
||||
template <std::size_t Count>
|
||||
constexpr span<element_type, Count> last() const noexcept;
|
||||
|
||||
constexpr span<element_type, dynamic_extent> last(size_type count) const noexcept;
|
||||
```
|
||||
|
||||
Return a subspan of the first/last `Count` elements. [`Expects`](#user-content-H-assert-expects) that `Count` does not exceed the `span`'s size.
|
||||
|
||||
```cpp
|
||||
template <std::size_t offset, std::size_t count = dynamic_extent>
|
||||
constexpr auto subspan() const noexcept;
|
||||
|
||||
constexpr span<element_type, dynamic_extent>
|
||||
subspan(size_type offset, size_type count = dynamic_extent) const noexcept;
|
||||
```
|
||||
|
||||
Return a subspan starting at `offset` and having size `count`. [`Expects`](#user-content-H-assert-expects) that `offset` does not exceed the `span`'s size,
|
||||
and that `offset == `[`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent) or `offset + count` does not exceed the `span`'s size.
|
||||
If `count` is `gsl::dynamic_extent`, the number of elements in the subspan is `size() - offset`.
|
||||
|
||||
```cpp
|
||||
constexpr size_type size() const noexcept;
|
||||
|
||||
constexpr size_type size_bytes() const noexcept;
|
||||
```
|
||||
|
||||
Returns the size respective the size in bytes of the `span`.
|
||||
|
||||
```cpp
|
||||
constexpr bool empty() const noexcept;
|
||||
```
|
||||
|
||||
Is the `span` empty?
|
||||
|
||||
```cpp
|
||||
constexpr reference operator[](size_type idx) const noexcept;
|
||||
```
|
||||
|
||||
Returns a reference to the element at the given index. [`Expects`](#user-content-H-assert-expects) that `idx` is less than the `span`'s size.
|
||||
|
||||
```cpp
|
||||
constexpr reference front() const noexcept;
|
||||
constexpr reference back() const noexcept;
|
||||
```
|
||||
|
||||
Returns a reference to the first/last element in the `span`. [`Expects`](#user-content-H-assert-expects) that the `span` is not empty.
|
||||
|
||||
```cpp
|
||||
constexpr pointer data() const noexcept;
|
||||
```
|
||||
|
||||
Returns a pointer to the beginning of the contained data.
|
||||
|
||||
```cpp
|
||||
constexpr iterator begin() const noexcept;
|
||||
constexpr iterator end() const noexcept;
|
||||
constexpr reverse_iterator rbegin() const noexcept;
|
||||
constexpr reverse_iterator rend() const noexcept;
|
||||
```
|
||||
|
||||
Returns an iterator to the first/last normal/reverse iterator.
|
||||
|
||||
```cpp
|
||||
template <class Type, std::size_t Extent>
|
||||
span(Type (&)[Extent]) -> span<Type, Extent>;
|
||||
|
||||
template <class Type, std::size_t Size>
|
||||
span(std::array<Type, Size>&) -> span<Type, Size>;
|
||||
|
||||
template <class Type, std::size_t Size>
|
||||
span(const std::array<Type, Size>&) -> span<const Type, Size>;
|
||||
|
||||
template <class Container,
|
||||
class Element = std::remove_pointer_t<decltype(std::declval<Container&>().data())>>
|
||||
span(Container&) -> span<Element>;
|
||||
|
||||
template <class Container,
|
||||
class Element = std::remove_pointer_t<decltype(std::declval<const Container&>().data())>>
|
||||
span(const Container&) -> span<Element>;
|
||||
```
|
||||
|
||||
Deduction guides.
|
||||
|
||||
```cpp
|
||||
template <class ElementType, std::size_t Extent>
|
||||
span<const byte, details::calculate_byte_size<ElementType, Extent>::value>
|
||||
as_bytes(span<ElementType, Extent> s) noexcept;
|
||||
|
||||
template <class ElementType, std::size_t Extent>
|
||||
span<byte, details::calculate_byte_size<ElementType, Extent>::value>
|
||||
as_writable_bytes(span<ElementType, Extent> s) noexcept;
|
||||
```
|
||||
|
||||
Converts a `span` into a `span` of `byte`s.
|
||||
|
||||
`as_writable_bytes` will only be available for non-const `ElementType`s.
|
||||
|
||||
## <a name="H-span_ext" />`<span_ext>`
|
||||
|
||||
This file is a companion for and included by [`<gsl/span>`](#user-content-H-span), and should not be used on its own. It contains useful features that aren't part of the `std::span` API as found inside the STL `<span>` header (with the exception of [`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent), which is included here due to implementation constraints).
|
||||
|
||||
- [`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent)
|
||||
- [`gsl::span`](#user-content-H-span_ext-span)
|
||||
- [`gsl::span` comparison operators](#user-content-H-span_ext-span_comparison_operators)
|
||||
- [`gsl::make_span`](#user-content-H-span_ext-make_span)
|
||||
- [`gsl::at`](#user-content-H-span_ext-at)
|
||||
- [`gsl::ssize`](#user-content-H-span_ext-ssize)
|
||||
- [`gsl::span` iterator functions](#user-content-H-span_ext-span_iterator_functions)
|
||||
|
||||
### <a name="H-span_ext-dynamic_extent" />`gsl::dynamic_extent`
|
||||
|
||||
Defines the extent value to be used by all `gsl::span` with dynamic extent.
|
||||
|
||||
Note: `std::dynamic_extent` is exposed by the STL `<span>` header and so ideally `gsl::dynamic_extent` would be under [`<gsl/span>`](#user-content-H-span), but to avoid cyclic dependency issues it is under `<span_ext>` instead.
|
||||
|
||||
### <a name="H-span_ext-span" />`gsl::span`
|
||||
|
||||
```cpp
|
||||
template <class ElementType, std::size_t Extent = dynamic_extent>
|
||||
class span;
|
||||
```
|
||||
|
||||
Forward declaration of `gsl::span`.
|
||||
|
||||
### <a name="H-span_ext-span_comparison_operators" />`gsl::span` comparison operators
|
||||
|
||||
```cpp
|
||||
template <class ElementType, std::size_t FirstExtent, std::size_t SecondExtent>
|
||||
constexpr bool operator==(span<ElementType, FirstExtent> l, span<ElementType, SecondExtent> r);
|
||||
template <class ElementType, std::size_t FirstExtent, std::size_t SecondExtent>
|
||||
constexpr bool operator!=(span<ElementType, FirstExtent> l, span<ElementType, SecondExtent> r);
|
||||
template <class ElementType, std::size_t Extent>
|
||||
constexpr bool operator<(span<ElementType, Extent> l, span<ElementType, Extent> r);
|
||||
template <class ElementType, std::size_t Extent>
|
||||
constexpr bool operator<=(span<ElementType, Extent> l, span<ElementType, Extent> r);
|
||||
template <class ElementType, std::size_t Extent>
|
||||
constexpr bool operator>(span<ElementType, Extent> l, span<ElementType, Extent> r);
|
||||
template <class ElementType, std::size_t Extent>
|
||||
constexpr bool operator>=(span<ElementType, Extent> l, span<ElementType, Extent> r);
|
||||
```
|
||||
|
||||
The comparison operators for two `span`s lexicographically compare the elements in the `span`s.
|
||||
|
||||
### <a name="H-span_ext-make_span" />`gsl::make_span`
|
||||
|
||||
```cpp
|
||||
template <class ElementType>
|
||||
constexpr span<ElementType> make_span(ElementType* ptr, typename span<ElementType>::size_type count);
|
||||
template <class ElementType>
|
||||
constexpr span<ElementType> make_span(ElementType* firstElem, ElementType* lastElem);
|
||||
template <class ElementType, std::size_t N>
|
||||
constexpr span<ElementType, N> make_span(ElementType (&arr)[N]) noexcept;
|
||||
template <class Container>
|
||||
constexpr span<typename Container::value_type> make_span(Container& cont);
|
||||
template <class Container>
|
||||
constexpr span<const typename Container::value_type> make_span(const Container& cont);
|
||||
template <class Ptr>
|
||||
constexpr span<typename Ptr::element_type> make_span(Ptr& cont, std::size_t count);
|
||||
template <class Ptr>
|
||||
constexpr span<typename Ptr::element_type> make_span(Ptr& cont);
|
||||
```
|
||||
|
||||
Utility function for creating a `span` with [`gsl::dynamic_extent`](#user-content-H-span_ext-dynamic_extent) from
|
||||
- pointer and length,
|
||||
- pointer to start and pointer to end,
|
||||
- a C style array, or
|
||||
- a container.
|
||||
|
||||
### <a name="H-span_ext-at" />`gsl::at`
|
||||
|
||||
```cpp
|
||||
template <class ElementType, std::size_t Extent>
|
||||
constexpr ElementType& at(span<ElementType, Extent> s, index i);
|
||||
```
|
||||
|
||||
The function `gsl::at` offers a safe way to access data with index bounds checking.
|
||||
|
||||
This is the specialization of [`gsl::at`](#user-content-H-util-at) for [`span`](#user-content-H-span-span). It returns a reference to the `i`th element and
|
||||
[`Expects`](#user-content-H-assert-expects) that the provided index is within the bounds of the `span`.
|
||||
|
||||
Note: `gsl::at` supports indexes up to `PTRDIFF_MAX`.
|
||||
|
||||
### <a name="H-span_ext-ssize" />`gsl::ssize`
|
||||
|
||||
```cpp
|
||||
template <class ElementType, std::size_t Extent>
|
||||
constexpr std::ptrdiff_t ssize(const span<ElementType, Extent>& s) noexcept;
|
||||
```
|
||||
|
||||
Return the size of a [`span`](#user-content-H-span-span) as a `ptrdiff_t`.
|
||||
|
||||
### <a name="H-span_ext-span_iterator_functions" />`gsl::span` iterator functions
|
||||
|
||||
```cpp
|
||||
template <class ElementType, std::size_t Extent>
|
||||
constexpr typename span<ElementType, Extent>::iterator
|
||||
begin(const span<ElementType, Extent>& s) noexcept;
|
||||
|
||||
template <class ElementType, std::size_t Extent = dynamic_extent>
|
||||
constexpr typename span<ElementType, Extent>::iterator
|
||||
end(const span<ElementType, Extent>& s) noexcept;
|
||||
|
||||
template <class ElementType, std::size_t Extent>
|
||||
constexpr typename span<ElementType, Extent>::reverse_iterator
|
||||
rbegin(const span<ElementType, Extent>& s) noexcept;
|
||||
|
||||
template <class ElementType, std::size_t Extent>
|
||||
constexpr typename span<ElementType, Extent>::reverse_iterator
|
||||
rend(const span<ElementType, Extent>& s) noexcept;
|
||||
|
||||
template <class ElementType, std::size_t Extent>
|
||||
constexpr typename span<ElementType, Extent>::iterator
|
||||
cbegin(const span<ElementType, Extent>& s) noexcept;
|
||||
|
||||
template <class ElementType, std::size_t Extent = dynamic_extent>
|
||||
constexpr typename span<ElementType, Extent>::iterator
|
||||
cend(const span<ElementType, Extent>& s) noexcept;
|
||||
|
||||
template <class ElementType, std::size_t Extent>
|
||||
constexpr typename span<ElementType, Extent>::reverse_iterator
|
||||
crbegin(const span<ElementType, Extent>& s) noexcept;
|
||||
|
||||
template <class ElementType, std::size_t Extent>
|
||||
constexpr typename span<ElementType, Extent>::reverse_iterator
|
||||
crend(const span<ElementType, Extent>& s) noexcept;
|
||||
```
|
||||
|
||||
Free functions for getting a non-const/const begin/end normal/reverse iterator for a [`span`](#user-content-H-span-span).
|
||||
|
||||
## <a name="H-zstring" />`<zstring>`
|
||||
|
||||
This header exports a family of `*zstring` types.
|
||||
|
||||
A `gsl::XXzstring<T>` is a typedef to `T`. It adds no checks whatsoever, it is just for having a syntax to describe
|
||||
that a pointer points to a zero terminated C style string. This helps static code analysis, and it helps human readers.
|
||||
|
||||
`basic_zstring` is a pointer to a C-string (zero-terminated array) with a templated char type. Used to implement the rest of the `*zstring` family.
|
||||
`zstring` is a zero terminated `char` string.
|
||||
`czstring` is a const zero terminated `char` string.
|
||||
`wzstring` is a zero terminated `wchar_t` string.
|
||||
`cwzstring` is a const zero terminated `wchar_t` string.
|
||||
`u16zstring` is a zero terminated `char16_t` string.
|
||||
`cu16zstring` is a const zero terminated `char16_t` string.
|
||||
`u32zstring` is a zero terminated `char32_t` string.
|
||||
`cu32zstring` is a const zero terminated `char32_t` string.
|
||||
|
||||
See [GSL.view](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#SS-views) and [SL.str.3: Use zstring or czstring to refer to a C-style, zero-terminated, sequence of characters](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rstr-zstring).
|
||||
|
||||
## <a name="H-util" />`<util>`
|
||||
|
||||
This header contains utility functions and classes. This header works without exceptions being available. The parts that require
|
||||
exceptions being available are in their own header file [narrow](#user-content-H-narrow).
|
||||
|
||||
See [GSL.util: Utilities](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#SS-utilities)
|
||||
|
||||
- [`gsl::narrow_cast`](#user-content-H-util-narrow_cast)
|
||||
- [`gsl::final_action`](#user-content-H-util-final_action)
|
||||
- [`gsl::at`](#user-content-H-util-at)
|
||||
|
||||
### <a name="H-util-index" />`gsl::index`
|
||||
|
||||
An alias to `std::ptrdiff_t`. It serves as the index type for all container indexes/subscripts/sizes.
|
||||
|
||||
### <a name="H-util-narrow_cast" />`gsl::narrow_cast`
|
||||
|
||||
`gsl::narrow_cast<T>(x)` is a named cast that is identical to a `static_cast<T>(x)`. It exists to make clear to static code analysis tools and to human readers that a lossy conversion is acceptable.
|
||||
|
||||
Note: compare the throwing version [`gsl::narrow`](#user-content-H-narrow-narrow) in header [narrow](#user-content-H-narrow).
|
||||
|
||||
See [ES.46: Avoid lossy (narrowing, truncating) arithmetic conversions](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-narrowing) and [ES.49: If you must use a cast, use a named cast](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-casts-named)
|
||||
|
||||
### <a name="H-util-final_action" />`gsl::final_action`
|
||||
|
||||
```cpp
|
||||
template <class F>
|
||||
class final_action { ... };
|
||||
```
|
||||
|
||||
`final_action` allows you to ensure something gets run at the end of a scope.
|
||||
|
||||
See [E.19: Use a final_action object to express cleanup if no suitable resource handle is available](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Re-finally)
|
||||
|
||||
#### Member functions
|
||||
|
||||
```cpp
|
||||
explicit final_action(const F& ff) noexcept;
|
||||
explicit final_action(F&& ff) noexcept;
|
||||
```
|
||||
|
||||
Construct an object with the action to invoke in the destructor.
|
||||
|
||||
```cpp
|
||||
~final_action() noexcept;
|
||||
```
|
||||
|
||||
The destructor will call the action that was passed in the constructor.
|
||||
|
||||
```cpp
|
||||
final_action(final_action&& other) noexcept;
|
||||
final_action(const final_action&) = delete;
|
||||
void operator=(const final_action&) = delete;
|
||||
void operator=(final_action&&) = delete;
|
||||
```
|
||||
|
||||
Move construction is allowed. Copy construction is deleted. Copy and move assignment are also explicitely deleted.
|
||||
|
||||
#### <a name="H-util-finally" />Non-member functions
|
||||
```cpp
|
||||
template <class F>
|
||||
auto finally(F&& f) noexcept;
|
||||
```
|
||||
|
||||
Creates a `gsl::final_action` object, deducing the template argument type from the type of the argument.
|
||||
|
||||
### <a name="H-util-at" />`gsl::at`
|
||||
|
||||
The function `gsl::at` offers a safe way to access data with index bounds checking.
|
||||
|
||||
Note: `gsl::at` supports indexes up to `PTRDIFF_MAX`.
|
||||
|
||||
See [ES.42: Keep use of pointers simple and straightforward](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-ptr)
|
||||
|
||||
```cpp
|
||||
template <class T, std::size_t N>
|
||||
constexpr T& at(T (&arr)[N], const index i);
|
||||
```
|
||||
|
||||
This overload returns a reference to the `i`s element of a C style array `arr`. It [`Expects`](#user-content-H-assert-expects) that the provided index is within the bounds of the array.
|
||||
|
||||
```cpp
|
||||
template <class Cont>
|
||||
constexpr auto at(Cont& cont, const index i) -> decltype(cont[cont.size()]);
|
||||
```
|
||||
|
||||
This overload returns a reference to the `i`s element of the container `cont`. It [`Expects`](#user-content-H-assert-expects) that the provided index is within the bounds of the array.
|
||||
|
||||
```cpp
|
||||
template <class T>
|
||||
constexpr T at(const std::initializer_list<T> cont, const index i);
|
||||
```
|
||||
|
||||
This overload returns a reference to the `i`s element of the initializer list `cont`. It [`Expects`](#user-content-H-assert-expects) that the provided index is within the bounds of the array.
|
||||
|
||||
```cpp
|
||||
template <class T, std::size_t extent = std::dynamic_extent>
|
||||
constexpr auto at(std::span<T, extent> sp, const index i) -> decltype(sp[sp.size()]);
|
||||
```
|
||||
|
||||
This overload returns a reference to the `i`s element of the `std::span` `sp`. It [`Expects`](#user-content-H-assert-expects) that the provided index is within the bounds of the array.
|
||||
|
||||
For [`gsl::at`](#user-content-H-span_ext-at) for [`gsl::span`](#user-content-H-span-span) see header [`span_ext`](#user-content-H-span_ext).
|
13
deps/GSL/include/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
# Add include folders to the library and targets that consume it
|
||||
# the SYSTEM keyword suppresses warnings for users of the library
|
||||
#
|
||||
# By adding this directory as an include directory the user gets a
|
||||
# namespace effect.
|
||||
#
|
||||
# IE:
|
||||
# #include <gsl/gsl>
|
||||
if(PROJECT_IS_TOP_LEVEL)
|
||||
target_include_directories(GSL INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
|
||||
else()
|
||||
target_include_directories(GSL SYSTEM INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
|
||||
endif()
|
63
deps/GSL/include/gsl/algorithm
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef GSL_ALGORITHM_H
|
||||
#define GSL_ALGORITHM_H
|
||||
|
||||
#include "assert" // for Expects
|
||||
#include "span" // for dynamic_extent, span
|
||||
|
||||
#include <algorithm> // for copy_n
|
||||
#include <cstddef> // for ptrdiff_t
|
||||
#include <type_traits> // for is_assignable
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
|
||||
// turn off some warnings that are noisy about our Expects statements
|
||||
#pragma warning(disable : 4127) // conditional expression is constant
|
||||
#pragma warning(disable : 4996) // unsafe use of std::copy_n
|
||||
|
||||
#endif // _MSC_VER
|
||||
|
||||
namespace gsl
|
||||
{
|
||||
// Note: this will generate faster code than std::copy using span iterator in older msvc+stl
|
||||
// not necessary for msvc since VS2017 15.8 (_MSC_VER >= 1915)
|
||||
template <class SrcElementType, std::size_t SrcExtent, class DestElementType,
|
||||
std::size_t DestExtent>
|
||||
void copy(span<SrcElementType, SrcExtent> src, span<DestElementType, DestExtent> dest)
|
||||
{
|
||||
static_assert(std::is_assignable<decltype(*dest.data()), decltype(*src.data())>::value,
|
||||
"Elements of source span can not be assigned to elements of destination span");
|
||||
static_assert(SrcExtent == dynamic_extent || DestExtent == dynamic_extent ||
|
||||
(SrcExtent <= DestExtent),
|
||||
"Source range is longer than target range");
|
||||
|
||||
Expects(dest.size() >= src.size());
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(stl.1) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
std::copy_n(src.data(), src.size(), dest.data());
|
||||
}
|
||||
|
||||
} // namespace gsl
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif // _MSC_VER
|
||||
|
||||
#endif // GSL_ALGORITHM_H
|
133
deps/GSL/include/gsl/assert
vendored
Normal file
@ -0,0 +1,133 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef GSL_ASSERT_H
|
||||
#define GSL_ASSERT_H
|
||||
|
||||
//
|
||||
// Temporary until MSVC STL supports no-exceptions mode.
|
||||
// Currently terminate is a no-op in this mode, so we add termination behavior back
|
||||
//
|
||||
#if defined(_MSC_VER) && (defined(_KERNEL_MODE) || (defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS))
|
||||
#define GSL_KERNEL_MODE
|
||||
|
||||
#define GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND
|
||||
#include <intrin.h>
|
||||
#define RANGE_CHECKS_FAILURE 0
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Winvalid-noreturn"
|
||||
#endif // defined(__clang__)
|
||||
|
||||
#else // defined(_MSC_VER) && (defined(_KERNEL_MODE) || (defined(_HAS_EXCEPTIONS) &&
|
||||
// !_HAS_EXCEPTIONS))
|
||||
|
||||
#include <exception>
|
||||
|
||||
#endif // defined(_MSC_VER) && (defined(_KERNEL_MODE) || (defined(_HAS_EXCEPTIONS) &&
|
||||
// !_HAS_EXCEPTIONS))
|
||||
|
||||
//
|
||||
// make suppress attributes parse for some compilers
|
||||
// Hopefully temporary until suppression standardization occurs
|
||||
//
|
||||
#if defined(__clang__)
|
||||
#define GSL_SUPPRESS(x) [[gsl::suppress(#x)]]
|
||||
#else
|
||||
#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__NVCC__)
|
||||
#define GSL_SUPPRESS(x) [[gsl::suppress(x)]]
|
||||
#else
|
||||
#define GSL_SUPPRESS(x)
|
||||
#endif // _MSC_VER
|
||||
#endif // __clang__
|
||||
|
||||
#if defined(__clang__) || defined(__GNUC__)
|
||||
#define GSL_LIKELY(x) __builtin_expect(!!(x), 1)
|
||||
#define GSL_UNLIKELY(x) __builtin_expect(!!(x), 0)
|
||||
|
||||
#else
|
||||
|
||||
#define GSL_LIKELY(x) (!!(x))
|
||||
#define GSL_UNLIKELY(x) (!!(x))
|
||||
#endif // defined(__clang__) || defined(__GNUC__)
|
||||
|
||||
//
|
||||
// GSL_ASSUME(cond)
|
||||
//
|
||||
// Tell the optimizer that the predicate cond must hold. It is unspecified
|
||||
// whether or not cond is actually evaluated.
|
||||
//
|
||||
#ifdef _MSC_VER
|
||||
#define GSL_ASSUME(cond) __assume(cond)
|
||||
#elif defined(__GNUC__)
|
||||
#define GSL_ASSUME(cond) ((cond) ? static_cast<void>(0) : __builtin_unreachable())
|
||||
#else
|
||||
#define GSL_ASSUME(cond) static_cast<void>((cond) ? 0 : 0)
|
||||
#endif
|
||||
|
||||
//
|
||||
// GSL.assert: assertions
|
||||
//
|
||||
|
||||
namespace gsl
|
||||
{
|
||||
|
||||
namespace details
|
||||
{
|
||||
#if defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND)
|
||||
|
||||
typedef void(__cdecl* terminate_handler)();
|
||||
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(f.6) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
[[noreturn]] inline void __cdecl default_terminate_handler()
|
||||
{
|
||||
__fastfail(RANGE_CHECKS_FAILURE);
|
||||
}
|
||||
|
||||
inline gsl::details::terminate_handler& get_terminate_handler() noexcept
|
||||
{
|
||||
static terminate_handler handler = &default_terminate_handler;
|
||||
return handler;
|
||||
}
|
||||
|
||||
#endif // defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND)
|
||||
|
||||
[[noreturn]] inline void terminate() noexcept
|
||||
{
|
||||
#if defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND)
|
||||
(*gsl::details::get_terminate_handler())();
|
||||
#else
|
||||
std::terminate();
|
||||
#endif // defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND)
|
||||
}
|
||||
|
||||
} // namespace details
|
||||
} // namespace gsl
|
||||
|
||||
#define GSL_CONTRACT_CHECK(type, cond) \
|
||||
(GSL_LIKELY(cond) ? static_cast<void>(0) : gsl::details::terminate())
|
||||
|
||||
#define Expects(cond) GSL_CONTRACT_CHECK("Precondition", cond)
|
||||
#define Ensures(cond) GSL_CONTRACT_CHECK("Postcondition", cond)
|
||||
|
||||
#if defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND) && defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif // GSL_ASSERT_H
|
188
deps/GSL/include/gsl/byte
vendored
Normal file
@ -0,0 +1,188 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef GSL_BYTE_H
|
||||
#define GSL_BYTE_H
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
// VS2017 15.8 added support for the __cpp_lib_byte definition
|
||||
// To do: drop _HAS_STD_BYTE when support for pre 15.8 expires
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#pragma warning(push)
|
||||
|
||||
// Turn MSVC /analyze rules that generate too much noise. TODO: fix in the tool.
|
||||
#pragma warning(disable : 26493) // don't use c-style casts // TODO: MSVC suppression in templates
|
||||
// does not always work
|
||||
|
||||
#ifndef GSL_USE_STD_BYTE
|
||||
// this tests if we are under MSVC and the standard lib has std::byte and it is enabled
|
||||
#if (defined(_HAS_STD_BYTE) && _HAS_STD_BYTE) || \
|
||||
(defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603)
|
||||
|
||||
#define GSL_USE_STD_BYTE 1
|
||||
|
||||
#else // (defined(_HAS_STD_BYTE) && _HAS_STD_BYTE) || (defined(__cpp_lib_byte) && __cpp_lib_byte >=
|
||||
// 201603)
|
||||
|
||||
#define GSL_USE_STD_BYTE 0
|
||||
|
||||
#endif // (defined(_HAS_STD_BYTE) && _HAS_STD_BYTE) || (defined(__cpp_lib_byte) && __cpp_lib_byte >=
|
||||
// 201603)
|
||||
#endif // GSL_USE_STD_BYTE
|
||||
|
||||
#else // _MSC_VER
|
||||
|
||||
#ifndef GSL_USE_STD_BYTE
|
||||
#include <cstddef> /* __cpp_lib_byte */
|
||||
// this tests if we are under GCC or Clang with enough -std=c++1z power to get us std::byte
|
||||
// also check if libc++ version is sufficient (> 5.0) or libstdc++ actually contains std::byte
|
||||
#if defined(__cplusplus) && (__cplusplus >= 201703L) && \
|
||||
(defined(__cpp_lib_byte) && (__cpp_lib_byte >= 201603) || \
|
||||
defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION >= 5000))
|
||||
|
||||
#define GSL_USE_STD_BYTE 1
|
||||
|
||||
#else // defined(__cplusplus) && (__cplusplus >= 201703L) &&
|
||||
// (defined(__cpp_lib_byte) && (__cpp_lib_byte >= 201603) ||
|
||||
// defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION >= 5000))
|
||||
|
||||
#define GSL_USE_STD_BYTE 0
|
||||
|
||||
#endif // defined(__cplusplus) && (__cplusplus >= 201703L) &&
|
||||
// (defined(__cpp_lib_byte) && (__cpp_lib_byte >= 201603) ||
|
||||
// defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION >= 5000))
|
||||
#endif // GSL_USE_STD_BYTE
|
||||
|
||||
#endif // _MSC_VER
|
||||
|
||||
// Use __may_alias__ attribute on gcc and clang
|
||||
#if defined __clang__ || (defined(__GNUC__) && __GNUC__ > 5)
|
||||
#define byte_may_alias __attribute__((__may_alias__))
|
||||
#else // defined __clang__ || defined __GNUC__
|
||||
#define byte_may_alias
|
||||
#endif // defined __clang__ || defined __GNUC__
|
||||
|
||||
#if GSL_USE_STD_BYTE
|
||||
#include <cstddef>
|
||||
#endif
|
||||
|
||||
namespace gsl
|
||||
{
|
||||
#if GSL_USE_STD_BYTE
|
||||
|
||||
using std::byte;
|
||||
using std::to_integer;
|
||||
|
||||
#else // GSL_USE_STD_BYTE
|
||||
|
||||
// This is a simple definition for now that allows
|
||||
// use of byte within span<> to be standards-compliant
|
||||
enum class byte_may_alias byte : unsigned char
|
||||
{
|
||||
};
|
||||
|
||||
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
|
||||
constexpr byte& operator<<=(byte& b, IntegerType shift) noexcept
|
||||
{
|
||||
return b = byte(static_cast<unsigned char>(b) << shift);
|
||||
}
|
||||
|
||||
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
|
||||
constexpr byte operator<<(byte b, IntegerType shift) noexcept
|
||||
{
|
||||
return byte(static_cast<unsigned char>(b) << shift);
|
||||
}
|
||||
|
||||
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
|
||||
constexpr byte& operator>>=(byte& b, IntegerType shift) noexcept
|
||||
{
|
||||
return b = byte(static_cast<unsigned char>(b) >> shift);
|
||||
}
|
||||
|
||||
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
|
||||
constexpr byte operator>>(byte b, IntegerType shift) noexcept
|
||||
{
|
||||
return byte(static_cast<unsigned char>(b) >> shift);
|
||||
}
|
||||
|
||||
constexpr byte& operator|=(byte& l, byte r) noexcept
|
||||
{
|
||||
return l = byte(static_cast<unsigned char>(l) | static_cast<unsigned char>(r));
|
||||
}
|
||||
|
||||
constexpr byte operator|(byte l, byte r) noexcept
|
||||
{
|
||||
return byte(static_cast<unsigned char>(l) | static_cast<unsigned char>(r));
|
||||
}
|
||||
|
||||
constexpr byte& operator&=(byte& l, byte r) noexcept
|
||||
{
|
||||
return l = byte(static_cast<unsigned char>(l) & static_cast<unsigned char>(r));
|
||||
}
|
||||
|
||||
constexpr byte operator&(byte l, byte r) noexcept
|
||||
{
|
||||
return byte(static_cast<unsigned char>(l) & static_cast<unsigned char>(r));
|
||||
}
|
||||
|
||||
constexpr byte& operator^=(byte& l, byte r) noexcept
|
||||
{
|
||||
return l = byte(static_cast<unsigned char>(l) ^ static_cast<unsigned char>(r));
|
||||
}
|
||||
|
||||
constexpr byte operator^(byte l, byte r) noexcept
|
||||
{
|
||||
return byte(static_cast<unsigned char>(l) ^ static_cast<unsigned char>(r));
|
||||
}
|
||||
|
||||
constexpr byte operator~(byte b) noexcept { return byte(~static_cast<unsigned char>(b)); }
|
||||
|
||||
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
|
||||
constexpr IntegerType to_integer(byte b) noexcept
|
||||
{
|
||||
return static_cast<IntegerType>(b);
|
||||
}
|
||||
|
||||
#endif // GSL_USE_STD_BYTE
|
||||
|
||||
template <typename T>
|
||||
// NOTE: need suppression since c++14 does not allow "return {t}"
|
||||
// GSL_SUPPRESS(type.4) // NO-FORMAT: attribute // TODO: suppression does not work
|
||||
constexpr byte to_byte(T t) noexcept
|
||||
{
|
||||
static_assert(std::is_same<T, unsigned char>::value,
|
||||
"gsl::to_byte(t) must be provided an unsigned char, otherwise data loss may occur. "
|
||||
"If you are calling to_byte with an integer constant use: gsl::to_byte<t>() version.");
|
||||
return byte(t);
|
||||
}
|
||||
|
||||
template <int I>
|
||||
constexpr byte to_byte() noexcept
|
||||
{
|
||||
static_assert(I >= 0 && I <= 255,
|
||||
"gsl::byte only has 8 bits of storage, values must be in range 0-255");
|
||||
return static_cast<byte>(I);
|
||||
}
|
||||
|
||||
} // namespace gsl
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif // _MSC_VER
|
||||
|
||||
#endif // GSL_BYTE_H
|
32
deps/GSL/include/gsl/gsl
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef GSL_GSL_H
|
||||
#define GSL_GSL_H
|
||||
|
||||
#include "algorithm" // copy
|
||||
#include "assert" // Ensures/Expects
|
||||
#include "byte" // byte
|
||||
#include "pointers" // owner, not_null
|
||||
#include "span" // span
|
||||
#include "zstring" // zstring
|
||||
#include "util" // finally()/narrow_cast()...
|
||||
|
||||
#ifdef __cpp_exceptions
|
||||
#include "narrow" // narrow()
|
||||
#endif
|
||||
|
||||
#endif // GSL_GSL_H
|
84
deps/GSL/include/gsl/narrow
vendored
Normal file
@ -0,0 +1,84 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef GSL_NARROW_H
|
||||
#define GSL_NARROW_H
|
||||
#include "assert" // for GSL_SUPPRESS
|
||||
#include "util" // for narrow_cast
|
||||
#include <exception> // for std::exception
|
||||
namespace gsl
|
||||
{
|
||||
struct narrowing_error : public std::exception
|
||||
{
|
||||
const char* what() const noexcept override { return "narrowing_error"; }
|
||||
};
|
||||
|
||||
// narrow() : a checked version of narrow_cast() that throws if the cast changed the value
|
||||
template <class T, class U, typename std::enable_if<std::is_arithmetic<T>::value>::type* = nullptr>
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
|
||||
GSL_SUPPRESS(f.6) // NO-FORMAT: attribute // TODO: MSVC /analyze does not recognise noexcept(false)
|
||||
GSL_SUPPRESS(es.46) // NO-FORMAT: attribute // The warning suggests that a floating->unsigned conversion can occur
|
||||
// in the static_cast below, and that gsl::narrow should be used instead.
|
||||
// Suppress this warning, since gsl::narrow is defined in terms of
|
||||
// static_cast
|
||||
// clang-format on
|
||||
constexpr T narrow(U u) noexcept(false)
|
||||
{
|
||||
constexpr const bool is_different_signedness =
|
||||
(std::is_signed<T>::value != std::is_signed<U>::value);
|
||||
|
||||
GSL_SUPPRESS(es.103) // NO-FORMAT: attribute // don't overflow
|
||||
GSL_SUPPRESS(es.104) // NO-FORMAT: attribute // don't underflow
|
||||
GSL_SUPPRESS(p.2) // NO-FORMAT: attribute // don't rely on undefined behavior
|
||||
const T t = narrow_cast<T>(u); // While this is technically undefined behavior in some cases (i.e., if the source value is of floating-point type
|
||||
// and cannot fit into the destination integral type), the resultant behavior is benign on the platforms
|
||||
// that we target (i.e., no hardware trap representations are hit).
|
||||
|
||||
#if defined(__clang__) || defined(__GNUC__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||
#endif
|
||||
// Note: NaN will always throw, since NaN != NaN
|
||||
if (static_cast<U>(t) != u || (is_different_signedness && ((t < T{}) != (u < U{}))))
|
||||
{
|
||||
throw narrowing_error{};
|
||||
}
|
||||
#if defined(__clang__) || defined(__GNUC__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
template <class T, class U, typename std::enable_if<!std::is_arithmetic<T>::value>::type* = nullptr>
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
|
||||
GSL_SUPPRESS(f.6) // NO-FORMAT: attribute // TODO: MSVC /analyze does not recognise noexcept(false)
|
||||
// clang-format on
|
||||
constexpr T narrow(U u) noexcept(false)
|
||||
{
|
||||
const T t = narrow_cast<T>(u);
|
||||
|
||||
if (static_cast<U>(t) != u)
|
||||
{
|
||||
throw narrowing_error{};
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
} // namespace gsl
|
||||
#endif // GSL_NARROW_H
|
348
deps/GSL/include/gsl/pointers
vendored
Normal file
@ -0,0 +1,348 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef GSL_POINTERS_H
|
||||
#define GSL_POINTERS_H
|
||||
|
||||
#include "assert" // for Ensures, Expects
|
||||
|
||||
#include <algorithm> // for forward
|
||||
#include <cstddef> // for ptrdiff_t, nullptr_t, size_t
|
||||
#include <memory> // for shared_ptr, unique_ptr
|
||||
#include <system_error> // for hash
|
||||
#include <type_traits> // for enable_if_t, is_convertible, is_assignable
|
||||
#include <utility> // for declval
|
||||
|
||||
#if !defined(GSL_NO_IOSTREAMS)
|
||||
#include <iosfwd> // for ostream
|
||||
#endif // !defined(GSL_NO_IOSTREAMS)
|
||||
|
||||
namespace gsl
|
||||
{
|
||||
|
||||
namespace details
|
||||
{
|
||||
template <typename T, typename = void>
|
||||
struct is_comparable_to_nullptr : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct is_comparable_to_nullptr<
|
||||
T,
|
||||
std::enable_if_t<std::is_convertible<decltype(std::declval<T>() != nullptr), bool>::value>>
|
||||
: std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
// Resolves to the more efficient of `const T` or `const T&`, in the context of returning a const-qualified value
|
||||
// of type T.
|
||||
//
|
||||
// Copied from cppfront's implementation of the CppCoreGuidelines F.16 (https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rf-in)
|
||||
template<typename T>
|
||||
using value_or_reference_return_t = std::conditional_t<
|
||||
sizeof(T) < 2*sizeof(void*) && std::is_trivially_copy_constructible<T>::value,
|
||||
const T,
|
||||
const T&>;
|
||||
|
||||
} // namespace details
|
||||
|
||||
//
|
||||
// GSL.owner: ownership pointers
|
||||
//
|
||||
using std::shared_ptr;
|
||||
using std::unique_ptr;
|
||||
|
||||
//
|
||||
// owner
|
||||
//
|
||||
// `gsl::owner<T>` is designed as a safety mechanism for code that must deal directly with raw pointers that own memory.
|
||||
// Ideally such code should be restricted to the implementation of low-level abstractions. `gsl::owner` can also be used
|
||||
// as a stepping point in converting legacy code to use more modern RAII constructs, such as smart pointers.
|
||||
//
|
||||
// T must be a pointer type
|
||||
// - disallow construction from any type other than pointer type
|
||||
//
|
||||
template <class T, class = std::enable_if_t<std::is_pointer<T>::value>>
|
||||
using owner = T;
|
||||
|
||||
//
|
||||
// not_null
|
||||
//
|
||||
// Restricts a pointer or smart pointer to only hold non-null values.
|
||||
//
|
||||
// Has zero size overhead over T.
|
||||
//
|
||||
// If T is a pointer (i.e. T == U*) then
|
||||
// - allow construction from U*
|
||||
// - disallow construction from nullptr_t
|
||||
// - disallow default construction
|
||||
// - ensure construction from null U* fails
|
||||
// - allow implicit conversion to U*
|
||||
//
|
||||
template <class T>
|
||||
class not_null
|
||||
{
|
||||
public:
|
||||
static_assert(details::is_comparable_to_nullptr<T>::value, "T cannot be compared to nullptr.");
|
||||
|
||||
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
|
||||
constexpr not_null(U&& u) noexcept(std::is_nothrow_move_constructible<T>::value) : ptr_(std::forward<U>(u))
|
||||
{
|
||||
Expects(ptr_ != nullptr);
|
||||
}
|
||||
|
||||
template <typename = std::enable_if_t<!std::is_same<std::nullptr_t, T>::value>>
|
||||
constexpr not_null(T u) noexcept(std::is_nothrow_move_constructible<T>::value) : ptr_(std::move(u))
|
||||
{
|
||||
Expects(ptr_ != nullptr);
|
||||
}
|
||||
|
||||
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
|
||||
constexpr not_null(const not_null<U>& other) noexcept(std::is_nothrow_move_constructible<T>::value) : not_null(other.get())
|
||||
{}
|
||||
|
||||
not_null(const not_null& other) = default;
|
||||
not_null& operator=(const not_null& other) = default;
|
||||
constexpr details::value_or_reference_return_t<T> get() const
|
||||
noexcept(noexcept(details::value_or_reference_return_t<T>{std::declval<T&>()}))
|
||||
{
|
||||
return ptr_;
|
||||
}
|
||||
|
||||
constexpr operator T() const { return get(); }
|
||||
constexpr decltype(auto) operator->() const { return get(); }
|
||||
constexpr decltype(auto) operator*() const { return *get(); }
|
||||
|
||||
// prevents compilation when someone attempts to assign a null pointer constant
|
||||
not_null(std::nullptr_t) = delete;
|
||||
not_null& operator=(std::nullptr_t) = delete;
|
||||
|
||||
// unwanted operators...pointers only point to single objects!
|
||||
not_null& operator++() = delete;
|
||||
not_null& operator--() = delete;
|
||||
not_null operator++(int) = delete;
|
||||
not_null operator--(int) = delete;
|
||||
not_null& operator+=(std::ptrdiff_t) = delete;
|
||||
not_null& operator-=(std::ptrdiff_t) = delete;
|
||||
void operator[](std::ptrdiff_t) const = delete;
|
||||
|
||||
private:
|
||||
T ptr_;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
auto make_not_null(T&& t) noexcept
|
||||
{
|
||||
return not_null<std::remove_cv_t<std::remove_reference_t<T>>>{std::forward<T>(t)};
|
||||
}
|
||||
|
||||
#if !defined(GSL_NO_IOSTREAMS)
|
||||
template <class T>
|
||||
std::ostream& operator<<(std::ostream& os, const not_null<T>& val)
|
||||
{
|
||||
os << val.get();
|
||||
return os;
|
||||
}
|
||||
#endif // !defined(GSL_NO_IOSTREAMS)
|
||||
|
||||
template <class T, class U>
|
||||
auto operator==(const not_null<T>& lhs,
|
||||
const not_null<U>& rhs) noexcept(noexcept(lhs.get() == rhs.get()))
|
||||
-> decltype(lhs.get() == rhs.get())
|
||||
{
|
||||
return lhs.get() == rhs.get();
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
auto operator!=(const not_null<T>& lhs,
|
||||
const not_null<U>& rhs) noexcept(noexcept(lhs.get() != rhs.get()))
|
||||
-> decltype(lhs.get() != rhs.get())
|
||||
{
|
||||
return lhs.get() != rhs.get();
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
auto operator<(const not_null<T>& lhs,
|
||||
const not_null<U>& rhs) noexcept(noexcept(std::less<>{}(lhs.get(), rhs.get())))
|
||||
-> decltype(std::less<>{}(lhs.get(), rhs.get()))
|
||||
{
|
||||
return std::less<>{}(lhs.get(), rhs.get());
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
auto operator<=(const not_null<T>& lhs,
|
||||
const not_null<U>& rhs) noexcept(noexcept(std::less_equal<>{}(lhs.get(), rhs.get())))
|
||||
-> decltype(std::less_equal<>{}(lhs.get(), rhs.get()))
|
||||
{
|
||||
return std::less_equal<>{}(lhs.get(), rhs.get());
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
auto operator>(const not_null<T>& lhs,
|
||||
const not_null<U>& rhs) noexcept(noexcept(std::greater<>{}(lhs.get(), rhs.get())))
|
||||
-> decltype(std::greater<>{}(lhs.get(), rhs.get()))
|
||||
{
|
||||
return std::greater<>{}(lhs.get(), rhs.get());
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
auto operator>=(const not_null<T>& lhs,
|
||||
const not_null<U>& rhs) noexcept(noexcept(std::greater_equal<>{}(lhs.get(), rhs.get())))
|
||||
-> decltype(std::greater_equal<>{}(lhs.get(), rhs.get()))
|
||||
{
|
||||
return std::greater_equal<>{}(lhs.get(), rhs.get());
|
||||
}
|
||||
|
||||
// more unwanted operators
|
||||
template <class T, class U>
|
||||
std::ptrdiff_t operator-(const not_null<T>&, const not_null<U>&) = delete;
|
||||
template <class T>
|
||||
not_null<T> operator-(const not_null<T>&, std::ptrdiff_t) = delete;
|
||||
template <class T>
|
||||
not_null<T> operator+(const not_null<T>&, std::ptrdiff_t) = delete;
|
||||
template <class T>
|
||||
not_null<T> operator+(std::ptrdiff_t, const not_null<T>&) = delete;
|
||||
|
||||
|
||||
template <class T, class U = decltype(std::declval<const T&>().get()), bool = std::is_default_constructible<std::hash<U>>::value>
|
||||
struct not_null_hash
|
||||
{
|
||||
std::size_t operator()(const T& value) const { return std::hash<U>{}(value.get()); }
|
||||
};
|
||||
|
||||
template <class T, class U>
|
||||
struct not_null_hash<T, U, false>
|
||||
{
|
||||
not_null_hash() = delete;
|
||||
not_null_hash(const not_null_hash&) = delete;
|
||||
not_null_hash& operator=(const not_null_hash&) = delete;
|
||||
};
|
||||
|
||||
} // namespace gsl
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <class T>
|
||||
struct hash<gsl::not_null<T>> : gsl::not_null_hash<gsl::not_null<T>>
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
namespace gsl
|
||||
{
|
||||
|
||||
//
|
||||
// strict_not_null
|
||||
//
|
||||
// Restricts a pointer or smart pointer to only hold non-null values,
|
||||
//
|
||||
// - provides a strict (i.e. explicit constructor from T) wrapper of not_null
|
||||
// - to be used for new code that wishes the design to be cleaner and make not_null
|
||||
// checks intentional, or in old code that would like to make the transition.
|
||||
//
|
||||
// To make the transition from not_null, incrementally replace not_null
|
||||
// by strict_not_null and fix compilation errors
|
||||
//
|
||||
// Expect to
|
||||
// - remove all unneeded conversions from raw pointer to not_null and back
|
||||
// - make API clear by specifying not_null in parameters where needed
|
||||
// - remove unnecessary asserts
|
||||
//
|
||||
template <class T>
|
||||
class strict_not_null : public not_null<T>
|
||||
{
|
||||
public:
|
||||
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
|
||||
constexpr explicit strict_not_null(U&& u) : not_null<T>(std::forward<U>(u))
|
||||
{}
|
||||
|
||||
template <typename = std::enable_if_t<!std::is_same<std::nullptr_t, T>::value>>
|
||||
constexpr explicit strict_not_null(T u) : not_null<T>(u)
|
||||
{}
|
||||
|
||||
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
|
||||
constexpr strict_not_null(const not_null<U>& other) : not_null<T>(other)
|
||||
{}
|
||||
|
||||
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
|
||||
constexpr strict_not_null(const strict_not_null<U>& other) : not_null<T>(other)
|
||||
{}
|
||||
|
||||
// To avoid invalidating the "not null" invariant, the contained pointer is actually copied
|
||||
// instead of moved. If it is a custom pointer, its constructor could in theory throw exceptions.
|
||||
strict_not_null(strict_not_null&& other) noexcept(std::is_nothrow_copy_constructible<T>::value) = default;
|
||||
strict_not_null(const strict_not_null& other) = default;
|
||||
strict_not_null& operator=(const strict_not_null& other) = default;
|
||||
strict_not_null& operator=(const not_null<T>& other)
|
||||
{
|
||||
not_null<T>::operator=(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// prevents compilation when someone attempts to assign a null pointer constant
|
||||
strict_not_null(std::nullptr_t) = delete;
|
||||
strict_not_null& operator=(std::nullptr_t) = delete;
|
||||
|
||||
// unwanted operators...pointers only point to single objects!
|
||||
strict_not_null& operator++() = delete;
|
||||
strict_not_null& operator--() = delete;
|
||||
strict_not_null operator++(int) = delete;
|
||||
strict_not_null operator--(int) = delete;
|
||||
strict_not_null& operator+=(std::ptrdiff_t) = delete;
|
||||
strict_not_null& operator-=(std::ptrdiff_t) = delete;
|
||||
void operator[](std::ptrdiff_t) const = delete;
|
||||
};
|
||||
|
||||
// more unwanted operators
|
||||
template <class T, class U>
|
||||
std::ptrdiff_t operator-(const strict_not_null<T>&, const strict_not_null<U>&) = delete;
|
||||
template <class T>
|
||||
strict_not_null<T> operator-(const strict_not_null<T>&, std::ptrdiff_t) = delete;
|
||||
template <class T>
|
||||
strict_not_null<T> operator+(const strict_not_null<T>&, std::ptrdiff_t) = delete;
|
||||
template <class T>
|
||||
strict_not_null<T> operator+(std::ptrdiff_t, const strict_not_null<T>&) = delete;
|
||||
|
||||
template <class T>
|
||||
auto make_strict_not_null(T&& t) noexcept
|
||||
{
|
||||
return strict_not_null<std::remove_cv_t<std::remove_reference_t<T>>>{std::forward<T>(t)};
|
||||
}
|
||||
|
||||
#if (defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L))
|
||||
|
||||
// deduction guides to prevent the ctad-maybe-unsupported warning
|
||||
template <class T>
|
||||
not_null(T) -> not_null<T>;
|
||||
template <class T>
|
||||
strict_not_null(T) -> strict_not_null<T>;
|
||||
|
||||
#endif // ( defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L) )
|
||||
|
||||
} // namespace gsl
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <class T>
|
||||
struct hash<gsl::strict_not_null<T>> : gsl::not_null_hash<gsl::strict_not_null<T>>
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
#endif // GSL_POINTERS_H
|
849
deps/GSL/include/gsl/span
vendored
Normal file
@ -0,0 +1,849 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef GSL_SPAN_H
|
||||
#define GSL_SPAN_H
|
||||
|
||||
#include "assert" // for Expects
|
||||
#include "byte" // for byte
|
||||
#include "span_ext" // for span specialization of gsl::at and other span-related extensions
|
||||
#include "util" // for narrow_cast
|
||||
|
||||
#include <array> // for array
|
||||
#include <cstddef> // for ptrdiff_t, size_t, nullptr_t
|
||||
#include <iterator> // for reverse_iterator, distance, random_access_...
|
||||
#include <memory> // for pointer_traits
|
||||
#include <type_traits> // for enable_if_t, declval, is_convertible, inte...
|
||||
|
||||
#if defined(__has_include) && __has_include(<version>)
|
||||
#include <version>
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
#pragma warning(push)
|
||||
|
||||
// turn off some warnings that are noisy about our Expects statements
|
||||
#pragma warning(disable : 4127) // conditional expression is constant
|
||||
#pragma warning( \
|
||||
disable : 4146) // unary minus operator applied to unsigned type, result still unsigned
|
||||
#pragma warning(disable : 4702) // unreachable code
|
||||
|
||||
// Turn MSVC /analyze rules that generate too much noise. TODO: fix in the tool.
|
||||
#pragma warning(disable : 26495) // uninitialized member when constructor calls constructor
|
||||
#pragma warning(disable : 26446) // parser bug does not allow attributes on some templates
|
||||
|
||||
#endif // _MSC_VER
|
||||
|
||||
// See if we have enough C++17 power to use a static constexpr data member
|
||||
// without needing an out-of-line definition
|
||||
#if !(defined(__cplusplus) && (__cplusplus >= 201703L))
|
||||
#define GSL_USE_STATIC_CONSTEXPR_WORKAROUND
|
||||
#endif // !(defined(__cplusplus) && (__cplusplus >= 201703L))
|
||||
|
||||
// GCC 7 does not like the signed unsigned mismatch (size_t ptrdiff_t)
|
||||
// While there is a conversion from signed to unsigned, it happens at
|
||||
// compiletime, so the compiler wouldn't have to warn indiscriminately, but
|
||||
// could check if the source value actually doesn't fit into the target type
|
||||
// and only warn in those cases.
|
||||
#if defined(__GNUC__) && __GNUC__ > 6
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wsign-conversion"
|
||||
#endif
|
||||
|
||||
namespace gsl
|
||||
{
|
||||
|
||||
// implementation details
|
||||
namespace details
|
||||
{
|
||||
template <class T>
|
||||
struct is_span_oracle : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <class ElementType, std::size_t Extent>
|
||||
struct is_span_oracle<gsl::span<ElementType, Extent>> : std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct is_span : public is_span_oracle<std::remove_cv_t<T>>
|
||||
{
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct is_std_array_oracle : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <class ElementType, std::size_t Extent>
|
||||
struct is_std_array_oracle<std::array<ElementType, Extent>> : std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct is_std_array : is_std_array_oracle<std::remove_cv_t<T>>
|
||||
{
|
||||
};
|
||||
|
||||
template <std::size_t From, std::size_t To>
|
||||
struct is_allowed_extent_conversion
|
||||
: std::integral_constant<bool, From == To || To == dynamic_extent>
|
||||
{
|
||||
};
|
||||
|
||||
template <class From, class To>
|
||||
struct is_allowed_element_type_conversion
|
||||
: std::integral_constant<bool, std::is_convertible<From (*)[], To (*)[]>::value>
|
||||
{
|
||||
};
|
||||
|
||||
template <class Type>
|
||||
class span_iterator
|
||||
{
|
||||
public:
|
||||
#if defined(__cpp_lib_ranges) || (defined(_MSVC_STL_VERSION) && defined(__cpp_lib_concepts))
|
||||
using iterator_concept = std::contiguous_iterator_tag;
|
||||
#endif // __cpp_lib_ranges
|
||||
using iterator_category = std::random_access_iterator_tag;
|
||||
using value_type = std::remove_cv_t<Type>;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = Type*;
|
||||
using reference = Type&;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
using _Unchecked_type = pointer;
|
||||
using _Prevent_inheriting_unwrap = span_iterator;
|
||||
#endif // _MSC_VER
|
||||
constexpr span_iterator() = default;
|
||||
|
||||
constexpr span_iterator(pointer begin, pointer end, pointer current)
|
||||
: begin_(begin), end_(end), current_(current)
|
||||
{}
|
||||
|
||||
constexpr operator span_iterator<const Type>() const noexcept
|
||||
{
|
||||
return {begin_, end_, current_};
|
||||
}
|
||||
|
||||
constexpr reference operator*() const noexcept
|
||||
{
|
||||
Expects(begin_ && end_);
|
||||
Expects(begin_ <= current_ && current_ < end_);
|
||||
return *current_;
|
||||
}
|
||||
|
||||
constexpr pointer operator->() const noexcept
|
||||
{
|
||||
Expects(begin_ && end_);
|
||||
Expects(begin_ <= current_ && current_ < end_);
|
||||
return current_;
|
||||
}
|
||||
constexpr span_iterator& operator++() noexcept
|
||||
{
|
||||
Expects(begin_ && current_ && end_);
|
||||
Expects(current_ < end_);
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
++current_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr span_iterator operator++(int) noexcept
|
||||
{
|
||||
span_iterator ret = *this;
|
||||
++*this;
|
||||
return ret;
|
||||
}
|
||||
|
||||
constexpr span_iterator& operator--() noexcept
|
||||
{
|
||||
Expects(begin_ && end_);
|
||||
Expects(begin_ < current_);
|
||||
--current_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr span_iterator operator--(int) noexcept
|
||||
{
|
||||
span_iterator ret = *this;
|
||||
--*this;
|
||||
return ret;
|
||||
}
|
||||
|
||||
constexpr span_iterator& operator+=(const difference_type n) noexcept
|
||||
{
|
||||
if (n != 0) Expects(begin_ && current_ && end_);
|
||||
if (n > 0) Expects(end_ - current_ >= n);
|
||||
if (n < 0) Expects(current_ - begin_ >= -n);
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
current_ += n;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr span_iterator operator+(const difference_type n) const noexcept
|
||||
{
|
||||
span_iterator ret = *this;
|
||||
ret += n;
|
||||
return ret;
|
||||
}
|
||||
|
||||
friend constexpr span_iterator operator+(const difference_type n,
|
||||
const span_iterator& rhs) noexcept
|
||||
{
|
||||
return rhs + n;
|
||||
}
|
||||
|
||||
constexpr span_iterator& operator-=(const difference_type n) noexcept
|
||||
{
|
||||
if (n != 0) Expects(begin_ && current_ && end_);
|
||||
if (n > 0) Expects(current_ - begin_ >= n);
|
||||
if (n < 0) Expects(end_ - current_ >= -n);
|
||||
GSL_SUPPRESS(bounds .1)
|
||||
current_ -= n;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr span_iterator operator-(const difference_type n) const noexcept
|
||||
{
|
||||
span_iterator ret = *this;
|
||||
ret -= n;
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <
|
||||
class Type2,
|
||||
std::enable_if_t<std::is_same<std::remove_cv_t<Type2>, value_type>::value, int> = 0>
|
||||
constexpr difference_type operator-(const span_iterator<Type2>& rhs) const noexcept
|
||||
{
|
||||
Expects(begin_ == rhs.begin_ && end_ == rhs.end_);
|
||||
return current_ - rhs.current_;
|
||||
}
|
||||
|
||||
constexpr reference operator[](const difference_type n) const noexcept
|
||||
{
|
||||
return *(*this + n);
|
||||
}
|
||||
|
||||
template <
|
||||
class Type2,
|
||||
std::enable_if_t<std::is_same<std::remove_cv_t<Type2>, value_type>::value, int> = 0>
|
||||
constexpr bool operator==(const span_iterator<Type2>& rhs) const noexcept
|
||||
{
|
||||
Expects(begin_ == rhs.begin_ && end_ == rhs.end_);
|
||||
return current_ == rhs.current_;
|
||||
}
|
||||
|
||||
template <
|
||||
class Type2,
|
||||
std::enable_if_t<std::is_same<std::remove_cv_t<Type2>, value_type>::value, int> = 0>
|
||||
constexpr bool operator!=(const span_iterator<Type2>& rhs) const noexcept
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
template <
|
||||
class Type2,
|
||||
std::enable_if_t<std::is_same<std::remove_cv_t<Type2>, value_type>::value, int> = 0>
|
||||
constexpr bool operator<(const span_iterator<Type2>& rhs) const noexcept
|
||||
{
|
||||
Expects(begin_ == rhs.begin_ && end_ == rhs.end_);
|
||||
return current_ < rhs.current_;
|
||||
}
|
||||
|
||||
template <
|
||||
class Type2,
|
||||
std::enable_if_t<std::is_same<std::remove_cv_t<Type2>, value_type>::value, int> = 0>
|
||||
constexpr bool operator>(const span_iterator<Type2>& rhs) const noexcept
|
||||
{
|
||||
return rhs < *this;
|
||||
}
|
||||
|
||||
template <
|
||||
class Type2,
|
||||
std::enable_if_t<std::is_same<std::remove_cv_t<Type2>, value_type>::value, int> = 0>
|
||||
constexpr bool operator<=(const span_iterator<Type2>& rhs) const noexcept
|
||||
{
|
||||
return !(rhs < *this);
|
||||
}
|
||||
|
||||
template <
|
||||
class Type2,
|
||||
std::enable_if_t<std::is_same<std::remove_cv_t<Type2>, value_type>::value, int> = 0>
|
||||
constexpr bool operator>=(const span_iterator<Type2>& rhs) const noexcept
|
||||
{
|
||||
return !(*this < rhs);
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// MSVC++ iterator debugging support; allows STL algorithms in 15.8+
|
||||
// to unwrap span_iterator to a pointer type after a range check in STL
|
||||
// algorithm calls
|
||||
friend constexpr void _Verify_range(span_iterator lhs, span_iterator rhs) noexcept
|
||||
{ // test that [lhs, rhs) forms a valid range inside an STL algorithm
|
||||
Expects(lhs.begin_ == rhs.begin_ // range spans have to match
|
||||
&& lhs.end_ == rhs.end_ &&
|
||||
lhs.current_ <= rhs.current_); // range must not be transposed
|
||||
}
|
||||
|
||||
constexpr void _Verify_offset(const difference_type n) const noexcept
|
||||
{ // test that *this + n is within the range of this call
|
||||
if (n != 0) Expects(begin_ && current_ && end_);
|
||||
if (n > 0) Expects(end_ - current_ >= n);
|
||||
if (n < 0) Expects(current_ - begin_ >= -n);
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
constexpr pointer _Unwrapped() const noexcept
|
||||
{ // after seeking *this to a high water mark, or using one of the
|
||||
// _Verify_xxx functions above, unwrap this span_iterator to a raw
|
||||
// pointer
|
||||
return current_;
|
||||
}
|
||||
|
||||
// Tell the STL that span_iterator should not be unwrapped if it can't
|
||||
// validate in advance, even in release / optimized builds:
|
||||
#if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND)
|
||||
static constexpr const bool _Unwrap_when_unverified = false;
|
||||
#else
|
||||
static constexpr bool _Unwrap_when_unverified = false;
|
||||
#endif
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(con.3) // NO-FORMAT: attribute // TODO: false positive
|
||||
// clang-format on
|
||||
constexpr void _Seek_to(const pointer p) noexcept
|
||||
{ // adjust the position of *this to previously verified location p
|
||||
// after _Unwrapped
|
||||
current_ = p;
|
||||
}
|
||||
#endif
|
||||
|
||||
pointer begin_ = nullptr;
|
||||
pointer end_ = nullptr;
|
||||
pointer current_ = nullptr;
|
||||
|
||||
template <typename Ptr>
|
||||
friend struct std::pointer_traits;
|
||||
};
|
||||
}} // namespace gsl::details
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <class Type>
|
||||
struct pointer_traits<::gsl::details::span_iterator<Type>>
|
||||
{
|
||||
using pointer = ::gsl::details::span_iterator<Type>;
|
||||
using element_type = Type;
|
||||
using difference_type = ptrdiff_t;
|
||||
|
||||
static constexpr element_type* to_address(const pointer i) noexcept { return i.current_; }
|
||||
};
|
||||
} // namespace std
|
||||
|
||||
namespace gsl { namespace details {
|
||||
template <std::size_t Ext>
|
||||
class extent_type
|
||||
{
|
||||
public:
|
||||
using size_type = std::size_t;
|
||||
|
||||
constexpr extent_type() noexcept = default;
|
||||
|
||||
constexpr explicit extent_type(extent_type<dynamic_extent>);
|
||||
|
||||
constexpr explicit extent_type(size_type size) { Expects(size == Ext); }
|
||||
|
||||
constexpr size_type size() const noexcept { return Ext; }
|
||||
|
||||
private:
|
||||
#if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND)
|
||||
static constexpr const size_type size_ = Ext; // static size equal to Ext
|
||||
#else
|
||||
static constexpr size_type size_ = Ext; // static size equal to Ext
|
||||
#endif
|
||||
};
|
||||
|
||||
template <>
|
||||
class extent_type<dynamic_extent>
|
||||
{
|
||||
public:
|
||||
using size_type = std::size_t;
|
||||
|
||||
template <size_type Other>
|
||||
constexpr explicit extent_type(extent_type<Other> ext) : size_(ext.size())
|
||||
{}
|
||||
|
||||
constexpr explicit extent_type(size_type size) : size_(size)
|
||||
{
|
||||
Expects(size != dynamic_extent);
|
||||
}
|
||||
|
||||
constexpr size_type size() const noexcept { return size_; }
|
||||
|
||||
private:
|
||||
size_type size_;
|
||||
};
|
||||
|
||||
template <std::size_t Ext>
|
||||
constexpr extent_type<Ext>::extent_type(extent_type<dynamic_extent> ext)
|
||||
{
|
||||
Expects(ext.size() == Ext);
|
||||
}
|
||||
|
||||
template <class ElementType, std::size_t Extent, std::size_t Offset, std::size_t Count>
|
||||
struct calculate_subspan_type
|
||||
{
|
||||
using type = span<ElementType, Count != dynamic_extent
|
||||
? Count
|
||||
: (Extent != dynamic_extent ? Extent - Offset : Extent)>;
|
||||
};
|
||||
} // namespace details
|
||||
|
||||
// [span], class template span
|
||||
template <class ElementType, std::size_t Extent>
|
||||
class span
|
||||
{
|
||||
public:
|
||||
// constants and types
|
||||
using element_type = ElementType;
|
||||
using value_type = std::remove_cv_t<ElementType>;
|
||||
using size_type = std::size_t;
|
||||
using pointer = element_type*;
|
||||
using const_pointer = const element_type*;
|
||||
using reference = element_type&;
|
||||
using const_reference = const element_type&;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
|
||||
using iterator = details::span_iterator<ElementType>;
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
|
||||
#if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND)
|
||||
static constexpr const size_type extent{Extent};
|
||||
#else
|
||||
static constexpr size_type extent{Extent};
|
||||
#endif
|
||||
|
||||
// [span.cons], span constructors, copy, assignment, and destructor
|
||||
template <bool Dependent = false,
|
||||
// "Dependent" is needed to make "std::enable_if_t<Dependent || Extent == 0 || Extent
|
||||
// == dynamic_extent>" SFINAE, since "std::enable_if_t<Extent == 0 || Extent ==
|
||||
// dynamic_extent>" is ill-formed when Extent is greater than 0.
|
||||
class = std::enable_if_t<(Dependent ||
|
||||
details::is_allowed_extent_conversion<0, Extent>::value)>>
|
||||
constexpr span() noexcept : storage_(nullptr, details::extent_type<0>())
|
||||
{}
|
||||
|
||||
template <std::size_t MyExtent = Extent, std::enable_if_t<MyExtent != dynamic_extent, int> = 0>
|
||||
constexpr explicit span(pointer ptr, size_type count) noexcept : storage_(ptr, count)
|
||||
{
|
||||
Expects(count == Extent);
|
||||
}
|
||||
|
||||
template <std::size_t MyExtent = Extent, std::enable_if_t<MyExtent == dynamic_extent, int> = 0>
|
||||
constexpr span(pointer ptr, size_type count) noexcept : storage_(ptr, count)
|
||||
{}
|
||||
|
||||
template <std::size_t MyExtent = Extent, std::enable_if_t<MyExtent != dynamic_extent, int> = 0>
|
||||
constexpr explicit span(pointer firstElem, pointer lastElem) noexcept
|
||||
: storage_(firstElem, narrow_cast<std::size_t>(lastElem - firstElem))
|
||||
{
|
||||
Expects(lastElem - firstElem == static_cast<difference_type>(Extent));
|
||||
}
|
||||
|
||||
template <std::size_t MyExtent = Extent, std::enable_if_t<MyExtent == dynamic_extent, int> = 0>
|
||||
constexpr span(pointer firstElem, pointer lastElem) noexcept
|
||||
: storage_(firstElem, narrow_cast<std::size_t>(lastElem - firstElem))
|
||||
{}
|
||||
|
||||
template <std::size_t N,
|
||||
std::enable_if_t<details::is_allowed_extent_conversion<N, Extent>::value, int> = 0>
|
||||
constexpr span(element_type (&arr)[N]) noexcept
|
||||
: storage_(KnownNotNull{arr}, details::extent_type<N>())
|
||||
{}
|
||||
|
||||
template <
|
||||
class T, std::size_t N,
|
||||
std::enable_if_t<(details::is_allowed_extent_conversion<N, Extent>::value &&
|
||||
details::is_allowed_element_type_conversion<T, element_type>::value),
|
||||
int> = 0>
|
||||
constexpr span(std::array<T, N>& arr) noexcept
|
||||
: storage_(KnownNotNull{arr.data()}, details::extent_type<N>())
|
||||
{}
|
||||
|
||||
template <class T, std::size_t N,
|
||||
std::enable_if_t<
|
||||
(details::is_allowed_extent_conversion<N, Extent>::value &&
|
||||
details::is_allowed_element_type_conversion<const T, element_type>::value),
|
||||
int> = 0>
|
||||
constexpr span(const std::array<T, N>& arr) noexcept
|
||||
: storage_(KnownNotNull{arr.data()}, details::extent_type<N>())
|
||||
{}
|
||||
|
||||
// NB: the SFINAE on these constructors uses .data() as an incomplete/imperfect proxy for the
|
||||
// requirement on Container to be a contiguous sequence container.
|
||||
template <std::size_t MyExtent = Extent, class Container,
|
||||
std::enable_if_t<
|
||||
MyExtent != dynamic_extent && !details::is_span<Container>::value &&
|
||||
!details::is_std_array<Container>::value &&
|
||||
std::is_pointer<decltype(std::declval<Container&>().data())>::value &&
|
||||
std::is_convertible<
|
||||
std::remove_pointer_t<decltype(std::declval<Container&>().data())> (*)[],
|
||||
element_type (*)[]>::value,
|
||||
int> = 0>
|
||||
constexpr explicit span(Container& cont) noexcept : span(cont.data(), cont.size())
|
||||
{}
|
||||
|
||||
template <std::size_t MyExtent = Extent, class Container,
|
||||
std::enable_if_t<
|
||||
MyExtent == dynamic_extent && !details::is_span<Container>::value &&
|
||||
!details::is_std_array<Container>::value &&
|
||||
std::is_pointer<decltype(std::declval<Container&>().data())>::value &&
|
||||
std::is_convertible<
|
||||
std::remove_pointer_t<decltype(std::declval<Container&>().data())> (*)[],
|
||||
element_type (*)[]>::value,
|
||||
int> = 0>
|
||||
constexpr span(Container& cont) noexcept : span(cont.data(), cont.size())
|
||||
{}
|
||||
|
||||
template <
|
||||
std::size_t MyExtent = Extent, class Container,
|
||||
std::enable_if_t<
|
||||
MyExtent != dynamic_extent && std::is_const<element_type>::value &&
|
||||
!details::is_span<Container>::value && !details::is_std_array<Container>::value &&
|
||||
std::is_pointer<decltype(std::declval<const Container&>().data())>::value &&
|
||||
std::is_convertible<
|
||||
std::remove_pointer_t<decltype(std::declval<const Container&>().data())> (*)[],
|
||||
element_type (*)[]>::value,
|
||||
int> = 0>
|
||||
constexpr explicit span(const Container& cont) noexcept : span(cont.data(), cont.size())
|
||||
{}
|
||||
|
||||
template <
|
||||
std::size_t MyExtent = Extent, class Container,
|
||||
std::enable_if_t<
|
||||
MyExtent == dynamic_extent && std::is_const<element_type>::value &&
|
||||
!details::is_span<Container>::value && !details::is_std_array<Container>::value &&
|
||||
std::is_pointer<decltype(std::declval<const Container&>().data())>::value &&
|
||||
std::is_convertible<
|
||||
std::remove_pointer_t<decltype(std::declval<const Container&>().data())> (*)[],
|
||||
element_type (*)[]>::value,
|
||||
int> = 0>
|
||||
constexpr span(const Container& cont) noexcept : span(cont.data(), cont.size())
|
||||
{}
|
||||
|
||||
constexpr span(const span& other) noexcept = default;
|
||||
|
||||
template <class OtherElementType, std::size_t OtherExtent, std::size_t MyExtent = Extent,
|
||||
std::enable_if_t<(MyExtent == dynamic_extent || MyExtent == OtherExtent) &&
|
||||
details::is_allowed_element_type_conversion<OtherElementType,
|
||||
element_type>::value,
|
||||
int> = 0>
|
||||
constexpr span(const span<OtherElementType, OtherExtent>& other) noexcept
|
||||
: storage_(other.data(), details::extent_type<OtherExtent>(other.size()))
|
||||
{}
|
||||
|
||||
template <class OtherElementType, std::size_t OtherExtent, std::size_t MyExtent = Extent,
|
||||
std::enable_if_t<MyExtent != dynamic_extent && OtherExtent == dynamic_extent &&
|
||||
details::is_allowed_element_type_conversion<OtherElementType,
|
||||
element_type>::value,
|
||||
int> = 0>
|
||||
constexpr explicit span(const span<OtherElementType, OtherExtent>& other) noexcept
|
||||
: storage_(other.data(), details::extent_type<OtherExtent>(other.size()))
|
||||
{}
|
||||
|
||||
~span() noexcept = default;
|
||||
constexpr span& operator=(const span& other) noexcept = default;
|
||||
|
||||
// [span.sub], span subviews
|
||||
template <std::size_t Count>
|
||||
constexpr span<element_type, Count> first() const noexcept
|
||||
{
|
||||
Expects(Count <= size());
|
||||
return span<element_type, Count>{data(), Count};
|
||||
}
|
||||
|
||||
template <std::size_t Count>
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
constexpr span<element_type, Count> last() const noexcept
|
||||
{
|
||||
Expects(Count <= size());
|
||||
return span<element_type, Count>{data() + (size() - Count), Count};
|
||||
}
|
||||
|
||||
template <std::size_t Offset, std::size_t Count = dynamic_extent>
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
constexpr auto subspan() const noexcept ->
|
||||
typename details::calculate_subspan_type<ElementType, Extent, Offset, Count>::type
|
||||
{
|
||||
Expects((size() >= Offset) && (Count == dynamic_extent || (Count <= size() - Offset)));
|
||||
using type =
|
||||
typename details::calculate_subspan_type<ElementType, Extent, Offset, Count>::type;
|
||||
return type{data() + Offset, Count == dynamic_extent ? size() - Offset : Count};
|
||||
}
|
||||
|
||||
constexpr span<element_type, dynamic_extent> first(size_type count) const noexcept
|
||||
{
|
||||
Expects(count <= size());
|
||||
return {data(), count};
|
||||
}
|
||||
|
||||
constexpr span<element_type, dynamic_extent> last(size_type count) const noexcept
|
||||
{
|
||||
Expects(count <= size());
|
||||
return make_subspan(size() - count, dynamic_extent, subspan_selector<Extent>{});
|
||||
}
|
||||
|
||||
constexpr span<element_type, dynamic_extent>
|
||||
subspan(size_type offset, size_type count = dynamic_extent) const noexcept
|
||||
{
|
||||
return make_subspan(offset, count, subspan_selector<Extent>{});
|
||||
}
|
||||
|
||||
// [span.obs], span observers
|
||||
constexpr size_type size() const noexcept { return storage_.size(); }
|
||||
|
||||
constexpr size_type size_bytes() const noexcept { return size() * sizeof(element_type); }
|
||||
|
||||
constexpr bool empty() const noexcept { return size() == 0; }
|
||||
|
||||
// [span.elem], span element access
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
constexpr reference operator[](size_type idx) const noexcept
|
||||
{
|
||||
Expects(idx < size());
|
||||
return data()[idx];
|
||||
}
|
||||
|
||||
constexpr reference front() const noexcept
|
||||
{
|
||||
Expects(size() > 0);
|
||||
return data()[0];
|
||||
}
|
||||
|
||||
constexpr reference back() const noexcept
|
||||
{
|
||||
Expects(size() > 0);
|
||||
return data()[size() - 1];
|
||||
}
|
||||
|
||||
constexpr pointer data() const noexcept { return storage_.data(); }
|
||||
|
||||
// [span.iter], span iterator support
|
||||
constexpr iterator begin() const noexcept
|
||||
{
|
||||
const auto data = storage_.data();
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
return {data, data + size(), data};
|
||||
}
|
||||
|
||||
constexpr iterator end() const noexcept
|
||||
{
|
||||
const auto data = storage_.data();
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
const auto endData = data + storage_.size();
|
||||
return {data, endData, endData};
|
||||
}
|
||||
|
||||
constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; }
|
||||
constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; }
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// Tell MSVC how to unwrap spans in range-based-for
|
||||
constexpr pointer _Unchecked_begin() const noexcept { return data(); }
|
||||
constexpr pointer _Unchecked_end() const noexcept
|
||||
{
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
return data() + size();
|
||||
}
|
||||
#endif // _MSC_VER
|
||||
|
||||
private:
|
||||
// Needed to remove unnecessary null check in subspans
|
||||
struct KnownNotNull
|
||||
{
|
||||
pointer p;
|
||||
};
|
||||
|
||||
// this implementation detail class lets us take advantage of the
|
||||
// empty base class optimization to pay for only storage of a single
|
||||
// pointer in the case of fixed-size spans
|
||||
template <class ExtentType>
|
||||
class storage_type : public ExtentType
|
||||
{
|
||||
public:
|
||||
// KnownNotNull parameter is needed to remove unnecessary null check
|
||||
// in subspans and constructors from arrays
|
||||
template <class OtherExtentType>
|
||||
constexpr storage_type(KnownNotNull data, OtherExtentType ext)
|
||||
: ExtentType(ext), data_(data.p)
|
||||
{}
|
||||
|
||||
template <class OtherExtentType>
|
||||
constexpr storage_type(pointer data, OtherExtentType ext) : ExtentType(ext), data_(data)
|
||||
{
|
||||
Expects(data || ExtentType::size() == 0);
|
||||
}
|
||||
|
||||
constexpr pointer data() const noexcept { return data_; }
|
||||
|
||||
private:
|
||||
pointer data_;
|
||||
};
|
||||
|
||||
storage_type<details::extent_type<Extent>> storage_;
|
||||
|
||||
// The rest is needed to remove unnecessary null check
|
||||
// in subspans and constructors from arrays
|
||||
constexpr span(KnownNotNull ptr, size_type count) noexcept : storage_(ptr, count) {}
|
||||
|
||||
template <std::size_t CallerExtent>
|
||||
class subspan_selector
|
||||
{
|
||||
};
|
||||
|
||||
template <std::size_t CallerExtent>
|
||||
constexpr span<element_type, dynamic_extent>
|
||||
make_subspan(size_type offset, size_type count, subspan_selector<CallerExtent>) const noexcept
|
||||
{
|
||||
const span<element_type, dynamic_extent> tmp(*this);
|
||||
return tmp.subspan(offset, count);
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
constexpr span<element_type, dynamic_extent>
|
||||
make_subspan(size_type offset, size_type count, subspan_selector<dynamic_extent>) const noexcept
|
||||
{
|
||||
Expects(size() >= offset);
|
||||
|
||||
if (count == dynamic_extent) { return {KnownNotNull{data() + offset}, size() - offset}; }
|
||||
|
||||
Expects(size() - offset >= count);
|
||||
return {KnownNotNull{data() + offset}, count};
|
||||
}
|
||||
};
|
||||
|
||||
#if (defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L))
|
||||
|
||||
// Deduction Guides
|
||||
template <class Type, std::size_t Extent>
|
||||
span(Type (&)[Extent]) -> span<Type, Extent>;
|
||||
|
||||
template <class Type, std::size_t Size>
|
||||
span(std::array<Type, Size>&) -> span<Type, Size>;
|
||||
|
||||
template <class Type, std::size_t Size>
|
||||
span(const std::array<Type, Size>&) -> span<const Type, Size>;
|
||||
|
||||
template <class Container,
|
||||
class Element = std::remove_pointer_t<decltype(std::declval<Container&>().data())>>
|
||||
span(Container&) -> span<Element>;
|
||||
|
||||
template <class Container,
|
||||
class Element = std::remove_pointer_t<decltype(std::declval<const Container&>().data())>>
|
||||
span(const Container&) -> span<Element>;
|
||||
|
||||
#endif // ( defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L) )
|
||||
|
||||
#if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND)
|
||||
#if defined(__clang__) && defined(_MSC_VER) && defined(__cplusplus) && (__cplusplus < 201703L)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated" // Bug in clang-cl.exe which raises a C++17 -Wdeprecated warning about this static constexpr workaround in C++14 mode.
|
||||
#endif // defined(__clang__) && defined(_MSC_VER) && defined(__cplusplus) && (__cplusplus < 201703L)
|
||||
template <class ElementType, std::size_t Extent>
|
||||
constexpr const typename span<ElementType, Extent>::size_type span<ElementType, Extent>::extent;
|
||||
#if defined(__clang__) && defined(_MSC_VER) && defined(__cplusplus) && (__cplusplus < 201703L)
|
||||
#pragma clang diagnostic pop
|
||||
#endif // defined(__clang__) && defined(_MSC_VER) && defined(__cplusplus) && (__cplusplus < 201703L)
|
||||
#endif
|
||||
|
||||
namespace details
|
||||
{
|
||||
// if we only supported compilers with good constexpr support then
|
||||
// this pair of classes could collapse down to a constexpr function
|
||||
|
||||
// we should use a narrow_cast<> to go to std::size_t, but older compilers may not see it as
|
||||
// constexpr
|
||||
// and so will fail compilation of the template
|
||||
template <class ElementType, std::size_t Extent>
|
||||
struct calculate_byte_size : std::integral_constant<std::size_t, sizeof(ElementType) * Extent>
|
||||
{
|
||||
static_assert(Extent < dynamic_extent / sizeof(ElementType), "Size is too big.");
|
||||
};
|
||||
|
||||
template <class ElementType>
|
||||
struct calculate_byte_size<ElementType, dynamic_extent>
|
||||
: std::integral_constant<std::size_t, dynamic_extent>
|
||||
{
|
||||
};
|
||||
} // namespace details
|
||||
|
||||
// [span.objectrep], views of object representation
|
||||
template <class ElementType, std::size_t Extent>
|
||||
span<const byte, details::calculate_byte_size<ElementType, Extent>::value>
|
||||
as_bytes(span<ElementType, Extent> s) noexcept
|
||||
{
|
||||
using type = span<const byte, details::calculate_byte_size<ElementType, Extent>::value>;
|
||||
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
return type{reinterpret_cast<const byte*>(s.data()), s.size_bytes()};
|
||||
}
|
||||
|
||||
template <class ElementType, std::size_t Extent,
|
||||
std::enable_if_t<!std::is_const<ElementType>::value, int> = 0>
|
||||
span<byte, details::calculate_byte_size<ElementType, Extent>::value>
|
||||
as_writable_bytes(span<ElementType, Extent> s) noexcept
|
||||
{
|
||||
using type = span<byte, details::calculate_byte_size<ElementType, Extent>::value>;
|
||||
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
return type{reinterpret_cast<byte*>(s.data()), s.size_bytes()};
|
||||
}
|
||||
|
||||
} // namespace gsl
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
|
||||
#pragma warning(pop)
|
||||
#endif // _MSC_VER
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ > 6
|
||||
#pragma GCC diagnostic pop
|
||||
#endif // __GNUC__ > 6
|
||||
|
||||
#endif // GSL_SPAN_H
|
214
deps/GSL/include/gsl/span_ext
vendored
Normal file
@ -0,0 +1,214 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef GSL_SPAN_EXT_H
|
||||
#define GSL_SPAN_EXT_H
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// File: span_ext
|
||||
// Purpose: continue offering features that have been cut from the official
|
||||
// implementation of span.
|
||||
// While modernizing gsl::span a number of features needed to be removed to
|
||||
// be compliant with the design of std::span
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "assert" // GSL_KERNEL_MODE
|
||||
#include "util" // for narrow_cast, narrow
|
||||
|
||||
#include <cstddef> // for ptrdiff_t, size_t
|
||||
#include <utility>
|
||||
|
||||
#ifndef GSL_KERNEL_MODE
|
||||
#include <algorithm> // for lexicographical_compare
|
||||
#endif // GSL_KERNEL_MODE
|
||||
|
||||
namespace gsl
|
||||
{
|
||||
|
||||
// [span.views.constants], constants
|
||||
GSL_INLINE constexpr const std::size_t dynamic_extent = narrow_cast<std::size_t>(-1);
|
||||
|
||||
template <class ElementType, std::size_t Extent = dynamic_extent>
|
||||
class span;
|
||||
|
||||
// std::equal and std::lexicographical_compare are not /kernel compatible
|
||||
// so all comparison operators must be removed for kernel mode.
|
||||
#ifndef GSL_KERNEL_MODE
|
||||
|
||||
// [span.comparison], span comparison operators
|
||||
template <class ElementType, std::size_t FirstExtent, std::size_t SecondExtent>
|
||||
constexpr bool operator==(span<ElementType, FirstExtent> l, span<ElementType, SecondExtent> r)
|
||||
{
|
||||
return std::equal(l.begin(), l.end(), r.begin(), r.end());
|
||||
}
|
||||
|
||||
template <class ElementType, std::size_t Extent>
|
||||
constexpr bool operator!=(span<ElementType, Extent> l, span<ElementType, Extent> r)
|
||||
{
|
||||
return !(l == r);
|
||||
}
|
||||
|
||||
template <class ElementType, std::size_t Extent>
|
||||
constexpr bool operator<(span<ElementType, Extent> l, span<ElementType, Extent> r)
|
||||
{
|
||||
return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end());
|
||||
}
|
||||
|
||||
template <class ElementType, std::size_t Extent>
|
||||
constexpr bool operator<=(span<ElementType, Extent> l, span<ElementType, Extent> r)
|
||||
{
|
||||
return !(l > r);
|
||||
}
|
||||
|
||||
template <class ElementType, std::size_t Extent>
|
||||
constexpr bool operator>(span<ElementType, Extent> l, span<ElementType, Extent> r)
|
||||
{
|
||||
return r < l;
|
||||
}
|
||||
|
||||
template <class ElementType, std::size_t Extent>
|
||||
constexpr bool operator>=(span<ElementType, Extent> l, span<ElementType, Extent> r)
|
||||
{
|
||||
return !(l < r);
|
||||
}
|
||||
|
||||
#endif // GSL_KERNEL_MODE
|
||||
|
||||
//
|
||||
// make_span() - Utility functions for creating spans
|
||||
//
|
||||
template <class ElementType>
|
||||
constexpr span<ElementType> make_span(ElementType* ptr, typename span<ElementType>::size_type count)
|
||||
{
|
||||
return span<ElementType>(ptr, count);
|
||||
}
|
||||
|
||||
template <class ElementType>
|
||||
constexpr span<ElementType> make_span(ElementType* firstElem, ElementType* lastElem)
|
||||
{
|
||||
return span<ElementType>(firstElem, lastElem);
|
||||
}
|
||||
|
||||
template <class ElementType, std::size_t N>
|
||||
constexpr span<ElementType, N> make_span(ElementType (&arr)[N]) noexcept
|
||||
{
|
||||
return span<ElementType, N>(arr);
|
||||
}
|
||||
|
||||
template <class Container>
|
||||
constexpr span<typename Container::value_type> make_span(Container& cont)
|
||||
{
|
||||
return span<typename Container::value_type>(cont);
|
||||
}
|
||||
|
||||
template <class Container>
|
||||
constexpr span<const typename Container::value_type> make_span(const Container& cont)
|
||||
{
|
||||
return span<const typename Container::value_type>(cont);
|
||||
}
|
||||
|
||||
template <class Ptr>
|
||||
[[deprecated("This function is deprecated. See GSL issue #1092.")]]
|
||||
constexpr span<typename Ptr::element_type> make_span(Ptr& cont, std::size_t count)
|
||||
{
|
||||
return span<typename Ptr::element_type>(cont, count);
|
||||
}
|
||||
|
||||
template <class Ptr>
|
||||
[[deprecated("This function is deprecated. See GSL issue #1092.")]]
|
||||
constexpr span<typename Ptr::element_type> make_span(Ptr& cont)
|
||||
{
|
||||
return span<typename Ptr::element_type>(cont);
|
||||
}
|
||||
|
||||
// Specialization of gsl::at for span
|
||||
template <class ElementType, std::size_t Extent>
|
||||
constexpr ElementType& at(span<ElementType, Extent> s, index i)
|
||||
{
|
||||
// No bounds checking here because it is done in span::operator[] called below
|
||||
Ensures(i >= 0);
|
||||
return s[narrow_cast<std::size_t>(i)];
|
||||
}
|
||||
|
||||
// [span.obs] Free observer functions
|
||||
template <class ElementType, std::size_t Extent>
|
||||
constexpr std::ptrdiff_t ssize(const span<ElementType, Extent>& s) noexcept
|
||||
{
|
||||
return static_cast<std::ptrdiff_t>(s.size());
|
||||
}
|
||||
|
||||
// [span.iter] Free functions for begin/end functions
|
||||
template <class ElementType, std::size_t Extent>
|
||||
constexpr typename span<ElementType, Extent>::iterator
|
||||
begin(const span<ElementType, Extent>& s) noexcept
|
||||
{
|
||||
return s.begin();
|
||||
}
|
||||
|
||||
template <class ElementType, std::size_t Extent = dynamic_extent>
|
||||
constexpr typename span<ElementType, Extent>::iterator
|
||||
end(const span<ElementType, Extent>& s) noexcept
|
||||
{
|
||||
return s.end();
|
||||
}
|
||||
|
||||
template <class ElementType, std::size_t Extent>
|
||||
constexpr typename span<ElementType, Extent>::reverse_iterator
|
||||
rbegin(const span<ElementType, Extent>& s) noexcept
|
||||
{
|
||||
return s.rbegin();
|
||||
}
|
||||
|
||||
template <class ElementType, std::size_t Extent>
|
||||
constexpr typename span<ElementType, Extent>::reverse_iterator
|
||||
rend(const span<ElementType, Extent>& s) noexcept
|
||||
{
|
||||
return s.rend();
|
||||
}
|
||||
|
||||
template <class ElementType, std::size_t Extent>
|
||||
constexpr typename span<ElementType, Extent>::iterator
|
||||
cbegin(const span<ElementType, Extent>& s) noexcept
|
||||
{
|
||||
return s.begin();
|
||||
}
|
||||
|
||||
template <class ElementType, std::size_t Extent = dynamic_extent>
|
||||
constexpr typename span<ElementType, Extent>::iterator
|
||||
cend(const span<ElementType, Extent>& s) noexcept
|
||||
{
|
||||
return s.end();
|
||||
}
|
||||
|
||||
template <class ElementType, std::size_t Extent>
|
||||
constexpr typename span<ElementType, Extent>::reverse_iterator
|
||||
crbegin(const span<ElementType, Extent>& s) noexcept
|
||||
{
|
||||
return s.rbegin();
|
||||
}
|
||||
|
||||
template <class ElementType, std::size_t Extent>
|
||||
constexpr typename span<ElementType, Extent>::reverse_iterator
|
||||
crend(const span<ElementType, Extent>& s) noexcept
|
||||
{
|
||||
return s.rend();
|
||||
}
|
||||
|
||||
} // namespace gsl
|
||||
|
||||
#endif // GSL_SPAN_EXT_H
|
4
deps/GSL/include/gsl/string_span
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
#pragma message( \
|
||||
"This header will soon be removed. Use <gsl/zstring> instead of <gsl/string_span>")
|
||||
#include "zstring"
|
157
deps/GSL/include/gsl/util
vendored
Normal file
@ -0,0 +1,157 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef GSL_UTIL_H
|
||||
#define GSL_UTIL_H
|
||||
|
||||
#include "assert" // for Expects
|
||||
|
||||
#include <array>
|
||||
#include <cstddef> // for ptrdiff_t, size_t
|
||||
#include <limits> // for numeric_limits
|
||||
#include <initializer_list> // for initializer_list
|
||||
#include <type_traits> // for is_signed, integral_constant
|
||||
#include <utility> // for exchange, forward
|
||||
|
||||
#if defined(__has_include) && __has_include(<version>)
|
||||
#include <version>
|
||||
#if defined(__cpp_lib_span) && __cpp_lib_span >= 202002L
|
||||
#include <span>
|
||||
#endif // __cpp_lib_span >= 202002L
|
||||
#endif //__has_include(<version>)
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4127) // conditional expression is constant
|
||||
|
||||
#endif // _MSC_VER
|
||||
|
||||
#if defined(__cplusplus) && (__cplusplus >= 201703L)
|
||||
#define GSL_NODISCARD [[nodiscard]]
|
||||
#else
|
||||
#define GSL_NODISCARD
|
||||
#endif // defined(__cplusplus) && (__cplusplus >= 201703L)
|
||||
|
||||
#if defined(__cpp_inline_variables)
|
||||
#define GSL_INLINE inline
|
||||
#else
|
||||
#define GSL_INLINE
|
||||
#endif
|
||||
|
||||
namespace gsl
|
||||
{
|
||||
//
|
||||
// GSL.util: utilities
|
||||
//
|
||||
|
||||
// index type for all container indexes/subscripts/sizes
|
||||
using index = std::ptrdiff_t;
|
||||
|
||||
// final_action allows you to ensure something gets run at the end of a scope
|
||||
template <class F>
|
||||
class final_action
|
||||
{
|
||||
public:
|
||||
explicit final_action(const F& ff) noexcept : f{ff} { }
|
||||
explicit final_action(F&& ff) noexcept : f{std::move(ff)} { }
|
||||
|
||||
~final_action() noexcept { if (invoke) f(); }
|
||||
|
||||
final_action(final_action&& other) noexcept
|
||||
: f(std::move(other.f)), invoke(std::exchange(other.invoke, false))
|
||||
{ }
|
||||
|
||||
final_action(const final_action&) = delete;
|
||||
void operator=(const final_action&) = delete;
|
||||
void operator=(final_action&&) = delete;
|
||||
|
||||
private:
|
||||
F f;
|
||||
bool invoke = true;
|
||||
};
|
||||
|
||||
// finally() - convenience function to generate a final_action
|
||||
template <class F>
|
||||
GSL_NODISCARD auto finally(F&& f) noexcept
|
||||
{
|
||||
return final_action<std::decay_t<F>>{std::forward<F>(f)};
|
||||
}
|
||||
|
||||
// narrow_cast(): a searchable way to do narrowing casts of values
|
||||
template <class T, class U>
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
constexpr T narrow_cast(U&& u) noexcept
|
||||
{
|
||||
return static_cast<T>(std::forward<U>(u));
|
||||
}
|
||||
|
||||
//
|
||||
// at() - Bounds-checked way of accessing builtin arrays, std::array, std::vector
|
||||
//
|
||||
template <class T, std::size_t N>
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute
|
||||
GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
constexpr T& at(T (&arr)[N], const index i)
|
||||
{
|
||||
static_assert(N <= static_cast<std::size_t>((std::numeric_limits<std::ptrdiff_t>::max)()), "We only support arrays up to PTRDIFF_MAX bytes.");
|
||||
Expects(i >= 0 && i < narrow_cast<index>(N));
|
||||
return arr[narrow_cast<std::size_t>(i)];
|
||||
}
|
||||
|
||||
template <class Cont>
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute
|
||||
GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
constexpr auto at(Cont& cont, const index i) -> decltype(cont[cont.size()])
|
||||
{
|
||||
Expects(i >= 0 && i < narrow_cast<index>(cont.size()));
|
||||
using size_type = decltype(cont.size());
|
||||
return cont[narrow_cast<size_type>(i)];
|
||||
}
|
||||
|
||||
template <class T>
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
constexpr T at(const std::initializer_list<T> cont, const index i)
|
||||
{
|
||||
Expects(i >= 0 && i < narrow_cast<index>(cont.size()));
|
||||
return *(cont.begin() + i);
|
||||
}
|
||||
|
||||
#if defined(__cpp_lib_span) && __cpp_lib_span >= 202002L
|
||||
template <class T, std::size_t extent = std::dynamic_extent>
|
||||
constexpr auto at(std::span<T, extent> sp, const index i) -> decltype(sp[sp.size()])
|
||||
{
|
||||
Expects(i >= 0 && i < narrow_cast<index>(sp.size()));
|
||||
return sp[gsl::narrow_cast<std::size_t>(i)];
|
||||
}
|
||||
#endif // __cpp_lib_span >= 202002L
|
||||
} // namespace gsl
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
|
||||
#pragma warning(pop)
|
||||
|
||||
#endif // _MSC_VER
|
||||
|
||||
#endif // GSL_UTIL_H
|
58
deps/GSL/include/gsl/zstring
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef GSL_ZSTRING_H
|
||||
#define GSL_ZSTRING_H
|
||||
|
||||
#include "span_ext" // for dynamic_extent
|
||||
|
||||
#include <cstddef> // for size_t, nullptr_t
|
||||
|
||||
namespace gsl
|
||||
{
|
||||
//
|
||||
// czstring and wzstring
|
||||
//
|
||||
// These are "tag" typedefs for C-style strings (i.e. null-terminated character arrays)
|
||||
// that allow static analysis to help find bugs.
|
||||
//
|
||||
// There are no additional features/semantics that we can find a way to add inside the
|
||||
// type system for these types that will not either incur significant runtime costs or
|
||||
// (sometimes needlessly) break existing programs when introduced.
|
||||
//
|
||||
|
||||
template <typename CharT, std::size_t Extent = dynamic_extent>
|
||||
using basic_zstring = CharT*;
|
||||
|
||||
using czstring = basic_zstring<const char, dynamic_extent>;
|
||||
|
||||
using cwzstring = basic_zstring<const wchar_t, dynamic_extent>;
|
||||
|
||||
using cu16zstring = basic_zstring<const char16_t, dynamic_extent>;
|
||||
|
||||
using cu32zstring = basic_zstring<const char32_t, dynamic_extent>;
|
||||
|
||||
using zstring = basic_zstring<char, dynamic_extent>;
|
||||
|
||||
using wzstring = basic_zstring<wchar_t, dynamic_extent>;
|
||||
|
||||
using u16zstring = basic_zstring<char16_t, dynamic_extent>;
|
||||
|
||||
using u32zstring = basic_zstring<char32_t, dynamic_extent>;
|
||||
|
||||
} // namespace gsl
|
||||
|
||||
#endif // GSL_ZSTRING_H
|
43
deps/GSL/pipelines/jobs.yml
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
parameters:
|
||||
CXXVersions: [ 14, 17, 20 ]
|
||||
buildTypes: [ 'Debug', 'Release' ]
|
||||
image: ''
|
||||
|
||||
compiler: ''
|
||||
compilerVersions: ["default"] # if default value, simply uses whatever version is on the machine.
|
||||
# the text of this default value doesn't actually matter.
|
||||
setupfile: ''
|
||||
extraCmakeArgs: ''
|
||||
|
||||
jobs:
|
||||
- ${{ each compilerVersion in parameters.compilerVersions }}:
|
||||
- ${{ each CXXVersion in parameters.CXXVersions }}:
|
||||
- ${{ each buildType in parameters.buildTypes }}:
|
||||
- job:
|
||||
displayName: ${{ format('{0} {1} C++{2} {3}', parameters.compiler, compilerVersion, CXXVersion, buildType) }}
|
||||
pool:
|
||||
vmImage: ${{ parameters.image }}
|
||||
continueOnError: false
|
||||
|
||||
steps:
|
||||
- ${{ if not(eq(parameters.setupfile, '')) }}:
|
||||
- template: ${{ parameters.setupfile }}
|
||||
parameters:
|
||||
version: ${{ compilerVersion }}
|
||||
|
||||
- task: CMake@1
|
||||
name: Configure
|
||||
inputs:
|
||||
workingDirectory: build
|
||||
cmakeArgs: '-DGSL_CXX_STANDARD=${{ CXXVersion }} -DCMAKE_BUILD_TYPE=${{ buildType }} -DCI_TESTING:BOOL=ON -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -Werror=dev ${{ parameters.extraCmakeArgs }} .. '
|
||||
|
||||
- task: CMake@1
|
||||
name: Build
|
||||
inputs:
|
||||
workingDirectory: build
|
||||
cmakeArgs: '--build . '
|
||||
|
||||
- script: ctest . --output-on-failure --no-compress-output
|
||||
name: CTest
|
||||
workingDirectory: build
|
||||
failOnStderr: true
|
9
deps/GSL/pipelines/setup_apple.yml
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
parameters:
|
||||
version: 0
|
||||
|
||||
steps:
|
||||
- script: |
|
||||
if [ "${{ parameters.version }}" != "default" ]; then sudo xcode-select -switch /Applications/Xcode_${{ parameters.version }}.app; fi
|
||||
|
||||
displayName: "Setup Xcode Version"
|
||||
failOnStderr: true
|
13
deps/GSL/pipelines/setup_clang.yml
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
parameters:
|
||||
version: 0
|
||||
|
||||
steps:
|
||||
- script: |
|
||||
echo "##vso[task.setvariable variable=CXX;]${CXX}"
|
||||
echo "##vso[task.setvariable variable=CC;]${CC}"
|
||||
|
||||
displayName: "Setup Clang Version"
|
||||
failOnStderr: true
|
||||
env:
|
||||
CC: clang-${{ parameters.version }}
|
||||
CXX: clang++-${{ parameters.version }}
|
14
deps/GSL/pipelines/setup_gcc.yml
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
parameters:
|
||||
version: 0
|
||||
|
||||
steps:
|
||||
- script: |
|
||||
echo "##vso[task.setvariable variable=CXX;]${CXX}"
|
||||
echo "##vso[task.setvariable variable=CC;]${CC}"
|
||||
if [ "${{ parameters.version }}" = "11" ]; then sudo apt-get install $CXX; fi
|
||||
|
||||
displayName: "Setup GCC Version"
|
||||
failOnStderr: true
|
||||
env:
|
||||
CC: gcc-${{ parameters.version }}
|
||||
CXX: g++-${{ parameters.version }}
|
0
deps/GSL/pipelines/steps.yml
vendored
Normal file
316
deps/GSL/tests/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,316 @@
|
||||
cmake_minimum_required(VERSION 3.14...3.16)
|
||||
|
||||
project(GSLTests LANGUAGES CXX)
|
||||
|
||||
set(GSL_CXX_STANDARD "14" CACHE STRING "Use c++ standard")
|
||||
|
||||
set(CMAKE_CXX_STANDARD ${GSL_CXX_STANDARD})
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
include(FindPkgConfig)
|
||||
include(ExternalProject)
|
||||
|
||||
# will make visual studio generated project group files
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
|
||||
if(CI_TESTING AND GSL_CXX_STANDARD EQUAL 20)
|
||||
add_compile_definitions(FORCE_STD_SPAN_TESTS=1)
|
||||
endif()
|
||||
|
||||
if(IOS)
|
||||
add_compile_definitions(GTEST_HAS_DEATH_TEST=1 IOS_PROCESS_DELAY_WORKAROUND=1)
|
||||
endif()
|
||||
|
||||
pkg_search_module(GTestMain gtest_main)
|
||||
if (NOT GTestMain_FOUND)
|
||||
# No pre-installed GTest is available, try to download it using Git.
|
||||
find_package(Git REQUIRED QUIET)
|
||||
|
||||
configure_file(CMakeLists.txt.in googletest-download/CMakeLists.txt)
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
|
||||
RESULT_VARIABLE result
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download
|
||||
)
|
||||
if(result)
|
||||
message(FATAL_ERROR "CMake step for googletest failed: ${result}")
|
||||
endif()
|
||||
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} --build .
|
||||
RESULT_VARIABLE result
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download
|
||||
)
|
||||
if(result)
|
||||
message(FATAL_ERROR "CMake step for googletest failed: ${result}")
|
||||
endif()
|
||||
|
||||
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||
set(GTestMain_LIBRARIES gtest_main)
|
||||
|
||||
add_subdirectory(
|
||||
${CMAKE_CURRENT_BINARY_DIR}/googletest-src
|
||||
${CMAKE_CURRENT_BINARY_DIR}/googletest-build
|
||||
EXCLUDE_FROM_ALL
|
||||
)
|
||||
endif()
|
||||
|
||||
if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
|
||||
find_package(Microsoft.GSL CONFIG REQUIRED)
|
||||
enable_testing()
|
||||
|
||||
if (NOT DEFINED Microsoft.GSL_VERSION)
|
||||
message(FATAL_ERROR "Microsoft.GSL_VERSION not defined!")
|
||||
endif()
|
||||
|
||||
message(STATUS "Microsoft.GSL_VERSION = ${Microsoft.GSL_VERSION}")
|
||||
endif()
|
||||
|
||||
if (MSVC AND (GSL_CXX_STANDARD GREATER_EQUAL 17))
|
||||
set(GSL_CPLUSPLUS_OPT -Zc:__cplusplus -permissive-)
|
||||
endif()
|
||||
|
||||
include(CheckCXXCompilerFlag)
|
||||
# this interface adds compile options to how the tests are run
|
||||
# please try to keep entries ordered =)
|
||||
add_library(gsl_tests_config INTERFACE)
|
||||
if(MSVC) # MSVC or simulating MSVC
|
||||
target_compile_options(gsl_tests_config INTERFACE
|
||||
${GSL_CPLUSPLUS_OPT}
|
||||
/EHsc
|
||||
/W4
|
||||
/WX
|
||||
$<$<CXX_COMPILER_ID:MSVC>:
|
||||
/wd4996 # Use of function or classes marked [[deprecated]]
|
||||
/wd26409 # CppCoreCheck - GTest
|
||||
/wd26426 # CppCoreCheck - GTest
|
||||
/wd26440 # CppCoreCheck - GTest
|
||||
/wd26446 # CppCoreCheck - prefer gsl::at()
|
||||
/wd26472 # CppCoreCheck - use gsl::narrow(_cast)
|
||||
/wd26481 # CppCoreCheck - use span instead of pointer arithmetic
|
||||
$<$<VERSION_LESS:$<CXX_COMPILER_VERSION>,1920>: # VS2015
|
||||
/wd4189 # variable is initialized but not referenced
|
||||
$<$<NOT:$<CONFIG:Debug>>: # Release, RelWithDebInfo
|
||||
/wd4702 # Unreachable code
|
||||
>
|
||||
>
|
||||
>
|
||||
$<$<CXX_COMPILER_ID:Clang>:
|
||||
-Weverything
|
||||
-Wfloat-equal
|
||||
-Wno-c++98-compat
|
||||
-Wno-c++98-compat-pedantic
|
||||
-Wno-covered-switch-default # GTest
|
||||
-Wno-deprecated-declarations # Allow tests for [[deprecated]] elements
|
||||
-Wno-global-constructors # GTest
|
||||
-Wno-language-extension-token # GTest gtest-port.h
|
||||
-Wno-missing-braces
|
||||
-Wno-missing-prototypes
|
||||
-Wno-shift-sign-overflow # GTest gtest-port.h
|
||||
-Wno-undef # GTest
|
||||
-Wno-used-but-marked-unused # GTest EXPECT_DEATH
|
||||
$<$<EQUAL:${GSL_CXX_STANDARD},14>: # no support for [[maybe_unused]]
|
||||
-Wno-unused-member-function
|
||||
-Wno-unused-variable
|
||||
$<$<VERSION_EQUAL:$<CXX_COMPILER_VERSION>,15.0.1>:
|
||||
-Wno-deprecated # False positive in MSVC Clang 15.0.1 raises a C++17 warning
|
||||
>
|
||||
>
|
||||
>
|
||||
)
|
||||
check_cxx_compiler_flag("-Wno-reserved-identifier" WARN_RESERVED_ID)
|
||||
if (WARN_RESERVED_ID)
|
||||
target_compile_options(gsl_tests_config INTERFACE "-Wno-reserved-identifier")
|
||||
endif()
|
||||
check_cxx_compiler_flag("-Wno-unsafe-buffer-usage" WARN_UNSAFE_BUFFER)
|
||||
if (WARN_UNSAFE_BUFFER)
|
||||
# This test uses very greedy heuristics such as "no pointer arithmetic on raw buffer"
|
||||
target_compile_options(gsl_tests_config INTERFACE "-Wno-unsafe-buffer-usage")
|
||||
endif()
|
||||
else()
|
||||
target_compile_options(gsl_tests_config INTERFACE
|
||||
-fno-strict-aliasing
|
||||
-Wall
|
||||
-Wcast-align
|
||||
-Wconversion
|
||||
-Wctor-dtor-privacy
|
||||
-Werror
|
||||
-Wextra
|
||||
-Wpedantic
|
||||
-Wshadow
|
||||
-Wsign-conversion
|
||||
-Wfloat-equal
|
||||
-Wno-deprecated-declarations # Allow tests for [[deprecated]] elements
|
||||
$<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>>:
|
||||
-Weverything
|
||||
-Wno-c++98-compat
|
||||
-Wno-c++98-compat-pedantic
|
||||
-Wno-missing-braces
|
||||
-Wno-covered-switch-default # GTest
|
||||
-Wno-global-constructors # GTest
|
||||
-Wno-missing-prototypes
|
||||
-Wno-padded
|
||||
-Wno-unknown-attributes
|
||||
-Wno-used-but-marked-unused # GTest EXPECT_DEATH
|
||||
-Wno-weak-vtables
|
||||
$<$<EQUAL:${GSL_CXX_STANDARD},14>: # no support for [[maybe_unused]]
|
||||
-Wno-unused-member-function
|
||||
-Wno-unused-variable
|
||||
>
|
||||
>
|
||||
$<$<CXX_COMPILER_ID:Clang>:
|
||||
$<$<AND:$<VERSION_GREATER:$<CXX_COMPILER_VERSION>,4.99>,$<VERSION_LESS:$<CXX_COMPILER_VERSION>,6>>:
|
||||
$<$<EQUAL:${GSL_CXX_STANDARD},17>:-Wno-undefined-func-template>
|
||||
>
|
||||
$<$<AND:$<EQUAL:${GSL_CXX_STANDARD},20>,$<OR:$<CXX_COMPILER_VERSION:11.0.0>,$<CXX_COMPILER_VERSION:10.0.0>>>:
|
||||
-Wno-zero-as-null-pointer-constant # failing Clang Ubuntu 20.04 tests, seems to be a bug with clang 10.0.0
|
||||
# and clang 11.0.0. (operator< is being re-written by the compiler
|
||||
# as operator<=> and raising the warning)
|
||||
>
|
||||
>
|
||||
$<$<CXX_COMPILER_ID:AppleClang>:
|
||||
$<$<AND:$<VERSION_GREATER:$<CXX_COMPILER_VERSION>,9.1>,$<VERSION_LESS:$<CXX_COMPILER_VERSION>,10>>:
|
||||
$<$<EQUAL:${GSL_CXX_STANDARD},17>:-Wno-undefined-func-template>
|
||||
>
|
||||
>
|
||||
$<$<CXX_COMPILER_ID:GNU>:
|
||||
-Wdouble-promotion # float implicit to double
|
||||
-Wlogical-op # suspicious uses of logical operators
|
||||
$<$<NOT:$<VERSION_LESS:$<CXX_COMPILER_VERSION>,6>>:
|
||||
-Wduplicated-cond # duplicated if-else conditions
|
||||
-Wmisleading-indentation
|
||||
-Wnull-dereference
|
||||
$<$<EQUAL:${GSL_CXX_STANDARD},14>: # no support for [[maybe_unused]]
|
||||
-Wno-unused-variable
|
||||
>
|
||||
>
|
||||
$<$<NOT:$<VERSION_LESS:$<CXX_COMPILER_VERSION>,7>>:
|
||||
-Wduplicated-branches # identical if-else branches
|
||||
>
|
||||
>
|
||||
)
|
||||
endif(MSVC)
|
||||
|
||||
# for tests to find the gtest header
|
||||
target_include_directories(gsl_tests_config SYSTEM INTERFACE
|
||||
googletest/googletest/include
|
||||
)
|
||||
|
||||
add_executable(gsl_tests
|
||||
algorithm_tests.cpp
|
||||
assertion_tests.cpp
|
||||
at_tests.cpp
|
||||
byte_tests.cpp
|
||||
notnull_tests.cpp
|
||||
owner_tests.cpp
|
||||
span_compatibility_tests.cpp
|
||||
span_ext_tests.cpp
|
||||
span_tests.cpp
|
||||
strict_notnull_tests.cpp
|
||||
|
||||
utils_tests.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(gsl_tests
|
||||
Microsoft.GSL::GSL
|
||||
gsl_tests_config
|
||||
${GTestMain_LIBRARIES}
|
||||
)
|
||||
add_test(gsl_tests gsl_tests)
|
||||
|
||||
# No exception tests
|
||||
|
||||
foreach(flag_var
|
||||
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
|
||||
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
|
||||
STRING (REGEX REPLACE "/EHsc" "" ${flag_var} "${${flag_var}}")
|
||||
endforeach(flag_var)
|
||||
|
||||
# this interface adds compile options to how the tests are run
|
||||
# please try to keep entries ordered =)
|
||||
add_library(gsl_tests_config_noexcept INTERFACE)
|
||||
if(MSVC) # MSVC or simulating MSVC
|
||||
target_compile_definitions(gsl_tests_config_noexcept INTERFACE
|
||||
_HAS_EXCEPTIONS=0 # disable exceptions in the Microsoft STL
|
||||
)
|
||||
target_compile_options(gsl_tests_config_noexcept INTERFACE
|
||||
${GSL_CPLUSPLUS_OPT}
|
||||
/W4
|
||||
/WX
|
||||
$<$<CXX_COMPILER_ID:MSVC>:
|
||||
/wd4577
|
||||
/wd4702
|
||||
/wd26440 # CppCoreCheck - GTest
|
||||
/wd26446 # CppCoreCheck - prefer gsl::at()
|
||||
>
|
||||
$<$<CXX_COMPILER_ID:Clang>:
|
||||
-Weverything
|
||||
-Wfloat-equal
|
||||
-Wno-c++98-compat
|
||||
-Wno-c++98-compat-pedantic
|
||||
-Wno-missing-prototypes
|
||||
-Wno-unknown-attributes
|
||||
$<$<EQUAL:${GSL_CXX_STANDARD},14>:
|
||||
$<$<VERSION_EQUAL:$<CXX_COMPILER_VERSION>,15.0.1>:
|
||||
-Wno-deprecated # False positive in MSVC Clang 15.0.1 raises a C++17 warning
|
||||
>
|
||||
>
|
||||
>
|
||||
)
|
||||
check_cxx_compiler_flag("-Wno-reserved-identifier" WARN_RESERVED_ID)
|
||||
if (WARN_RESERVED_ID)
|
||||
target_compile_options(gsl_tests_config_noexcept INTERFACE "-Wno-reserved-identifier")
|
||||
endif()
|
||||
check_cxx_compiler_flag("-Wno-unsafe-buffer-usage" WARN_UNSAFE_BUFFER)
|
||||
if (WARN_UNSAFE_BUFFER)
|
||||
# This test uses very greedy heuristics such as "no pointer arithmetic on raw buffer"
|
||||
target_compile_options(gsl_tests_config_noexcept INTERFACE "-Wno-unsafe-buffer-usage")
|
||||
endif()
|
||||
else()
|
||||
target_compile_options(gsl_tests_config_noexcept INTERFACE
|
||||
-fno-exceptions
|
||||
-fno-strict-aliasing
|
||||
-Wall
|
||||
-Wcast-align
|
||||
-Wconversion
|
||||
-Wctor-dtor-privacy
|
||||
-Werror
|
||||
-Wextra
|
||||
-Wpedantic
|
||||
-Wshadow
|
||||
-Wsign-conversion
|
||||
-Wfloat-equal
|
||||
$<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>>:
|
||||
-Weverything
|
||||
-Wno-c++98-compat
|
||||
-Wno-c++98-compat-pedantic
|
||||
-Wno-missing-prototypes
|
||||
-Wno-unknown-attributes
|
||||
-Wno-weak-vtables
|
||||
>
|
||||
$<$<CXX_COMPILER_ID:GNU>:
|
||||
-Wdouble-promotion # float implicit to double
|
||||
-Wlogical-op # suspicious uses of logical operators
|
||||
-Wuseless-cast # casting to its own type
|
||||
$<$<NOT:$<VERSION_LESS:$<CXX_COMPILER_VERSION>,6>>:
|
||||
-Wduplicated-cond # duplicated if-else conditions
|
||||
-Wmisleading-indentation
|
||||
-Wnull-dereference
|
||||
>
|
||||
$<$<NOT:$<VERSION_LESS:$<CXX_COMPILER_VERSION>,7>>:
|
||||
-Wduplicated-branches # identical if-else branches
|
||||
>
|
||||
$<$<NOT:$<VERSION_LESS:$<CXX_COMPILER_VERSION>,8>>:
|
||||
-Wcast-align=strict # increase alignment (i.e. char* to int*)
|
||||
>
|
||||
>
|
||||
)
|
||||
endif(MSVC)
|
||||
|
||||
add_executable(gsl_noexcept_tests no_exception_ensure_tests.cpp)
|
||||
target_link_libraries(gsl_noexcept_tests
|
||||
Microsoft.GSL::GSL
|
||||
gsl_tests_config_noexcept
|
||||
)
|
||||
add_test(gsl_noexcept_tests gsl_noexcept_tests)
|
14
deps/GSL/tests/CMakeLists.txt.in
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
cmake_minimum_required(VERSION 3.0.2)
|
||||
project(googletest-download NONE)
|
||||
|
||||
include(ExternalProject)
|
||||
ExternalProject_Add(googletest
|
||||
GIT_REPOSITORY https://github.com/google/googletest.git
|
||||
GIT_TAG 1b18723e874b256c1e39378c6774a90701d70f7a
|
||||
SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src"
|
||||
BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
TEST_COMMAND ""
|
||||
)
|
224
deps/GSL/tests/algorithm_tests.cpp
vendored
Normal file
@ -0,0 +1,224 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <array> // for array
|
||||
#include <cstddef> // for size_t
|
||||
#include <gsl/algorithm> // for copy
|
||||
#include <gsl/span> // for span
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "deathTestCommon.h"
|
||||
|
||||
namespace gsl
|
||||
{
|
||||
struct fail_fast;
|
||||
} // namespace gsl
|
||||
|
||||
using namespace gsl;
|
||||
|
||||
TEST(algorithm_tests, same_type)
|
||||
{
|
||||
// dynamic source and destination span
|
||||
{
|
||||
std::array<int, 5> src{1, 2, 3, 4, 5};
|
||||
std::array<int, 10> dst{};
|
||||
|
||||
const span<int> src_span(src);
|
||||
const span<int> dst_span(dst);
|
||||
|
||||
copy(src_span, dst_span);
|
||||
copy(src_span, dst_span.subspan(src_span.size()));
|
||||
|
||||
for (std::size_t i = 0; i < src.size(); ++i)
|
||||
{
|
||||
EXPECT_TRUE(dst[i] == src[i]);
|
||||
EXPECT_TRUE(dst[i + src.size()] == src[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// static source and dynamic destination span
|
||||
{
|
||||
std::array<int, 5> src{1, 2, 3, 4, 5};
|
||||
std::array<int, 10> dst{};
|
||||
|
||||
const span<int, 5> src_span(src);
|
||||
const span<int> dst_span(dst);
|
||||
|
||||
copy(src_span, dst_span);
|
||||
copy(src_span, dst_span.subspan(src_span.size()));
|
||||
|
||||
for (std::size_t i = 0; i < src.size(); ++i)
|
||||
{
|
||||
EXPECT_TRUE(dst[i] == src[i]);
|
||||
EXPECT_TRUE(dst[i + src.size()] == src[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// dynamic source and static destination span
|
||||
{
|
||||
std::array<int, 5> src{1, 2, 3, 4, 5};
|
||||
std::array<int, 10> dst{};
|
||||
|
||||
const gsl::span<int> src_span(src);
|
||||
const gsl::span<int, 10> dst_span(dst);
|
||||
|
||||
copy(src_span, dst_span);
|
||||
copy(src_span, dst_span.subspan(src_span.size()));
|
||||
|
||||
for (std::size_t i = 0; i < src.size(); ++i)
|
||||
{
|
||||
EXPECT_TRUE(dst[i] == src[i]);
|
||||
EXPECT_TRUE(dst[i + src.size()] == src[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// static source and destination span
|
||||
{
|
||||
std::array<int, 5> src{1, 2, 3, 4, 5};
|
||||
std::array<int, 10> dst{};
|
||||
|
||||
const span<int, 5> src_span(src);
|
||||
const span<int, 10> dst_span(dst);
|
||||
|
||||
copy(src_span, dst_span);
|
||||
copy(src_span, dst_span.subspan(src_span.size()));
|
||||
|
||||
for (std::size_t i = 0; i < src.size(); ++i)
|
||||
{
|
||||
EXPECT_TRUE(dst[i] == src[i]);
|
||||
EXPECT_TRUE(dst[i + src.size()] == src[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(algorithm_tests, compatible_type)
|
||||
{
|
||||
// dynamic source and destination span
|
||||
{
|
||||
std::array<short, 5> src{1, 2, 3, 4, 5};
|
||||
std::array<int, 10> dst{};
|
||||
|
||||
const span<short> src_span(src);
|
||||
const span<int> dst_span(dst);
|
||||
|
||||
copy(src_span, dst_span);
|
||||
copy(src_span, dst_span.subspan(src_span.size()));
|
||||
|
||||
for (std::size_t i = 0; i < src.size(); ++i)
|
||||
{
|
||||
EXPECT_TRUE(dst[i] == src[i]);
|
||||
EXPECT_TRUE(dst[i + src.size()] == src[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// static source and dynamic destination span
|
||||
{
|
||||
std::array<short, 5> src{1, 2, 3, 4, 5};
|
||||
std::array<int, 10> dst{};
|
||||
|
||||
const span<short, 5> src_span(src);
|
||||
const span<int> dst_span(dst);
|
||||
|
||||
copy(src_span, dst_span);
|
||||
copy(src_span, dst_span.subspan(src_span.size()));
|
||||
|
||||
for (std::size_t i = 0; i < src.size(); ++i)
|
||||
{
|
||||
EXPECT_TRUE(dst[i] == src[i]);
|
||||
EXPECT_TRUE(dst[i + src.size()] == src[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// dynamic source and static destination span
|
||||
{
|
||||
std::array<short, 5> src{1, 2, 3, 4, 5};
|
||||
std::array<int, 10> dst{};
|
||||
|
||||
const span<short> src_span(src);
|
||||
const span<int, 10> dst_span(dst);
|
||||
|
||||
copy(src_span, dst_span);
|
||||
copy(src_span, dst_span.subspan(src_span.size()));
|
||||
|
||||
for (std::size_t i = 0; i < src.size(); ++i)
|
||||
{
|
||||
EXPECT_TRUE(dst[i] == src[i]);
|
||||
EXPECT_TRUE(dst[i + src.size()] == src[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// static source and destination span
|
||||
{
|
||||
std::array<short, 5> src{1, 2, 3, 4, 5};
|
||||
std::array<int, 10> dst{};
|
||||
|
||||
const span<short, 5> src_span(src);
|
||||
const span<int, 10> dst_span(dst);
|
||||
|
||||
copy(src_span, dst_span);
|
||||
copy(src_span, dst_span.subspan(src_span.size()));
|
||||
|
||||
for (std::size_t i = 0; i < src.size(); ++i)
|
||||
{
|
||||
EXPECT_TRUE(dst[i] == src[i]);
|
||||
EXPECT_TRUE(dst[i + src.size()] == src[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
TEST(algorithm_tests, incompatible_type)
|
||||
{
|
||||
std::array<int, 4> src{1, 2, 3, 4};
|
||||
std::array<int*, 12> dst{};
|
||||
|
||||
span<int> src_span_dyn(src);
|
||||
span<int, 4> src_span_static(src);
|
||||
span<int*> dst_span_dyn(dst);
|
||||
span<int*, 4> dst_span_static(dst);
|
||||
|
||||
// every line should produce a compilation error
|
||||
copy(src_span_dyn, dst_span_dyn);
|
||||
copy(src_span_dyn, dst_span_static);
|
||||
copy(src_span_static, dst_span_dyn);
|
||||
copy(src_span_static, dst_span_static);
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(algorithm_tests, small_destination_span)
|
||||
{
|
||||
const auto terminateHandler = std::set_terminate([] {
|
||||
std::cerr << "Expected Death. small_destination_span";
|
||||
std::abort();
|
||||
});
|
||||
const auto expected = GetExpectedDeathString(terminateHandler);
|
||||
|
||||
std::array<int, 12> src{1, 2, 3, 4};
|
||||
std::array<int, 4> dst{};
|
||||
|
||||
const span<int> src_span_dyn(src);
|
||||
const span<int, 12> src_span_static(src);
|
||||
const span<int> dst_span_dyn(dst);
|
||||
const span<int, 4> dst_span_static(dst);
|
||||
|
||||
EXPECT_DEATH(copy(src_span_dyn, dst_span_dyn), expected);
|
||||
EXPECT_DEATH(copy(src_span_dyn, dst_span_static), expected);
|
||||
EXPECT_DEATH(copy(src_span_static, dst_span_dyn), expected);
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
copy(src_span_static, dst_span_static);
|
||||
#endif
|
||||
}
|
60
deps/GSL/tests/assertion_tests.cpp
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "deathTestCommon.h"
|
||||
#include <gsl/assert> // for Ensures, Expects
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace gsl;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
int f(int i)
|
||||
{
|
||||
Expects(i > 0 && i < 10);
|
||||
return i;
|
||||
}
|
||||
|
||||
int g(int i)
|
||||
{
|
||||
i++;
|
||||
Ensures(i > 0 && i < 10);
|
||||
return i;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST(assertion_tests, expects)
|
||||
{
|
||||
const auto terminateHandler = std::set_terminate([] {
|
||||
std::cerr << "Expected Death. expects";
|
||||
std::abort();
|
||||
});
|
||||
|
||||
EXPECT_TRUE(f(2) == 2);
|
||||
EXPECT_DEATH(f(10), GetExpectedDeathString(terminateHandler));
|
||||
}
|
||||
|
||||
TEST(assertion_tests, ensures)
|
||||
{
|
||||
const auto terminateHandler = std::set_terminate([] {
|
||||
std::cerr << "Expected Death. ensures";
|
||||
std::abort();
|
||||
});
|
||||
|
||||
EXPECT_TRUE(g(2) == 3);
|
||||
EXPECT_DEATH(g(9), GetExpectedDeathString(terminateHandler));
|
||||
}
|
173
deps/GSL/tests/at_tests.cpp
vendored
Normal file
@ -0,0 +1,173 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <gsl/util> // for at
|
||||
|
||||
#include <array> // for array
|
||||
#include <cstddef> // for size_t
|
||||
#include <exception> // for terminate
|
||||
#include <initializer_list> // for initializer_list
|
||||
#include <vector> // for vector
|
||||
#if defined(__cplusplus) && __cplusplus >= 202002L
|
||||
#include <span>
|
||||
#endif // __cplusplus >= 202002L
|
||||
|
||||
#include "deathTestCommon.h"
|
||||
|
||||
TEST(at_tests, static_array)
|
||||
{
|
||||
int a[4] = {1, 2, 3, 4};
|
||||
const int(&c_a)[4] = a;
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
EXPECT_TRUE(&gsl::at(a, i) == &a[i]);
|
||||
EXPECT_TRUE(&gsl::at(c_a, i) == &a[i]);
|
||||
}
|
||||
|
||||
const auto terminateHandler = std::set_terminate([] {
|
||||
std::cerr << "Expected Death. static_array";
|
||||
std::abort();
|
||||
});
|
||||
const auto expected = GetExpectedDeathString(terminateHandler);
|
||||
|
||||
EXPECT_DEATH(gsl::at(a, -1), expected);
|
||||
EXPECT_DEATH(gsl::at(a, 4), expected);
|
||||
EXPECT_DEATH(gsl::at(c_a, -1), expected);
|
||||
EXPECT_DEATH(gsl::at(c_a, 4), expected);
|
||||
}
|
||||
|
||||
TEST(at_tests, std_array)
|
||||
{
|
||||
std::array<int, 4> a = {1, 2, 3, 4};
|
||||
const std::array<int, 4>& c_a = a;
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
EXPECT_TRUE(&gsl::at(a, i) == &a[static_cast<std::size_t>(i)]);
|
||||
EXPECT_TRUE(&gsl::at(c_a, i) == &a[static_cast<std::size_t>(i)]);
|
||||
}
|
||||
|
||||
const auto terminateHandler = std::set_terminate([] {
|
||||
std::cerr << "Expected Death. std_array";
|
||||
std::abort();
|
||||
});
|
||||
const auto expected = GetExpectedDeathString(terminateHandler);
|
||||
|
||||
EXPECT_DEATH(gsl::at(a, -1), expected);
|
||||
EXPECT_DEATH(gsl::at(a, 4), expected);
|
||||
EXPECT_DEATH(gsl::at(c_a, -1), expected);
|
||||
EXPECT_DEATH(gsl::at(c_a, 4), expected);
|
||||
}
|
||||
|
||||
TEST(at_tests, std_vector)
|
||||
{
|
||||
std::vector<int> a = {1, 2, 3, 4};
|
||||
const std::vector<int>& c_a = a;
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
EXPECT_TRUE(&gsl::at(a, i) == &a[static_cast<std::size_t>(i)]);
|
||||
EXPECT_TRUE(&gsl::at(c_a, i) == &a[static_cast<std::size_t>(i)]);
|
||||
}
|
||||
|
||||
const auto terminateHandler = std::set_terminate([] {
|
||||
std::cerr << "Expected Death. std_vector";
|
||||
std::abort();
|
||||
});
|
||||
const auto expected = GetExpectedDeathString(terminateHandler);
|
||||
|
||||
EXPECT_DEATH(gsl::at(a, -1), expected);
|
||||
EXPECT_DEATH(gsl::at(a, 4), expected);
|
||||
EXPECT_DEATH(gsl::at(c_a, -1), expected);
|
||||
EXPECT_DEATH(gsl::at(c_a, 4), expected);
|
||||
}
|
||||
|
||||
TEST(at_tests, InitializerList)
|
||||
{
|
||||
const std::initializer_list<int> a = {1, 2, 3, 4};
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
EXPECT_TRUE(gsl::at(a, i) == i + 1);
|
||||
EXPECT_TRUE(gsl::at({1, 2, 3, 4}, i) == i + 1);
|
||||
}
|
||||
|
||||
const auto terminateHandler = std::set_terminate([] {
|
||||
std::cerr << "Expected Death. InitializerList";
|
||||
std::abort();
|
||||
});
|
||||
const auto expected = GetExpectedDeathString(terminateHandler);
|
||||
|
||||
EXPECT_DEATH(gsl::at(a, -1), expected);
|
||||
EXPECT_DEATH(gsl::at(a, 4), expected);
|
||||
EXPECT_DEATH(gsl::at({1, 2, 3, 4}, -1), expected);
|
||||
EXPECT_DEATH(gsl::at({1, 2, 3, 4}, 4), expected);
|
||||
}
|
||||
|
||||
#if defined(FORCE_STD_SPAN_TESTS) || defined(__cpp_lib_span) && __cpp_lib_span >= 202002L
|
||||
TEST(at_tests, std_span)
|
||||
{
|
||||
std::vector<int> vec{1, 2, 3, 4, 5};
|
||||
std::span sp{vec};
|
||||
|
||||
std::vector<int> cvec{1, 2, 3, 4, 5};
|
||||
std::span csp{cvec};
|
||||
|
||||
for (gsl::index i = 0; i < gsl::narrow_cast<gsl::index>(vec.size()); ++i)
|
||||
{
|
||||
EXPECT_TRUE(&gsl::at(sp, i) == &vec[gsl::narrow_cast<size_t>(i)]);
|
||||
EXPECT_TRUE(&gsl::at(csp, i) == &cvec[gsl::narrow_cast<size_t>(i)]);
|
||||
}
|
||||
|
||||
const auto terminateHandler = std::set_terminate([] {
|
||||
std::cerr << "Expected Death. std_span";
|
||||
std::abort();
|
||||
});
|
||||
const auto expected = GetExpectedDeathString(terminateHandler);
|
||||
|
||||
EXPECT_DEATH(gsl::at(sp, -1), expected);
|
||||
EXPECT_DEATH(gsl::at(sp, gsl::narrow_cast<gsl::index>(sp.size())), expected);
|
||||
EXPECT_DEATH(gsl::at(csp, -1), expected);
|
||||
EXPECT_DEATH(gsl::at(csp, gsl::narrow_cast<gsl::index>(sp.size())), expected);
|
||||
}
|
||||
#endif // defined(FORCE_STD_SPAN_TESTS) || defined(__cpp_lib_span) && __cpp_lib_span >= 202002L
|
||||
|
||||
#if !defined(_MSC_VER) || defined(__clang__) || _MSC_VER >= 1910
|
||||
static constexpr bool test_constexpr()
|
||||
{
|
||||
int a1[4] = {1, 2, 3, 4};
|
||||
const int(&c_a1)[4] = a1;
|
||||
std::array<int, 4> a2 = {1, 2, 3, 4};
|
||||
const std::array<int, 4>& c_a2 = a2;
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
if (&gsl::at(a1, i) != &a1[i]) return false;
|
||||
if (&gsl::at(c_a1, i) != &a1[i]) return false;
|
||||
// requires C++17:
|
||||
// if (&gsl::at(a2, i) != &a2[static_cast<std::size_t>(i)]) return false;
|
||||
if (&gsl::at(c_a2, i) != &c_a2[static_cast<std::size_t>(i)]) return false;
|
||||
if (gsl::at({1, 2, 3, 4}, i) != i + 1) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static_assert(test_constexpr(), "FAIL");
|
||||
#endif
|
134
deps/GSL/tests/byte_tests.cpp
vendored
Normal file
@ -0,0 +1,134 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <gsl/byte> // for to_byte, to_integer, byte, operator&, ope...
|
||||
|
||||
using namespace std;
|
||||
using namespace gsl;
|
||||
|
||||
namespace
|
||||
{
|
||||
int modify_both(gsl::byte& b, int& i)
|
||||
{
|
||||
i = 10;
|
||||
b = to_byte<5>();
|
||||
return i;
|
||||
}
|
||||
|
||||
TEST(byte_tests, construction)
|
||||
{
|
||||
{
|
||||
const byte b = static_cast<byte>(4);
|
||||
EXPECT_TRUE(static_cast<unsigned char>(b) == 4);
|
||||
}
|
||||
|
||||
{
|
||||
const byte b = byte(12);
|
||||
EXPECT_TRUE(static_cast<unsigned char>(b) == 12);
|
||||
}
|
||||
|
||||
{
|
||||
const byte b = to_byte<12>();
|
||||
EXPECT_TRUE(static_cast<unsigned char>(b) == 12);
|
||||
}
|
||||
{
|
||||
const unsigned char uc = 12;
|
||||
const byte b = to_byte(uc);
|
||||
EXPECT_TRUE(static_cast<unsigned char>(b) == 12);
|
||||
}
|
||||
|
||||
#if defined(__cplusplus) && (__cplusplus >= 201703L)
|
||||
{
|
||||
const byte b{14};
|
||||
EXPECT_TRUE(static_cast<unsigned char>(b) == 14);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
to_byte(char{});
|
||||
to_byte(3);
|
||||
to_byte(3u);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(byte_tests, bitwise_operations)
|
||||
{
|
||||
const byte b = to_byte<0xFF>();
|
||||
|
||||
byte a = to_byte<0x00>();
|
||||
EXPECT_TRUE((b | a) == to_byte<0xFF>());
|
||||
EXPECT_TRUE(a == to_byte<0x00>());
|
||||
|
||||
a |= b;
|
||||
EXPECT_TRUE(a == to_byte<0xFF>());
|
||||
|
||||
a = to_byte<0x01>();
|
||||
EXPECT_TRUE((b & a) == to_byte<0x01>());
|
||||
|
||||
a &= b;
|
||||
EXPECT_TRUE(a == to_byte<0x01>());
|
||||
|
||||
EXPECT_TRUE((b ^ a) == to_byte<0xFE>());
|
||||
|
||||
EXPECT_TRUE(a == to_byte<0x01>());
|
||||
a ^= b;
|
||||
EXPECT_TRUE(a == to_byte<0xFE>());
|
||||
|
||||
a = to_byte<0x01>();
|
||||
EXPECT_TRUE(~a == to_byte<0xFE>());
|
||||
|
||||
a = to_byte<0xFF>();
|
||||
EXPECT_TRUE((a << 4) == to_byte<0xF0>());
|
||||
EXPECT_TRUE((a >> 4) == to_byte<0x0F>());
|
||||
|
||||
a <<= 4;
|
||||
EXPECT_TRUE(a == to_byte<0xF0>());
|
||||
a >>= 4;
|
||||
EXPECT_TRUE(a == to_byte<0x0F>());
|
||||
}
|
||||
|
||||
TEST(byte_tests, to_integer)
|
||||
{
|
||||
const byte b = to_byte<0x12>();
|
||||
|
||||
EXPECT_TRUE(0x12 == gsl::to_integer<char>(b));
|
||||
EXPECT_TRUE(0x12 == gsl::to_integer<short>(b));
|
||||
EXPECT_TRUE(0x12 == gsl::to_integer<long>(b));
|
||||
EXPECT_TRUE(0x12 == gsl::to_integer<long long>(b));
|
||||
|
||||
EXPECT_TRUE(0x12 == gsl::to_integer<unsigned char>(b));
|
||||
EXPECT_TRUE(0x12 == gsl::to_integer<unsigned short>(b));
|
||||
EXPECT_TRUE(0x12 == gsl::to_integer<unsigned long>(b));
|
||||
EXPECT_TRUE(0x12 == gsl::to_integer<unsigned long long>(b));
|
||||
|
||||
// EXPECT_TRUE(0x12 == gsl::to_integer<float>(b)); // expect compile-time error
|
||||
// EXPECT_TRUE(0x12 == gsl::to_integer<double>(b)); // expect compile-time error
|
||||
}
|
||||
|
||||
TEST(byte_tests, aliasing)
|
||||
{
|
||||
int i{0};
|
||||
const int res = modify_both(reinterpret_cast<byte&>(i), i);
|
||||
EXPECT_TRUE(res == i);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
copy(src_span_static, dst_span_static);
|
||||
#endif
|
11
deps/GSL/tests/deathTestCommon.h
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
#include <gsl/assert>
|
||||
|
||||
constexpr char deathstring[] = "Expected Death";
|
||||
constexpr char failed_set_terminate_deathstring[] = ".*";
|
||||
|
||||
// This prevents a failed call to set_terminate from failing the test suite.
|
||||
constexpr const char* GetExpectedDeathString(std::terminate_handler handle)
|
||||
{
|
||||
return handle ? deathstring : failed_set_terminate_deathstring;
|
||||
}
|
55
deps/GSL/tests/no_exception_ensure_tests.cpp
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdlib> // for std::exit
|
||||
#include <gsl/span> // for span
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
|
||||
int operator_subscript_no_throw() noexcept
|
||||
{
|
||||
int arr[10];
|
||||
const gsl::span<int> sp{arr};
|
||||
return sp[11];
|
||||
}
|
||||
|
||||
[[noreturn]] void test_terminate() { std::exit(0); }
|
||||
|
||||
void setup_termination_handler() noexcept
|
||||
{
|
||||
#if defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND)
|
||||
|
||||
auto& handler = gsl::details::get_terminate_handler();
|
||||
handler = &test_terminate;
|
||||
|
||||
#else
|
||||
|
||||
std::set_terminate(test_terminate);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
int main() noexcept
|
||||
{
|
||||
std::cout << "Running main() from " __FILE__ "\n";
|
||||
#if defined(IOS_PROCESS_DELAY_WORKAROUND)
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
#endif
|
||||
setup_termination_handler();
|
||||
operator_subscript_no_throw();
|
||||
return -1;
|
||||
}
|
648
deps/GSL/tests/notnull_tests.cpp
vendored
Normal file
@ -0,0 +1,648 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <gsl/pointers> // for not_null, operator<, operator<=, operator>
|
||||
|
||||
#include <algorithm> // for addressof
|
||||
#include <cstdint> // for uint16_t
|
||||
#include <memory> // for shared_ptr, make_shared, operator<, opera...
|
||||
#include <sstream> // for operator<<, ostringstream, basic_ostream:...
|
||||
#include <string> // for basic_string, operator==, string, operator<<
|
||||
#include <typeinfo> // for type_info
|
||||
#include <variant> // for variant, monostate, get
|
||||
|
||||
#include "deathTestCommon.h"
|
||||
using namespace gsl;
|
||||
|
||||
struct MyBase
|
||||
{
|
||||
};
|
||||
struct MyDerived : public MyBase
|
||||
{
|
||||
};
|
||||
struct Unrelated
|
||||
{
|
||||
};
|
||||
|
||||
// stand-in for a user-defined ref-counted class
|
||||
template <typename T>
|
||||
struct RefCounted
|
||||
{
|
||||
RefCounted(T* p) : p_(p) {}
|
||||
operator T*() { return p_; }
|
||||
T* p_;
|
||||
};
|
||||
|
||||
// user defined smart pointer with comparison operators returning non bool value
|
||||
template <typename T>
|
||||
struct CustomPtr
|
||||
{
|
||||
CustomPtr(T* p) : p_(p) {}
|
||||
operator T*() const { return p_; }
|
||||
bool operator!=(std::nullptr_t) const { return p_ != nullptr; }
|
||||
T* p_ = nullptr;
|
||||
};
|
||||
|
||||
template <typename T, typename U>
|
||||
std::string operator==(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
|
||||
{
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
return reinterpret_cast<const void*>(lhs.p_) == reinterpret_cast<const void*>(rhs.p_) ? "true"
|
||||
: "false";
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
std::string operator!=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
|
||||
{
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
return reinterpret_cast<const void*>(lhs.p_) != reinterpret_cast<const void*>(rhs.p_) ? "true"
|
||||
: "false";
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
std::string operator<(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
|
||||
{
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
return reinterpret_cast<const void*>(lhs.p_) < reinterpret_cast<const void*>(rhs.p_) ? "true"
|
||||
: "false";
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
std::string operator>(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
|
||||
{
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
return reinterpret_cast<const void*>(lhs.p_) > reinterpret_cast<const void*>(rhs.p_) ? "true"
|
||||
: "false";
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
std::string operator<=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
|
||||
{
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
return reinterpret_cast<const void*>(lhs.p_) <= reinterpret_cast<const void*>(rhs.p_) ? "true"
|
||||
: "false";
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
std::string operator>=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
|
||||
{
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
return reinterpret_cast<const void*>(lhs.p_) >= reinterpret_cast<const void*>(rhs.p_) ? "true"
|
||||
: "false";
|
||||
}
|
||||
|
||||
struct NonCopyableNonMovable
|
||||
{
|
||||
NonCopyableNonMovable() = default;
|
||||
NonCopyableNonMovable(const NonCopyableNonMovable&) = delete;
|
||||
NonCopyableNonMovable& operator=(const NonCopyableNonMovable&) = delete;
|
||||
NonCopyableNonMovable(NonCopyableNonMovable&&) = delete;
|
||||
NonCopyableNonMovable& operator=(NonCopyableNonMovable&&) = delete;
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(f .4) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
bool helper(not_null<int*> p) { return *p == 12; }
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(f .4) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
bool helper_const(not_null<const int*> p) { return *p == 12; }
|
||||
|
||||
int* return_pointer() { return nullptr; }
|
||||
} // namespace
|
||||
|
||||
TEST(notnull_tests, TestNotNullConstructors)
|
||||
{
|
||||
{
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
not_null<int*> p = nullptr; // yay...does not compile!
|
||||
not_null<std::vector<char>*> p1 = 0; // yay...does not compile!
|
||||
not_null<int*> p2; // yay...does not compile!
|
||||
std::unique_ptr<int> up = std::make_unique<int>(120);
|
||||
not_null<int*> p3 = up;
|
||||
|
||||
// Forbid non-nullptr assignable types
|
||||
not_null<std::vector<int>> f(std::vector<int>{1});
|
||||
not_null<int> z(10);
|
||||
not_null<std::vector<int>> y({1, 2});
|
||||
#endif
|
||||
}
|
||||
|
||||
const auto terminateHandler = std::set_terminate([] {
|
||||
std::cerr << "Expected Death. TestNotNullConstructors";
|
||||
std::abort();
|
||||
});
|
||||
const auto expected = GetExpectedDeathString(terminateHandler);
|
||||
|
||||
{
|
||||
// from shared pointer
|
||||
int i = 12;
|
||||
auto rp = RefCounted<int>(&i);
|
||||
not_null<int*> p(rp);
|
||||
EXPECT_TRUE(p.get() == &i);
|
||||
|
||||
not_null<std::shared_ptr<int>> x(
|
||||
std::make_shared<int>(10)); // shared_ptr<int> is nullptr assignable
|
||||
|
||||
int* pi = nullptr;
|
||||
EXPECT_DEATH((not_null<decltype(pi)>(pi)), expected);
|
||||
}
|
||||
|
||||
{
|
||||
// from pointer to local
|
||||
int t = 42;
|
||||
|
||||
not_null<int*> x = &t;
|
||||
helper(&t);
|
||||
helper_const(&t);
|
||||
|
||||
EXPECT_TRUE(*x == 42);
|
||||
}
|
||||
|
||||
{
|
||||
// from raw pointer
|
||||
// from not_null pointer
|
||||
|
||||
int t = 42;
|
||||
int* p = &t;
|
||||
|
||||
not_null<int*> x = p;
|
||||
helper(p);
|
||||
helper_const(p);
|
||||
helper(x);
|
||||
helper_const(x);
|
||||
|
||||
EXPECT_TRUE(*x == 42);
|
||||
}
|
||||
|
||||
{
|
||||
// from raw const pointer
|
||||
// from not_null const pointer
|
||||
|
||||
int t = 42;
|
||||
const int* cp = &t;
|
||||
|
||||
not_null<const int*> x = cp;
|
||||
helper_const(cp);
|
||||
helper_const(x);
|
||||
|
||||
EXPECT_TRUE(*x == 42);
|
||||
}
|
||||
|
||||
{
|
||||
// from not_null const pointer, using auto
|
||||
int t = 42;
|
||||
const int* cp = &t;
|
||||
|
||||
auto x = not_null<const int*>{cp};
|
||||
|
||||
EXPECT_TRUE(*x == 42);
|
||||
}
|
||||
|
||||
{
|
||||
// from returned pointer
|
||||
|
||||
EXPECT_DEATH(helper(return_pointer()), expected);
|
||||
EXPECT_DEATH(helper_const(return_pointer()), expected);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ostream_helper(T v)
|
||||
{
|
||||
not_null<T*> p(&v);
|
||||
{
|
||||
std::ostringstream os;
|
||||
std::ostringstream ref;
|
||||
os << static_cast<void*>(p);
|
||||
ref << static_cast<void*>(&v);
|
||||
EXPECT_TRUE(os.str() == ref.str());
|
||||
}
|
||||
{
|
||||
std::ostringstream os;
|
||||
std::ostringstream ref;
|
||||
os << *p;
|
||||
ref << v;
|
||||
EXPECT_TRUE(os.str() == ref.str());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(notnull_tests, TestNotNullostream)
|
||||
{
|
||||
ostream_helper<int>(17);
|
||||
ostream_helper<float>(21.5f);
|
||||
ostream_helper<double>(3.4566e-7);
|
||||
ostream_helper<char>('c');
|
||||
ostream_helper<uint16_t>(0x0123u);
|
||||
ostream_helper<const char*>("cstring");
|
||||
ostream_helper<std::string>("string");
|
||||
}
|
||||
|
||||
TEST(notnull_tests, TestNotNullCasting)
|
||||
{
|
||||
MyBase base;
|
||||
MyDerived derived;
|
||||
Unrelated unrelated;
|
||||
not_null<Unrelated*> u{&unrelated};
|
||||
(void) u;
|
||||
not_null<MyDerived*> p{&derived};
|
||||
not_null<MyBase*> q(&base);
|
||||
q = p; // allowed with heterogeneous copy ctor
|
||||
EXPECT_TRUE(q == p);
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
q = u; // no viable conversion possible between MyBase* and Unrelated*
|
||||
p = q; // not possible to implicitly convert MyBase* to MyDerived*
|
||||
|
||||
not_null<Unrelated*> r = p;
|
||||
not_null<Unrelated*> s = reinterpret_cast<Unrelated*>(p);
|
||||
#endif
|
||||
not_null<Unrelated*> t(reinterpret_cast<Unrelated*>(p.get()));
|
||||
EXPECT_TRUE(reinterpret_cast<void*>(p.get()) == reinterpret_cast<void*>(t.get()));
|
||||
}
|
||||
|
||||
TEST(notnull_tests, TestNotNullAssignment)
|
||||
{
|
||||
const auto terminateHandler = std::set_terminate([] {
|
||||
std::cerr << "Expected Death. TestNotNullAssignmentd";
|
||||
std::abort();
|
||||
});
|
||||
const auto expected = GetExpectedDeathString(terminateHandler);
|
||||
|
||||
int i = 12;
|
||||
not_null<int*> p(&i);
|
||||
EXPECT_TRUE(helper(p));
|
||||
|
||||
int* q = nullptr;
|
||||
EXPECT_DEATH(p = not_null<int*>(q), expected);
|
||||
}
|
||||
|
||||
TEST(notnull_tests, TestNotNullRawPointerComparison)
|
||||
{
|
||||
int ints[2] = {42, 43};
|
||||
int* p1 = &ints[0];
|
||||
const int* p2 = &ints[1];
|
||||
|
||||
using NotNull1 = not_null<decltype(p1)>;
|
||||
using NotNull2 = not_null<decltype(p2)>;
|
||||
|
||||
EXPECT_TRUE((NotNull1(p1) == NotNull1(p1)) == true);
|
||||
EXPECT_TRUE((NotNull1(p1) == NotNull2(p2)) == false);
|
||||
|
||||
EXPECT_TRUE((NotNull1(p1) != NotNull1(p1)) == false);
|
||||
EXPECT_TRUE((NotNull1(p1) != NotNull2(p2)) == true);
|
||||
|
||||
EXPECT_TRUE((NotNull1(p1) < NotNull1(p1)) == false);
|
||||
EXPECT_TRUE((NotNull1(p1) < NotNull2(p2)) == (p1 < p2));
|
||||
EXPECT_TRUE((NotNull2(p2) < NotNull1(p1)) == (p2 < p1));
|
||||
|
||||
EXPECT_TRUE((NotNull1(p1) > NotNull1(p1)) == false);
|
||||
EXPECT_TRUE((NotNull1(p1) > NotNull2(p2)) == (p1 > p2));
|
||||
EXPECT_TRUE((NotNull2(p2) > NotNull1(p1)) == (p2 > p1));
|
||||
|
||||
EXPECT_TRUE((NotNull1(p1) <= NotNull1(p1)) == true);
|
||||
EXPECT_TRUE((NotNull1(p1) <= NotNull2(p2)) == (p1 <= p2));
|
||||
EXPECT_TRUE((NotNull2(p2) <= NotNull1(p1)) == (p2 <= p1));
|
||||
}
|
||||
|
||||
TEST(notnull_tests, TestNotNullDereferenceOperator)
|
||||
{
|
||||
{
|
||||
auto sp1 = std::make_shared<NonCopyableNonMovable>();
|
||||
|
||||
using NotNullSp1 = not_null<decltype(sp1)>;
|
||||
EXPECT_TRUE(typeid(*sp1) == typeid(*NotNullSp1(sp1)));
|
||||
EXPECT_TRUE(std::addressof(*NotNullSp1(sp1)) == std::addressof(*sp1));
|
||||
}
|
||||
|
||||
{
|
||||
int ints[1] = {42};
|
||||
CustomPtr<int> p1(&ints[0]);
|
||||
|
||||
using NotNull1 = not_null<decltype(p1)>;
|
||||
EXPECT_TRUE(typeid(*NotNull1(p1)) == typeid(*p1));
|
||||
EXPECT_TRUE(*NotNull1(p1) == 42);
|
||||
*NotNull1(p1) = 43;
|
||||
EXPECT_TRUE(ints[0] == 43);
|
||||
}
|
||||
|
||||
{
|
||||
int v = 42;
|
||||
gsl::not_null<int*> p(&v);
|
||||
EXPECT_TRUE(typeid(*p) == typeid(*(&v)));
|
||||
*p = 43;
|
||||
EXPECT_TRUE(v == 43);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(notnull_tests, TestNotNullSharedPtrComparison)
|
||||
{
|
||||
auto sp1 = std::make_shared<int>(42);
|
||||
auto sp2 = std::make_shared<const int>(43);
|
||||
|
||||
using NotNullSp1 = not_null<decltype(sp1)>;
|
||||
using NotNullSp2 = not_null<decltype(sp2)>;
|
||||
|
||||
EXPECT_TRUE((NotNullSp1(sp1) == NotNullSp1(sp1)) == true);
|
||||
EXPECT_TRUE((NotNullSp1(sp1) == NotNullSp2(sp2)) == false);
|
||||
|
||||
EXPECT_TRUE((NotNullSp1(sp1) != NotNullSp1(sp1)) == false);
|
||||
EXPECT_TRUE((NotNullSp1(sp1) != NotNullSp2(sp2)) == true);
|
||||
|
||||
EXPECT_TRUE((NotNullSp1(sp1) < NotNullSp1(sp1)) == false);
|
||||
EXPECT_TRUE((NotNullSp1(sp1) < NotNullSp2(sp2)) == (sp1 < sp2));
|
||||
EXPECT_TRUE((NotNullSp2(sp2) < NotNullSp1(sp1)) == (sp2 < sp1));
|
||||
|
||||
EXPECT_TRUE((NotNullSp1(sp1) > NotNullSp1(sp1)) == false);
|
||||
EXPECT_TRUE((NotNullSp1(sp1) > NotNullSp2(sp2)) == (sp1 > sp2));
|
||||
EXPECT_TRUE((NotNullSp2(sp2) > NotNullSp1(sp1)) == (sp2 > sp1));
|
||||
|
||||
EXPECT_TRUE((NotNullSp1(sp1) <= NotNullSp1(sp1)) == true);
|
||||
EXPECT_TRUE((NotNullSp1(sp1) <= NotNullSp2(sp2)) == (sp1 <= sp2));
|
||||
EXPECT_TRUE((NotNullSp2(sp2) <= NotNullSp1(sp1)) == (sp2 <= sp1));
|
||||
|
||||
EXPECT_TRUE((NotNullSp1(sp1) >= NotNullSp1(sp1)) == true);
|
||||
EXPECT_TRUE((NotNullSp1(sp1) >= NotNullSp2(sp2)) == (sp1 >= sp2));
|
||||
EXPECT_TRUE((NotNullSp2(sp2) >= NotNullSp1(sp1)) == (sp2 >= sp1));
|
||||
}
|
||||
|
||||
TEST(notnull_tests, TestNotNullCustomPtrComparison)
|
||||
{
|
||||
int ints[2] = {42, 43};
|
||||
CustomPtr<int> p1(&ints[0]);
|
||||
CustomPtr<const int> p2(&ints[1]);
|
||||
|
||||
using NotNull1 = not_null<decltype(p1)>;
|
||||
using NotNull2 = not_null<decltype(p2)>;
|
||||
|
||||
EXPECT_TRUE((NotNull1(p1) == NotNull1(p1)) == "true");
|
||||
EXPECT_TRUE((NotNull1(p1) == NotNull2(p2)) == "false");
|
||||
|
||||
EXPECT_TRUE((NotNull1(p1) != NotNull1(p1)) == "false");
|
||||
EXPECT_TRUE((NotNull1(p1) != NotNull2(p2)) == "true");
|
||||
|
||||
EXPECT_TRUE((NotNull1(p1) < NotNull1(p1)) == "false");
|
||||
EXPECT_TRUE((NotNull1(p1) < NotNull2(p2)) == (p1 < p2));
|
||||
EXPECT_TRUE((NotNull2(p2) < NotNull1(p1)) == (p2 < p1));
|
||||
|
||||
EXPECT_TRUE((NotNull1(p1) > NotNull1(p1)) == "false");
|
||||
EXPECT_TRUE((NotNull1(p1) > NotNull2(p2)) == (p1 > p2));
|
||||
EXPECT_TRUE((NotNull2(p2) > NotNull1(p1)) == (p2 > p1));
|
||||
|
||||
EXPECT_TRUE((NotNull1(p1) <= NotNull1(p1)) == "true");
|
||||
EXPECT_TRUE((NotNull1(p1) <= NotNull2(p2)) == (p1 <= p2));
|
||||
EXPECT_TRUE((NotNull2(p2) <= NotNull1(p1)) == (p2 <= p1));
|
||||
|
||||
EXPECT_TRUE((NotNull1(p1) >= NotNull1(p1)) == "true");
|
||||
EXPECT_TRUE((NotNull1(p1) >= NotNull2(p2)) == (p1 >= p2));
|
||||
EXPECT_TRUE((NotNull2(p2) >= NotNull1(p1)) == (p2 >= p1));
|
||||
}
|
||||
|
||||
#if defined(__cplusplus) && (__cplusplus >= 201703L)
|
||||
|
||||
TEST(notnull_tests, TestNotNullConstructorTypeDeduction)
|
||||
{
|
||||
{
|
||||
int i = 42;
|
||||
|
||||
not_null x{&i};
|
||||
helper(not_null{&i});
|
||||
helper_const(not_null{&i});
|
||||
|
||||
EXPECT_TRUE(*x == 42);
|
||||
}
|
||||
|
||||
{
|
||||
const int i = 42;
|
||||
|
||||
not_null x{&i};
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
helper(not_null{&i});
|
||||
#endif
|
||||
helper_const(not_null{&i});
|
||||
|
||||
EXPECT_TRUE(*x == 42);
|
||||
}
|
||||
|
||||
{
|
||||
int i = 42;
|
||||
int* p = &i;
|
||||
|
||||
not_null x{p};
|
||||
helper(not_null{p});
|
||||
helper_const(not_null{p});
|
||||
|
||||
EXPECT_TRUE(*x == 42);
|
||||
}
|
||||
|
||||
{
|
||||
const int i = 42;
|
||||
const int* p = &i;
|
||||
|
||||
not_null x{p};
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
helper(not_null{p});
|
||||
#endif
|
||||
helper_const(not_null{p});
|
||||
|
||||
EXPECT_TRUE(*x == 42);
|
||||
}
|
||||
|
||||
const auto terminateHandler = std::set_terminate([] {
|
||||
std::cerr << "Expected Death. TestNotNullConstructorTypeDeduction";
|
||||
std::abort();
|
||||
});
|
||||
const auto expected = GetExpectedDeathString(terminateHandler);
|
||||
|
||||
{
|
||||
auto workaround_macro = []() {
|
||||
int* p1 = nullptr;
|
||||
const not_null x{p1};
|
||||
};
|
||||
EXPECT_DEATH(workaround_macro(), expected);
|
||||
}
|
||||
|
||||
{
|
||||
auto workaround_macro = []() {
|
||||
const int* p1 = nullptr;
|
||||
const not_null x{p1};
|
||||
};
|
||||
EXPECT_DEATH(workaround_macro(), expected);
|
||||
}
|
||||
|
||||
{
|
||||
int* p = nullptr;
|
||||
|
||||
EXPECT_DEATH(helper(not_null{p}), expected);
|
||||
EXPECT_DEATH(helper_const(not_null{p}), expected);
|
||||
}
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
{
|
||||
not_null x{nullptr};
|
||||
helper(not_null{nullptr});
|
||||
helper_const(not_null{nullptr});
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(notnull_tests, TestVariantEmplace)
|
||||
{
|
||||
int i = 0;
|
||||
std::variant<std::monostate, not_null<int*>> v;
|
||||
v.emplace<not_null<int*>>(&i);
|
||||
|
||||
EXPECT_FALSE(v.valueless_by_exception());
|
||||
EXPECT_TRUE(v.index() == 1);
|
||||
EXPECT_TRUE(std::get<not_null<int*>>(v) == &i);
|
||||
}
|
||||
#endif // #if defined(__cplusplus) && (__cplusplus >= 201703L)
|
||||
|
||||
TEST(notnull_tests, TestMakeNotNull)
|
||||
{
|
||||
{
|
||||
int i = 42;
|
||||
|
||||
const auto x = make_not_null(&i);
|
||||
helper(make_not_null(&i));
|
||||
helper_const(make_not_null(&i));
|
||||
|
||||
EXPECT_TRUE(*x == 42);
|
||||
}
|
||||
|
||||
{
|
||||
const int i = 42;
|
||||
|
||||
const auto x = make_not_null(&i);
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
helper(make_not_null(&i));
|
||||
#endif
|
||||
helper_const(make_not_null(&i));
|
||||
|
||||
EXPECT_TRUE(*x == 42);
|
||||
}
|
||||
|
||||
{
|
||||
int i = 42;
|
||||
int* p = &i;
|
||||
|
||||
const auto x = make_not_null(p);
|
||||
helper(make_not_null(p));
|
||||
helper_const(make_not_null(p));
|
||||
|
||||
EXPECT_TRUE(*x == 42);
|
||||
}
|
||||
|
||||
{
|
||||
const int i = 42;
|
||||
const int* p = &i;
|
||||
|
||||
const auto x = make_not_null(p);
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
helper(make_not_null(p));
|
||||
#endif
|
||||
helper_const(make_not_null(p));
|
||||
|
||||
EXPECT_TRUE(*x == 42);
|
||||
}
|
||||
|
||||
const auto terminateHandler = std::set_terminate([] {
|
||||
std::cerr << "Expected Death. TestMakeNotNull";
|
||||
std::abort();
|
||||
});
|
||||
const auto expected = GetExpectedDeathString(terminateHandler);
|
||||
|
||||
{
|
||||
const auto workaround_macro = []() {
|
||||
int* p1 = nullptr;
|
||||
const auto x = make_not_null(p1);
|
||||
EXPECT_TRUE(*x == 42);
|
||||
};
|
||||
EXPECT_DEATH(workaround_macro(), expected);
|
||||
}
|
||||
|
||||
{
|
||||
const auto workaround_macro = []() {
|
||||
const int* p1 = nullptr;
|
||||
const auto x = make_not_null(p1);
|
||||
EXPECT_TRUE(*x == 42);
|
||||
};
|
||||
EXPECT_DEATH(workaround_macro(), expected);
|
||||
}
|
||||
|
||||
{
|
||||
int* p = nullptr;
|
||||
|
||||
EXPECT_DEATH(helper(make_not_null(p)), expected);
|
||||
EXPECT_DEATH(helper_const(make_not_null(p)), expected);
|
||||
}
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
{
|
||||
EXPECT_DEATH(make_not_null(nullptr), expected);
|
||||
EXPECT_DEATH(helper(make_not_null(nullptr)), expected);
|
||||
EXPECT_DEATH(helper_const(make_not_null(nullptr)), expected);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(notnull_tests, TestStdHash)
|
||||
{
|
||||
{
|
||||
int x = 42;
|
||||
int y = 99;
|
||||
not_null<int*> nn{&x};
|
||||
const not_null<int*> cnn{&x};
|
||||
|
||||
std::hash<not_null<int*>> hash_nn;
|
||||
std::hash<int*> hash_intptr;
|
||||
|
||||
EXPECT_TRUE(hash_nn(nn) == hash_intptr(&x));
|
||||
EXPECT_FALSE(hash_nn(nn) == hash_intptr(&y));
|
||||
EXPECT_FALSE(hash_nn(nn) == hash_intptr(nullptr));
|
||||
}
|
||||
|
||||
{
|
||||
const int x = 42;
|
||||
const int y = 99;
|
||||
not_null<const int*> nn{&x};
|
||||
const not_null<const int*> cnn{&x};
|
||||
|
||||
std::hash<not_null<const int*>> hash_nn;
|
||||
std::hash<const int*> hash_intptr;
|
||||
|
||||
EXPECT_TRUE(hash_nn(nn) == hash_intptr(&x));
|
||||
EXPECT_FALSE(hash_nn(nn) == hash_intptr(&y));
|
||||
EXPECT_FALSE(hash_nn(nn) == hash_intptr(nullptr));
|
||||
}
|
||||
}
|
43
deps/GSL/tests/owner_tests.cpp
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <gsl/pointers> // for owner
|
||||
|
||||
using namespace gsl;
|
||||
|
||||
GSL_SUPPRESS(f .23) // NO-FORMAT: attribute
|
||||
void f(int* i) { *i += 1; }
|
||||
|
||||
TEST(owner_tests, basic_test)
|
||||
{
|
||||
owner<int*> p = new int(120);
|
||||
EXPECT_TRUE(*p == 120);
|
||||
f(p);
|
||||
EXPECT_TRUE(*p == 121);
|
||||
delete p;
|
||||
}
|
||||
|
||||
TEST(owner_tests, check_pointer_constraint)
|
||||
{
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
{
|
||||
owner<int> integerTest = 10;
|
||||
owner<std::shared_ptr<int>> sharedPtrTest(new int(10));
|
||||
}
|
||||
#endif
|
||||
}
|
1023
deps/GSL/tests/span_compatibility_tests.cpp
vendored
Normal file
380
deps/GSL/tests/span_ext_tests.cpp
vendored
Normal file
@ -0,0 +1,380 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <gsl/span> // for span and span_ext
|
||||
#include <gsl/util> // for narrow_cast, at
|
||||
|
||||
#include <array> // for array
|
||||
#include <exception> // for terminate
|
||||
#include <iostream> // for cerr
|
||||
#include <vector> // for vector
|
||||
|
||||
using namespace std;
|
||||
using namespace gsl;
|
||||
|
||||
#include "deathTestCommon.h"
|
||||
|
||||
TEST(span_ext_test, make_span_from_pointer_length_constructor)
|
||||
{
|
||||
const auto terminateHandler = std::set_terminate([] {
|
||||
std::cerr << "Expected Death. from_pointer_length_constructor";
|
||||
std::abort();
|
||||
});
|
||||
const auto expected = GetExpectedDeathString(terminateHandler);
|
||||
|
||||
int arr[4] = {1, 2, 3, 4};
|
||||
|
||||
{
|
||||
auto s = make_span(&arr[0], 2);
|
||||
EXPECT_TRUE(s.size() == 2);
|
||||
EXPECT_TRUE(s.data() == &arr[0]);
|
||||
EXPECT_TRUE(s[0] == 1);
|
||||
EXPECT_TRUE(s[1] == 2);
|
||||
}
|
||||
|
||||
{
|
||||
int* p = nullptr;
|
||||
auto s = make_span(p, narrow_cast<gsl::span<int>::size_type>(0));
|
||||
EXPECT_TRUE(s.size() == 0);
|
||||
EXPECT_TRUE(s.data() == nullptr);
|
||||
}
|
||||
|
||||
{
|
||||
int* p = nullptr;
|
||||
auto workaround_macro = [=]() { make_span(p, 2); };
|
||||
EXPECT_DEATH(workaround_macro(), expected);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(span_ext_test, make_span_from_pointer_pointer_construction)
|
||||
{
|
||||
int arr[4] = {1, 2, 3, 4};
|
||||
|
||||
{
|
||||
auto s = make_span(&arr[0], &arr[2]);
|
||||
EXPECT_TRUE(s.size() == 2);
|
||||
EXPECT_TRUE(s.data() == &arr[0]);
|
||||
EXPECT_TRUE(s[0] == 1);
|
||||
EXPECT_TRUE(s[1] == 2);
|
||||
}
|
||||
|
||||
{
|
||||
auto s = make_span(&arr[0], &arr[0]);
|
||||
EXPECT_TRUE(s.size() == 0);
|
||||
EXPECT_TRUE(s.data() == &arr[0]);
|
||||
}
|
||||
|
||||
{
|
||||
int* p = nullptr;
|
||||
auto s = make_span(p, p);
|
||||
EXPECT_TRUE(s.size() == 0);
|
||||
EXPECT_TRUE(s.data() == nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(span_ext_test, make_span_from_array_constructor)
|
||||
{
|
||||
int arr[5] = {1, 2, 3, 4, 5};
|
||||
int arr2d[2][3] = {1, 2, 3, 4, 5, 6};
|
||||
int arr3d[2][3][2] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
|
||||
|
||||
{
|
||||
const auto s = make_span(arr);
|
||||
EXPECT_TRUE(s.size() == 5);
|
||||
EXPECT_TRUE(s.data() == std::addressof(arr[0]));
|
||||
}
|
||||
|
||||
{
|
||||
const auto s = make_span(std::addressof(arr2d[0]), 1);
|
||||
EXPECT_TRUE(s.size() == 1);
|
||||
EXPECT_TRUE(s.data() == std::addressof(arr2d[0]));
|
||||
}
|
||||
|
||||
{
|
||||
const auto s = make_span(std::addressof(arr3d[0]), 1);
|
||||
EXPECT_TRUE(s.size() == 1);
|
||||
EXPECT_TRUE(s.data() == std::addressof(arr3d[0]));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(span_ext_test, make_span_from_dynamic_array_constructor)
|
||||
{
|
||||
double(*arr)[3][4] = new double[100][3][4];
|
||||
|
||||
{
|
||||
auto s = make_span(&arr[0][0][0], 10);
|
||||
EXPECT_TRUE(s.size() == 10);
|
||||
EXPECT_TRUE(s.data() == &arr[0][0][0]);
|
||||
}
|
||||
|
||||
delete[] arr;
|
||||
}
|
||||
|
||||
TEST(span_ext_test, make_span_from_std_array_constructor)
|
||||
{
|
||||
std::array<int, 4> arr = {1, 2, 3, 4};
|
||||
|
||||
{
|
||||
auto s = make_span(arr);
|
||||
EXPECT_TRUE(s.size() == arr.size());
|
||||
EXPECT_TRUE(s.data() == arr.data());
|
||||
}
|
||||
|
||||
// This test checks for the bug found in gcc 6.1, 6.2, 6.3, 6.4, 6.5 7.1, 7.2, 7.3 - issue #590
|
||||
{
|
||||
gsl::span<int> s1 = make_span(arr);
|
||||
|
||||
static gsl::span<int> s2;
|
||||
s2 = s1;
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ == 6 && (__GNUC_MINOR__ == 4 || __GNUC_MINOR__ == 5) && \
|
||||
__GNUC_PATCHLEVEL__ == 0 && defined(__OPTIMIZE__)
|
||||
// Known to be broken in gcc 6.4 and 6.5 with optimizations
|
||||
// Issue in gcc: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83116
|
||||
EXPECT_TRUE(s1.size() == 4);
|
||||
EXPECT_TRUE(s2.size() == 0);
|
||||
#else
|
||||
EXPECT_TRUE(s1.size() == s2.size());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
TEST(span_ext_test, make_span_from_const_std_array_constructor)
|
||||
{
|
||||
const std::array<int, 4> arr = {1, 2, 3, 4};
|
||||
|
||||
{
|
||||
auto s = make_span(arr);
|
||||
EXPECT_TRUE(s.size() == arr.size());
|
||||
EXPECT_TRUE(s.data() == arr.data());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(span_ext_test, make_span_from_std_array_const_constructor)
|
||||
{
|
||||
std::array<const int, 4> arr = {1, 2, 3, 4};
|
||||
|
||||
{
|
||||
auto s = make_span(arr);
|
||||
EXPECT_TRUE(s.size() == arr.size());
|
||||
EXPECT_TRUE(s.data() == arr.data());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(span_ext_test, make_span_from_container_constructor)
|
||||
{
|
||||
std::vector<int> v = {1, 2, 3};
|
||||
const std::vector<int> cv = v;
|
||||
|
||||
{
|
||||
auto s = make_span(v);
|
||||
EXPECT_TRUE(s.size() == v.size());
|
||||
EXPECT_TRUE(s.data() == v.data());
|
||||
|
||||
auto cs = make_span(cv);
|
||||
EXPECT_TRUE(cs.size() == cv.size());
|
||||
EXPECT_TRUE(cs.data() == cv.data());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(span_test, interop_with_gsl_at)
|
||||
{
|
||||
std::vector<int> vec{1, 2, 3, 4, 5};
|
||||
gsl::span<int> sp{vec};
|
||||
|
||||
std::vector<int> cvec{1, 2, 3, 4, 5};
|
||||
gsl::span<int> csp{cvec};
|
||||
|
||||
for (gsl::index i = 0; i < gsl::narrow_cast<gsl::index>(vec.size()); ++i)
|
||||
{
|
||||
EXPECT_TRUE(&gsl::at(sp, i) == &vec[gsl::narrow_cast<size_t>(i)]);
|
||||
EXPECT_TRUE(&gsl::at(csp, i) == &cvec[gsl::narrow_cast<size_t>(i)]);
|
||||
}
|
||||
|
||||
const auto terminateHandler = std::set_terminate([] {
|
||||
std::cerr << "Expected Death. interop_with_gsl_at";
|
||||
std::abort();
|
||||
});
|
||||
const auto expected = GetExpectedDeathString(terminateHandler);
|
||||
|
||||
EXPECT_DEATH(gsl::at(sp, -1), expected);
|
||||
EXPECT_DEATH(gsl::at(sp, gsl::narrow_cast<gsl::index>(sp.size())), expected);
|
||||
EXPECT_DEATH(gsl::at(csp, -1), expected);
|
||||
EXPECT_DEATH(gsl::at(csp, gsl::narrow_cast<gsl::index>(sp.size())), expected);
|
||||
}
|
||||
|
||||
TEST(span_ext_test, iterator_free_functions)
|
||||
{
|
||||
int a[] = {1, 2, 3, 4};
|
||||
gsl::span<int> s{a};
|
||||
|
||||
EXPECT_TRUE((std::is_same<decltype(s.begin()), decltype(begin(s))>::value));
|
||||
EXPECT_TRUE((std::is_same<decltype(s.end()), decltype(end(s))>::value));
|
||||
|
||||
EXPECT_TRUE((std::is_same<decltype(std::cbegin(s)), decltype(cbegin(s))>::value));
|
||||
EXPECT_TRUE((std::is_same<decltype(std::cend(s)), decltype(cend(s))>::value));
|
||||
|
||||
EXPECT_TRUE((std::is_same<decltype(s.rbegin()), decltype(rbegin(s))>::value));
|
||||
EXPECT_TRUE((std::is_same<decltype(s.rend()), decltype(rend(s))>::value));
|
||||
|
||||
EXPECT_TRUE((std::is_same<decltype(std::crbegin(s)), decltype(crbegin(s))>::value));
|
||||
EXPECT_TRUE((std::is_same<decltype(std::crend(s)), decltype(crend(s))>::value));
|
||||
|
||||
EXPECT_TRUE(s.begin() == begin(s));
|
||||
EXPECT_TRUE(s.end() == end(s));
|
||||
|
||||
EXPECT_TRUE(s.rbegin() == rbegin(s));
|
||||
EXPECT_TRUE(s.rend() == rend(s));
|
||||
|
||||
EXPECT_TRUE(s.begin() == cbegin(s));
|
||||
EXPECT_TRUE(s.end() == cend(s));
|
||||
|
||||
EXPECT_TRUE(s.rbegin() == crbegin(s));
|
||||
EXPECT_TRUE(s.rend() == crend(s));
|
||||
}
|
||||
|
||||
TEST(span_ext_test, ssize_free_function)
|
||||
{
|
||||
int a[] = {1, 2, 3, 4};
|
||||
gsl::span<int> s{a};
|
||||
|
||||
EXPECT_FALSE((std::is_same<decltype(s.size()), decltype(ssize(s))>::value));
|
||||
EXPECT_TRUE(s.size() == static_cast<std::size_t>(ssize(s)));
|
||||
}
|
||||
|
||||
#ifndef GSL_KERNEL_MODE
|
||||
TEST(span_ext_test, comparison_operators)
|
||||
{
|
||||
{
|
||||
gsl::span<int> s1;
|
||||
gsl::span<int> s2;
|
||||
EXPECT_TRUE(s1 == s2);
|
||||
EXPECT_FALSE(s1 != s2);
|
||||
EXPECT_FALSE(s1 < s2);
|
||||
EXPECT_TRUE(s1 <= s2);
|
||||
EXPECT_FALSE(s1 > s2);
|
||||
EXPECT_TRUE(s1 >= s2);
|
||||
EXPECT_TRUE(s2 == s1);
|
||||
EXPECT_FALSE(s2 != s1);
|
||||
EXPECT_FALSE(s2 != s1);
|
||||
EXPECT_TRUE(s2 <= s1);
|
||||
EXPECT_FALSE(s2 > s1);
|
||||
EXPECT_TRUE(s2 >= s1);
|
||||
}
|
||||
|
||||
{
|
||||
int arr[] = {2, 1};
|
||||
gsl::span<int> s1 = arr;
|
||||
gsl::span<int> s2 = arr;
|
||||
|
||||
EXPECT_TRUE(s1 == s2);
|
||||
EXPECT_FALSE(s1 != s2);
|
||||
EXPECT_FALSE(s1 < s2);
|
||||
EXPECT_TRUE(s1 <= s2);
|
||||
EXPECT_FALSE(s1 > s2);
|
||||
EXPECT_TRUE(s1 >= s2);
|
||||
EXPECT_TRUE(s2 == s1);
|
||||
EXPECT_FALSE(s2 != s1);
|
||||
EXPECT_FALSE(s2 < s1);
|
||||
EXPECT_TRUE(s2 <= s1);
|
||||
EXPECT_FALSE(s2 > s1);
|
||||
EXPECT_TRUE(s2 >= s1);
|
||||
}
|
||||
|
||||
{
|
||||
int arr[] = {2, 1}; // bigger
|
||||
|
||||
gsl::span<int> s1;
|
||||
gsl::span<int> s2 = arr;
|
||||
|
||||
EXPECT_TRUE(s1 != s2);
|
||||
EXPECT_TRUE(s2 != s1);
|
||||
EXPECT_FALSE(s1 == s2);
|
||||
EXPECT_FALSE(s2 == s1);
|
||||
EXPECT_TRUE(s1 < s2);
|
||||
EXPECT_FALSE(s2 < s1);
|
||||
EXPECT_TRUE(s1 <= s2);
|
||||
EXPECT_FALSE(s2 <= s1);
|
||||
EXPECT_TRUE(s2 > s1);
|
||||
EXPECT_FALSE(s1 > s2);
|
||||
EXPECT_TRUE(s2 >= s1);
|
||||
EXPECT_FALSE(s1 >= s2);
|
||||
}
|
||||
|
||||
{
|
||||
int arr1[] = {1, 2};
|
||||
int arr2[] = {1, 2};
|
||||
gsl::span<int> s1 = arr1;
|
||||
gsl::span<int> s2 = arr2;
|
||||
|
||||
EXPECT_TRUE(s1 == s2);
|
||||
EXPECT_FALSE(s1 != s2);
|
||||
EXPECT_FALSE(s1 < s2);
|
||||
EXPECT_TRUE(s1 <= s2);
|
||||
EXPECT_FALSE(s1 > s2);
|
||||
EXPECT_TRUE(s1 >= s2);
|
||||
EXPECT_TRUE(s2 == s1);
|
||||
EXPECT_FALSE(s2 != s1);
|
||||
EXPECT_FALSE(s2 < s1);
|
||||
EXPECT_TRUE(s2 <= s1);
|
||||
EXPECT_FALSE(s2 > s1);
|
||||
EXPECT_TRUE(s2 >= s1);
|
||||
}
|
||||
|
||||
{
|
||||
int arr[] = {1, 2, 3};
|
||||
|
||||
gsl::span<int> s1 = {&arr[0], 2}; // shorter
|
||||
gsl::span<int> s2 = arr; // longer
|
||||
|
||||
EXPECT_TRUE(s1 != s2);
|
||||
EXPECT_TRUE(s2 != s1);
|
||||
EXPECT_FALSE(s1 == s2);
|
||||
EXPECT_FALSE(s2 == s1);
|
||||
EXPECT_TRUE(s1 < s2);
|
||||
EXPECT_FALSE(s2 < s1);
|
||||
EXPECT_TRUE(s1 <= s2);
|
||||
EXPECT_FALSE(s2 <= s1);
|
||||
EXPECT_TRUE(s2 > s1);
|
||||
EXPECT_FALSE(s1 > s2);
|
||||
EXPECT_TRUE(s2 >= s1);
|
||||
EXPECT_FALSE(s1 >= s2);
|
||||
}
|
||||
|
||||
{
|
||||
int arr1[] = {1, 2}; // smaller
|
||||
int arr2[] = {2, 1}; // bigger
|
||||
|
||||
gsl::span<int> s1 = arr1;
|
||||
gsl::span<int> s2 = arr2;
|
||||
|
||||
EXPECT_TRUE(s1 != s2);
|
||||
EXPECT_TRUE(s2 != s1);
|
||||
EXPECT_FALSE(s1 == s2);
|
||||
EXPECT_FALSE(s2 == s1);
|
||||
EXPECT_TRUE(s1 < s2);
|
||||
EXPECT_FALSE(s2 < s1);
|
||||
EXPECT_TRUE(s1 <= s2);
|
||||
EXPECT_FALSE(s2 <= s1);
|
||||
EXPECT_TRUE(s2 > s1);
|
||||
EXPECT_FALSE(s1 > s2);
|
||||
EXPECT_TRUE(s2 >= s1);
|
||||
EXPECT_FALSE(s1 >= s2);
|
||||
}
|
||||
}
|
||||
#endif // GSL_KERNEL_MODE
|
1383
deps/GSL/tests/span_tests.cpp
vendored
Normal file
304
deps/GSL/tests/strict_notnull_tests.cpp
vendored
Normal file
@ -0,0 +1,304 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <gsl/pointers> // for not_null, operator<, operator<=, operator>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "deathTestCommon.h"
|
||||
|
||||
using namespace gsl;
|
||||
|
||||
namespace
|
||||
{
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
bool helper(not_null<int*> p) { return *p == 12; }
|
||||
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
bool helper_const(not_null<const int*> p) { return *p == 12; }
|
||||
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
bool strict_helper(strict_not_null<int*> p) { return *p == 12; }
|
||||
|
||||
// clang-format off
|
||||
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute
|
||||
// clang-format on
|
||||
bool strict_helper_const(strict_not_null<const int*> p) { return *p == 12; }
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
int* return_pointer() { return nullptr; }
|
||||
const int* return_pointer_const() { return nullptr; }
|
||||
#endif
|
||||
} // namespace
|
||||
|
||||
TEST(strict_notnull_tests, TestStrictNotNull)
|
||||
{
|
||||
{
|
||||
// raw ptr <-> strict_not_null
|
||||
int x = 42;
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
strict_not_null<int*> snn = &x;
|
||||
strict_helper(&x);
|
||||
strict_helper_const(&x);
|
||||
strict_helper(return_pointer());
|
||||
strict_helper_const(return_pointer_const());
|
||||
#endif
|
||||
|
||||
const strict_not_null<int*> snn1{&x};
|
||||
|
||||
helper(snn1);
|
||||
helper_const(snn1);
|
||||
|
||||
EXPECT_TRUE(*snn1 == 42);
|
||||
}
|
||||
|
||||
{
|
||||
// raw ptr <-> strict_not_null
|
||||
const int x = 42;
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
strict_not_null<int*> snn = &x;
|
||||
strict_helper(&x);
|
||||
strict_helper_const(&x);
|
||||
strict_helper(return_pointer());
|
||||
strict_helper_const(return_pointer_const());
|
||||
#endif
|
||||
|
||||
const strict_not_null<const int*> snn1{&x};
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
helper(snn1);
|
||||
#endif
|
||||
helper_const(snn1);
|
||||
|
||||
EXPECT_TRUE(*snn1 == 42);
|
||||
}
|
||||
|
||||
{
|
||||
// strict_not_null -> strict_not_null
|
||||
int x = 42;
|
||||
|
||||
strict_not_null<int*> snn1{&x};
|
||||
const strict_not_null<int*> snn2{&x};
|
||||
|
||||
strict_helper(snn1);
|
||||
strict_helper_const(snn1);
|
||||
strict_helper_const(snn2);
|
||||
|
||||
EXPECT_TRUE(snn1 == snn2);
|
||||
}
|
||||
|
||||
{
|
||||
// strict_not_null -> strict_not_null
|
||||
const int x = 42;
|
||||
|
||||
strict_not_null<const int*> snn1{&x};
|
||||
const strict_not_null<const int*> snn2{&x};
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
strict_helper(snn1);
|
||||
#endif
|
||||
strict_helper_const(snn1);
|
||||
strict_helper_const(snn2);
|
||||
|
||||
EXPECT_TRUE(snn1 == snn2);
|
||||
}
|
||||
|
||||
{
|
||||
// strict_not_null -> not_null
|
||||
int x = 42;
|
||||
|
||||
strict_not_null<int*> snn{&x};
|
||||
|
||||
const not_null<int*> nn1 = snn;
|
||||
const not_null<int*> nn2{snn};
|
||||
|
||||
helper(snn);
|
||||
helper_const(snn);
|
||||
|
||||
EXPECT_TRUE(snn == nn1);
|
||||
EXPECT_TRUE(snn == nn2);
|
||||
}
|
||||
|
||||
{
|
||||
// strict_not_null -> not_null
|
||||
const int x = 42;
|
||||
|
||||
strict_not_null<const int*> snn{&x};
|
||||
|
||||
const not_null<const int*> nn1 = snn;
|
||||
const not_null<const int*> nn2{snn};
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
helper(snn);
|
||||
#endif
|
||||
helper_const(snn);
|
||||
|
||||
EXPECT_TRUE(snn == nn1);
|
||||
EXPECT_TRUE(snn == nn2);
|
||||
}
|
||||
|
||||
{
|
||||
// not_null -> strict_not_null
|
||||
int x = 42;
|
||||
|
||||
not_null<int*> nn{&x};
|
||||
|
||||
const strict_not_null<int*> snn1{nn};
|
||||
const strict_not_null<int*> snn2{nn};
|
||||
|
||||
strict_helper(nn);
|
||||
strict_helper_const(nn);
|
||||
|
||||
EXPECT_TRUE(snn1 == nn);
|
||||
EXPECT_TRUE(snn2 == nn);
|
||||
|
||||
std::hash<strict_not_null<int*>> hash_snn;
|
||||
std::hash<not_null<int*>> hash_nn;
|
||||
|
||||
EXPECT_TRUE(hash_nn(snn1) == hash_nn(nn));
|
||||
EXPECT_TRUE(hash_snn(snn1) == hash_nn(nn));
|
||||
EXPECT_TRUE(hash_nn(snn1) == hash_nn(snn2));
|
||||
EXPECT_TRUE(hash_snn(snn1) == hash_snn(nn));
|
||||
}
|
||||
|
||||
{
|
||||
// not_null -> strict_not_null
|
||||
const int x = 42;
|
||||
|
||||
not_null<const int*> nn{&x};
|
||||
|
||||
const strict_not_null<const int*> snn1{nn};
|
||||
const strict_not_null<const int*> snn2{nn};
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
strict_helper(nn);
|
||||
#endif
|
||||
strict_helper_const(nn);
|
||||
|
||||
EXPECT_TRUE(snn1 == nn);
|
||||
EXPECT_TRUE(snn2 == nn);
|
||||
|
||||
std::hash<strict_not_null<const int*>> hash_snn;
|
||||
std::hash<not_null<const int*>> hash_nn;
|
||||
|
||||
EXPECT_TRUE(hash_nn(snn1) == hash_nn(nn));
|
||||
EXPECT_TRUE(hash_snn(snn1) == hash_nn(nn));
|
||||
EXPECT_TRUE(hash_nn(snn1) == hash_nn(snn2));
|
||||
EXPECT_TRUE(hash_snn(snn1) == hash_snn(nn));
|
||||
}
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
{
|
||||
strict_not_null<int*> p{nullptr};
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(__cplusplus) && (__cplusplus >= 201703L)
|
||||
|
||||
TEST(strict_notnull_tests, TestStrictNotNullConstructorTypeDeduction)
|
||||
{
|
||||
const auto terminateHandler = std::set_terminate([] {
|
||||
std::cerr << "Expected Death. TestStrictNotNullConstructorTypeDeduction";
|
||||
std::abort();
|
||||
});
|
||||
const auto expected = GetExpectedDeathString(terminateHandler);
|
||||
|
||||
{
|
||||
int i = 42;
|
||||
|
||||
strict_not_null x{&i};
|
||||
helper(strict_not_null{&i});
|
||||
helper_const(strict_not_null{&i});
|
||||
|
||||
EXPECT_TRUE(*x == 42);
|
||||
}
|
||||
|
||||
{
|
||||
const int i = 42;
|
||||
|
||||
strict_not_null x{&i};
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
helper(strict_not_null{&i});
|
||||
#endif
|
||||
helper_const(strict_not_null{&i});
|
||||
|
||||
EXPECT_TRUE(*x == 42);
|
||||
}
|
||||
|
||||
{
|
||||
int i = 42;
|
||||
int* p = &i;
|
||||
|
||||
strict_not_null x{p};
|
||||
helper(strict_not_null{p});
|
||||
helper_const(strict_not_null{p});
|
||||
|
||||
EXPECT_TRUE(*x == 42);
|
||||
}
|
||||
|
||||
{
|
||||
const int i = 42;
|
||||
const int* p = &i;
|
||||
|
||||
strict_not_null x{p};
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
helper(strict_not_null{p});
|
||||
#endif
|
||||
helper_const(strict_not_null{p});
|
||||
|
||||
EXPECT_TRUE(*x == 42);
|
||||
}
|
||||
|
||||
{
|
||||
auto workaround_macro = []() {
|
||||
int* p1 = nullptr;
|
||||
const strict_not_null x{p1};
|
||||
};
|
||||
EXPECT_DEATH(workaround_macro(), expected);
|
||||
}
|
||||
|
||||
{
|
||||
auto workaround_macro = []() {
|
||||
const int* p1 = nullptr;
|
||||
const strict_not_null x{p1};
|
||||
};
|
||||
EXPECT_DEATH(workaround_macro(), expected);
|
||||
}
|
||||
|
||||
{
|
||||
int* p = nullptr;
|
||||
|
||||
EXPECT_DEATH(helper(strict_not_null{p}), expected);
|
||||
EXPECT_DEATH(helper_const(strict_not_null{p}), expected);
|
||||
}
|
||||
|
||||
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||
{
|
||||
strict_not_null x{nullptr};
|
||||
helper(strict_not_null{nullptr});
|
||||
helper_const(strict_not_null{nullptr});
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif // #if defined(__cplusplus) && (__cplusplus >= 201703L)
|
165
deps/GSL/tests/utils_tests.cpp
vendored
Normal file
@ -0,0 +1,165 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <algorithm> // for move
|
||||
#include <complex>
|
||||
#include <cstddef> // for std::ptrdiff_t
|
||||
#include <cstdint> // for uint32_t, int32_t
|
||||
#include <functional> // for reference_wrapper, _Bind_helper<>::type
|
||||
#include <gsl/narrow> // for narrow, narrowing_error
|
||||
#include <gsl/util> // finally, narrow_cast
|
||||
#include <limits> // for numeric_limits
|
||||
#include <type_traits> // for is_same
|
||||
|
||||
using namespace gsl;
|
||||
|
||||
namespace
|
||||
{
|
||||
void f(int& i) { i += 1; }
|
||||
static int j = 0;
|
||||
void g() { j += 1; }
|
||||
} // namespace
|
||||
|
||||
TEST(utils_tests, sanity_check_for_gsl_index_typedef)
|
||||
{
|
||||
static_assert(std::is_same<gsl::index, std::ptrdiff_t>::value,
|
||||
"gsl::index represents wrong arithmetic type");
|
||||
}
|
||||
|
||||
TEST(utils_tests, finally_lambda)
|
||||
{
|
||||
int i = 0;
|
||||
{
|
||||
auto _ = finally([&]() { f(i); });
|
||||
EXPECT_TRUE(i == 0);
|
||||
}
|
||||
EXPECT_TRUE(i == 1);
|
||||
}
|
||||
|
||||
TEST(utils_tests, finally_lambda_move)
|
||||
{
|
||||
int i = 0;
|
||||
{
|
||||
auto _1 = finally([&]() { f(i); });
|
||||
{
|
||||
auto _2 = std::move(_1);
|
||||
EXPECT_TRUE(i == 0);
|
||||
}
|
||||
EXPECT_TRUE(i == 1);
|
||||
{
|
||||
auto _2 = std::move(_1);
|
||||
EXPECT_TRUE(i == 1);
|
||||
}
|
||||
EXPECT_TRUE(i == 1);
|
||||
}
|
||||
EXPECT_TRUE(i == 1);
|
||||
}
|
||||
|
||||
TEST(utils_tests, finally_const_lvalue_lambda)
|
||||
{
|
||||
int i = 0;
|
||||
{
|
||||
const auto const_lvalue_lambda = [&]() { f(i); };
|
||||
auto _ = finally(const_lvalue_lambda);
|
||||
EXPECT_TRUE(i == 0);
|
||||
}
|
||||
EXPECT_TRUE(i == 1);
|
||||
}
|
||||
|
||||
TEST(utils_tests, finally_mutable_lvalue_lambda)
|
||||
{
|
||||
int i = 0;
|
||||
{
|
||||
auto mutable_lvalue_lambda = [&]() { f(i); };
|
||||
auto _ = finally(mutable_lvalue_lambda);
|
||||
EXPECT_TRUE(i == 0);
|
||||
}
|
||||
EXPECT_TRUE(i == 1);
|
||||
}
|
||||
|
||||
TEST(utils_tests, finally_function_with_bind)
|
||||
{
|
||||
int i = 0;
|
||||
{
|
||||
auto _ = finally([&i] { return f(i); });
|
||||
EXPECT_TRUE(i == 0);
|
||||
}
|
||||
EXPECT_TRUE(i == 1);
|
||||
}
|
||||
|
||||
TEST(utils_tests, finally_function_ptr)
|
||||
{
|
||||
j = 0;
|
||||
{
|
||||
auto _ = finally(&g);
|
||||
EXPECT_TRUE(j == 0);
|
||||
}
|
||||
EXPECT_TRUE(j == 1);
|
||||
}
|
||||
|
||||
TEST(utils_tests, finally_function)
|
||||
{
|
||||
j = 0;
|
||||
{
|
||||
auto _ = finally(g);
|
||||
EXPECT_TRUE(j == 0);
|
||||
}
|
||||
EXPECT_TRUE(j == 1);
|
||||
}
|
||||
|
||||
TEST(utils_tests, narrow_cast)
|
||||
{
|
||||
int n = 120;
|
||||
char c = narrow_cast<char>(n);
|
||||
EXPECT_TRUE(c == 120);
|
||||
|
||||
n = 300;
|
||||
unsigned char uc = narrow_cast<unsigned char>(n);
|
||||
EXPECT_TRUE(uc == 44);
|
||||
}
|
||||
|
||||
#ifndef GSL_KERNEL_MODE
|
||||
TEST(utils_tests, narrow)
|
||||
{
|
||||
int n = 120;
|
||||
const char c = narrow<char>(n);
|
||||
EXPECT_TRUE(c == 120);
|
||||
|
||||
n = 300;
|
||||
EXPECT_THROW(narrow<char>(n), narrowing_error);
|
||||
|
||||
const auto int32_max = std::numeric_limits<int32_t>::max();
|
||||
const auto int32_min = std::numeric_limits<int32_t>::min();
|
||||
|
||||
EXPECT_TRUE(narrow<uint32_t>(int32_t(0)) == 0);
|
||||
EXPECT_TRUE(narrow<uint32_t>(int32_t(1)) == 1);
|
||||
EXPECT_TRUE(narrow<uint32_t>(int32_max) == static_cast<uint32_t>(int32_max));
|
||||
|
||||
EXPECT_THROW(narrow<uint32_t>(int32_t(-1)), narrowing_error);
|
||||
EXPECT_THROW(narrow<uint32_t>(int32_min), narrowing_error);
|
||||
|
||||
n = -42;
|
||||
EXPECT_THROW(narrow<unsigned>(n), narrowing_error);
|
||||
|
||||
EXPECT_TRUE(
|
||||
narrow<std::complex<float>>(std::complex<double>(4, 2)) == std::complex<float>(4, 2));
|
||||
EXPECT_THROW(narrow<std::complex<float>>(std::complex<double>(4.2)), narrowing_error);
|
||||
|
||||
EXPECT_TRUE(narrow<int>(float(1)) == 1);
|
||||
}
|
||||
#endif // GSL_KERNEL_MODE
|
1
deps/WinToast
vendored
@ -1 +0,0 @@
|
||||
Subproject commit 5e441fd03543b999edb663caf8df7be37c0d575c
|
5
deps/WinToast/.editorconfig
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
[*.{cpp,h}]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
trim_trailing_whitespace = true
|
||||
charset = utf-8
|
63
deps/WinToast/.gitattributes
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
###############################################################################
|
||||
# Set default behavior to automatically normalize line endings.
|
||||
###############################################################################
|
||||
* text=auto
|
||||
|
||||
###############################################################################
|
||||
# Set default behavior for command prompt diff.
|
||||
#
|
||||
# This is need for earlier builds of msysgit that does not have it on by
|
||||
# default for csharp files.
|
||||
# Note: This is only used by command line
|
||||
###############################################################################
|
||||
#*.cs diff=csharp
|
||||
|
||||
###############################################################################
|
||||
# Set the merge driver for project and solution files
|
||||
#
|
||||
# Merging from the command prompt will add diff markers to the files if there
|
||||
# are conflicts (Merging from VS is not affected by the settings below, in VS
|
||||
# the diff markers are never inserted). Diff markers may cause the following
|
||||
# file extensions to fail to load in VS. An alternative would be to treat
|
||||
# these files as binary and thus will always conflict and require user
|
||||
# intervention with every merge. To do so, just uncomment the entries below
|
||||
###############################################################################
|
||||
#*.sln merge=binary
|
||||
#*.csproj merge=binary
|
||||
#*.vbproj merge=binary
|
||||
#*.vcxproj merge=binary
|
||||
#*.vcproj merge=binary
|
||||
#*.dbproj merge=binary
|
||||
#*.fsproj merge=binary
|
||||
#*.lsproj merge=binary
|
||||
#*.wixproj merge=binary
|
||||
#*.modelproj merge=binary
|
||||
#*.sqlproj merge=binary
|
||||
#*.wwaproj merge=binary
|
||||
|
||||
###############################################################################
|
||||
# behavior for image files
|
||||
#
|
||||
# image files are treated as binary by default.
|
||||
###############################################################################
|
||||
#*.jpg binary
|
||||
#*.png binary
|
||||
#*.gif binary
|
||||
|
||||
###############################################################################
|
||||
# diff behavior for common document formats
|
||||
#
|
||||
# Convert binary document formats to text before diffing them. This feature
|
||||
# is only available from the command line. Turn it on by uncommenting the
|
||||
# entries below.
|
||||
###############################################################################
|
||||
#*.doc diff=astextplain
|
||||
#*.DOC diff=astextplain
|
||||
#*.docx diff=astextplain
|
||||
#*.DOCX diff=astextplain
|
||||
#*.dot diff=astextplain
|
||||
#*.DOT diff=astextplain
|
||||
#*.pdf diff=astextplain
|
||||
#*.PDF diff=astextplain
|
||||
#*.rtf diff=astextplain
|
||||
#*.RTF diff=astextplain
|
2
deps/WinToast/.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
patreon: mohabouje
|
||||
custom: https://paypal.me/mohabouje
|
41
deps/WinToast/.gitignore
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.obj
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
*.smod
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
*.lib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
*.ipch
|
||||
*.exp
|
||||
*.opensdf
|
||||
|
||||
# Visual Studio
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
.vs/
|
||||
Debug/
|
||||
Release/
|
||||
enc_temp_folder/
|
||||
/example/qt-gui-example/build-WinToastExample-Desktop_Qt_5_9_2_MSVC2015_32bit-Debug
|
21
deps/WinToast/LICENSE.txt
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2016 Mohammed Boujemaoui Boulaghmoudi
|
||||
|
||||
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.
|
248
deps/WinToast/README.md
vendored
Normal file
@ -0,0 +1,248 @@
|
||||
![releases](https://img.shields.io/github/tag/mohabouje/WinToast.svg)
|
||||
![issues](https://img.shields.io/github/issues/mohabouje/WinToast.svg)
|
||||
![license](https://img.shields.io/github/license/mohabouje/WinToast.svg)
|
||||
![GitHub contributors](https://img.shields.io/github/contributors/mohabouje/WinToast.svg)
|
||||
![built](https://img.shields.io/badge/built%20with-MVSC-6f62ba.svg)
|
||||
![dowloads](https://img.shields.io/github/downloads/mohabouje/WinToast/total.svg)
|
||||
|
||||
[![GitHub forks](https://img.shields.io/github/forks/mohabouje/WinToast.svg?style=social&label=Fork)]()
|
||||
[![GitHub stars](https://img.shields.io/github/stars/mohabouje/WinToast.svg?style=social&label=Star)]()
|
||||
[![GitHub watchers](https://img.shields.io/github/watchers/mohabouje/WinToast.svg?style=social&label=Watch)]()
|
||||
|
||||
***
|
||||
|
||||
WinToast
|
||||
===================
|
||||
|
||||
WinToast is a lightly library written in C++ which brings a complete integration of the modern **toast notifications** of **Windows 8** & **Windows 10**.
|
||||
|
||||
Toast notifications allows your app to inform the users about relevant information and timely events that they should see and take action upon inside your app, such as a new instant message, a new friend request, breaking news, or a calendar event.
|
||||
|
||||
- [WinToast](#wintoast)
|
||||
- [Toast Templates](#toast-templates)
|
||||
- [Event Handler](#event-handler)
|
||||
- [Expiration Time](#expiration-time)
|
||||
- [Additional features available on Windows 10](#additional-features-available-on-windows-10)
|
||||
- [Error Handling](#error-handling)
|
||||
- [Example of Usage](#example-of-usage)
|
||||
- [Installation](#installation)
|
||||
- [Toast configuration on Windows 10](#toast-configuration-on-windows-10)
|
||||
- [Projects using WinToast](#projects-using-wintoast)
|
||||
|
||||
|
||||
<div id='id1' />
|
||||
|
||||
## Toast Templates
|
||||
|
||||
WinToast integrates all standard templates available in the [ToastTemplateType enumeration](https://msdn.microsoft.com/en-us/library/windows/apps/br208660.aspx).
|
||||
|
||||
| Template | Description | Example |
|
||||
| :------- | ----: | :---: |
|
||||
| `ImageAndText01` | A large image and a single string wrapped across three lines of text. | ![enter image description here](assets/images/Toast_6.png) |
|
||||
| `ImageAndText02` | A large image, one string of bold text on the first line, one string of regular text wrapped across the second and third lines. | ![12](assets/images/Toast_7.png) |
|
||||
| `ImageAndText03` | A large image, one string of bold text wrapped across the first two lines, one string of regular text on the third line. | ![enter image description here](assets/images/Toast_8.png) |
|
||||
| `ImageAndText04` | A large image, one string of bold text on the first line, one string of regular text on the second line, one string of regular text on the third line. | ![enter image description here](assets/images/ToastImageAndText04.png) |
|
||||
| `Text01` | Single string wrapped across three lines of text. | ![enter image description here](assets/images/Toast_1.png)|
|
||||
| `Text02` | One string of bold text on the first line, one string of regular text wrapped across the second and third lines. | ![enter image description here](assets/images/Toast_2.png) |
|
||||
| `Text03` | One string of bold text wrapped across the first two lines, one string of regular text on the third line. | ![enter image description here](assets/images/Toast_4.png)|
|
||||
| `Text04` | One string of bold text on the first line, one string of regular text on the second line, one string of regular text on the third line. | ![enter image description here](assets/images/Toast_5.png) |
|
||||
|
||||
Example of a `ImageAndText02` template:
|
||||
|
||||
```cpp
|
||||
WinToastTemplate templ = WinToastTemplate(WinToastTemplate::ImageAndText02);
|
||||
templ.setTextField(L"title", WinToastTemplate::FirstLine);
|
||||
templ.setTextField(L"subtitle", WinToastTemplate::SecondLine);
|
||||
templ.setImagePath(L"C:/example.png");
|
||||
```
|
||||
**Note:** The user can use the default system sound or specify a sound to play when a toast notification is displayed. Same behavior for the toast notification image, by default Windows try to use the app icon.*
|
||||
|
||||
<div id='id3' />
|
||||
|
||||
## Event Handler
|
||||
|
||||
WinToast handle different events:
|
||||
|
||||
- **Activated**: Occurs when user activates a toast notification through a click or touch. Apps that are running subscribe to this event
|
||||
- **Dismissed**: Occurs when a toast notification leaves the screen, either by expiring or being explicitly dismissed by the user.
|
||||
* Application Hidden: The application hid the toast using ToastNotifier.hide.
|
||||
* User Canceled: The user dismissed the toast.
|
||||
* Timed Out: The toast has expired
|
||||
- **Failed**: Occurs when an error is caused when Windows attempts to raise a toast notification.
|
||||
|
||||
Create your custom handler to interact with the user actions by subclassing the interface `IWinToastHandler`:
|
||||
|
||||
```cpp
|
||||
class WinToastHandlerExample : public IWinToastHandler {
|
||||
public:
|
||||
WinToastHandlerExample();
|
||||
// Public interfaces
|
||||
void toastActivated() const override;
|
||||
void toastDismissed(WinToastDismissalReason state) const override;
|
||||
void toastFailed() const override;
|
||||
};
|
||||
```
|
||||
<div id='id4' />
|
||||
|
||||
## Expiration Time
|
||||
|
||||
Set the time after which a toast notification is no longer considered current or valid and should not be displayed. Windows attempts to raise toast notifications immediately after you call Show, so this property is rarely used.
|
||||
|
||||
> For Windows 8.x app, this property also causes the toast notification to be removed from the
|
||||
> Action Center once the specified data and time is reached.
|
||||
|
||||
**Note:** Default Windows behavior is to hide notification automatically after time set in Windows Ease of Access Settings.
|
||||
If you need to preserve notification in Windows Action Center for longer period of time, you have to call `WinToastTemplate::setExpiration` method.
|
||||
|
||||
<div id='id5' />
|
||||
|
||||
## Additional features available on Windows 10
|
||||
|
||||
If your system supports the new modern features (Version > Windows 8.1) available in Windows 10, you can add some interesting fields as:
|
||||
|
||||
- **Actions**: you can add your own actions, this fact allow you to interact with user in a different way:
|
||||
|
||||
```cpp
|
||||
WinToastTemplate templ = WinToastTemplate(WinToastTemplate::Text02);
|
||||
templ.setTextField(L"Do you think this feature is cool?", WinToastTemplate::FirstLine);
|
||||
templ.setTextField(L"Ofc,it is!", WinToastTemplate::SecondLine);
|
||||
|
||||
std::vector<std::wstring> actions;
|
||||
actions.push_back(L"Yes");
|
||||
actions.push_back(L"No");
|
||||
for (auto const &action : actions)
|
||||
templ.addAction(action);
|
||||
WinToast::instance()->showToast(templ, handler)
|
||||
```
|
||||
|
||||
!["Toast with some actions"](https://lh3.googleusercontent.com/uJE_H0aBisOZ-9GynEWgA7Hha8tHEI-i0aHrFuOFDBsPSD-IJ-qEN0Y7XY4VI5hp_5MQ9xjWbFcm)
|
||||
- **Attribution text**: you can add/remove the attribution text, by default is empty. Use `WinToastTemplate::setAttributionText` to modify it.
|
||||
- **Duration**: The amount of time the toast should display. This attribute can have one of the following values:
|
||||
- *System*: default system configuration.
|
||||
- *Short*: default system short time configuration.
|
||||
- *Long*: default system long time configuration.
|
||||
- **Audio Properties**: you can modify the different behaviors of the sound:
|
||||
- *Default*: plays the audio file just one time.
|
||||
- *Silent*: turn off the sound.
|
||||
- *Loop*: plays the given sound in a loop during the toast existence.
|
||||
|
||||
> WinToast allows the modification of the default audio file. Add
|
||||
> the given file in to your projects resources (*must be ms-appx:// or
|
||||
> ms-appdata:// path*) and define it by calling: `WinToastTemplate::setAudioPath`
|
||||
|
||||
***By default, WinToast checks if your systems support the features, ignoring the not supported ones.***
|
||||
|
||||
<div id='id2' />
|
||||
|
||||
## Error Handling
|
||||
There are several reasons WinToast can fail that's why the library notifies caller about fail reason. Those are the code for each failure:
|
||||
|
||||
| WinToastError | Error Code | Error message |
|
||||
|--|--|--|
|
||||
| `NoError` | 0x00 | No error. The process was executed correctly |
|
||||
| `NotInitialized` | 0x01 | The library has not been initialized |
|
||||
| `SystemNotSupported` | 0x02 | The OS does not support WinToast |
|
||||
| `ShellLinkNotCreated` | 0x03 | The library was not able to create a Shell Link for the app |
|
||||
| `InvalidAppUserModelID` | 0x04 | The AUMI is not a valid one |
|
||||
| `InvalidParameters` | 0x05 | The parameters used to configure the library are not valid normally because an invalid AUMI or App Name |
|
||||
| `NotDisplayed` | 0x06 | The toast was created correctly but WinToast was not able to display the toast |
|
||||
| `UnknownError` | 0x07 | Unknown error |
|
||||
|
||||
A common example of usage is to check while initializing the library or showing a toast notification the possible failure code:
|
||||
|
||||
```cpp
|
||||
WinToast::WinToastError error;
|
||||
const bool succedded = WinToast::instance()->initialize(&error);
|
||||
if (!succedded) {
|
||||
std::wcout << L"Error, could not initialize the lib. Error number: "
|
||||
<< error << std::endl;
|
||||
}
|
||||
...
|
||||
// Configure the template
|
||||
...
|
||||
const bool launched = WinToast::instance()->showToast(templ, handler, &error);
|
||||
if (!launched) {
|
||||
std::wcout << L"Error: Could not launch your toast notification. Error: "
|
||||
<< error << std::endl;
|
||||
}
|
||||
```
|
||||
|
||||
<div id='id6' />
|
||||
|
||||
## Example of Usage
|
||||
|
||||
*For an easy usage, you can just use the available singleton instance.*
|
||||
|
||||
First step, Import the header file wintoastlib.h to your project. You should check if your Windows Version is supported by the library.
|
||||
|
||||
```cpp
|
||||
using namespace WinToastLib;
|
||||
....
|
||||
if (!WinToast::isCompatible()) {
|
||||
std::wcout << L"Error, your system in not supported!" << std::endl;
|
||||
}
|
||||
```
|
||||
|
||||
Configure your [App User Model Id](https://msdn.microsoft.com/en-us/library/windows/desktop/dd378459%28v=vs.85%29.aspx), this can be done by using the existing helper:
|
||||
|
||||
```cpp
|
||||
|
||||
WinToast::instance()->setAppName(L"WinToastExample");
|
||||
const auto aumi = WinToast::configureAUMI(L"mohabouje", L"wintoast", L"wintoastexample", L"20161006");
|
||||
WinToast::instance()->setAppUserModelId(aumi);
|
||||
```
|
||||
|
||||
Initialize all the dependencies and check if WinToast has been initialized successfully in your system:
|
||||
|
||||
```cpp
|
||||
if (!WinToast::instance()->initialize()) {
|
||||
std::wcout << L"Error, could not initialize the lib!" << std::endl;
|
||||
}
|
||||
```
|
||||
|
||||
Implement your own action handler by subclassing the interface `IWinToastHandler` and custom your template:
|
||||
|
||||
```cpp
|
||||
WinToastHandlerExample* handler = new WinToastHandlerExample;
|
||||
WinToastTemplate templ = WinToastTemplate(WinToastTemplate::ImageAndText02);
|
||||
templ.setImagePath(L"C:/example.png");
|
||||
templ.setTextField(L"title", WinToastTemplate::FirstLine);
|
||||
templ.setTextField(L"subtitle", WinToastTemplate::SecondLine);
|
||||
```
|
||||
|
||||
Finally show the results:
|
||||
|
||||
```cpp
|
||||
|
||||
if (!WinToast::instance()->showToast(templ, handler)) {
|
||||
std::wcout << L"Error: Could not launch your toast notification!" << std::endl;
|
||||
}
|
||||
```
|
||||
<div id='id7' />
|
||||
|
||||
## Installation
|
||||
|
||||
If you are using a package manager, there is a port for [vcpkg](https://github.com/microsoft/vcpkg/). Otherwise, the easiest way is to copy the source files as external dependencies.
|
||||
|
||||
## Toast configuration on Windows 10
|
||||
|
||||
Windows allows the configuration of the default behavior of a toast notification. This can be done in the *Ease of Access* configuration by modifying the *Other options* tab.
|
||||
|
||||
The system configuration helps you to define how long you want notifications to appear for (5 seconds to 5 minutes) as turning on visual notifications for sound.
|
||||
|
||||
![Ease of Access configuration](https://camo.githubusercontent.com/56c8edd1a7a4a43be07ba211d9d828478fdbad39/68747470733a2f2f7777772e686f77746f6765656b2e636f6d2f77702d636f6e74656e742f75706c6f6164732f323031362f30332f656173655f6f665f6163636573732e706e67)
|
||||
|
||||
<div id='id8' />
|
||||
|
||||
## Projects using WinToast
|
||||
- [Git for Windows](https://github.com/git-for-windows/git): A fork of Git containing Windows-specific patches.
|
||||
- [QGIS](https://github.com/qgis/QGIS): QGIS is a free, open source, cross platform (lin/win/mac) geographical information system (GIS)
|
||||
- [MEGAsync](https://github.com/meganz/MEGAsync): Easy automated syncing between your computers and your MEGA Cloud Drive
|
||||
- [chatterino2](https://github.com/Chatterino/chatterino2): Chat client for twitch.tv
|
||||
- [nheko](https://github.com/Nheko-Reborn/nheko): Desktop client for the Matrix protocol.
|
||||
- [EDPathFinder](https://github.com/neotron/EDPathFinder): A program that creates an optimal route that passes through two or more systems in Elite.
|
||||
- [AntiExploit](https://github.com/Empier/Anti-Exploit): antiexploit utility for Windows.
|
||||
- [Zroya](https://github.com/malja/zroya): Python extension for creating native Windows notifications..
|
||||
- [PidginWinToastNotifications](https://github.com/ChristianGalla/PidginWinToastNotifications): Windows Toast Notification Plugin for Pidgin.
|
||||
- [Dnai-Editor](https://github.com/Nicolas-Constanty/Dnai.Editor): Visual Scripting, node editor.
|
||||
- [Spectral](https://gitlab.com/b0/spectral): A glossy client for Matrix, written in QtQuick Controls 2 and C++.
|
1
deps/WinToast/_config.yml
vendored
Normal file
@ -0,0 +1 @@
|
||||
theme: jekyll-theme-architect
|
BIN
deps/WinToast/assets/images/ToastImageAndText04.png
vendored
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
deps/WinToast/assets/images/ToastText02Phone.png
vendored
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
deps/WinToast/assets/images/Toast_1.png
vendored
Normal file
After Width: | Height: | Size: 5.3 KiB |
BIN
deps/WinToast/assets/images/Toast_2.png
vendored
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
deps/WinToast/assets/images/Toast_4.png
vendored
Normal file
After Width: | Height: | Size: 5.3 KiB |
BIN
deps/WinToast/assets/images/Toast_5.png
vendored
Normal file
After Width: | Height: | Size: 4.7 KiB |
BIN
deps/WinToast/assets/images/Toast_6.png
vendored
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
deps/WinToast/assets/images/Toast_7.png
vendored
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
deps/WinToast/assets/images/Toast_8.png
vendored
Normal file
After Width: | Height: | Size: 22 KiB |
1
deps/WinToast/docs/_config.yml
vendored
Normal file
@ -0,0 +1 @@
|
||||
theme: jekyll-theme-leap-day
|
185
deps/WinToast/docs/index.md
vendored
Normal file
@ -0,0 +1,185 @@
|
||||
# WinToast
|
||||
|
||||
WinToast is a lightly library written in C++ which brings a complete integration of the modern **toast notifications** of **Windows 8** & **Windows 10**.
|
||||
|
||||
Toast notifications allows your app to inform the users about relevant information and timely events that they should see and take action upon inside your app, such as a new instant message, a new friend request, breaking news, or a calendar event.
|
||||
|
||||
## Event Handler
|
||||
|
||||
WinToast implements a common interface `IWinToastHandler` to handle events:
|
||||
|
||||
- **Activated**: Occurs when user activates a toast notification through a click or touch. Apps that are running subscribe to this event
|
||||
- **Dismissed**: Occurs when a toast notification leaves the screen, either by expiring or being explicitly dismissed by the user.
|
||||
* Application Hidden: The application hid the toast using ToastNotifier.hide.
|
||||
* User Canceled: The user dismissed the toast.
|
||||
* Timed Out: The toast has expired
|
||||
- **Failed**: Occurs when an error is caused when Windows attempts to raise a toast notification.
|
||||
|
||||
Users can creates their own custom handler to interact with the user actions. For example:
|
||||
|
||||
```cpp
|
||||
class WinToastHandlerExample : public IWinToastHandler {
|
||||
public:
|
||||
WinToastHandlerExample();
|
||||
// Public interfaces
|
||||
void toastActivated() const override;
|
||||
void toastDismissed(WinToastDismissalReason state) const override;
|
||||
void toastFailed() const override;
|
||||
};
|
||||
|
||||
```
|
||||
## Error Handling
|
||||
|
||||
There are several reasons WinToast can fail that's why the library notifies the caller about any possible failure reason. Those are the code for each failure:
|
||||
|
||||
| WinToastError | Error Code | Error message |
|
||||
| ----------------------- | ---------- | ------------------------------------------------------------ |
|
||||
| `NoError` | 0x00 | No error. The process was executed correctly |
|
||||
| `NotInitialized` | 0x01 | The library has not been initialized |
|
||||
| `SystemNotSupported` | 0x02 | The OS does not support WinToast |
|
||||
| `ShellLinkNotCreated` | 0x03 | The library was not able to create a Shell Link for the app |
|
||||
| `InvalidAppUserModelID` | 0x04 | The AUMI is not a valid one |
|
||||
| `InvalidParameters` | 0x05 | The parameters used to configure the library are not valid normally because an invalid AUMI or App Name |
|
||||
| `NotDisplayed` | 0x06 | The toast was created correctly but WinToast was not able to display the toast |
|
||||
| `UnknownError` | 0x07 | Unknown error |
|
||||
|
||||
A common example of usage is to check while initializing the library or showing a toast notification the possible failure code:
|
||||
|
||||
```cpp
|
||||
WinToast::WinToastError error;
|
||||
const bool succedded = WinToast::instance()->initialize(&error);
|
||||
if (!succedded) {
|
||||
std::wcout << L"Error, could not initialize the lib. Error: "
|
||||
<< WinToast::strerror(error) << std::endl;
|
||||
}
|
||||
```
|
||||
|
||||
## Properties
|
||||
|
||||
### Templates
|
||||
|
||||
WinToast integrates all standard templates available in the [ToastTemplateType enumeration](https://msdn.microsoft.com/en-us/library/windows/apps/br208660.aspx).
|
||||
|
||||
|
||||
|
||||
| Template | Description | Example |
|
||||
| :--------------- | -----------------------------------------------------------: | :----------------------------------------------------------: |
|
||||
| `ImageAndText01` | A large image and a single string wrapped across three lines of text. | ![enter image description here](https://i-msdn.sec.s-msft.com/dynimg/IC601606.png) |
|
||||
| `ImageAndText02` | A large image, one string of bold text on the first line, one string of regular text wrapped across the second and third lines. | ![12](https://i-msdn.sec.s-msft.com/dynimg/IC601607.png) |
|
||||
| `ImageAndText03` | A large image, one string of bold text wrapped across the first two lines, one string of regular text on the third line. | ![enter image description here](https://i-msdn.sec.s-msft.com/dynimg/IC601608.png) |
|
||||
| `ImageAndText04` | A large image, one string of bold text on the first line, one string of regular text on the second line, one string of regular text on the third line. | ![enter image description here](https://i-msdn.sec.s-msft.com/dynimg/IC601609.png) |
|
||||
| `Text01` | Single string wrapped across three lines of text. | ![enter image description here](https://i-msdn.sec.s-msft.com/dynimg/IC601602.png) |
|
||||
| `Text02` | One string of bold text on the first line, one string of regular text wrapped across the second and third lines. | ![enter image description here](https://i-msdn.sec.s-msft.com/dynimg/IC601603.png) |
|
||||
| `Text03` | One string of bold text wrapped across the first two lines, one string of regular text on the third line. | ![enter image description here](https://i-msdn.sec.s-msft.com/dynimg/IC601604.png) |
|
||||
| `Text04` | One string of bold text on the first line, one string of regular text on the second line, one string of regular text on the third line. | ![enter image description here](https://i-msdn.sec.s-msft.com/dynimg/IC601605.png) |
|
||||
|
||||
Example of a `ImageAndText02` template:
|
||||
|
||||
```cpp
|
||||
WinToastTemplate templ = WinToastTemplate(WinToastTemplate::ImageAndText02);
|
||||
templ.setTextField(L"title", WinToastTemplate::FirstLine);
|
||||
templ.setTextField(L"subtitle", WinToastTemplate::SecondLine);
|
||||
templ.setImagePath(L"C:/example.png");
|
||||
```
|
||||
|
||||
**Note:** The user can use the default system sound or specify a sound to play when a toast notification is displayed. Same behavior for the toast notification image, by default Windows try to use the app icon.
|
||||
|
||||
### Expiration Time
|
||||
|
||||
This property sets the time after which a toast notification is no longer considered current or valid and should not be displayed. Windows attempts to raise toast notifications immediately after you call Show, so this property is rarely used.
|
||||
|
||||
> For Windows 8.x app, this property also causes the toast notification to be removed from the
|
||||
> Action Center once the specified data and time is reached.
|
||||
|
||||
> Not: Default Windows behavior is to hide notification automatically after time set in Windows Ease of Access Settings.
|
||||
|
||||
If you need to preserve notification in Windows Action Center for longer period of time, you have to call `WinToastTemplate::setExpiration` method.
|
||||
|
||||
### Actions
|
||||
|
||||
WinToast provides an easy interface to add actions (buttons) to a toast notification. This feature allows the interaction with user in a different way:
|
||||
|
||||
```cpp
|
||||
WinToastTemplate templ = WinToastTemplate(WinToastTemplate::Text02);
|
||||
templ.setTextField(L"Do you think this feature is cool?", WinToastTemplate::FirstLine);
|
||||
templ.setTextField(L"Ofc,it is!", WinToastTemplate::SecondLine);
|
||||
|
||||
std::vector<std::wstring> actions;
|
||||
actions.push_back(L"Yes");
|
||||
actions.push_back(L"No");
|
||||
for (auto const &action : actions)
|
||||
templ.addAction(action);
|
||||
WinToast::instance()->showToast(templ, handler)
|
||||
```
|
||||
|
||||
This code will display something like this:
|
||||
|
||||
!["Toast with some actions"](https://lh3.googleusercontent.com/uJE_H0aBisOZ-9GynEWgA7Hha8tHEI-i0aHrFuOFDBsPSD-IJ-qEN0Y7XY4VI5hp_5MQ9xjWbFcm)
|
||||
|
||||
### Atribution Text
|
||||
|
||||
In the latest versions of Windows, users can add/remove an attribution text (empty by default). WinToast integrates a simple interface to change this property `WinToastTemplate::setAttributionText`:
|
||||
|
||||
```c++
|
||||
WinToastTemplate templ = WinToastTemplate(WinToastTemplate::Text01);
|
||||
templ.setTextField(L"Do you think this feature is cool?", WinToastTemplate::FirstLine);
|
||||
templ.setAttributionText(L"This is an attribution text");
|
||||
WinToast::instance()->showToast(templ, handler)
|
||||
```
|
||||
|
||||
### Duration
|
||||
|
||||
Users can change the amount of time the toast should be displayed. This attribute can have one of the following values:
|
||||
|
||||
- *System*: default system configuration.
|
||||
- *Short*: default system short time configuration.
|
||||
- *Long*: default system long time configuration.
|
||||
|
||||
```c++
|
||||
WinToastTemplate templ = WinToastTemplate(WinToastTemplate::Text01);
|
||||
templ.setFirstLine(L"I will be displayed for a long time");
|
||||
templ.setDuration(WinToastTemplate::Duration::Long);
|
||||
WinToast::instance()->showToast(templ, handler)
|
||||
```
|
||||
|
||||
### Audio
|
||||
|
||||
Users can modify the different behaviors of the sound. For instance, users can specify the default play mode:
|
||||
|
||||
- *Default*: plays the audio file just one time.
|
||||
- *Silent*: turn off the sound.
|
||||
- *Loop*: plays the given sound in a loop during the toast existence.
|
||||
|
||||
> WinToast allows the modification of the default audio file. There are different audio files installed by default in the system that can be used via the `WinToastTemplate::AudioSystemFile` enumeration. See more details in this [link](https://docs.microsoft.com/en-us/uwp/schemas/tiles/toastschema/element-audio).
|
||||
>
|
||||
> For instance, to display an alarm that will play the same sound in a loop we could do something like this:
|
||||
>
|
||||
> ```c++
|
||||
> WinToastTemplate templ = WinToastTemplate(WinToastTemplate::Text01);
|
||||
> templ.setFirstLine(L"I am an alarm");
|
||||
> templ.setDuration(WinToastTemplate::Duration::Long);
|
||||
> templ.setAudioMode(WinToastTemplate::AudioOption::Loop);
|
||||
> templ.setAudioPath(WinToastTemplate::AudioSystemFile::Alarm);
|
||||
> WinToast::instance()->showToast(templ, handler)
|
||||
> ```
|
||||
|
||||
## Toast configuration on Windows 10
|
||||
|
||||
Windows allows the configuration of the default behavior of a toast notification. This can be done in the *Ease of Access* configuration by modifying the *Other options* tab.
|
||||
|
||||
The system configuration helps you to define how long you want notifications to appear for (5 seconds to 5 minutes) as turning on visual notifications for sound.
|
||||
|
||||
![Ease of Access configuration](https://camo.githubusercontent.com/56c8edd1a7a4a43be07ba211d9d828478fdbad39/68747470733a2f2f7777772e686f77746f6765656b2e636f6d2f77702d636f6e74656e742f75706c6f6164732f323031362f30332f656173655f6f665f6163636573732e706e67)
|
||||
|
||||
<div id='id8' />
|
||||
|
||||
## Projects using WinToast
|
||||
- [Git for Windows](https://github.com/git-for-windows/git): A fork of Git containing Windows-specific patches.
|
||||
- [QGIS](https://github.com/qgis/QGIS): QGIS is a free, open source, cross platform (lin/win/mac) geographical information system (GIS)
|
||||
- [nheko](https://github.com/mujx/nheko): Desktop client for the Matrix protocol.
|
||||
- [EDPathFinder](https://github.com/neotron/EDPathFinder): A program that creates an optimal route that passes through two or more systems in Elite.
|
||||
- [AntiExploit](https://github.com/Empier/Anti-Exploit): antiexploit utility for Windows.
|
||||
- [Zroya](https://github.com/malja/zroya): Python extension for creating native Windows notifications..
|
||||
- [PidginWinToastNotifications](https://github.com/ChristianGalla/PidginWinToastNotifications): Windows Toast Notification Plugin for Pidgin.
|
||||
- [Dnai-Editor](https://github.com/Nicolas-Constanty/Dnai.Editor): Visual Scripting, node editor.
|
||||
- [Spectral](https://gitlab.com/b0/spectral): A glossy client for Matrix, written in QtQuick Controls 2 and C++.
|
20
deps/WinToast/example/console-example/README.MD
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
|
||||
|
||||
WinToast Console Example!
|
||||
===================
|
||||
|
||||
WinToast Contole Example [OPTIONS]
|
||||
--action : Set the actions in buttons
|
||||
--aumi : Set the App User Model Id
|
||||
--appname : Set the default appname
|
||||
--appid : Set the App Id
|
||||
--expirems : Set the default expiration time
|
||||
--text : Set the text for the notifications
|
||||
--image : set the image path
|
||||
--help : Print the help description
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
"WinToast Contole Example.exe" --appname "Yolo" --aumi "My.Console.Example" --image "if_terminal_298878.png" --expirems 10000 --action Yes --action No --text "Do you want to try to take over the world?"
|
||||
|
31
deps/WinToast/example/console-example/WinToast Console Example.sln
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.27130.2027
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WinToast Console Example", "WinToast Console Example.vcxproj", "{7C5AC60D-8668-47B6-9D05-FB363F854065}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{7C5AC60D-8668-47B6-9D05-FB363F854065}.Debug|x64.ActiveCfg = Debug|Win32
|
||||
{7C5AC60D-8668-47B6-9D05-FB363F854065}.Debug|x64.Build.0 = Debug|Win32
|
||||
{7C5AC60D-8668-47B6-9D05-FB363F854065}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{7C5AC60D-8668-47B6-9D05-FB363F854065}.Debug|x86.Build.0 = Debug|Win32
|
||||
{7C5AC60D-8668-47B6-9D05-FB363F854065}.Release|x64.ActiveCfg = Release|x64
|
||||
{7C5AC60D-8668-47B6-9D05-FB363F854065}.Release|x64.Build.0 = Release|x64
|
||||
{7C5AC60D-8668-47B6-9D05-FB363F854065}.Release|x86.ActiveCfg = Release|Win32
|
||||
{7C5AC60D-8668-47B6-9D05-FB363F854065}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {ABA98BF8-B665-455B-A51E-B36DD616139C}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
103
deps/WinToast/example/console-example/WinToast Console Example.vcxproj
vendored
Normal file
@ -0,0 +1,103 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>15.0</VCProjectVersion>
|
||||
<ProjectGuid>{7C5AC60D-8668-47B6-9D05-FB363F854065}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Console</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Platform)'=='Win32'">
|
||||
<Link>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Platform)'=='x64'">
|
||||
<Link>
|
||||
<TargetMachine>MachineX64</TargetMachine>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<Optimization>MinSpace</Optimization>
|
||||
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\src\wintoastlib.cpp" />
|
||||
<ClCompile Include="main.cpp">
|
||||
<AdditionalIncludeDirectories>..\..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\src\wintoastlib.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="if_terminal_298878.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\.editorconfig" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
38
deps/WinToast/example/console-example/WinToast Console Example.vcxproj.filters
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\wintoastlib.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\src\wintoastlib.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="if_terminal_298878.png">
|
||||
<Filter>Resource Files</Filter>
|
||||
</Image>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\.editorconfig" />
|
||||
</ItemGroup>
|
||||
</Project>
|
BIN
deps/WinToast/example/console-example/if_terminal_298878.png
vendored
Normal file
After Width: | Height: | Size: 1.0 KiB |
184
deps/WinToast/example/console-example/main.cpp
vendored
Normal file
@ -0,0 +1,184 @@
|
||||
#include "wintoastlib.h"
|
||||
#include <string> // std::string, std::stoi
|
||||
|
||||
using namespace WinToastLib;
|
||||
|
||||
class CustomHandler : public IWinToastHandler {
|
||||
public:
|
||||
void toastActivated() const {
|
||||
std::wcout << L"The user clicked in this toast" << std::endl;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void toastActivated(int actionIndex) const {
|
||||
std::wcout << L"The user clicked on action #" << actionIndex << std::endl;
|
||||
exit(16 + actionIndex);
|
||||
}
|
||||
|
||||
void toastDismissed(WinToastDismissalReason state) const {
|
||||
switch (state) {
|
||||
case UserCanceled:
|
||||
std::wcout << L"The user dismissed this toast" << std::endl;
|
||||
exit(1);
|
||||
break;
|
||||
case TimedOut:
|
||||
std::wcout << L"The toast has timed out" << std::endl;
|
||||
exit(2);
|
||||
break;
|
||||
case ApplicationHidden:
|
||||
std::wcout << L"The application hid the toast using ToastNotifier.hide()" << std::endl;
|
||||
exit(3);
|
||||
break;
|
||||
default:
|
||||
std::wcout << L"Toast not activated" << std::endl;
|
||||
exit(4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void toastFailed() const {
|
||||
std::wcout << L"Error showing current toast" << std::endl;
|
||||
exit(5);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
enum Results {
|
||||
ToastClicked, // user clicked on the toast
|
||||
ToastDismissed, // user dismissed the toast
|
||||
ToastTimeOut, // toast timed out
|
||||
ToastHided, // application hid the toast
|
||||
ToastNotActivated, // toast was not activated
|
||||
ToastFailed, // toast failed
|
||||
SystemNotSupported, // system does not support toasts
|
||||
UnhandledOption, // unhandled option
|
||||
MultipleTextNotSupported, // multiple texts were provided
|
||||
InitializationFailure, // toast notification manager initialization failure
|
||||
ToastNotLaunched // toast could not be launched
|
||||
};
|
||||
|
||||
|
||||
#define COMMAND_ACTION L"--action"
|
||||
#define COMMAND_AUMI L"--aumi"
|
||||
#define COMMAND_APPNAME L"--appname"
|
||||
#define COMMAND_APPID L"--appid"
|
||||
#define COMMAND_EXPIREMS L"--expirems"
|
||||
#define COMMAND_TEXT L"--text"
|
||||
#define COMMAND_HELP L"--help"
|
||||
#define COMMAND_IMAGE L"--image"
|
||||
#define COMMAND_SHORTCUT L"--only-create-shortcut"
|
||||
#define COMMAND_AUDIOSTATE L"--audio-state"
|
||||
#define COMMAND_ATTRIBUTE L"--attribute"
|
||||
|
||||
void print_help() {
|
||||
std::wcout << "WinToast Console Example [OPTIONS]" << std::endl;
|
||||
std::wcout << "\t" << COMMAND_ACTION << L" : Set the actions in buttons" << std::endl;
|
||||
std::wcout << "\t" << COMMAND_AUMI << L" : Set the App User Model Id" << std::endl;
|
||||
std::wcout << "\t" << COMMAND_APPNAME << L" : Set the default appname" << std::endl;
|
||||
std::wcout << "\t" << COMMAND_APPID << L" : Set the App Id" << std::endl;
|
||||
std::wcout << "\t" << COMMAND_EXPIREMS << L" : Set the default expiration time" << std::endl;
|
||||
std::wcout << "\t" << COMMAND_TEXT << L" : Set the text for the notifications" << std::endl;
|
||||
std::wcout << "\t" << COMMAND_IMAGE << L" : set the image path" << std::endl;
|
||||
std::wcout << "\t" << COMMAND_ATTRIBUTE << L" : set the attribute for the notification" << std::endl;
|
||||
std::wcout << "\t" << COMMAND_SHORTCUT << L" : create the shortcut for the app" << std::endl;
|
||||
std::wcout << "\t" << COMMAND_AUDIOSTATE << L" : set the audio state: Default = 0, Silent = 1, Loop = 2" << std::endl;
|
||||
std::wcout << "\t" << COMMAND_HELP << L" : Print the help description" << std::endl;
|
||||
}
|
||||
|
||||
|
||||
int wmain(int argc, LPWSTR *argv)
|
||||
{
|
||||
if (argc == 1) {
|
||||
print_help();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!WinToast::isCompatible()) {
|
||||
std::wcerr << L"Error, your system in not supported!" << std::endl;
|
||||
return Results::SystemNotSupported;
|
||||
}
|
||||
|
||||
LPWSTR appName = L"Console WinToast Example",
|
||||
appUserModelID = L"WinToast Console Example",
|
||||
text = NULL,
|
||||
imagePath = NULL,
|
||||
attribute = L"default";
|
||||
std::vector<std::wstring> actions;
|
||||
INT64 expiration = 0;
|
||||
|
||||
|
||||
bool onlyCreateShortcut = false;
|
||||
WinToastTemplate::AudioOption audioOption = WinToastTemplate::AudioOption::Default;
|
||||
|
||||
int i;
|
||||
for (i = 1; i < argc; i++)
|
||||
if (!wcscmp(COMMAND_IMAGE, argv[i]))
|
||||
imagePath = argv[++i];
|
||||
else if (!wcscmp(COMMAND_ACTION, argv[i]))
|
||||
actions.push_back(argv[++i]);
|
||||
else if (!wcscmp(COMMAND_EXPIREMS, argv[i]))
|
||||
expiration = wcstol(argv[++i], NULL, 10);
|
||||
else if (!wcscmp(COMMAND_APPNAME, argv[i]))
|
||||
appName = argv[++i];
|
||||
else if (!wcscmp(COMMAND_AUMI, argv[i]) || !wcscmp(COMMAND_APPID, argv[i]))
|
||||
appUserModelID = argv[++i];
|
||||
else if (!wcscmp(COMMAND_TEXT, argv[i]))
|
||||
text = argv[++i];
|
||||
else if (!wcscmp(COMMAND_ATTRIBUTE, argv[i]))
|
||||
attribute = argv[++i];
|
||||
else if (!wcscmp(COMMAND_SHORTCUT, argv[i]))
|
||||
onlyCreateShortcut = true;
|
||||
else if (!wcscmp(COMMAND_AUDIOSTATE, argv[i]))
|
||||
audioOption = static_cast<WinToastTemplate::AudioOption>(std::stoi(argv[++i]));
|
||||
else if (!wcscmp(COMMAND_HELP, argv[i])) {
|
||||
print_help();
|
||||
return 0;
|
||||
} else {
|
||||
std::wcerr << L"Option not recognized: " << argv[i] << std::endl;
|
||||
return Results::UnhandledOption;
|
||||
}
|
||||
|
||||
WinToast::instance()->setAppName(appName);
|
||||
WinToast::instance()->setAppUserModelId(appUserModelID);
|
||||
|
||||
if (onlyCreateShortcut) {
|
||||
if (imagePath || text || actions.size() > 0 || expiration) {
|
||||
std::wcerr << L"--only-create-shortcut does not accept images/text/actions/expiration" << std::endl;
|
||||
return 9;
|
||||
}
|
||||
enum WinToast::ShortcutResult result = WinToast::instance()->createShortcut();
|
||||
return result ? 16 + result : 0;
|
||||
}
|
||||
|
||||
if (!text)
|
||||
text = L"Hello, world!";
|
||||
|
||||
if (!WinToast::instance()->initialize()) {
|
||||
std::wcerr << L"Error, your system in not compatible!" << std::endl;
|
||||
return Results::InitializationFailure;
|
||||
}
|
||||
|
||||
bool withImage = (imagePath != NULL);
|
||||
WinToastTemplate templ( withImage ? WinToastTemplate::ImageAndText02 : WinToastTemplate::Text02);
|
||||
templ.setTextField(text, WinToastTemplate::FirstLine);
|
||||
templ.setAudioOption(audioOption);
|
||||
templ.setAttributionText(attribute);
|
||||
|
||||
for (auto const &action : actions)
|
||||
templ.addAction(action);
|
||||
if (expiration)
|
||||
templ.setExpiration(expiration);
|
||||
if (withImage)
|
||||
templ.setImagePath(imagePath);
|
||||
|
||||
|
||||
if (WinToast::instance()->showToast(templ, new CustomHandler()) < 0) {
|
||||
std::wcerr << L"Could not launch your toast notification!";
|
||||
return Results::ToastFailed;
|
||||
}
|
||||
|
||||
// Give the handler a chance for 15 seconds (or the expiration plus 1 second)
|
||||
Sleep(expiration ? (DWORD)expiration + 1000 : 15000);
|
||||
|
||||
exit(2);
|
||||
}
|
27
deps/WinToast/example/qt-gui-example/WinToastExample/WinToastExample.pro
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
#-------------------------------------------------
|
||||
#
|
||||
# Project created by QtCreator 2016-10-01T17:29:36
|
||||
#
|
||||
#-------------------------------------------------
|
||||
|
||||
QT += core gui
|
||||
CONFIG += c++11
|
||||
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
|
||||
TARGET = WinToastExample
|
||||
TEMPLATE = app
|
||||
|
||||
|
||||
SOURCES += main.cpp\
|
||||
mainwindow.cpp \
|
||||
../../../src/wintoastlib.cpp
|
||||
|
||||
HEADERS += mainwindow.h \
|
||||
../../../src/wintoastlib.h
|
||||
|
||||
FORMS += mainwindow.ui
|
||||
|
||||
#win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../../../lib/Release/ -lWinToastLib
|
||||
#else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../../lib/Debug/ -lWinToastLib
|
||||
|
11
deps/WinToast/example/qt-gui-example/WinToastExample/main.cpp
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
#include "mainwindow.h"
|
||||
#include <QApplication>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication a(argc, argv);
|
||||
MainWindow w;
|
||||
w.show();
|
||||
|
||||
return a.exec();
|
||||
}
|
94
deps/WinToast/example/qt-gui-example/WinToastExample/mainwindow.cpp
vendored
Normal file
@ -0,0 +1,94 @@
|
||||
#include "mainwindow.h"
|
||||
#include "ui_mainwindow.h"
|
||||
#include <QDebug>
|
||||
#include <qfiledialog.h>
|
||||
#include <qmessagebox.h>
|
||||
|
||||
#include "../../../src/wintoastlib.h"
|
||||
using namespace WinToastLib;
|
||||
MainWindow::MainWindow(QWidget *parent) :
|
||||
QMainWindow(parent),
|
||||
ui(new Ui::MainWindow)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
ui->audioMode->addItem("Default", WinToastTemplate::AudioOption::Default);
|
||||
ui->audioMode->addItem("Loop", WinToastTemplate::AudioOption::Loop);
|
||||
ui->audioMode->addItem("Silence", WinToastTemplate::AudioOption::Silent);
|
||||
|
||||
ui->audioSystemFile->addItem("Default", WinToastTemplate::AudioSystemFile::DefaultSound);
|
||||
ui->audioSystemFile->addItem("Mail", WinToastTemplate::AudioSystemFile::Mail);
|
||||
ui->audioSystemFile->addItem("SMS", WinToastTemplate::AudioSystemFile::SMS);
|
||||
ui->audioSystemFile->addItem("Alarm", WinToastTemplate::AudioSystemFile::Alarm);
|
||||
|
||||
WinToast::instance()->setAppName(L"WinToastExample");
|
||||
WinToast::instance()->setAppUserModelId(
|
||||
WinToast::configureAUMI(L"mohabouje", L"wintoast", L"wintoastexample", L"20161006"));
|
||||
if (!WinToast::instance()->initialize()) {
|
||||
qDebug() << "Error, your system in not compatible!";
|
||||
}
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void MainWindow::on_imagePathSelector_clicked()
|
||||
{
|
||||
const QString fileName = QFileDialog::getOpenFileName(this, "Select an image", QDir::currentPath(), "*.png");
|
||||
if (fileName.isEmpty())
|
||||
return;
|
||||
ui->imagePath->setText(QDir::toNativeSeparators(fileName));
|
||||
|
||||
}
|
||||
|
||||
class CustomHandler : public IWinToastHandler {
|
||||
public:
|
||||
void toastActivated() const {
|
||||
std::wcout << L"The user clicked in this toast" << std::endl;
|
||||
}
|
||||
|
||||
void toastActivated(int actionIndex) const {
|
||||
std::wcout << L"The user clicked on button #" << actionIndex << L" in this toast" << std::endl;
|
||||
}
|
||||
|
||||
void toastFailed() const {
|
||||
std::wcout << L"Error showing current toast" << std::endl;
|
||||
}
|
||||
void toastDismissed(WinToastDismissalReason state) const {
|
||||
switch (state) {
|
||||
case UserCanceled:
|
||||
std::wcout << L"The user dismissed this toast" << std::endl;
|
||||
break;
|
||||
case ApplicationHidden:
|
||||
std::wcout << L"The application hid the toast using ToastNotifier.hide()" << std::endl;
|
||||
break;
|
||||
case TimedOut:
|
||||
std::wcout << L"The toast has timed out" << std::endl;
|
||||
break;
|
||||
default:
|
||||
std::wcout << L"Toast not activated" << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void MainWindow::on_showToast_clicked()
|
||||
{
|
||||
WinToastTemplate templ = WinToastTemplate(WinToastTemplate::ImageAndText04);
|
||||
templ.setImagePath(ui->imagePath->text().toStdWString());
|
||||
templ.setTextField(ui->firstLine->text().toStdWString(), WinToastTemplate::FirstLine);
|
||||
templ.setTextField(ui->secondLine->text().toStdWString(), WinToastTemplate::SecondLine);
|
||||
templ.setTextField(ui->secondLine->text().toStdWString(), WinToastTemplate::ThirdLine);
|
||||
templ.setExpiration(ui->spinBox->value() * 1000);
|
||||
templ.setAudioPath(static_cast<WinToastTemplate::AudioSystemFile>(ui->audioSystemFile->currentData().toInt()));
|
||||
templ.setAudioOption(static_cast<WinToastTemplate::AudioOption>(ui->audioMode->currentData().toInt()));
|
||||
if (ui->addYes->isChecked()) templ.addAction(L"Yes");
|
||||
if (ui->addNo->isChecked()) templ.addAction(L"No");
|
||||
|
||||
|
||||
if (WinToast::instance()->showToast(templ, new CustomHandler()) < 0) {
|
||||
QMessageBox::warning(this, "Error", "Could not launch your toast notification!");
|
||||
}
|
||||
}
|
27
deps/WinToast/example/qt-gui-example/WinToastExample/mainwindow.h
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include <QMainWindow>
|
||||
|
||||
namespace Ui {
|
||||
class MainWindow;
|
||||
}
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MainWindow(QWidget *parent = 0);
|
||||
~MainWindow();
|
||||
|
||||
private slots:
|
||||
void on_imagePathSelector_clicked();
|
||||
|
||||
void on_showToast_clicked();
|
||||
|
||||
private:
|
||||
Ui::MainWindow *ui;
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
190
deps/WinToast/example/qt-gui-example/WinToastExample/mainwindow.ui
vendored
Normal file
@ -0,0 +1,190 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>670</width>
|
||||
<height>220</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>WinToast Example</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralWidget">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="4" column="2">
|
||||
<widget class="QComboBox" name="audioSystemFile"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>First Line</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Second Line</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<widget class="QCheckBox" name="addYes">
|
||||
<property name="text">
|
||||
<string>Add Yes Action</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Audio System File</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="2">
|
||||
<widget class="QWidget" name="widget_2" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="showToast">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Show Toast</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Image Path</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="0">
|
||||
<widget class="QCheckBox" name="addNo">
|
||||
<property name="text">
|
||||
<string>Add No Action</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QLineEdit" name="secondLine"/>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Expiration time (secs)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLineEdit" name="firstLine"/>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QSpinBox" name="spinBox">
|
||||
<property name="maximum">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>2</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="imagePath">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="imagePathSelector">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="2">
|
||||
<widget class="QComboBox" name="audioMode"/>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Audio Mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
1183
deps/WinToast/src/wintoastlib.cpp
vendored
Normal file
234
deps/WinToast/src/wintoastlib.h
vendored
Normal file
@ -0,0 +1,234 @@
|
||||
/* * Copyright (C) 2016-2019 Mohammed Boujemaoui <mohabouje@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef WINTOASTLIB_H
|
||||
#define WINTOASTLIB_H
|
||||
#include <Windows.h>
|
||||
#include <sdkddkver.h>
|
||||
#include <WinUser.h>
|
||||
#include <ShObjIdl.h>
|
||||
#include <wrl/implements.h>
|
||||
#include <wrl/event.h>
|
||||
#include <windows.ui.notifications.h>
|
||||
#include <strsafe.h>
|
||||
#include <Psapi.h>
|
||||
#include <ShlObj.h>
|
||||
#include <roapi.h>
|
||||
#include <propvarutil.h>
|
||||
#include <functiondiscoverykeys.h>
|
||||
#include <iostream>
|
||||
#include <winstring.h>
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
using namespace Microsoft::WRL;
|
||||
using namespace ABI::Windows::Data::Xml::Dom;
|
||||
using namespace ABI::Windows::Foundation;
|
||||
using namespace ABI::Windows::UI::Notifications;
|
||||
using namespace Windows::Foundation;
|
||||
|
||||
|
||||
namespace WinToastLib {
|
||||
|
||||
class IWinToastHandler {
|
||||
public:
|
||||
enum WinToastDismissalReason {
|
||||
UserCanceled = ToastDismissalReason::ToastDismissalReason_UserCanceled,
|
||||
ApplicationHidden = ToastDismissalReason::ToastDismissalReason_ApplicationHidden,
|
||||
TimedOut = ToastDismissalReason::ToastDismissalReason_TimedOut
|
||||
};
|
||||
virtual ~IWinToastHandler() = default;
|
||||
virtual void toastActivated() const = 0;
|
||||
virtual void toastActivated(int actionIndex) const = 0;
|
||||
virtual void toastDismissed(WinToastDismissalReason state) const = 0;
|
||||
virtual void toastFailed() const = 0;
|
||||
};
|
||||
|
||||
class WinToastTemplate {
|
||||
public:
|
||||
enum class Scenario { Default, Alarm, IncomingCall, Reminder };
|
||||
enum Duration { System, Short, Long };
|
||||
enum AudioOption { Default = 0, Silent, Loop };
|
||||
enum TextField { FirstLine = 0, SecondLine, ThirdLine };
|
||||
enum WinToastTemplateType {
|
||||
ImageAndText01 = ToastTemplateType::ToastTemplateType_ToastImageAndText01,
|
||||
ImageAndText02 = ToastTemplateType::ToastTemplateType_ToastImageAndText02,
|
||||
ImageAndText03 = ToastTemplateType::ToastTemplateType_ToastImageAndText03,
|
||||
ImageAndText04 = ToastTemplateType::ToastTemplateType_ToastImageAndText04,
|
||||
Text01 = ToastTemplateType::ToastTemplateType_ToastText01,
|
||||
Text02 = ToastTemplateType::ToastTemplateType_ToastText02,
|
||||
Text03 = ToastTemplateType::ToastTemplateType_ToastText03,
|
||||
Text04 = ToastTemplateType::ToastTemplateType_ToastText04,
|
||||
};
|
||||
|
||||
enum AudioSystemFile {
|
||||
DefaultSound,
|
||||
IM,
|
||||
Mail,
|
||||
Reminder,
|
||||
SMS,
|
||||
Alarm,
|
||||
Alarm2,
|
||||
Alarm3,
|
||||
Alarm4,
|
||||
Alarm5,
|
||||
Alarm6,
|
||||
Alarm7,
|
||||
Alarm8,
|
||||
Alarm9,
|
||||
Alarm10,
|
||||
Call,
|
||||
Call1,
|
||||
Call2,
|
||||
Call3,
|
||||
Call4,
|
||||
Call5,
|
||||
Call6,
|
||||
Call7,
|
||||
Call8,
|
||||
Call9,
|
||||
Call10,
|
||||
};
|
||||
|
||||
|
||||
WinToastTemplate(_In_ WinToastTemplateType type = WinToastTemplateType::ImageAndText02);
|
||||
~WinToastTemplate();
|
||||
|
||||
void setFirstLine(_In_ const std::wstring& text);
|
||||
void setSecondLine(_In_ const std::wstring& text);
|
||||
void setThirdLine(_In_ const std::wstring& text);
|
||||
void setTextField(_In_ const std::wstring& txt, _In_ TextField pos);
|
||||
void setAttributionText(_In_ const std::wstring& attributionText);
|
||||
void setImagePath(_In_ const std::wstring& imgPath);
|
||||
void setAudioPath(_In_ WinToastTemplate::AudioSystemFile audio);
|
||||
void setAudioPath(_In_ const std::wstring& audioPath);
|
||||
void setAudioOption(_In_ WinToastTemplate::AudioOption audioOption);
|
||||
void setDuration(_In_ Duration duration);
|
||||
void setExpiration(_In_ INT64 millisecondsFromNow);
|
||||
void setScenario(_In_ Scenario scenario);
|
||||
void addAction(_In_ const std::wstring& label);
|
||||
|
||||
std::size_t textFieldsCount() const;
|
||||
std::size_t actionsCount() const;
|
||||
bool hasImage() const;
|
||||
const std::vector<std::wstring>& textFields() const;
|
||||
const std::wstring& textField(_In_ TextField pos) const;
|
||||
const std::wstring& actionLabel(_In_ std::size_t pos) const;
|
||||
const std::wstring& imagePath() const;
|
||||
const std::wstring& audioPath() const;
|
||||
const std::wstring& attributionText() const;
|
||||
const std::wstring& scenario() const;
|
||||
INT64 expiration() const;
|
||||
WinToastTemplateType type() const;
|
||||
WinToastTemplate::AudioOption audioOption() const;
|
||||
Duration duration() const;
|
||||
private:
|
||||
std::vector<std::wstring> _textFields{};
|
||||
std::vector<std::wstring> _actions{};
|
||||
std::wstring _imagePath{};
|
||||
std::wstring _audioPath{};
|
||||
std::wstring _attributionText{};
|
||||
std::wstring _scenario{L"Default"};
|
||||
INT64 _expiration{0};
|
||||
AudioOption _audioOption{WinToastTemplate::AudioOption::Default};
|
||||
WinToastTemplateType _type{WinToastTemplateType::Text01};
|
||||
Duration _duration{Duration::System};
|
||||
};
|
||||
|
||||
class WinToast {
|
||||
public:
|
||||
enum WinToastError {
|
||||
NoError = 0,
|
||||
NotInitialized,
|
||||
SystemNotSupported,
|
||||
ShellLinkNotCreated,
|
||||
InvalidAppUserModelID,
|
||||
InvalidParameters,
|
||||
InvalidHandler,
|
||||
NotDisplayed,
|
||||
UnknownError
|
||||
};
|
||||
|
||||
enum ShortcutResult {
|
||||
SHORTCUT_UNCHANGED = 0,
|
||||
SHORTCUT_WAS_CHANGED = 1,
|
||||
SHORTCUT_WAS_CREATED = 2,
|
||||
|
||||
SHORTCUT_MISSING_PARAMETERS = -1,
|
||||
SHORTCUT_INCOMPATIBLE_OS = -2,
|
||||
SHORTCUT_COM_INIT_FAILURE = -3,
|
||||
SHORTCUT_CREATE_FAILED = -4
|
||||
};
|
||||
|
||||
enum ShortcutPolicy {
|
||||
/* Don't check, create, or modify a shortcut. */
|
||||
SHORTCUT_POLICY_IGNORE = 0,
|
||||
/* Require a shortcut with matching AUMI, don't create or modify an existing one. */
|
||||
SHORTCUT_POLICY_REQUIRE_NO_CREATE = 1,
|
||||
/* Require a shortcut with matching AUMI, create if missing, modify if not matching.
|
||||
* This is the default. */
|
||||
SHORTCUT_POLICY_REQUIRE_CREATE = 2,
|
||||
};
|
||||
|
||||
WinToast(void);
|
||||
virtual ~WinToast();
|
||||
static WinToast* instance();
|
||||
static bool isCompatible();
|
||||
static bool isSupportingModernFeatures();
|
||||
static std::wstring configureAUMI(_In_ const std::wstring& companyName,
|
||||
_In_ const std::wstring& productName,
|
||||
_In_ const std::wstring& subProduct = std::wstring(),
|
||||
_In_ const std::wstring& versionInformation = std::wstring());
|
||||
static const std::wstring& strerror(_In_ WinToastError error);
|
||||
virtual bool initialize(_Out_opt_ WinToastError* error = nullptr);
|
||||
virtual bool isInitialized() const;
|
||||
virtual bool hideToast(_In_ INT64 id);
|
||||
virtual INT64 showToast(_In_ const WinToastTemplate& toast, _In_ IWinToastHandler* handler, _Out_opt_ WinToastError* error = nullptr);
|
||||
virtual void clear();
|
||||
virtual enum ShortcutResult createShortcut();
|
||||
|
||||
const std::wstring& appName() const;
|
||||
const std::wstring& appUserModelId() const;
|
||||
void setAppUserModelId(_In_ const std::wstring& aumi);
|
||||
void setAppName(_In_ const std::wstring& appName);
|
||||
void setShortcutPolicy(_In_ ShortcutPolicy policy);
|
||||
|
||||
protected:
|
||||
bool _isInitialized{false};
|
||||
bool _hasCoInitialized{false};
|
||||
ShortcutPolicy _shortcutPolicy{SHORTCUT_POLICY_REQUIRE_CREATE};
|
||||
std::wstring _appName{};
|
||||
std::wstring _aumi{};
|
||||
std::map<INT64, ComPtr<IToastNotification>> _buffer{};
|
||||
|
||||
HRESULT validateShellLinkHelper(_Out_ bool& wasChanged);
|
||||
HRESULT createShellLinkHelper();
|
||||
HRESULT setImageFieldHelper(_In_ IXmlDocument *xml, _In_ const std::wstring& path);
|
||||
HRESULT setAudioFieldHelper(_In_ IXmlDocument *xml, _In_ const std::wstring& path, _In_opt_ WinToastTemplate::AudioOption option = WinToastTemplate::AudioOption::Default);
|
||||
HRESULT setTextFieldHelper(_In_ IXmlDocument *xml, _In_ const std::wstring& text, _In_ UINT32 pos);
|
||||
HRESULT setAttributionTextFieldHelper(_In_ IXmlDocument *xml, _In_ const std::wstring& text);
|
||||
HRESULT addActionHelper(_In_ IXmlDocument *xml, _In_ const std::wstring& action, _In_ const std::wstring& arguments);
|
||||
HRESULT addDurationHelper(_In_ IXmlDocument *xml, _In_ const std::wstring& duration);
|
||||
HRESULT addScenarioHelper(_In_ IXmlDocument *xml, _In_ const std::wstring& scenario);
|
||||
ComPtr<IToastNotifier> notifier(_In_ bool* succeded) const;
|
||||
void setError(_Out_opt_ WinToastError* error, _In_ WinToastError value);
|
||||
};
|
||||
}
|
||||
#endif // WINTOASTLIB_H
|
1
deps/asmjit
vendored
@ -1 +0,0 @@
|
||||
Subproject commit a63d41e80ba72f652c450d3bd6614327cde8531c
|
10
deps/asmjit/.editorconfig
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
# Editor configuration, see https://editorconfig.org for more details.
|
||||
root = true
|
||||
|
||||
[*.{cpp,h,natvis}]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
1
deps/asmjit/.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1 @@
|
||||
github: kobalicek
|
42
deps/asmjit/.github/ISSUE_TEMPLATE/01_bug_report.yml
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
name: Bug Report
|
||||
description: File a bug report
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Before you hit the submit button:
|
||||
* Please see our [Contribution Guidelines](https://github.com/asmjit/asmjit/blob/master/CONTRIBUTING.md).
|
||||
* Make sure that you use a recent AsmJit (master branch) before filing a bug report.
|
||||
* Make sure that you use logging and error handling features to collect as much information as possible, if applicable.
|
||||
- type: textarea
|
||||
id: issue-description
|
||||
attributes:
|
||||
label: Issue Description
|
||||
description: Please share a clear and concise description of the issue and optionally provide reproducibility information and output from AsmJit's logger.
|
||||
placeholder: Description
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: operating-system
|
||||
attributes:
|
||||
label: Operating System
|
||||
multiple: true
|
||||
options:
|
||||
- Not specified / possibly all
|
||||
- Windows
|
||||
- Linux
|
||||
- Mac
|
||||
- Android
|
||||
- Other
|
||||
- type: dropdown
|
||||
id: target-architecture
|
||||
attributes:
|
||||
label: Architecture
|
||||
multiple: true
|
||||
options:
|
||||
- Not specified
|
||||
- X86 / X86_64
|
||||
- AArch32
|
||||
- AArch64
|
||||
- RISC-V
|
||||
- Other
|
18
deps/asmjit/.github/ISSUE_TEMPLATE/02_feature_request.yml
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
name: Feature Request
|
||||
description: Request a new feature or enhancement
|
||||
labels: [enhancement]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Before you hit the submit button:
|
||||
* Please see our [Contribution Guidelines](https://github.com/asmjit/asmjit/blob/master/CONTRIBUTING.md).
|
||||
* Make sure that you use a recent AsmJit (master branch) before filing a feature request.
|
||||
- type: textarea
|
||||
id: issue-description
|
||||
attributes:
|
||||
label: Issue Description
|
||||
description: Please share a clear and concise description of a new feature or enhancement.
|
||||
placeholder: Description
|
||||
validations:
|
||||
required: true
|
18
deps/asmjit/.github/ISSUE_TEMPLATE/03_help_question.yml
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
name: Help & Questions
|
||||
description: Ask a question or get help
|
||||
labels: [question]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Before you hit the submit button:
|
||||
* Please see our [Contribution Guidelines](https://github.com/asmjit/asmjit/blob/master/CONTRIBUTING.md).
|
||||
* [Gitter Chat](https://app.gitter.im/#/room/#asmjit:gitter.im) is usually faster to get answers.
|
||||
* If you need a help, please include as much information as possible to make it clear what the intend is.
|
||||
- type: textarea
|
||||
id: issue-description
|
||||
attributes:
|
||||
label: Details
|
||||
description: The description of the problem or question.
|
||||
validations:
|
||||
required: true
|
11
deps/asmjit/.github/ISSUE_TEMPLATE/99_other_issues.yml
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
name: Other Issues
|
||||
description: Something that doesn't fit the other categories
|
||||
body:
|
||||
- type: textarea
|
||||
id: issue-description
|
||||
attributes:
|
||||
label: Issue Description
|
||||
description: Please share a clear and concise description of the issue.
|
||||
placeholder: Description
|
||||
validations:
|
||||
required: true
|
25
deps/asmjit/.github/workflows/build-config.json
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"diagnostics": {
|
||||
"asan": { "definitions": ["ASMJIT_SANITIZE=address"] },
|
||||
"ubsan": { "definitions": ["ASMJIT_SANITIZE=undefined"] },
|
||||
"msan": { "definitions": ["ASMJIT_SANITIZE=memory"] }
|
||||
},
|
||||
|
||||
"valgrind_arguments": [
|
||||
"--leak-check=full",
|
||||
"--show-reachable=yes",
|
||||
"--track-origins=yes"
|
||||
],
|
||||
|
||||
"tests": [
|
||||
{ "optional": true, "cmd": ["asmjit_test_unit", "--quick"] },
|
||||
{ "optional": true, "cmd": ["asmjit_test_assembler"] },
|
||||
{ "optional": true, "cmd": ["asmjit_test_assembler", "--validate"] },
|
||||
{ "optional": true, "cmd": ["asmjit_test_emitters"] },
|
||||
{ "optional": true, "cmd": ["asmjit_test_execute"] },
|
||||
{ "optional": true, "cmd": ["asmjit_test_compiler"] },
|
||||
{ "optional": true, "cmd": ["asmjit_test_instinfo"] },
|
||||
{ "optional": true, "cmd": ["asmjit_test_x86_sections"] },
|
||||
{ "optional": true, "cmd": ["asmjit_test_perf", "--quick"] }
|
||||
]
|
||||
}
|
227
deps/asmjit/.github/workflows/build.yml
vendored
Normal file
@ -0,0 +1,227 @@
|
||||
name: "Build"
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
source-check:
|
||||
name: "source check"
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: "Setup node.js"
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "*"
|
||||
|
||||
- name: "Check Enumerations"
|
||||
run: |
|
||||
cd tools
|
||||
node enumgen.js --verify
|
||||
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- { title: "linux-lib" , host: "ubuntu-latest" , arch: "x64" , cc: "clang" , conf: "Debug" }
|
||||
- { title: "macos-lib" , host: "macos-latest" , arch: "x64" , cc: "clang" , conf: "Debug" }
|
||||
- { title: "windows-lib" , host: "windows-latest", arch: "x64" , cc: "vs2022" , conf: "Debug" }
|
||||
|
||||
- { title: "diag-analyze" , host: "ubuntu-latest" , arch: "x64" , cc: "clang-17", conf: "Debug" , diagnostics: "analyze-build" }
|
||||
- { title: "diag-asan" , host: "ubuntu-latest" , arch: "x64" , cc: "clang-17", conf: "Release", diagnostics: "asan", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "diag-msan" , host: "ubuntu-latest" , arch: "x64" , cc: "clang-17", conf: "Release", diagnostics: "msan", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "diag-ubsan" , host: "ubuntu-latest" , arch: "x64" , cc: "clang-17", conf: "Release", diagnostics: "ubsan", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "diag-valgrind" , host: "ubuntu-latest" , arch: "x64" , cc: "clang-17", conf: "Release", diagnostics: "valgrind", defs: "ASMJIT_TEST=1" }
|
||||
|
||||
- { title: "no-deprecated" , host: "ubuntu-latest" , arch: "x64" , cc: "clang-17", conf: "Release", defs: "ASMJIT_TEST=1,ASMJIT_NO_DEPRECATED=1" }
|
||||
- { title: "no-intrinsics" , host: "ubuntu-latest" , arch: "x64" , cc: "clang-17", conf: "Release", defs: "ASMJIT_TEST=1,ASMJIT_NO_INTRINSICS=1" }
|
||||
- { title: "no-logging" , host: "ubuntu-latest" , arch: "x64" , cc: "clang-17", conf: "Release", defs: "ASMJIT_TEST=1,ASMJIT_NO_LOGGING=1" }
|
||||
- { title: "no-logging-text" , host: "ubuntu-latest" , arch: "x64" , cc: "clang-17", conf: "Release", defs: "ASMJIT_TEST=1,ASMJIT_NO_LOGGING=1,ASMJIT_NO_TEXT=1" }
|
||||
- { title: "no-builder" , host: "ubuntu-latest" , arch: "x64" , cc: "clang-17", conf: "Release", defs: "ASMJIT_TEST=1,ASMJIT_NO_BUILDER=1" }
|
||||
- { title: "no-compiler" , host: "ubuntu-latest" , arch: "x64" , cc: "clang-17", conf: "Release", defs: "ASMJIT_TEST=1,ASMJIT_NO_COMPILER=1" }
|
||||
- { title: "no-introspection", host: "ubuntu-latest" , arch: "x64" , cc: "clang-17", conf: "Release", defs: "ASMJIT_TEST=1,ASMJIT_NO_COMPILER=1,ASMJIT_NO_INTROSPECTION=1" }
|
||||
- { title: "no-jit" , host: "ubuntu-latest" , arch: "x64" , cc: "clang-17", conf: "Release", defs: "ASMJIT_TEST=1,ASMJIT_NO_JIT=1" }
|
||||
- { title: "no-validation" , host: "ubuntu-latest" , arch: "x64" , cc: "clang-17", conf: "Release", defs: "ASMJIT_TEST=1,ASMJIT_NO_VALIDATION=1" }
|
||||
- { title: "no-x86" , host: "ubuntu-latest" , arch: "x64" , cc: "clang-17", conf: "Release", defs: "ASMJIT_TEST=1,ASMJIT_NO_X86=1" }
|
||||
- { title: "no-aarch64" , host: "ubuntu-latest" , arch: "x64" , cc: "clang-17", conf: "Release", defs: "ASMJIT_TEST=1,ASMJIT_NO_AARCH64=1" }
|
||||
|
||||
- { title: "linux" , host: "ubuntu-20.04" , arch: "x86" , cc: "gcc-7" , conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-20.04" , arch: "x86" , cc: "gcc-7" , conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-20.04" , arch: "x64" , cc: "gcc-7" , conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-20.04" , arch: "x64" , cc: "gcc-7" , conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-20.04" , arch: "x86" , cc: "gcc-8" , conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-20.04" , arch: "x86" , cc: "gcc-8" , conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-20.04" , arch: "x64" , cc: "gcc-8" , conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-20.04" , arch: "x64" , cc: "gcc-8" , conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x86" , cc: "gcc-9" , conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x86" , cc: "gcc-9" , conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x64" , cc: "gcc-9" , conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x64" , cc: "gcc-9" , conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x86" , cc: "gcc-10" , conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x86" , cc: "gcc-10" , conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x64" , cc: "gcc-10" , conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x64" , cc: "gcc-10" , conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x86" , cc: "gcc-11" , conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x86" , cc: "gcc-11" , conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x64" , cc: "gcc-11" , conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x64" , cc: "gcc-11" , conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x86" , cc: "gcc-12" , conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x86" , cc: "gcc-12" , conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x64" , cc: "gcc-12" , conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x64" , cc: "gcc-12" , conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x86" , cc: "gcc-13" , conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x86" , cc: "gcc-13" , conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x64" , cc: "gcc-13" , conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x64" , cc: "gcc-13" , conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-20.04" , arch: "x86" , cc: "clang-10", conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-20.04" , arch: "x86" , cc: "clang-10", conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-20.04" , arch: "x64" , cc: "clang-10", conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-20.04" , arch: "x64" , cc: "clang-10", conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x86" , cc: "clang-11", conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x86" , cc: "clang-11", conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x64" , cc: "clang-11", conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x64" , cc: "clang-11", conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x86" , cc: "clang-12", conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x86" , cc: "clang-12", conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x64" , cc: "clang-12", conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x64" , cc: "clang-12", conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x86" , cc: "clang-13", conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x86" , cc: "clang-13", conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x64" , cc: "clang-13", conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x64" , cc: "clang-13", conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x86" , cc: "clang-14", conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x86" , cc: "clang-14", conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x64" , cc: "clang-14", conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x64" , cc: "clang-14", conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x86" , cc: "clang-15", conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x86" , cc: "clang-15", conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x64" , cc: "clang-15", conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x64" , cc: "clang-15", conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x86" , cc: "clang-16", conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x86" , cc: "clang-16", conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x64" , cc: "clang-16", conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x64" , cc: "clang-16", conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x86" , cc: "clang-17", conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x86" , cc: "clang-17", conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x64" , cc: "clang-17", conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x64" , cc: "clang-17", conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "macos" , host: "macos-12" , arch: "x64" , cc: "gcc-11" , conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||
- { title: "macos" , host: "macos-12" , arch: "x64" , cc: "gcc-11" , conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "macos" , host: "macos-12" , arch: "x64" , cc: "clang" , conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||
- { title: "macos" , host: "macos-12" , arch: "x64" , cc: "clang" , conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "windows" , host: "windows-2019" , arch: "x86" , cc: "vs2019" , conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||
- { title: "windows" , host: "windows-2019" , arch: "x86" , cc: "vs2019" , conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "windows" , host: "windows-2019" , arch: "x64" , cc: "vs2019" , conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||
- { title: "windows" , host: "windows-2019" , arch: "x64" , cc: "vs2019" , conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "windows" , host: "windows-2022" , arch: "x86" , cc: "vs2022" , conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||
- { title: "windows" , host: "windows-2022" , arch: "x86" , cc: "vs2022" , conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "windows" , host: "windows-2022" , arch: "x64" , cc: "vs2022" , conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||
- { title: "windows" , host: "windows-2022" , arch: "x64" , cc: "vs2022" , conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||
|
||||
- { title: "freebsd" , host: "macos-12" , arch: "x86-64" , cc: "clang" , conf: "Release", vm: "freebsd", vm_ver: "13.2", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "netbsd" , host: "macos-12" , arch: "x86-64" , cc: "clang" , conf: "Release", vm: "netbsd" , vm_ver: "9.3" , defs: "ASMJIT_TEST=1" }
|
||||
- { title: "openbsd" , host: "macos-12" , arch: "x86-64" , cc: "clang" , conf: "Release", vm: "openbsd", vm_ver: "7.4" , defs: "ASMJIT_TEST=1" }
|
||||
- { title: "openbsd" , host: "ubuntu-latest" , arch: "arm64" , cc: "clang" , conf: "Release", vm: "openbsd", vm_ver: "7.4" , defs: "ASMJIT_TEST=1" }
|
||||
|
||||
- { title: "debian" , host: "ubuntu-latest" , arch: "arm/v7" , cc: "clang" , conf: "Release", vm: "debian:unstable", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "debian" , host: "ubuntu-latest" , arch: "arm64" , cc: "clang" , conf: "Release", vm: "debian:unstable", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "debian" , host: "ubuntu-latest" , arch: "riscv64", cc: "clang" , conf: "Release", vm: "debian:unstable", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "debian" , host: "ubuntu-latest" , arch: "ppc64le", cc: "clang" , conf: "Release", vm: "debian:unstable", defs: "ASMJIT_TEST=1" }
|
||||
|
||||
name: "${{matrix.title}}/${{matrix.arch}}, ${{matrix.cc}} ${{matrix.conf}}"
|
||||
runs-on: "${{matrix.host}}"
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: "source"
|
||||
|
||||
- name: "Checkout Build Actions"
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: build-actions/build-actions
|
||||
path: "build-actions"
|
||||
|
||||
- name: "Python"
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.x"
|
||||
|
||||
- name: QEMU
|
||||
if: ${{matrix.vm && !matrix.vm_ver}}
|
||||
uses: docker/setup-qemu-action@v3
|
||||
with:
|
||||
platforms: linux/${{matrix.arch}}
|
||||
|
||||
- name: "Build & Test - Native"
|
||||
if: ${{!matrix.vm}}
|
||||
run: python build-actions/action.py
|
||||
--step=all
|
||||
--source-dir=source
|
||||
--config=source/.github/workflows/build-config.json
|
||||
--compiler=${{matrix.cc}}
|
||||
--diagnostics=${{matrix.diagnostics}}
|
||||
--architecture=${{matrix.arch}}
|
||||
--problem-matcher=auto
|
||||
--build-type=${{matrix.conf}}
|
||||
--build-defs=${{matrix.defs}}
|
||||
|
||||
- name: "Build & Test - Cross Platform Actions"
|
||||
if: ${{matrix.vm && matrix.vm_ver}}
|
||||
uses: cross-platform-actions/action@master
|
||||
with:
|
||||
operating_system: ${{matrix.vm}}
|
||||
architecture: ${{matrix.arch}}
|
||||
version: ${{matrix.vm_ver}}
|
||||
sync_files: "runner-to-vm"
|
||||
shutdown_vm: false
|
||||
shell: bash
|
||||
run: |
|
||||
set -e
|
||||
|
||||
PATH="/usr/sbin:/usr/pkg/sbin:/usr/pkg/bin:$PATH:$(pwd)/build-actions"
|
||||
CI_NETBSD_USE_PKGIN=1
|
||||
|
||||
export PATH
|
||||
export CI_NETBSD_USE_PKGIN
|
||||
|
||||
sh ./build-actions/prepare-environment.sh
|
||||
python3 build-actions/action.py \
|
||||
--step=all \
|
||||
--source-dir=source \
|
||||
--config=source/.github/workflows/build-config.json \
|
||||
--compiler=${{matrix.cc}} \
|
||||
--diagnostics=${{matrix.diagnostics}} \
|
||||
--architecture=${{matrix.arch}} \
|
||||
--problem-matcher=auto \
|
||||
--build-type=${{matrix.conf}} \
|
||||
--build-defs=${{matrix.defs}}
|
||||
|
||||
- name: "Build & Test - Docker + QEMU"
|
||||
if: ${{matrix.vm && !matrix.vm_ver}}
|
||||
run: |
|
||||
docker run \
|
||||
--rm \
|
||||
-v $(pwd):/${{github.workspace}} \
|
||||
-w ${{github.workspace}}/build-actions \
|
||||
--platform linux/${{matrix.arch}} \
|
||||
${{matrix.vm}} \
|
||||
bash action.sh \
|
||||
--step=all \
|
||||
--source-dir=../source \
|
||||
--config=../source/.github/workflows/build-config.json \
|
||||
--compiler=${{matrix.cc}} \
|
||||
--diagnostics=${{matrix.diagnostics}} \
|
||||
--architecture=${{matrix.arch}} \
|
||||
--problem-matcher=auto \
|
||||
--build-type=${{matrix.conf}} \
|
||||
--build-defs=${{matrix.defs}}
|
3
deps/asmjit/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/build
|
||||
/build_*
|
||||
.vscode
|
728
deps/asmjit/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,728 @@
|
||||
cmake_minimum_required(VERSION 3.8 FATAL_ERROR)
|
||||
|
||||
cmake_policy(PUSH)
|
||||
|
||||
if (POLICY CMP0063)
|
||||
cmake_policy(SET CMP0063 NEW) # Honor visibility properties.
|
||||
endif()
|
||||
|
||||
if (POLICY CMP0092)
|
||||
cmake_policy(SET CMP0092 NEW) # Don't add -W3 warning level by default.
|
||||
endif()
|
||||
|
||||
# Don't create a project if it was already created by another CMakeLists.txt.
|
||||
# This allows one library to embed another library without making a collision.
|
||||
if (NOT CMAKE_PROJECT_NAME OR "${CMAKE_PROJECT_NAME}" STREQUAL "asmjit")
|
||||
project(asmjit CXX)
|
||||
endif()
|
||||
|
||||
include(CheckCXXCompilerFlag)
|
||||
INCLUDE(CheckCXXSourceCompiles)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
# AsmJit - Deprecated
|
||||
# ===================
|
||||
|
||||
if (DEFINED ASMJIT_BUILD_EMBED)
|
||||
message(DEPRECATION "ASMJIT_BUILD_EMBED is deprecated, use ASMJIT_EMBED")
|
||||
set(ASMJIT_EMBED "${ASMJIT_BUILD_EMBED}")
|
||||
endif()
|
||||
|
||||
if (DEFINED ASMJIT_BUILD_STATIC)
|
||||
message(DEPRECATION "ASMJIT_BUILD_STATIC is deprecated, use ASMJIT_STATIC")
|
||||
set(ASMJIT_STATIC "${ASMJIT_BUILD_STATIC}")
|
||||
endif()
|
||||
|
||||
# AsmJit - Configuration - Build
|
||||
# ==============================
|
||||
|
||||
if (NOT DEFINED ASMJIT_TEST)
|
||||
set(ASMJIT_TEST FALSE)
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED ASMJIT_EMBED)
|
||||
set(ASMJIT_EMBED FALSE)
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED ASMJIT_STATIC)
|
||||
set(ASMJIT_STATIC ${ASMJIT_EMBED})
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED ASMJIT_SANITIZE)
|
||||
set(ASMJIT_SANITIZE FALSE)
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED ASMJIT_NO_CUSTOM_FLAGS)
|
||||
set(ASMJIT_NO_CUSTOM_FLAGS FALSE)
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED ASMJIT_NO_NATVIS)
|
||||
set(ASMJIT_NO_NATVIS FALSE)
|
||||
endif()
|
||||
|
||||
# EMBED implies STATIC.
|
||||
if (ASMJIT_EMBED AND NOT ASMJIT_STATIC)
|
||||
set(ASMJIT_STATIC TRUE)
|
||||
endif()
|
||||
|
||||
# AsmJit - Configuration - Backend
|
||||
# ================================
|
||||
|
||||
if (NOT DEFINED ASMJIT_NO_X86)
|
||||
set(ASMJIT_NO_X86 FALSE)
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED ASMJIT_NO_AARCH64)
|
||||
set(ASMJIT_NO_AARCH64 FALSE)
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED ASMJIT_NO_FOREIGN)
|
||||
set(ASMJIT_NO_FOREIGN FALSE)
|
||||
endif()
|
||||
|
||||
# AsmJit - Configuration - Features
|
||||
# =================================
|
||||
|
||||
if (NOT DEFINED ASMJIT_NO_DEPRECATED)
|
||||
set(ASMJIT_NO_DEPRECATED FALSE)
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED ASMJIT_NO_SHM_OPEN)
|
||||
set(ASMJIT_NO_SHM_OPEN FALSE)
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED ASMJIT_NO_JIT)
|
||||
set(ASMJIT_NO_JIT FALSE)
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED ASMJIT_NO_TEXT)
|
||||
set(ASMJIT_NO_TEXT FALSE)
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED ASMJIT_NO_LOGGING)
|
||||
set(ASMJIT_NO_LOGGING ${ASMJIT_NO_TEXT})
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED ASMJIT_NO_VALIDATION)
|
||||
set(ASMJIT_NO_VALIDATION FALSE)
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED ASMJIT_NO_INTROSPECTION)
|
||||
set(ASMJIT_NO_INTROSPECTION FALSE)
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED ASMJIT_NO_BUILDER)
|
||||
set(ASMJIT_NO_BUILDER FALSE)
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED ASMJIT_NO_COMPILER)
|
||||
if (ASMJIT_NO_BUILDER OR ASMJIT_NO_INTROSPECTION)
|
||||
set(ASMJIT_NO_COMPILER TRUE)
|
||||
else()
|
||||
set(ASMJIT_NO_COMPILER FALSE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# AsmJit - Configuration - CMake Introspection
|
||||
# ============================================
|
||||
|
||||
set(ASMJIT_DIR "${CMAKE_CURRENT_LIST_DIR}" CACHE PATH "Location of 'asmjit'")
|
||||
set(ASMJIT_TEST "${ASMJIT_TEST}" CACHE BOOL "Build 'asmjit' test applications")
|
||||
set(ASMJIT_EMBED "${ASMJIT_EMBED}" CACHE BOOL "Embed 'asmjit' library (no targets)")
|
||||
set(ASMJIT_STATIC "${ASMJIT_STATIC}" CACHE BOOL "Build 'asmjit' library as static")
|
||||
set(ASMJIT_SANITIZE "${ASMJIT_SANITIZE}" CACHE STRING "Build with sanitizers: 'address', 'undefined', etc...")
|
||||
set(ASMJIT_NO_NATVIS "${ASMJIT_NO_NATVIS}" CACHE BOOL "Disable natvis support (embedding asmjit.natvis in PDB)")
|
||||
set(ASMJIT_NO_CUSTOM_FLAGS "${ASMJIT_NO_CUSTOM_FLAGS}" CACHE BOOL "Disable extra compilation flags added by AsmJit to its targets")
|
||||
|
||||
set(ASMJIT_NO_X86 "${ASMJIT_NO_X86}" CACHE BOOL "Disable X86/X64 backend")
|
||||
set(ASMJIT_NO_AARCH64 "${ASMJIT_NO_AARCH64}" CACHE BOOL "Disable AArch64 backend")
|
||||
set(ASMJIT_NO_FOREIGN "${ASMJIT_NO_FOREIGN}" CACHE BOOL "Disable all foreign architectures (enables only a target architecture)")
|
||||
|
||||
set(ASMJIT_NO_DEPRECATED "${ASMJIT_NO_DEPRECATED}" CACHE BOOL "Disable deprecated API at build time")
|
||||
set(ASMJIT_NO_SHM_OPEN "${ASMJIT_NO_SHM_OPEN}" CACHE BOOL "Disable the use of shm_open() even on platforms where it's supported")
|
||||
set(ASMJIT_NO_JIT "${ASMJIT_NO_JIT}" CACHE BOOL "Disable VirtMem, JitAllocator, and JitRuntime at build time")
|
||||
set(ASMJIT_NO_TEXT "${ASMJIT_NO_TEXT}" CACHE BOOL "Disable textual representation of instructions, enums, cpu features, ...")
|
||||
set(ASMJIT_NO_LOGGING "${ASMJIT_NO_LOGGING}" CACHE BOOL "Disable logging features at build time")
|
||||
set(ASMJIT_NO_VALIDATION "${ASMJIT_NO_VALIDATION}" CACHE BOOL "Disable instruction validation API at build time")
|
||||
set(ASMJIT_NO_INTROSPECTION "${ASMJIT_NO_INTROSPECTION}" CACHE BOOL "Disable instruction introspection API at build time")
|
||||
set(ASMJIT_NO_BUILDER "${ASMJIT_NO_BUILDER}" CACHE BOOL "Disable Builder emitter at build time")
|
||||
set(ASMJIT_NO_COMPILER "${ASMJIT_NO_COMPILER}" CACHE BOOL "Disable Compiler emitter at build time")
|
||||
|
||||
# AsmJit - Project
|
||||
# ================
|
||||
|
||||
set(ASMJIT_INCLUDE_DIRS "${ASMJIT_DIR}/src") # Include directory is the same as source dir.
|
||||
set(ASMJIT_DEPS "") # AsmJit dependencies (libraries) for the linker.
|
||||
set(ASMJIT_LIBS "") # Dependencies of libs/apps that want to use AsmJit.
|
||||
set(ASMJIT_CFLAGS "") # Public compiler flags.
|
||||
set(ASMJIT_PRIVATE_CFLAGS "") # Private compiler flags independent of build type.
|
||||
set(ASMJIT_PRIVATE_CFLAGS_DBG "") # Private compiler flags used by debug builds.
|
||||
set(ASMJIT_PRIVATE_CFLAGS_REL "") # Private compiler flags used by release builds.
|
||||
set(ASMJIT_SANITIZE_CFLAGS "") # Compiler flags required by currently enabled sanitizers.
|
||||
set(ASMJIT_SANITIZE_LFLAGS "") # Linker flags required by currently enabled sanitizers.
|
||||
|
||||
# AsmJit - Utilities
|
||||
# ==================
|
||||
|
||||
function(asmjit_detect_cflags out)
|
||||
set(out_array ${${out}})
|
||||
foreach(flag ${ARGN})
|
||||
string(REGEX REPLACE "[+]" "x" flag_signature "${flag}")
|
||||
string(REGEX REPLACE "[-=:;/.\]" "_" flag_signature "${flag_signature}")
|
||||
check_cxx_compiler_flag(${flag} "__CxxFlag_${flag_signature}")
|
||||
if (${__CxxFlag_${flag_signature}})
|
||||
list(APPEND out_array "${flag}")
|
||||
endif()
|
||||
endforeach()
|
||||
set(${out} "${out_array}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Support for various sanitizers provided by C/C++ compilers.
|
||||
function(asmjit_detect_sanitizers out)
|
||||
set(_out_array ${${out}})
|
||||
set(_flags "")
|
||||
|
||||
foreach(_arg ${ARGN})
|
||||
string(REPLACE "," ";" _arg "${_arg}")
|
||||
list(APPEND _flags ${_arg})
|
||||
endforeach()
|
||||
|
||||
foreach(_flag ${_flags})
|
||||
if (NOT "${_flag}" MATCHES "^-fsanitize=")
|
||||
SET(_flag "-fsanitize=${_flag}")
|
||||
endif()
|
||||
|
||||
# Sanitizers also require link flags, see CMAKE_REQUIRED_FLAGS.
|
||||
set(CMAKE_REQUIRED_FLAGS "${_flag}")
|
||||
asmjit_detect_cflags(_out_array ${_flag})
|
||||
unset(CMAKE_REQUIRED_FLAGS)
|
||||
endforeach()
|
||||
|
||||
set(${out} "${_out_array}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(asmjit_add_target target target_type)
|
||||
set(single_val "")
|
||||
set(multi_val SOURCES LIBRARIES CFLAGS CFLAGS_DBG CFLAGS_REL)
|
||||
cmake_parse_arguments("X" "" "${single_val}" "${multi_val}" ${ARGN})
|
||||
|
||||
if ("${target_type}" MATCHES "^(EXECUTABLE|TEST)$")
|
||||
add_executable(${target} ${X_SOURCES})
|
||||
else()
|
||||
add_library(${target} ${target_type} ${X_SOURCES})
|
||||
endif()
|
||||
|
||||
set_target_properties(${target} PROPERTIES DEFINE_SYMBOL "")
|
||||
target_link_libraries(${target} PRIVATE ${X_LIBRARIES})
|
||||
|
||||
# target_link_options was added in cmake v3.13, don't use it for now...
|
||||
foreach(link_flag ${ASMJIT_PRIVATE_LFLAGS})
|
||||
set_property(TARGET ${target} APPEND_STRING PROPERTY LINK_FLAGS " ${link_flag}")
|
||||
endforeach()
|
||||
|
||||
target_compile_features(${target} PUBLIC cxx_std_11)
|
||||
set_property(TARGET ${target} PROPERTY CXX_EXTENSIONS NO)
|
||||
set_property(TARGET ${target} PROPERTY CXX_VISIBILITY_PRESET hidden)
|
||||
target_compile_options(${target} PRIVATE ${X_CFLAGS} ${ASMJIT_SANITIZE_CFLAGS} $<$<CONFIG:Debug>:${X_CFLAGS_DBG}> $<$<NOT:$<CONFIG:Debug>>:${X_CFLAGS_REL}>)
|
||||
|
||||
if ("${target_type}" STREQUAL "TEST")
|
||||
add_test(NAME ${target} COMMAND ${target})
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# AsmJit - Compiler Support
|
||||
# =========================
|
||||
|
||||
set(ASMJIT_INCLUDE_DIRS "${ASMJIT_DIR}/src") # Include directory is the same as source dir.
|
||||
set(ASMJIT_DEPS "") # AsmJit dependencies (libraries) for the linker.
|
||||
set(ASMJIT_LIBS "") # Dependencies of libs/apps that want to use AsmJit.
|
||||
set(ASMJIT_CFLAGS "") # Public compiler flags.
|
||||
set(ASMJIT_PRIVATE_CFLAGS "") # Private compiler flags independent of build type.
|
||||
set(ASMJIT_PRIVATE_CFLAGS_DBG "") # Private compiler flags used by debug builds.
|
||||
set(ASMJIT_PRIVATE_CFLAGS_REL "") # Private compiler flags used by release builds.
|
||||
set(ASMJIT_PRIVATE_LFLAGS "") # Private linker flags.
|
||||
set(ASMJIT_SANITIZE_CFLAGS "") # Compiler flags required by currently enabled sanitizers.
|
||||
set(ASMJIT_SANITIZE_LFLAGS "") # Linker flags required by currently enabled sanitizers.
|
||||
|
||||
# We will have to keep this most likely forever as some users may still be using it.
|
||||
set(ASMJIT_INCLUDE_DIR "${ASMJIT_INCLUDE_DIRS}")
|
||||
|
||||
if (NOT ASMJIT_NO_CUSTOM_FLAGS)
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC" OR "x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
|
||||
list(APPEND ASMJIT_PRIVATE_CFLAGS
|
||||
-MP # [+] Multi-Process Compilation.
|
||||
-GF # [+] Eliminate duplicate strings.
|
||||
-Zc:__cplusplus # [+] Conforming __cplusplus definition.
|
||||
-Zc:inline # [+] Remove unreferenced COMDAT.
|
||||
-Zc:strictStrings # [+] Strict const qualification of string literals.
|
||||
-Zc:threadSafeInit- # [-] Thread-safe statics.
|
||||
-W4) # [+] Warning level 4.
|
||||
|
||||
list(APPEND ASMJIT_PRIVATE_CFLAGS_DBG
|
||||
-GS) # [+] Buffer security-check.
|
||||
|
||||
list(APPEND ASMJIT_PRIVATE_CFLAGS_REL
|
||||
-GS- # [-] Buffer security-check.
|
||||
-O2 # [+] Favor speed over size.
|
||||
-Oi) # [+] Generate intrinsic functions.
|
||||
elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "^(GNU|Clang|AppleClang)$")
|
||||
list(APPEND ASMJIT_PRIVATE_CFLAGS -Wall -Wextra -Wconversion)
|
||||
list(APPEND ASMJIT_PRIVATE_CFLAGS -fno-math-errno)
|
||||
list(APPEND ASMJIT_PRIVATE_CFLAGS_REL -O2)
|
||||
|
||||
# -fno-semantic-interposition is not available on apple - the compiler issues a warning, which is not detected.
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
|
||||
asmjit_detect_cflags(ASMJIT_PRIVATE_CFLAGS -fno-threadsafe-statics)
|
||||
else()
|
||||
asmjit_detect_cflags(ASMJIT_PRIVATE_CFLAGS -fno-threadsafe-statics -fno-semantic-interposition)
|
||||
endif()
|
||||
|
||||
# The following flags can save few bytes in the resulting binary.
|
||||
asmjit_detect_cflags(ASMJIT_PRIVATE_CFLAGS_REL
|
||||
-fmerge-all-constants # Merge all constants even if it violates ISO C++.
|
||||
-fno-enforce-eh-specs) # Don't enforce termination if noexcept function throws.
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Support for sanitizers.
|
||||
if (ASMJIT_SANITIZE)
|
||||
ASMJIT_detect_sanitizers(ASMJIT_SANITIZE_CFLAGS ${ASMJIT_SANITIZE})
|
||||
if (ASMJIT_SANITIZE_CFLAGS)
|
||||
message("-- Enabling sanitizers: '${ASMJIT_SANITIZE_CFLAGS}'")
|
||||
|
||||
# Linker must receive the same flags as the compiler when it comes to sanitizers.
|
||||
set(ASMJIT_SANITIZE_LFLAGS ${ASMJIT_SANITIZE_CFLAGS})
|
||||
|
||||
# Don't omit frame pointer if sanitizers are enabled.
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC" OR "x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
|
||||
list(APPEND ASMJIT_SANITIZE_CFLAGS -Oy-)
|
||||
else()
|
||||
list(APPEND ASMJIT_SANITIZE_CFLAGS -fno-omit-frame-pointer -g)
|
||||
endif()
|
||||
|
||||
list(APPEND ASMJIT_PRIVATE_CFLAGS ${ASMJIT_SANITIZE_CFLAGS})
|
||||
list(APPEND ASMJIT_PRIVATE_LFLAGS ${ASMJIT_SANITIZE_LFLAGS})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
# Dependency: nothing extra at the moment.
|
||||
elseif ("${CMAKE_SYSTEM_NAME}" STREQUAL "Android")
|
||||
# Dependency: libc is the only required library on Android as it also provides libthread.
|
||||
message("-- Dependency: adding libc (Android target detected)")
|
||||
list(APPEND ASMJIT_DEPS c)
|
||||
elseif ("${CMAKE_SYSTEM_NAME}" STREQUAL "Haiku")
|
||||
# Dependency: libroot is used by Haiku instead of libc, so link to libroot and libpthread.
|
||||
message("-- Dependency: adding libroot and libpthread (Haiku target detected)")
|
||||
list(APPEND ASMJIT_DEPS root pthread)
|
||||
else()
|
||||
# Dependency: libc is always required.
|
||||
message("-- Dependency: adding libc (Linux, BSD, or other UNIX/POSIX environment)")
|
||||
list(APPEND ASMJIT_DEPS c)
|
||||
|
||||
# Dependency: pthread (required so AsmJit can use pthread_lock).
|
||||
check_cxx_source_compiles("
|
||||
#include <pthread.h>
|
||||
int main() {
|
||||
pthread_mutex_t m;
|
||||
pthread_mutex_init(&m, nullptr);
|
||||
return pthread_mutex_destroy(&m);
|
||||
}
|
||||
" ASMJIT_LIBC_HAS_LIBPTHREAD)
|
||||
if (ASMJIT_LIBC_HAS_LIBPTHREAD)
|
||||
message("-- Dependency: libpthread provided by libc (not linking to libpthread)")
|
||||
else()
|
||||
message("-- Dependency: libpthread not provided by libc, linking to libpthread")
|
||||
list(APPEND ASMJIT_DEPS pthread)
|
||||
endif()
|
||||
|
||||
# Dependency: shm_open (required so AsmJit can use shm_open on supported platforms).
|
||||
if ("${CMAKE_SYSTEM_NAME}" MATCHES "^(Linux|NetBSD)$" AND NOT ASMJIT_NO_SHM_OPEN)
|
||||
check_cxx_source_compiles("
|
||||
#include <sys/mman.h>
|
||||
int main() {
|
||||
const char file_name[1] {};
|
||||
return shm_open(file_name, 0, 0);
|
||||
}
|
||||
" ASMJIT_LIBC_HAS_LIBRT)
|
||||
if (ASMJIT_LIBC_HAS_LIBRT)
|
||||
message("-- Dependency: shm_open provided by libc (not linking to librt)")
|
||||
else()
|
||||
message("-- Dependency: shm_open not provided by libc, linking to librt")
|
||||
list(APPEND ASMJIT_DEPS rt)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(ASMJIT_LIBS ${ASMJIT_DEPS})
|
||||
if (NOT ASMJIT_EMBED)
|
||||
list(INSERT ASMJIT_LIBS 0 asmjit)
|
||||
endif()
|
||||
|
||||
if (ASMJIT_EMBED)
|
||||
set(ASMJIT_TARGET_TYPE "EMBED")
|
||||
elseif (ASMJIT_STATIC)
|
||||
set(ASMJIT_TARGET_TYPE "STATIC")
|
||||
else()
|
||||
set(ASMJIT_TARGET_TYPE "SHARED")
|
||||
endif()
|
||||
|
||||
foreach(build_option # AsmJit build options.
|
||||
ASMJIT_STATIC
|
||||
ASMJIT_NO_DEPRECATED
|
||||
# AsmJit backends selection.
|
||||
ASMJIT_NO_X86
|
||||
ASMJIT_NO_AARCH64
|
||||
ASMJIT_NO_FOREIGN
|
||||
# AsmJit features selection.
|
||||
ASMJIT_NO_JIT
|
||||
ASMJIT_NO_TEXT
|
||||
ASMJIT_NO_LOGGING
|
||||
ASMJIT_NO_INTROSPECTION
|
||||
ASMJIT_NO_VALIDATION
|
||||
ASMJIT_NO_BUILDER
|
||||
ASMJIT_NO_COMPILER)
|
||||
if (${build_option})
|
||||
List(APPEND ASMJIT_CFLAGS "-D${build_option}")
|
||||
List(APPEND ASMJIT_PRIVATE_CFLAGS "-D${build_option}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# AsmJit - Linker Support
|
||||
# =======================
|
||||
|
||||
if (WIN32)
|
||||
if (CMAKE_LINKER MATCHES "link\\.exe" OR CMAKE_LINKER MATCHES "lld-link\\.exe")
|
||||
set(ASMJIT_LINKER_SUPPORTS_NATVIS TRUE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# AsmJit - Source
|
||||
# ===============
|
||||
|
||||
set(ASMJIT_SRC_LIST
|
||||
asmjit/asmjit.h
|
||||
asmjit/asmjit-scope-begin.h
|
||||
asmjit/asmjit-scope-end.h
|
||||
|
||||
asmjit/core.h
|
||||
asmjit/core/api-build_p.h
|
||||
asmjit/core/api-config.h
|
||||
asmjit/core/archtraits.cpp
|
||||
asmjit/core/archtraits.h
|
||||
asmjit/core/archcommons.h
|
||||
asmjit/core/assembler.cpp
|
||||
asmjit/core/assembler.h
|
||||
asmjit/core/builder.cpp
|
||||
asmjit/core/builder.h
|
||||
asmjit/core/codebuffer.h
|
||||
asmjit/core/codeholder.cpp
|
||||
asmjit/core/codeholder.h
|
||||
asmjit/core/codewriter.cpp
|
||||
asmjit/core/codewriter_p.h
|
||||
asmjit/core/compiler.cpp
|
||||
asmjit/core/compiler.h
|
||||
asmjit/core/compilerdefs.h
|
||||
asmjit/core/constpool.cpp
|
||||
asmjit/core/constpool.h
|
||||
asmjit/core/cpuinfo.cpp
|
||||
asmjit/core/cpuinfo.h
|
||||
asmjit/core/emithelper.cpp
|
||||
asmjit/core/emithelper_p.h
|
||||
asmjit/core/emitter.cpp
|
||||
asmjit/core/emitter.h
|
||||
asmjit/core/emitterutils.cpp
|
||||
asmjit/core/emitterutils_p.h
|
||||
asmjit/core/environment.cpp
|
||||
asmjit/core/environment.h
|
||||
asmjit/core/errorhandler.cpp
|
||||
asmjit/core/errorhandler.h
|
||||
asmjit/core/formatter.cpp
|
||||
asmjit/core/formatter.h
|
||||
asmjit/core/func.cpp
|
||||
asmjit/core/func.h
|
||||
asmjit/core/funcargscontext.cpp
|
||||
asmjit/core/funcargscontext_p.h
|
||||
asmjit/core/globals.cpp
|
||||
asmjit/core/globals.h
|
||||
asmjit/core/inst.cpp
|
||||
asmjit/core/inst.h
|
||||
asmjit/core/instdb.cpp
|
||||
asmjit/core/instdb_p.h
|
||||
asmjit/core/jitallocator.cpp
|
||||
asmjit/core/jitallocator.h
|
||||
asmjit/core/jitruntime.cpp
|
||||
asmjit/core/jitruntime.h
|
||||
asmjit/core/logger.cpp
|
||||
asmjit/core/logger.h
|
||||
asmjit/core/misc_p.h
|
||||
asmjit/core/operand.cpp
|
||||
asmjit/core/operand.h
|
||||
asmjit/core/osutils.cpp
|
||||
asmjit/core/osutils.h
|
||||
asmjit/core/osutils_p.h
|
||||
asmjit/core/raassignment_p.h
|
||||
asmjit/core/rabuilders_p.h
|
||||
asmjit/core/radefs_p.h
|
||||
asmjit/core/ralocal.cpp
|
||||
asmjit/core/ralocal_p.h
|
||||
asmjit/core/rapass.cpp
|
||||
asmjit/core/rapass_p.h
|
||||
asmjit/core/rastack.cpp
|
||||
asmjit/core/rastack_p.h
|
||||
asmjit/core/string.cpp
|
||||
asmjit/core/string.h
|
||||
asmjit/core/support.cpp
|
||||
asmjit/core/support.h
|
||||
asmjit/core/target.cpp
|
||||
asmjit/core/target.h
|
||||
asmjit/core/type.cpp
|
||||
asmjit/core/type.h
|
||||
asmjit/core/virtmem.cpp
|
||||
asmjit/core/virtmem.h
|
||||
asmjit/core/zone.cpp
|
||||
asmjit/core/zone.h
|
||||
asmjit/core/zonehash.cpp
|
||||
asmjit/core/zonehash.h
|
||||
asmjit/core/zonelist.cpp
|
||||
asmjit/core/zonelist.h
|
||||
asmjit/core/zonestack.cpp
|
||||
asmjit/core/zonestack.h
|
||||
asmjit/core/zonestring.h
|
||||
asmjit/core/zonetree.cpp
|
||||
asmjit/core/zonetree.h
|
||||
asmjit/core/zonevector.cpp
|
||||
asmjit/core/zonevector.h
|
||||
|
||||
asmjit/a64.h
|
||||
asmjit/arm.h
|
||||
asmjit/arm/armformatter.cpp
|
||||
asmjit/arm/armformatter_p.h
|
||||
asmjit/arm/armglobals.h
|
||||
asmjit/arm/armoperand.h
|
||||
asmjit/arm/armutils.h
|
||||
asmjit/arm/a64archtraits_p.h
|
||||
asmjit/arm/a64assembler.cpp
|
||||
asmjit/arm/a64assembler.h
|
||||
asmjit/arm/a64builder.cpp
|
||||
asmjit/arm/a64builder.h
|
||||
asmjit/arm/a64compiler.cpp
|
||||
asmjit/arm/a64compiler.h
|
||||
asmjit/arm/a64emithelper.cpp
|
||||
asmjit/arm/a64emithelper_p.h
|
||||
asmjit/arm/a64emitter.h
|
||||
asmjit/arm/a64formatter.cpp
|
||||
asmjit/arm/a64formatter_p.h
|
||||
asmjit/arm/a64func.cpp
|
||||
asmjit/arm/a64func_p.h
|
||||
asmjit/arm/a64globals.h
|
||||
asmjit/arm/a64instapi.cpp
|
||||
asmjit/arm/a64instapi_p.h
|
||||
asmjit/arm/a64instdb.cpp
|
||||
asmjit/arm/a64instdb.h
|
||||
asmjit/arm/a64operand.cpp
|
||||
asmjit/arm/a64operand.h
|
||||
asmjit/arm/a64rapass.cpp
|
||||
asmjit/arm/a64rapass_p.h
|
||||
|
||||
asmjit/x86.h
|
||||
asmjit/x86/x86archtraits_p.h
|
||||
asmjit/x86/x86assembler.cpp
|
||||
asmjit/x86/x86assembler.h
|
||||
asmjit/x86/x86builder.cpp
|
||||
asmjit/x86/x86builder.h
|
||||
asmjit/x86/x86compiler.cpp
|
||||
asmjit/x86/x86compiler.h
|
||||
asmjit/x86/x86emithelper.cpp
|
||||
asmjit/x86/x86emithelper_p.h
|
||||
asmjit/x86/x86emitter.h
|
||||
asmjit/x86/x86formatter.cpp
|
||||
asmjit/x86/x86formatter_p.h
|
||||
asmjit/x86/x86func.cpp
|
||||
asmjit/x86/x86func_p.h
|
||||
asmjit/x86/x86globals.h
|
||||
asmjit/x86/x86instdb.cpp
|
||||
asmjit/x86/x86instdb.h
|
||||
asmjit/x86/x86instdb_p.h
|
||||
asmjit/x86/x86instapi.cpp
|
||||
asmjit/x86/x86instapi_p.h
|
||||
asmjit/x86/x86operand.cpp
|
||||
asmjit/x86/x86operand.h
|
||||
asmjit/x86/x86rapass.cpp
|
||||
asmjit/x86/x86rapass_p.h
|
||||
)
|
||||
|
||||
if (MSVC AND NOT ASMJIT_NO_NATVIS)
|
||||
list(APPEND ASMJIT_SRC_LIST asmjit.natvis)
|
||||
endif()
|
||||
|
||||
set(ASMJIT_SRC "")
|
||||
foreach(src_file ${ASMJIT_SRC_LIST})
|
||||
set(src_file "${ASMJIT_DIR}/src/${src_file}")
|
||||
list(APPEND ASMJIT_SRC ${src_file})
|
||||
|
||||
if ("${src_file}" MATCHES "\\.natvis")
|
||||
if (ASMJIT_LINKER_SUPPORTS_NATVIS)
|
||||
list(APPEND ASMJIT_PRIVATE_LFLAGS "-natvis:${src_file}")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
source_group(TREE "${ASMJIT_DIR}" FILES ${ASMJIT_SRC})
|
||||
|
||||
# AsmJit - Summary
|
||||
# ================
|
||||
|
||||
message("** AsmJit Summary **")
|
||||
message(" ASMJIT_DIR=${ASMJIT_DIR}")
|
||||
message(" ASMJIT_TEST=${ASMJIT_TEST}")
|
||||
message(" ASMJIT_TARGET_TYPE=${ASMJIT_TARGET_TYPE}")
|
||||
message(" ASMJIT_DEPS=${ASMJIT_DEPS}")
|
||||
message(" ASMJIT_LIBS=${ASMJIT_LIBS}")
|
||||
message(" ASMJIT_CFLAGS=${ASMJIT_CFLAGS}")
|
||||
message(" ASMJIT_PRIVATE_CFLAGS=${ASMJIT_PRIVATE_CFLAGS}")
|
||||
message(" ASMJIT_PRIVATE_CFLAGS_DBG=${ASMJIT_PRIVATE_CFLAGS_DBG}")
|
||||
message(" ASMJIT_PRIVATE_CFLAGS_REL=${ASMJIT_PRIVATE_CFLAGS_REL}")
|
||||
|
||||
# AsmJit - Targets
|
||||
# ================
|
||||
|
||||
if (NOT ASMJIT_EMBED)
|
||||
# Add AsmJit target.
|
||||
asmjit_add_target(asmjit "${ASMJIT_TARGET_TYPE}"
|
||||
SOURCES ${ASMJIT_SRC}
|
||||
LIBRARIES ${ASMJIT_DEPS}
|
||||
CFLAGS ${ASMJIT_PRIVATE_CFLAGS}
|
||||
CFLAGS_DBG ${ASMJIT_PRIVATE_CFLAGS_DBG}
|
||||
CFLAGS_REL ${ASMJIT_PRIVATE_CFLAGS_REL})
|
||||
|
||||
target_compile_options(asmjit INTERFACE ${ASMJIT_CFLAGS})
|
||||
target_include_directories(asmjit BEFORE INTERFACE
|
||||
$<BUILD_INTERFACE:${ASMJIT_INCLUDE_DIRS}>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
|
||||
|
||||
# Add blend2d::blend2d alias.
|
||||
add_library(asmjit::asmjit ALIAS asmjit)
|
||||
# TODO: [CMAKE] Deprecated alias - we use projectname::libraryname convention now.
|
||||
add_library(AsmJit::AsmJit ALIAS asmjit)
|
||||
|
||||
# Add AsmJit install instructions (library and public headers).
|
||||
if (NOT ASMJIT_NO_INSTALL)
|
||||
install(TARGETS asmjit
|
||||
EXPORT asmjit-config
|
||||
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
|
||||
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")
|
||||
install(EXPORT asmjit-config
|
||||
NAMESPACE asmjit::
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/asmjit")
|
||||
|
||||
foreach(_src_file ${ASMJIT_SRC_LIST})
|
||||
if ("${_src_file}" MATCHES "\\.h$" AND NOT "${_src_file}" MATCHES "_p\\.h$")
|
||||
get_filename_component(_src_dir ${_src_file} PATH)
|
||||
install(FILES "${ASMJIT_DIR}/src/${_src_file}" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${_src_dir}")
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
# Add AsmJit tests.
|
||||
if (ASMJIT_TEST)
|
||||
enable_testing()
|
||||
|
||||
# Special target that always uses embedded AsmJit.
|
||||
asmjit_add_target(asmjit_test_unit TEST
|
||||
SOURCES ${ASMJIT_SRC}
|
||||
test/asmjit_test_unit.cpp
|
||||
test/broken.cpp
|
||||
test/broken.h
|
||||
LIBRARIES ${ASMJIT_DEPS}
|
||||
CFLAGS ${ASMJIT_PRIVATE_CFLAGS}
|
||||
-DASMJIT_TEST
|
||||
-DASMJIT_STATIC
|
||||
CFLAGS_DBG ${ASMJIT_PRIVATE_CFLAGS_DBG}
|
||||
CFLAGS_REL ${ASMJIT_PRIVATE_CFLAGS_REL})
|
||||
target_include_directories(asmjit_test_unit BEFORE PRIVATE ${ASMJIT_INCLUDE_DIRS})
|
||||
|
||||
asmjit_add_target(asmjit_test_assembler TEST
|
||||
SOURCES test/asmjit_test_assembler.cpp
|
||||
test/asmjit_test_assembler.h
|
||||
test/asmjit_test_assembler_a64.cpp
|
||||
test/asmjit_test_assembler_x64.cpp
|
||||
test/asmjit_test_assembler_x86.cpp
|
||||
LIBRARIES asmjit::asmjit
|
||||
CFLAGS ${ASMJIT_PRIVATE_CFLAGS}
|
||||
CFLAGS_DBG ${ASMJIT_PRIVATE_CFLAGS_DBG}
|
||||
CFLAGS_REL ${ASMJIT_PRIVATE_CFLAGS_REL})
|
||||
|
||||
asmjit_add_target(asmjit_test_perf EXECUTABLE
|
||||
SOURCES test/asmjit_test_perf.cpp
|
||||
test/asmjit_test_perf_a64.cpp
|
||||
test/asmjit_test_perf_x86.cpp
|
||||
SOURCES test/asmjit_test_perf.h
|
||||
LIBRARIES asmjit::asmjit
|
||||
CFLAGS ${ASMJIT_PRIVATE_CFLAGS}
|
||||
CFLAGS_DBG ${ASMJIT_PRIVATE_CFLAGS_DBG}
|
||||
CFLAGS_REL ${ASMJIT_PRIVATE_CFLAGS_REL})
|
||||
|
||||
foreach(_target asmjit_test_emitters
|
||||
asmjit_test_execute
|
||||
asmjit_test_x86_sections)
|
||||
asmjit_add_target(${_target} TEST
|
||||
SOURCES test/${_target}.cpp
|
||||
LIBRARIES asmjit::asmjit
|
||||
CFLAGS ${ASMJIT_PRIVATE_CFLAGS}
|
||||
CFLAGS_DBG ${ASMJIT_PRIVATE_CFLAGS_DBG}
|
||||
CFLAGS_REL ${ASMJIT_PRIVATE_CFLAGS_REL})
|
||||
endforeach()
|
||||
|
||||
if (NOT ASMJIT_NO_INTROSPECTION)
|
||||
asmjit_add_target(asmjit_test_instinfo TEST
|
||||
SOURCES test/asmjit_test_instinfo.cpp
|
||||
LIBRARIES asmjit::asmjit
|
||||
CFLAGS ${ASMJIT_PRIVATE_CFLAGS}
|
||||
CFLAGS_DBG ${ASMJIT_PRIVATE_CFLAGS_DBG}
|
||||
CFLAGS_REL ${ASMJIT_PRIVATE_CFLAGS_REL})
|
||||
endif()
|
||||
|
||||
if (NOT (ASMJIT_NO_BUILDER OR ASMJIT_NO_COMPILER))
|
||||
# Vectorcall tests and XMM tests require at least SSE2 in 32-bit mode (in 64-bit mode it's implicit).
|
||||
# Some compilers don't like passing -msse2 for 64-bit targets, and some compilers targeting non-x86
|
||||
# would pass "-msse2" compile flag check, but with a warning not detected by CMake. Thus, verify that
|
||||
# our target is really 32-bit X86 and only use -msse2 or -arch:SSE2 flags when necessary.
|
||||
set(ASMJIT_SSE2_CFLAGS "")
|
||||
|
||||
check_cxx_source_compiles("
|
||||
#if defined(_M_IX86) || defined(__X86__) || defined(__i386__)
|
||||
int target_is_32_bit_x86() { return 1; }
|
||||
#else
|
||||
// Compile error...
|
||||
#endif
|
||||
|
||||
int main() {
|
||||
return target_is_32_bit_x86();
|
||||
}
|
||||
" ASMJIT_TARGET_IS_32_BIT_X86)
|
||||
|
||||
if (ASMJIT_TARGET_IS_32_BIT_X86)
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC" OR "x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
|
||||
asmjit_detect_cflags(ASMJIT_SSE2_CFLAGS "-arch:SSE2")
|
||||
else()
|
||||
asmjit_detect_cflags(ASMJIT_SSE2_CFLAGS "-msse2")
|
||||
endif()
|
||||
endif()
|
||||
asmjit_add_target(asmjit_test_compiler TEST
|
||||
SOURCES test/asmjit_test_compiler.cpp
|
||||
test/asmjit_test_compiler.h
|
||||
test/asmjit_test_compiler_a64.cpp
|
||||
test/asmjit_test_compiler_x86.cpp
|
||||
LIBRARIES asmjit::asmjit
|
||||
CFLAGS ${ASMJIT_PRIVATE_CFLAGS} ${ASMJIT_SSE2_CFLAGS}
|
||||
CFLAGS_DBG ${ASMJIT_PRIVATE_CFLAGS_DBG}
|
||||
CFLAGS_REL ${ASMJIT_PRIVATE_CFLAGS_REL})
|
||||
endif()
|
||||
|
||||
endif()
|
||||
endif()
|
||||
|
||||
cmake_policy(POP)
|
100
deps/asmjit/CONTRIBUTING.md
vendored
Normal file
@ -0,0 +1,100 @@
|
||||
## How to Contribute to AsmJit
|
||||
|
||||
### Did you find a bug or something isn't working as expected?
|
||||
|
||||
* Please use [Issues](https://github.com/asmjit/asmjit/issues) page to report bugs or create a [pull request](https://github.com/asmjit/asmjit/pulls) if you have already fixed it.
|
||||
|
||||
* Make sure that when a bug is reported it provides as much information as possible to make it easy to either reproduce it locally or to at least guess where the problem could be. AsmJit is a low-level tool, which makes it very easy to emit code that would crash or not work as intended. Always use AsmJit's [Logging](https://asmjit.com/doc/group__asmjit__logging.html) and [Error Handling](https://asmjit.com/doc/group__asmjit__error__handling.html) features first to analyze whether there is not a simple to catch bug in your own code.
|
||||
|
||||
* Don't be afraid to ask for help if you don't know how to solve a particular problem or in case it's unclear how to do it. The community would help if the problem is well described and has a solution. In general we always try to at least improve the documentation in case it doesn't provide enough information and users must ask for help.
|
||||
|
||||
### Asking questions
|
||||
|
||||
* We prefer GitHub issues to be used for reporting bugs or feature requests, but it's still okay to do that. Consider joining our [Gitter Chat](https://app.gitter.im/#/room/#asmjit:gitter.im) to ask questions; it has an active community that can quickly.
|
||||
|
||||
### Suggesting feature requests
|
||||
|
||||
* It's very likely that when using AsmJit you have found something that AsmJit doesn't provide and it would be handy to have it built-in. The [Issues](https://github.com/asmjit/asmjit/issues) page can be used to submit feature requests, but please keep in mind that AsmJit is a relatively small project and not all requested features will be accepted, especially if they are non-trivial, time consuming to implement, or the scope of the feature doesn't match AsmJit goals.
|
||||
|
||||
* If you have already implemented the feature you are suggesting, please open a [pull request](https://github.com/asmjit/asmjit/pulls).
|
||||
|
||||
* Ports (requesting new AsmJit backends) can be reported as feature requests, but only by people that are willing to work on them as creating new ports takes a lot of time.
|
||||
|
||||
### Suggesting a documentation enhancement
|
||||
|
||||
* [AsmJit's documentation](https://asmjit.com/doc/index.html) is auto-generated from source code, so if you would like to improve it just open a [pull request](https://github.com/asmjit/asmjit/pulls) with your changes. The documentation uses [Doxygen](https://www.doxygen.nl/) as a front-end, so please use `\ref`, etc... to create links in documentation when necessary.
|
||||
|
||||
### Suggesting a website content enhancement
|
||||
|
||||
* [AsmJit's website](https://asmjit.com) is also generated, but not from public sources at the moment. If you did find an issue on the website you can either use contact on the [support page](https://asmjit.com/support.html) or just discuss the change in our [Gitter Chat](https://app.gitter.im/#/room/#asmjit:gitter.im). Alternatively, opening a regular issue is also okay.
|
||||
|
||||
|
||||
## Coding Style & Consistency
|
||||
|
||||
* If you decide to open a pull request, make sure that the code you submit uses the same convention as the rest of the code. We prefer keeping the code consistent.
|
||||
|
||||
* [.editorconfig](./.editorconfig) should help with basic settings.
|
||||
|
||||
* Initially, AsmJit coding style was based on Google C++ Style Guide, but it has diverged from it.
|
||||
|
||||
* Include guards use `<PATH_TO_SRC>_H_INCLUDED` format.
|
||||
|
||||
* `asmjit` namespace must be open by `ASMJIT_BEGIN_NAMESPACE` and closed by `ASMJIT_END_NAMESPACE`
|
||||
|
||||
* `asmjit::xxx` (backend specific) nested namespace must be open by `ASMJIT_BEGIN_SUB_NAMESPACE(xxx)` and closed by `ASMJIT_END_SUB_NAMESPACE`.
|
||||
|
||||
* Opening bracket is on the same line, like `struct Something {`, `if (condition) {`, etc...
|
||||
|
||||
* The code uses a soft limit of 120 characters per line (including documentation), but it's not enforced and it's okay to use more when it makes sense (for example defining tables, etc...).
|
||||
|
||||
* Since AsmJit doesn't use Exceptions nor RTTI the code cannot use containers provided by the C++ standard library as they use exception handling by design. In general, we try to only use a bare minimum from the C++ standard library to make it viable to use AsmJit even in C code bases where JIT complier is implemented in C++ ([Erlang](https://www.erlang.org/) can be seen as a great example).
|
||||
|
||||
## Testing
|
||||
|
||||
* AsmJit uses a minimalist unit testing framework to write unit tests to avoid third-party dependencies.
|
||||
|
||||
* At the moment tests are in the same file as the implementation and are only compiled when `ASMJIT_TEST` macro is defined.
|
||||
|
||||
* Use `-DASMJIT_TEST=1` when invoking [CMake](https://cmake.org/) to compile AsmJit tests.
|
||||
|
||||
* Unit tests are compiled to a single `asmjit_test_unit[.exe]` executable.
|
||||
|
||||
* Other tests have their own executables based on what is tested.
|
||||
|
||||
* Always add assembler tests when adding new instructions, see [asmjit_test_assembler_x64.cpp](./test/asmjit_test_assembler_x64.cpp) and [asmjit_test_assembler_a64.cpp](./test/asmjit_test_assembler_a64.cpp) for more details.
|
||||
|
||||
## Pull Request Messages
|
||||
|
||||
* If a change fixes a bug the message should should start with `[bug]`.
|
||||
|
||||
* If a change fixes or enhances documentation it should start with `[doc]`.
|
||||
|
||||
* If a change fixes or enhances our CI it should start with `[ci]`.
|
||||
|
||||
* If a change breaks ABI it must start with `[abi]`.
|
||||
|
||||
* Otherwise there is no suggested prefix.
|
||||
|
||||
## ABI Changes
|
||||
|
||||
* ABI changes happen, but they are usually accumulated and committed within a short time window to not break it often. In general we prefer to break ABI once a year, or once 6 months if there is something that has a high priority. There are no hard rules though.
|
||||
|
||||
* AsmJit uses an `inline namespace`, which should make it impossible to link to AsmJit library that is ABI incompatible. When ABI break happens AsmJit version and ABI namespace is changed, see [asmjit/core/api-config.h](./src/asmjit/core/api-config.h) for more details.
|
||||
|
||||
* What is an ABI break?
|
||||
|
||||
* Modifying a public struct/class in a way that its functionality is altered and/or its size is changed
|
||||
|
||||
* Adding/removing virtual functions to/from classes, respectively
|
||||
|
||||
* Changing a signature of a public function or a class member function.
|
||||
|
||||
* Changing the value of an enum or global constant (for example instructions are now sorted by name, so adding a new instruction is an ABI break)
|
||||
|
||||
* Possibly more, but these were the most common...
|
||||
|
||||
* What is not ABI break?
|
||||
|
||||
* Extending the functionality by using reserved members of a struct/class
|
||||
|
||||
* Changing anything that is internal and that doesn't leak to public headers
|
17
deps/asmjit/LICENSE.md
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
Copyright (c) 2008-2024 The AsmJit Authors
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
70
deps/asmjit/README.md
vendored
Normal file
@ -0,0 +1,70 @@
|
||||
AsmJit
|
||||
------
|
||||
|
||||
AsmJit is a lightweight library for machine code generation written in C++ language.
|
||||
|
||||
* [Official Home Page (asmjit.com)](https://asmjit.com)
|
||||
* [Official Repository (asmjit/asmjit)](https://github.com/asmjit/asmjit)
|
||||
* [Public Chat Channel](https://app.gitter.im/#/room/#asmjit:gitter.im)
|
||||
* [Zlib License](./LICENSE.md)
|
||||
|
||||
See [asmjit.com](https://asmjit.com) page for more details, examples, and documentation.
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
* [Documentation Index](https://asmjit.com/doc/index.html)
|
||||
* [Build Instructions](https://asmjit.com/doc/group__asmjit__build.html)
|
||||
|
||||
Contributing
|
||||
------------
|
||||
|
||||
* See [CONTRIBUTING](./CONTRIBUTING.md) page for more details
|
||||
|
||||
Breaking Changes
|
||||
----------------
|
||||
|
||||
Breaking the API is sometimes inevitable, what to do?
|
||||
|
||||
* See [Breaking Changes Guide](https://asmjit.com/doc/group__asmjit__breaking__changes.html), which is now part of AsmJit documentation
|
||||
* See asmjit tests, they always compile and provide implementation of many use-cases:
|
||||
* [asmjit_test_emitters.cpp](./test/asmjit_test_emitters.cpp) - Tests that demonstrate the purpose of emitters
|
||||
* [asmjit_test_assembler_x86.cpp](./test/asmjit_test_assembler_x86.cpp) - Tests targeting AsmJit's Assembler (x86/x64)
|
||||
* [asmjit_test_compiler_x86.cpp](./test/asmjit_test_compiler_x86.cpp) - Tests targeting AsmJit's Compiler (x86/x64)
|
||||
* [asmjit_test_instinfo.cpp](./test/asmjit_test_instinfo.cpp) - Tests that query instruction information
|
||||
* [asmjit_test_x86_sections.cpp](./test/asmjit_test_x86_sections.cpp) - Multiple sections test.
|
||||
* Visit our [Gitter Chat](https://app.gitter.im/#/room/#asmjit:gitter.im) if you need a quick help
|
||||
|
||||
Project Organization
|
||||
--------------------
|
||||
|
||||
* **`/`** - Project root
|
||||
* **src** - Source code
|
||||
* **asmjit** - Source code and headers (always point include path in here)
|
||||
* **core** - Core API, backend independent except relocations
|
||||
* **arm** - ARM specific API, used only by ARM and AArch64 backends
|
||||
* **x86** - X86 specific API, used only by X86 and X64 backends
|
||||
* **test** - Unit and integration tests (don't embed in your project)
|
||||
* **tools** - Tools used for configuring, documenting, and generating files
|
||||
|
||||
Ports
|
||||
-----
|
||||
|
||||
* [ ] 32-bit ARM/Thumb port (work in progress)
|
||||
* [ ] RISC-V port (not in progress, help welcome)
|
||||
|
||||
Support
|
||||
-------
|
||||
|
||||
* AsmJit project has both community and commercial support, see [AsmJit's Support Page](https://asmjit.com/support.html)
|
||||
* You can help the development and maintenance through Petr Kobalicek's [GitHub sponsors Profile](https://github.com/sponsors/kobalicek)
|
||||
|
||||
Notable Donors List:
|
||||
|
||||
* [ZehMatt](https://github.com/ZehMatt)
|
||||
|
||||
|
||||
Authors & Maintainers
|
||||
---------------------
|
||||
|
||||
* Petr Kobalicek <kobalicek.petr@gmail.com>
|
16
deps/asmjit/db/README.md
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
AsmJit Instruction Database
|
||||
---------------------------
|
||||
|
||||
This is a database of instructions that is used by AsmJit to generate its internal database and also assembler implementations. This project started initially as AsmDB, but was merged to AsmJit later to make the maintenance easier. The database was created in a way so that each instruction definition would only need a single line in JSON data file. The data is then processed by architecture specific data readers that make the data canonical and ready for processing.
|
||||
|
||||
AsmJit database provides the following ISAs:
|
||||
|
||||
* `isa_x86.json` - provides X86 instruction data (both 32-bit and 64-bit)
|
||||
* `isa_aarch32.json` - provides AArch32 instruction data (A32/T16/T32 encoding)
|
||||
* `isa_aarch64.json` - provides AArch64 instruction data (A64 encoding)
|
||||
* `isa_aarch64_sme.json` - provides AArch64 SME instruction data (work-in-progress)
|
||||
|
||||
To Be Documented
|
||||
----------------
|
||||
|
||||
This project will be refactored and documented in the future.
|
988
deps/asmjit/db/aarch32.js
vendored
Normal file
@ -0,0 +1,988 @@
|
||||
// This file is part of AsmJit project <https://asmjit.com>
|
||||
//
|
||||
// See asmjit.h or LICENSE.md for license and copyright information
|
||||
// SPDX-License-Identifier: Zlib
|
||||
|
||||
|
||||
(function($scope, $as) {
|
||||
"use strict";
|
||||
|
||||
function FAIL(msg) { throw new Error("[AArch32] " + msg); }
|
||||
|
||||
// Import
|
||||
// ======
|
||||
|
||||
const base = $scope.base ? $scope.base : require("./base.js");
|
||||
const exp = $scope.exp ? $scope.exp : require("./exp.js")
|
||||
|
||||
const hasOwn = Object.prototype.hasOwnProperty;
|
||||
const dict = base.dict;
|
||||
const NONE = base.NONE;
|
||||
const Parsing = base.Parsing;
|
||||
const MapUtils = base.MapUtils;
|
||||
|
||||
// Export
|
||||
// ======
|
||||
|
||||
const arm = $scope[$as] = dict();
|
||||
|
||||
// Database
|
||||
// ========
|
||||
|
||||
arm.dbName = "isa_aarch32.json";
|
||||
|
||||
// asmdb.aarch32.Utils
|
||||
// ===================
|
||||
|
||||
// Can be used to assign the number of bits each part of the opcode occupies.
|
||||
// NOTE: THUMB instructions that use halfword must always specify the width
|
||||
// of all registers as many instructions accept only LO (r0..r7) registers.
|
||||
const FieldInfo = {
|
||||
"P" : { "bits": 1 },
|
||||
"U" : { "bits": 1 },
|
||||
"W" : { "bits": 1 },
|
||||
"S" : { "bits": 1 },
|
||||
"R" : { "bits": 1 },
|
||||
"H" : { "bits": 1 },
|
||||
"isFp32": { "bits": 1 },
|
||||
"F" : { "bits": 1 },
|
||||
"align" : { "bits": 2 },
|
||||
"ja" : { "bits": 1 },
|
||||
"jb" : { "bits": 1 },
|
||||
"op" : { "bits": 1 }, // TODO: This should be fixed.
|
||||
"sz" : { "bits": 2 },
|
||||
"sop" : { "bits": 2 },
|
||||
"cond" : { "bits": 4 },
|
||||
"cmode" : { "bits": 4 },
|
||||
"Cn" : { "bits": 4 },
|
||||
"Cm" : { "bits": 4 },
|
||||
|
||||
"Rd" : { "bits": 4, "read": false, "write": true },
|
||||
"Rd2" : { "bits": 4, "read": false, "write": true },
|
||||
"RdLo" : { "bits": 4, "read": false, "write": true },
|
||||
"RdHi" : { "bits": 4, "read": false, "write": true },
|
||||
"RdList": { "bits": 4, "read": false, "write": true , "list": true },
|
||||
"Rx" : { "bits": 4, "read": true , "write": true },
|
||||
"RxLo" : { "bits": 4, "read": true , "write": true },
|
||||
"RxHi" : { "bits": 4, "read": true , "write": true },
|
||||
"Rn" : { "bits": 4, "read": true , "write": false },
|
||||
"Rm" : { "bits": 4, "read": true , "write": false },
|
||||
"Ra" : { "bits": 4, "read": true , "write": false },
|
||||
"Rs" : { "bits": 4, "read": true , "write": false },
|
||||
"Rs2" : { "bits": 4, "read": true , "write": false },
|
||||
"RsList": { "bits": 4, "read": true , "write": false , "list": true },
|
||||
|
||||
"Sd" : { "bits": 4, "read": false, "write": true },
|
||||
"Sd2" : { "bits": 4, "read": false, "write": true },
|
||||
"SdList": { "bits": 4, "read": false, "write": true , "list": true },
|
||||
"Sx" : { "bits": 4, "read": true , "write": true },
|
||||
"Sn" : { "bits": 4, "read": true , "write": false },
|
||||
"Sm" : { "bits": 4, "read": true , "write": false },
|
||||
"Ss" : { "bits": 4, "read": true , "write": false },
|
||||
"Ss2" : { "bits": 4, "read": true , "write": false },
|
||||
"SsList": { "bits": 4, "read": true , "write": false , "list": true },
|
||||
|
||||
"Dd" : { "bits": 4, "read": false, "write": true },
|
||||
"Dd2" : { "bits": 4, "read": false, "write": true },
|
||||
"Dd3" : { "bits": 4, "read": false, "write": true },
|
||||
"Dd4" : { "bits": 4, "read": false, "write": true },
|
||||
"DdList": { "bits": 4, "read": false, "write": true , "list": true },
|
||||
"Dx" : { "bits": 4, "read": true , "write": true },
|
||||
"Dx2" : { "bits": 4, "read": true , "write": true },
|
||||
"Dn" : { "bits": 4, "read": true , "write": false },
|
||||
"Dn2" : { "bits": 4, "read": true , "write": false },
|
||||
"Dn3" : { "bits": 4, "read": true , "write": false },
|
||||
"Dn4" : { "bits": 4, "read": true , "write": false },
|
||||
"Dm" : { "bits": 4, "read": true , "write": false },
|
||||
"Ds" : { "bits": 4, "read": true , "write": false },
|
||||
"Ds2" : { "bits": 4, "read": true , "write": false },
|
||||
"Ds3" : { "bits": 4, "read": true , "write": false },
|
||||
"Ds4" : { "bits": 4, "read": true , "write": false },
|
||||
"DsList": { "bits": 4, "read": true , "write": false , "list": true },
|
||||
|
||||
"Vd" : { "bits": 4, "read": false, "write": true },
|
||||
"Vd2" : { "bits": 4, "read": false, "write": true },
|
||||
"Vd3" : { "bits": 4, "read": false, "write": true },
|
||||
"Vd4" : { "bits": 4, "read": false, "write": true },
|
||||
"Vx" : { "bits": 4, "read": true , "write": true },
|
||||
"Vx2" : { "bits": 4, "read": true , "write": true },
|
||||
"Vn" : { "bits": 4, "read": true , "write": false },
|
||||
"Vm" : { "bits": 4, "read": true , "write": false },
|
||||
"Vs" : { "bits": 4, "read": true , "write": false },
|
||||
"Vs2" : { "bits": 4, "read": true , "write": false },
|
||||
};
|
||||
|
||||
arm.FieldInfo = FieldInfo;
|
||||
|
||||
// ARM utilities.
|
||||
class Utils {
|
||||
static splitInstructionSignature(s) {
|
||||
const names = s.match(/^[\w\|]+/)[0];
|
||||
s = s.substring(names.length);
|
||||
|
||||
const opOffset = s.indexOf(" ")
|
||||
const suffix = s.substring(0, opOffset).trim();
|
||||
const operands = opOffset === -1 ? "" : s.substring(opOffset + 1).trim();
|
||||
|
||||
return {
|
||||
names: names.split("|").map((base)=>{ return base + suffix}),
|
||||
operands: operands
|
||||
}
|
||||
}
|
||||
|
||||
static parseShiftOp(s) {
|
||||
const m = s.match(/^(sop|lsl_or_asr|lsl|lsr|asr|ror|rrx) /);
|
||||
return m ? m[1] : "";
|
||||
}
|
||||
|
||||
static parseDtArray(s) {
|
||||
const out = [];
|
||||
if (!s) return out;
|
||||
|
||||
const arr = s.split("|");
|
||||
let i;
|
||||
|
||||
// First expand anything between X-Y, for example s8-32 would be expanded to [s8, s16, s32].
|
||||
for (i = 0; i < arr.length; i++) {
|
||||
const v = arr[i];
|
||||
|
||||
if (v.indexOf("-") !== -1) {
|
||||
const m = /^([A-Za-z]+)?(\d+)-(\d+)$/.exec(v);
|
||||
if (!m)
|
||||
FAIL(`Couldn't parse '${s}' data-type`);
|
||||
|
||||
let type = m[1] || "";
|
||||
let size = parseInt(m[2], 10);
|
||||
let last = parseInt(m[3], 10);
|
||||
|
||||
if (!Utils.checkDtSize(size) || !Utils.checkDtSize(last))
|
||||
FAIL(`Invalid dt width in '${s}'`);
|
||||
|
||||
do {
|
||||
out.push(type + String(size));
|
||||
size <<= 1;
|
||||
} while (size <= last);
|
||||
}
|
||||
else {
|
||||
out.push(v);
|
||||
}
|
||||
}
|
||||
|
||||
// Now expand 'x' to 's' and 'u'.
|
||||
i = 0;
|
||||
while (i < out.length) {
|
||||
const v = out[i];
|
||||
if (v.startsWith("x")) {
|
||||
out.splice(i, 1, "s" + v.substr(1), "u" + v.substr(1));
|
||||
i += 2;
|
||||
}
|
||||
else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static checkDtSize(x) {
|
||||
return x === 8 || x === 16 || x === 32 || x === 64;
|
||||
}
|
||||
}
|
||||
arm.Utils = Utils;
|
||||
|
||||
function normalizeNumber(n) {
|
||||
return n < 0 ? 0x100000000 + n : n;
|
||||
}
|
||||
|
||||
function decomposeOperand(s) {
|
||||
const elementSuffix = "[#i]";
|
||||
let element = null;
|
||||
let consecutive = 0;
|
||||
let userRegList = false;
|
||||
|
||||
if (s.endsWith("^")) {
|
||||
userRegList = true;
|
||||
s = s.substring(0, s.length - 1);
|
||||
}
|
||||
|
||||
if (s.endsWith(elementSuffix)) {
|
||||
element = "#i";
|
||||
s = s.substring(0, s.length - elementSuffix.length);
|
||||
}
|
||||
|
||||
if (s.endsWith("++")) {
|
||||
consecutive = 2;
|
||||
s = s.substr(0, s.length - 2);
|
||||
}
|
||||
else if (s.endsWith("+")) {
|
||||
consecutive = 1;
|
||||
s = s.substr(0, s.length - 1);
|
||||
}
|
||||
|
||||
let m = s.match(/==|\!=|>=|<=|\*/);
|
||||
let restrict = false;
|
||||
|
||||
if (m) {
|
||||
restrict = s.substr(m.index);
|
||||
s = s.substr(0, m.index);
|
||||
}
|
||||
|
||||
return {
|
||||
data : s,
|
||||
element : element,
|
||||
restrict: restrict,
|
||||
consecutive: consecutive,
|
||||
userRegList: true
|
||||
};
|
||||
}
|
||||
|
||||
function splitOpcodeFields(s) {
|
||||
const arr = s.split("|");
|
||||
const out = [];
|
||||
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
const val = arr[i];
|
||||
if (/^[0-1A-Z]{2,}$/.test(val))
|
||||
out.push.apply(out, val.match(/([0-1]+)|[A-Z]/g));
|
||||
else
|
||||
out.push(val);
|
||||
}
|
||||
|
||||
return out.map((field) => { return field.trim(); });
|
||||
}
|
||||
|
||||
// asmdb.aarch32.Operand
|
||||
// =====================
|
||||
|
||||
// ARM operand.
|
||||
class Operand extends base.Operand {
|
||||
constructor(def) {
|
||||
super(def);
|
||||
}
|
||||
|
||||
hasMemModes() {
|
||||
return Object.keys(this.memModes).length !== 0;
|
||||
}
|
||||
|
||||
get name() {
|
||||
switch (this.type) {
|
||||
case "reg": return this.reg;
|
||||
case "mem": return this.mem;
|
||||
case "imm": return this.imm;
|
||||
case "rel": return this.rel;
|
||||
default : return "";
|
||||
}
|
||||
}
|
||||
|
||||
get scale() {
|
||||
if (this.restrict && this.restrict.startsWith("*"))
|
||||
return parseInt(this.restrict.substr(1), 10);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
isRelative() {
|
||||
if (this.type === "imm")
|
||||
return this.name === "relA" || this.name === "relS" || this.name === "relZ";
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
arm.Operand = Operand;
|
||||
|
||||
// asmdb.aarch32.Instruction
|
||||
// =========================
|
||||
|
||||
function patternFromOperand(key) {
|
||||
return key;
|
||||
// return key.replace(/\b(?:[RVDS](?:d|s|n|m|x|x2))\b/, "R");
|
||||
}
|
||||
|
||||
// Rewrite a memory operand expression (either base or index) to a simplified one, which is okay
|
||||
// to be generated as C++ expression. In general, we want to simplify != to a more favorable code.
|
||||
function simplifyMemoryExpression(e) {
|
||||
if (e.type === "binary" && e.op === "!=" && e.right.type === "var") {
|
||||
// Rewrite A != PC to A < PC
|
||||
if (e.right.name === "PC") { e.op = "<"; }
|
||||
|
||||
// Rewrite A != HI to A < 8
|
||||
if (e.right.name === "HI") { e.op = "<"; e.right = exp.Imm(8); }
|
||||
|
||||
// Rewrite A != XX to A < SP || A == LR
|
||||
if (e.right.name === "XX") {
|
||||
return exp.Or(exp.Lt(e.left, exp.Var("SP")),
|
||||
exp.Eq(e.left.clone(), exp.Var("LR")));
|
||||
}
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
// ARM instruction.
|
||||
class Instruction extends base.Instruction {
|
||||
constructor(db, data) {
|
||||
super(db, data);
|
||||
// name, operands, encoding, opcode, metadata
|
||||
|
||||
const encoding = hasOwn.call(data, "a32") ? "a32" :
|
||||
hasOwn.call(data, "t32") ? "t32" :
|
||||
hasOwn.call(data, "t16") ? "t16" : "";
|
||||
|
||||
this.name = data.name;
|
||||
this.it = dict(); // THUMB's 'it' flags.
|
||||
this.apsr = dict();
|
||||
this.fpcsr = dict();
|
||||
this.calc = dict(); // Calculations required to generate opcode.
|
||||
this.immCond = []; // Immediate value conditions (array of conditions).
|
||||
|
||||
this.s = null; // Instruction S flag (null, true, or false).
|
||||
this.dt = []; // Instruction <dt> field (first data-type).
|
||||
this.dt2 = []; // Instruction <dt2> field (second data-type).
|
||||
|
||||
this.availableFrom = ""; // Instruction supported by from ARMv???.
|
||||
this.availableUntil = ""; // Instruction supported by until ARMv???.
|
||||
|
||||
this._assignOperands(data.operands);
|
||||
this._assignEncoding(encoding.toUpperCase());
|
||||
this._assignOpcode(data[encoding]);
|
||||
|
||||
for (let k in data) {
|
||||
if (k === "name" || k == encoding || k === "operands")
|
||||
continue;
|
||||
this._assignAttribute(k, data[k]);
|
||||
}
|
||||
|
||||
this._updateOperandsInfo();
|
||||
this._postProcess();
|
||||
}
|
||||
|
||||
_assignAttribute(key, value) {
|
||||
switch (key) {
|
||||
case "it":
|
||||
for (let it of value.split(" "))
|
||||
this.it[it.trim()] = true;
|
||||
break;
|
||||
|
||||
case "apsr":
|
||||
case "fpcsr":
|
||||
this._assignAttributeKeyValue(key, value);
|
||||
break;
|
||||
|
||||
case "imm":
|
||||
this.imm = exp.parse(value);
|
||||
break;
|
||||
|
||||
case "calc":
|
||||
for (let calcKey in value)
|
||||
this.calc[calcKey] = exp.parse(value[calcKey]);
|
||||
break;
|
||||
|
||||
default:
|
||||
super._assignAttribute(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
_assignAttributeKeyValue(name, content) {
|
||||
const attributes = content.trim().split(/[ ]+/);
|
||||
|
||||
for (let i = 0; i < attributes.length; i++) {
|
||||
const attr = attributes[i].trim();
|
||||
if (!attr)
|
||||
continue;
|
||||
|
||||
const eq = attr.indexOf("=");
|
||||
let key = eq === -1 ? attr : attr.substr(0, eq);
|
||||
let val = eq === -1 ? true : attr.substr(eq + 1);
|
||||
|
||||
// If the key contains "|" it's a definition of multiple attributes.
|
||||
if (key.indexOf("|") !== -1) {
|
||||
const dot = key.indexOf(".");
|
||||
|
||||
const base = dot === -1 ? "" : key.substr(0, dot + 1);
|
||||
const keys = (dot === -1 ? key : key.substr(dot + 1)).split("|");
|
||||
|
||||
for (let j = 0; j < keys.length; j++)
|
||||
this[name][base + keys[j]] = val;
|
||||
}
|
||||
else {
|
||||
this[name][key] = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_assignEncoding(s) {
|
||||
this.arch = s === "T16" || s === "T32" ? "THUMB" : "ARM";
|
||||
this.encoding = s;
|
||||
}
|
||||
|
||||
_assignOperands(s) {
|
||||
if (!s) return;
|
||||
|
||||
// Split into individual operands and push them to `operands`.
|
||||
const arr = base.Parsing.splitOperands(s);
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
let def = arr[i];
|
||||
const op = new Operand(def);
|
||||
|
||||
const consecutive = def.match(/(\d+)x\{(.*)\}([+][+]?)/);
|
||||
if (consecutive)
|
||||
def = consecutive[2];
|
||||
|
||||
op.sign = false;
|
||||
op.element = null;
|
||||
op.shiftOp = "";
|
||||
op.shiftImm = null;
|
||||
|
||||
// Handle {optional} attribute.
|
||||
if (Parsing.isOptional(def)) {
|
||||
op.optional = true;
|
||||
def = Parsing.clearOptional(def);
|
||||
}
|
||||
|
||||
// Handle commutativity <-> symbol.
|
||||
if (Parsing.isCommutative(def)) {
|
||||
op.commutative = true;
|
||||
def = Parsing.clearCommutative(def);
|
||||
}
|
||||
|
||||
// Handle shift operation.
|
||||
let shiftOp = Utils.parseShiftOp(def);
|
||||
if (shiftOp) {
|
||||
op.shiftOp = shiftOp;
|
||||
def = def.substring(shiftOp.length + 1);
|
||||
}
|
||||
|
||||
if (def.startsWith("[")) {
|
||||
op.type = "mem";
|
||||
op.memModes = dict();
|
||||
|
||||
op.base = null;
|
||||
op.index = null;
|
||||
op.offset = null;
|
||||
|
||||
let mem = def;
|
||||
let didHaveMemMode = false;
|
||||
|
||||
for (;;) {
|
||||
if (mem.endsWith("!")) {
|
||||
op.memModes.preIndex = true;
|
||||
mem = mem.substring(0, mem.length - 1);
|
||||
|
||||
didHaveMemMode = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (mem.endsWith("@")) {
|
||||
op.memModes.postIndex = true;
|
||||
mem = mem.substring(0, mem.length - 1);
|
||||
|
||||
didHaveMemMode = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (mem.endsWith("{!}")) {
|
||||
op.memModes.offset = true;
|
||||
op.memModes.preIndex = true;
|
||||
mem = mem.substring(0, mem.length - 3);
|
||||
|
||||
didHaveMemMode = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mem.endsWith("{@}")) {
|
||||
op.memModes.offset = true;
|
||||
op.memModes.postIndex = true;
|
||||
mem = mem.substring(0, mem.length - 3);
|
||||
|
||||
didHaveMemMode = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (!mem.endsWith("]"))
|
||||
FAIL(`Unknown memory operand '${mem}' in '${def}'`);
|
||||
|
||||
let parts = mem.substring(1, mem.length - 1).split(",").map(function(s) { return s.trim() });
|
||||
for (let i = 0; i < parts.length; i++) {
|
||||
const part = parts[i];
|
||||
|
||||
const m = part.match(/^\{(lsl|sop)\s+#(\w+)\}$/);
|
||||
if (m) {
|
||||
op.shiftOp = m[1];
|
||||
op.shiftImm = m[2];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i === 0) {
|
||||
op.base = dict();
|
||||
op.base.field = part;
|
||||
op.base.exp = null;
|
||||
|
||||
const m = part.match(/^([A-Za-z]\w*)/);
|
||||
if (m.length < part.length) {
|
||||
op.base.exp = simplifyMemoryExpression(exp.parse(part));
|
||||
op.base.field = m[1];
|
||||
}
|
||||
}
|
||||
else if (part.startsWith("#")) {
|
||||
let p = part.substring(1);
|
||||
let u = "1";
|
||||
let alwaysNegative = false;
|
||||
|
||||
let offExp = null;
|
||||
let offMul = 1;
|
||||
|
||||
if (p.startsWith("+/-")) {
|
||||
u = "U";
|
||||
p = p.substring(3);
|
||||
}
|
||||
|
||||
if (p.startsWith("-")) {
|
||||
alwaysNegative = false;
|
||||
p = p.substring(1);
|
||||
}
|
||||
|
||||
const expMatch = p.match(/^([A-Za-z]\w*)==/);
|
||||
if (expMatch) {
|
||||
offExp = exp.parse(p);
|
||||
p = p.substr(0, expMatch[1].length);
|
||||
}
|
||||
|
||||
const mulMatch = p.match(/\s*\*\s*(\d+)$/);
|
||||
if (mulMatch) {
|
||||
offMul = parseInt(mulMatch[1]);
|
||||
p = p.substr(0, mulMatch.index);
|
||||
}
|
||||
|
||||
op.offset = dict();
|
||||
op.offset.field = p;
|
||||
op.offset.u = u;
|
||||
op.offset.exp = offExp;
|
||||
op.offset.mul = offMul;
|
||||
op.offset.negative = alwaysNegative;
|
||||
}
|
||||
else {
|
||||
let p = part;
|
||||
let u = "1";
|
||||
|
||||
if (p.startsWith("+/-")) {
|
||||
u = "U";
|
||||
p = p.substring(3);
|
||||
}
|
||||
|
||||
op.index = dict();
|
||||
op.index.field = p;
|
||||
op.index.u = u;
|
||||
|
||||
const m = p.match(/^([A-Za-z]\w*)/);
|
||||
if (m.length < p.length) {
|
||||
op.index.exp = simplifyMemoryExpression(exp.parse(p));
|
||||
op.index.field = m[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!op.hasMemModes() && (op.offset || op.index))
|
||||
op.memModes.offset = true;
|
||||
|
||||
op.mem = mem;
|
||||
}
|
||||
else if (def.startsWith("#")) {
|
||||
const obj = decomposeOperand(def);
|
||||
const imm = obj.data;
|
||||
|
||||
op.type = "imm";
|
||||
op.imm = imm.substring(1); // Immediate operand name.
|
||||
op.immSize = 0; // Immediate size in bits.
|
||||
op.restrict = obj.restrict; // Immediate condition.
|
||||
}
|
||||
else {
|
||||
const obj = decomposeOperand(def);
|
||||
const reg = obj.data;
|
||||
|
||||
const type = reg.substr(0, 1).toLowerCase();
|
||||
const info = FieldInfo[reg];
|
||||
|
||||
if (!info)
|
||||
FAIL(`Unknown register operand '${reg}' in '${def}'`);
|
||||
|
||||
op.type = info.list ? "reg-list" : "reg";
|
||||
op.reg = reg; // Register name (as specified in manual).
|
||||
op.regType = type; // Register type.
|
||||
op.regList = !!info.list; // Register list.
|
||||
op.read = info.read; // Register access (read).
|
||||
op.write = info.write; // Register access (write).
|
||||
op.element = obj.element; // Register element[] access.
|
||||
op.restrict = obj.restrict; // Register condition.
|
||||
op.consecutive = obj.consecutive;
|
||||
}
|
||||
|
||||
this.operands.push(op);
|
||||
|
||||
if (consecutive) {
|
||||
const count = parseInt(consecutive[1]);
|
||||
for (let n = 2; n <= count; n++) {
|
||||
const def = consecutive[3].replace(op.reg, op.reg + n);
|
||||
const opN = new Operand(def);
|
||||
opN.type = "reg";
|
||||
opN.reg = op.reg + n;
|
||||
opN.regType = op.regType;
|
||||
opN.read = op.read;
|
||||
opN.write = op.write;
|
||||
opN.element = op.element;
|
||||
opN.consecutive = consecutive[3].length;
|
||||
this.operands.push(opN);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_assignOpcode(s) {
|
||||
this.opcodeString = s;
|
||||
|
||||
let opcodeIndex = 0;
|
||||
let opcodeValue = 0;
|
||||
|
||||
let patternMap = {};
|
||||
|
||||
// Split opcode into its fields.
|
||||
const arr = splitOpcodeFields(s);
|
||||
const dup = dict();
|
||||
|
||||
const fields = this.fields;
|
||||
const pattern = [];
|
||||
|
||||
const fieldMap = Object.create(null);
|
||||
for (let field of arr) {
|
||||
fieldMap[field] = true;
|
||||
}
|
||||
|
||||
for (let i = arr.length - 1; i >= 0; i--) {
|
||||
let key = arr[i];
|
||||
let m;
|
||||
|
||||
if (/^[0-1]+$/.test(key)) {
|
||||
// This part of the opcode is RAW bits, they contribute to the `opcodeValue`.
|
||||
opcodeValue |= parseInt(key, 2) << opcodeIndex;
|
||||
opcodeIndex += key.length;
|
||||
pattern.unshift("_".repeat(key.length));
|
||||
}
|
||||
else {
|
||||
pattern.unshift(patternFromOperand(key));
|
||||
patternMap[patternFromOperand(key)] = true;
|
||||
|
||||
let size = 0;
|
||||
let mask = 0;
|
||||
let bits = 0;
|
||||
let from = -1;
|
||||
|
||||
let lbit = key.startsWith("'");
|
||||
let hbit = key.endsWith("'");
|
||||
|
||||
if ((m = key.match(/\[\s*(\d+)\s*\:\s*(\d+)\s*\]$/))) {
|
||||
const a = parseInt(m[1], 10);
|
||||
const b = parseInt(m[2], 10);
|
||||
if (a < b)
|
||||
FAIL(`Invalid bit range '${key}' in opcode '${s}'`);
|
||||
from = b;
|
||||
size = a - b + 1;
|
||||
mask = ((1 << size) - 1) << b;
|
||||
key = key.substr(0, m.index).trim();
|
||||
}
|
||||
else if ((m = key.match(/\[\s*(\d+)\s*\]$/))) {
|
||||
from = parseInt(m[1], 10);
|
||||
size = 1;
|
||||
mask = 1 << from;
|
||||
key = key.substr(0, m.index).trim();
|
||||
}
|
||||
else if ((m = key.match(/\:\s*(\d+)$/))) {
|
||||
size = parseInt(m[1], 10);
|
||||
bits = size;
|
||||
key = key.substr(0, m.index).trim();
|
||||
}
|
||||
else {
|
||||
const key_ = key;
|
||||
|
||||
if (lbit || hbit) {
|
||||
from = 0;
|
||||
|
||||
if (lbit && hbit)
|
||||
FAIL(`Couldn't recognize the format of '${key}' in opcode '${s}'`);
|
||||
|
||||
if (lbit) {
|
||||
key = key.substring(1);
|
||||
}
|
||||
|
||||
if (hbit) {
|
||||
key = key.substring(0, key.length - 1);
|
||||
from = 4;
|
||||
}
|
||||
|
||||
size = 1;
|
||||
}
|
||||
else if (FieldInfo[key]) {
|
||||
// Sizes of some standard fields can be assigned automatically.
|
||||
size = FieldInfo[key].bits;
|
||||
bits = size;
|
||||
|
||||
if (fieldMap["'" + key])
|
||||
from = 1;
|
||||
}
|
||||
else if (key.length === 1) {
|
||||
// Sizes of one-letter fields (like 'U', 'F', etc...) is 1 if not specified.
|
||||
size = 1;
|
||||
bits = 1;
|
||||
}
|
||||
else {
|
||||
FAIL(`Couldn't recognize the size of '${key}' in opcode '${s}'`);
|
||||
}
|
||||
|
||||
if (dup[key_] === true) {
|
||||
bits = 0;
|
||||
lbit = 0;
|
||||
hbit = 0;
|
||||
}
|
||||
else {
|
||||
dup[key_] = true;
|
||||
}
|
||||
}
|
||||
|
||||
let field = fields[key];
|
||||
if (!field) {
|
||||
field = {
|
||||
index: opcodeIndex,
|
||||
values: [],
|
||||
bits: 0,
|
||||
mask: 0,
|
||||
lbit: 0,
|
||||
hbit: 0 // Only 1 if a single quote (') was used.
|
||||
}
|
||||
fields[key] = field;
|
||||
}
|
||||
|
||||
if (from === -1)
|
||||
from = field.bits;
|
||||
|
||||
field.mask |= mask;
|
||||
field.bits += bits;
|
||||
field.lbit += lbit;
|
||||
field.hbit += hbit;
|
||||
field.values.push({
|
||||
index: opcodeIndex,
|
||||
from: from,
|
||||
size: size
|
||||
});
|
||||
|
||||
opcodeIndex += size;
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < pattern.length; i++)
|
||||
if (pattern[i] === 'U')
|
||||
pattern[i] = "_";
|
||||
|
||||
// Normalize all fields.
|
||||
for (let key in fields) {
|
||||
const field = fields[key];
|
||||
|
||||
// There should be either number of bits or mask, there shouldn't be both.
|
||||
if (!field.bits && !field.mask)
|
||||
FAIL(`Part '${key}' of opcode '${s}' contains neither size nor mask`);
|
||||
|
||||
if (field.bits && field.mask)
|
||||
FAIL(`Part '${key}' of opcode '${s}' contains both size and mask`);
|
||||
|
||||
if (field.bits)
|
||||
field.mask = ((1 << field.bits) - 1);
|
||||
else if (field.mask)
|
||||
field.bits = 32 - Math.clz32(field.mask);
|
||||
|
||||
// Handle field that used single-quote.
|
||||
if (field.lbit) {
|
||||
field.mask = (field.mask << 1) | 0x1;
|
||||
field.bits++;
|
||||
}
|
||||
|
||||
if (field.hbit) {
|
||||
field.mask |= 1 << field.bits;
|
||||
field.bits++;
|
||||
}
|
||||
|
||||
const op = this.operandByName(key);
|
||||
if (op && op.isImm())
|
||||
op.immSize = field.bits;
|
||||
}
|
||||
|
||||
// Check if the opcode value has the correct number of bits (either 16 or 32).
|
||||
if (opcodeIndex !== 16 && opcodeIndex !== 32)
|
||||
FAIL(`The number of bits '${opcodeIndex}' used by the opcode '${s}' doesn't match 16 or 32`);
|
||||
this.opcodeValue = normalizeNumber(opcodeValue);
|
||||
}
|
||||
|
||||
_assignSpecificAttribute(key, value) {
|
||||
// Support ARMv?+ and ARMv?- attributes.
|
||||
if (/^ARM\w+[+-]$/.test(key)) {
|
||||
const armv = key.substr(0, key.length - 1);
|
||||
const sign = key.substr(key.length - 1);
|
||||
|
||||
if (sign === "+")
|
||||
this.availableFrom = armv;
|
||||
else
|
||||
this.availableUntil = armv;
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (key) {
|
||||
case "it": {
|
||||
const values = String(value).split("|");
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
const value = values[i];
|
||||
switch (value) {
|
||||
case "in" : this.it.IN = true; break;
|
||||
case "out" : this.it.OUT = true; break;
|
||||
case "any" : this.it.IN = true;
|
||||
this.it.OUT = true; break;
|
||||
case "last": this.it.LAST = true; break;
|
||||
case "def" : this.it.DEF = true; break;
|
||||
default:
|
||||
this.report(`${this.name}: Unhandled IT value '${value}'`);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// ARM instruction name could consist of name and optional type information
|
||||
// specified as <dt> and <dt2> in ARM manuals. We parse this information and
|
||||
// store it to `dt` and `dt2` fields. In addition, we also recognize the `S`
|
||||
// suffix (uppercase) of the instruction and mark it as `S` instruction. After
|
||||
// that the name is normalized to be lowercased.
|
||||
//
|
||||
// This functionality requires all the instruction data to be already set-up.
|
||||
_postProcess() {
|
||||
let s = this.name;
|
||||
|
||||
// Parse <dt> and <dt2> fields.
|
||||
if (s.indexOf(".") !== -1) {
|
||||
const parts = s.split(".");
|
||||
this.name = parts[0];
|
||||
|
||||
if (parts.length > 3)
|
||||
FAIL(`Couldn't recognize name attributes of '${s}'`);
|
||||
|
||||
for (let i = 1; i < parts.length; i++) {
|
||||
const dt = Utils.parseDtArray(parts[i]);
|
||||
if (i === 1)
|
||||
this.dt = dt;
|
||||
else
|
||||
this.dt2 = dt;
|
||||
}
|
||||
}
|
||||
|
||||
// Recognize "S" suffix.
|
||||
if (this.name.endsWith("S")) {
|
||||
this.name = this.name.substr(0, this.name.length - 1) + "s";
|
||||
this.s = true;
|
||||
}
|
||||
|
||||
this.dt.sort();
|
||||
}
|
||||
|
||||
operandByName(name) {
|
||||
const operands = this.operands;
|
||||
for (let i = 0; i < operands.length; i++) {
|
||||
const op = operands[i];
|
||||
if (op.name === name)
|
||||
return op;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
arm.Instruction = Instruction;
|
||||
|
||||
// asmdb.aarch32.ISA
|
||||
// =================
|
||||
|
||||
function mergeGroupData(data, group) {
|
||||
for (let k in group) {
|
||||
switch (k) {
|
||||
case "group":
|
||||
case "data":
|
||||
break;
|
||||
|
||||
case "ext":
|
||||
data[k] = (data[k] ? data[k] + " " : "") + group[k];
|
||||
break;
|
||||
|
||||
default:
|
||||
if (data[k] === undefined)
|
||||
data[k] = group[k]
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ISA extends base.ISA {
|
||||
constructor(data) {
|
||||
super(data);
|
||||
this.addData(data || NONE);
|
||||
}
|
||||
|
||||
_addInstructions(groups) {
|
||||
for (let group of groups) {
|
||||
for (let inst of group.data) {
|
||||
const sgn = Utils.splitInstructionSignature(inst.inst);
|
||||
const data = MapUtils.cloneExcept(inst, { "inst": true });
|
||||
|
||||
mergeGroupData(data, group)
|
||||
|
||||
for (let j = 0; j < sgn.names.length; j++) {
|
||||
data.name = sgn.names[j];
|
||||
data.operands = sgn.operands;
|
||||
if (j > 0)
|
||||
data.aliasOf = sgn.names[0];
|
||||
this._addInstruction(new Instruction(this, data));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
/*
|
||||
_addInstructions(instructions) {
|
||||
for (let i = 0; i < instructions.length; i++) {
|
||||
const obj = instructions[i];
|
||||
const sgn = obj.inst;
|
||||
const sep = sgn.indexOf(" ");
|
||||
|
||||
const names = (sep !== -1 ? sgn.substring(0, sep) : sgn).trim().split("/");
|
||||
const operands = sep !== -1 ? sgn.substring(sep + 1) : "";
|
||||
|
||||
const encoding = hasOwn.call(obj, "a32") ? "a32" :
|
||||
hasOwn.call(obj, "t32") ? "t32" :
|
||||
hasOwn.call(obj, "t16") ? "t16" : "";
|
||||
|
||||
if (!encoding)
|
||||
FAIL(`Instruction ${names.join("/")} doesn't encoding, it must provide either a32, t32, or t16 field`);
|
||||
|
||||
for (let j = 0; j < names.length; j++) {
|
||||
const inst = new Instruction(this, names[j], operands, encoding.toUpperCase(), obj[encoding], obj);
|
||||
if (j > 0)
|
||||
inst.aliasOf = names[0];
|
||||
this._addInstruction(inst);
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
*/
|
||||
}
|
||||
arm.ISA = ISA;
|
||||
|
||||
}).apply(this, typeof module === "object" && module && module.exports
|
||||
? [module, "exports"] : [this.asmdb || (this.asmdb = {}), "aarch32"]);
|
921
deps/asmjit/db/aarch64.js
vendored
Normal file
@ -0,0 +1,921 @@
|
||||
// This file is part of AsmJit project <https://asmjit.com>
|
||||
//
|
||||
// See asmjit.h or LICENSE.md for license and copyright information
|
||||
// SPDX-License-Identifier: Zlib
|
||||
|
||||
|
||||
(function($scope, $as) {
|
||||
"use strict";
|
||||
|
||||
function FAIL(msg) { throw new Error("[AArch64] " + msg); }
|
||||
|
||||
// Import
|
||||
// ======
|
||||
|
||||
const base = $scope.base ? $scope.base : require("./base.js");
|
||||
const exp = $scope.exp ? $scope.exp : require("./exp.js")
|
||||
|
||||
const hasOwn = Object.prototype.hasOwnProperty;
|
||||
const dict = base.dict;
|
||||
const NONE = base.NONE;
|
||||
const Parsing = base.Parsing;
|
||||
const MapUtils = base.MapUtils;
|
||||
|
||||
// Export
|
||||
// ======
|
||||
|
||||
const arm = $scope[$as] = dict();
|
||||
|
||||
// Database
|
||||
// ========
|
||||
|
||||
arm.dbName = "isa_aarch64.json";
|
||||
|
||||
// asmdb.aarch64.Utils
|
||||
// ===================
|
||||
|
||||
// Can be used to assign the number of bits each part of the opcode occupies.
|
||||
// NOTE: THUMB instructions that use halfword must always specify the width
|
||||
// of all registers as many instructions accept only LO (r0..r7) registers.
|
||||
const FieldInfo = {
|
||||
"P" : { "bits": 1 },
|
||||
"U" : { "bits": 1 },
|
||||
"W" : { "bits": 1 },
|
||||
"S" : { "bits": 1 },
|
||||
"R" : { "bits": 1 },
|
||||
"H" : { "bits": 1 },
|
||||
"F" : { "bits": 1 },
|
||||
"post" : { "bits": 1 },
|
||||
"!post" : { "bits": 1 },
|
||||
"op" : { "bits": 1 }, // TODO: This should be fixed.
|
||||
"s" : { "bits": 1 },
|
||||
"sz" : { "bits": 2 },
|
||||
"msz" : { "bits": 2 },
|
||||
"sop" : { "bits": 2 },
|
||||
"cond" : { "bits": 4 },
|
||||
"nzcv" : { "bits": 4 },
|
||||
"cmode" : { "bits": 4 },
|
||||
"CRn" : { "bits": 4 },
|
||||
"CRm" : { "bits": 4 },
|
||||
|
||||
"Rx" : { "bits": 5, "read": true , "write": true },
|
||||
"Rx2" : { "bits": 5, "read": true , "write": true },
|
||||
"Rdn" : { "bits": 5, "read": true , "write": true },
|
||||
"Rd" : { "bits": 5, "read": false, "write": true },
|
||||
"Rd2" : { "bits": 5, "read": false, "write": true },
|
||||
"Rs" : { "bits": 5, "read": true , "write": false },
|
||||
"Rs2" : { "bits": 5, "read": true , "write": false },
|
||||
"Rn" : { "bits": 5, "read": true , "write": false },
|
||||
"Rm" : { "bits": 5, "read": true , "write": false },
|
||||
"Ra" : { "bits": 5, "read": true , "write": false },
|
||||
"Rt" : { "bits": 5, "read": true , "write": false },
|
||||
"Rt2" : { "bits": 5, "read": true , "write": false },
|
||||
|
||||
"Wx" : { "bits": 5, "read": true , "write": true },
|
||||
"Wx2" : { "bits": 5, "read": true , "write": true },
|
||||
"Wdn" : { "bits": 5, "read": true , "write": true },
|
||||
"Wd" : { "bits": 5, "read": false, "write": true },
|
||||
"Wd2" : { "bits": 5, "read": false, "write": true },
|
||||
"Ws" : { "bits": 5, "read": true , "write": false },
|
||||
"Ws2" : { "bits": 5, "read": true , "write": false },
|
||||
"Wn" : { "bits": 5, "read": true , "write": false },
|
||||
"Wm" : { "bits": 5, "read": true , "write": false },
|
||||
"Wa" : { "bits": 5, "read": true , "write": false },
|
||||
"Wt" : { "bits": 5, "read": true , "write": false },
|
||||
"Wt2" : { "bits": 5, "read": true , "write": false },
|
||||
|
||||
"Xx" : { "bits": 5, "read": true , "write": true },
|
||||
"Xx2" : { "bits": 5, "read": true , "write": true },
|
||||
"Xdn" : { "bits": 5, "read": true , "write": true },
|
||||
"Xd" : { "bits": 5, "read": false, "write": true },
|
||||
"Xd2" : { "bits": 5, "read": false, "write": true },
|
||||
"Xs" : { "bits": 5, "read": true , "write": false },
|
||||
"Xs2" : { "bits": 5, "read": true , "write": false },
|
||||
"Xn" : { "bits": 5, "read": true , "write": false },
|
||||
"Xm" : { "bits": 5, "read": true , "write": false },
|
||||
"Xa" : { "bits": 5, "read": true , "write": false },
|
||||
"Xt" : { "bits": 5, "read": true , "write": false },
|
||||
"Xt2" : { "bits": 5, "read": true , "write": false },
|
||||
|
||||
"Bx" : { "bits": 5, "read": true , "write": true },
|
||||
"Bx2" : { "bits": 5, "read": true , "write": true },
|
||||
"Bdn" : { "bits": 5, "read": true , "write": true },
|
||||
"Bd" : { "bits": 5, "read": false, "write": true },
|
||||
"Bd2" : { "bits": 5, "read": false, "write": true },
|
||||
"Bs" : { "bits": 5, "read": true , "write": false },
|
||||
"Bs2" : { "bits": 5, "read": true , "write": false },
|
||||
"Bn" : { "bits": 5, "read": true , "write": false },
|
||||
"Bm" : { "bits": 5, "read": true , "write": false },
|
||||
"Ba" : { "bits": 5, "read": true , "write": false },
|
||||
|
||||
"Hx" : { "bits": 5, "read": true , "write": true },
|
||||
"Hx2" : { "bits": 5, "read": true , "write": true },
|
||||
"Hdn" : { "bits": 5, "read": true , "write": true },
|
||||
"Hd" : { "bits": 5, "read": false, "write": true },
|
||||
"Hd2" : { "bits": 5, "read": false, "write": true },
|
||||
"Hs" : { "bits": 5, "read": true , "write": false },
|
||||
"Hs2" : { "bits": 5, "read": true , "write": false },
|
||||
"Hn" : { "bits": 5, "read": true , "write": false },
|
||||
"Hm" : { "bits": 5, "read": true , "write": false },
|
||||
"Ha" : { "bits": 5, "read": true , "write": false },
|
||||
|
||||
"Sx" : { "bits": 5, "read": true , "write": true },
|
||||
"Sx2" : { "bits": 5, "read": true , "write": true },
|
||||
"Sdn" : { "bits": 5, "read": true , "write": true },
|
||||
"Sd" : { "bits": 5, "read": false, "write": true },
|
||||
"Sd2" : { "bits": 5, "read": false, "write": true },
|
||||
"Ss" : { "bits": 5, "read": true , "write": false },
|
||||
"Ss2" : { "bits": 5, "read": true , "write": false },
|
||||
"Sn" : { "bits": 5, "read": true , "write": false },
|
||||
"Sm" : { "bits": 5, "read": true , "write": false },
|
||||
"Sa" : { "bits": 5, "read": true , "write": false },
|
||||
|
||||
"Dx" : { "bits": 5, "read": true , "write": true },
|
||||
"Dx2" : { "bits": 5, "read": true , "write": true },
|
||||
"Ddn" : { "bits": 5, "read": true , "write": true },
|
||||
"Dd" : { "bits": 5, "read": false, "write": true },
|
||||
"Dd2" : { "bits": 5, "read": false, "write": true },
|
||||
"Ds" : { "bits": 5, "read": true , "write": false },
|
||||
"Ds2" : { "bits": 5, "read": true , "write": false },
|
||||
"Dn" : { "bits": 5, "read": true , "write": false },
|
||||
"Dn2" : { "bits": 5, "read": true , "write": false },
|
||||
"Dm" : { "bits": 5, "read": true , "write": false },
|
||||
"Da" : { "bits": 5, "read": true , "write": false },
|
||||
|
||||
"Qx" : { "bits": 5, "read": true , "write": true },
|
||||
"Qx2" : { "bits": 5, "read": true , "write": true },
|
||||
"Qdn" : { "bits": 5, "read": true , "write": true },
|
||||
"Qd" : { "bits": 5, "read": false, "write": true },
|
||||
"Qd2" : { "bits": 5, "read": false, "write": true },
|
||||
"Qs" : { "bits": 5, "read": true , "write": false },
|
||||
"Qs2" : { "bits": 5, "read": true , "write": false },
|
||||
"Qn" : { "bits": 5, "read": true , "write": false },
|
||||
"Qn2" : { "bits": 5, "read": true , "write": false },
|
||||
"Qm" : { "bits": 5, "read": true , "write": false },
|
||||
"Qa" : { "bits": 5, "read": true , "write": false },
|
||||
|
||||
"Vx" : { "bits": 5, "read": true , "write": true },
|
||||
"Vx2" : { "bits": 5, "read": true , "write": true },
|
||||
"Vdn" : { "bits": 5, "read": true , "write": true },
|
||||
"Vd" : { "bits": 5, "read": false, "write": true },
|
||||
"Vd2" : { "bits": 5, "read": false, "write": true },
|
||||
"Vs" : { "bits": 5, "read": true , "write": false },
|
||||
"Vs2" : { "bits": 5, "read": true , "write": false },
|
||||
"Vn" : { "bits": 5, "read": true , "write": false },
|
||||
"Vm" : { "bits": 5, "read": true , "write": false },
|
||||
"Va" : { "bits": 5, "read": true , "write": false },
|
||||
|
||||
"Zx" : { "bits": 5, "read": true , "write": true },
|
||||
"Zx2" : { "bits": 5, "read": true , "write": true },
|
||||
"Zda" : { "bits": 5, "read": true , "write": true },
|
||||
"Zdn" : { "bits": 5, "read": true , "write": true },
|
||||
"Zdn2" : { "bits": 5, "read": true , "write": true },
|
||||
"Zd" : { "bits": 5, "read": false, "write": true },
|
||||
"Zd2" : { "bits": 5, "read": false, "write": true },
|
||||
"Zs" : { "bits": 5, "read": true , "write": false },
|
||||
"Zs2" : { "bits": 5, "read": true , "write": false },
|
||||
"Zn" : { "bits": 5, "read": true , "write": false },
|
||||
"Zm" : { "bits": 5, "read": true , "write": false },
|
||||
"Zk" : { "bits": 5, "read": true , "write": false },
|
||||
"Za" : { "bits": 5, "read": true , "write": false },
|
||||
|
||||
"Pdn" : { "bits": 4, "read": true , "write": true },
|
||||
"Pdm" : { "bits": 4, "read": true , "write": true },
|
||||
"Pd" : { "bits": 4, "read": false, "write": true },
|
||||
"Ps" : { "bits": 4, "read": true , "write": false },
|
||||
"Pn" : { "bits": 4, "read": true , "write": false },
|
||||
"Pm" : { "bits": 4, "read": true , "write": false },
|
||||
"Pg" : { "bits": 4, "read": true , "write": false }
|
||||
};
|
||||
|
||||
arm.FieldInfo = FieldInfo;
|
||||
|
||||
// AArch64 utilities.
|
||||
class Utils {
|
||||
static splitInstructionSignature(s) {
|
||||
const names = s.match(/^[\w\|]+/)[0];
|
||||
s = s.substring(names.length);
|
||||
|
||||
const opOffset = s.indexOf(" ")
|
||||
const suffix = s.substring(0, opOffset).trim();
|
||||
const operands = opOffset === -1 ? "" : s.substring(opOffset + 1).trim();
|
||||
|
||||
return {
|
||||
names: names.split("|").map((base)=>{ return base + suffix}),
|
||||
operands: operands
|
||||
}
|
||||
}
|
||||
|
||||
static parseShiftOrExtendOp(s) {
|
||||
const space = s.indexOf(" ");
|
||||
if (space === -1)
|
||||
return "";
|
||||
|
||||
const ops = s.substring(0, space).trim();
|
||||
for (let op of ops.split("|"))
|
||||
if (!/^(sop|extend|lsl|lsr|asr|uxtw|sxtw|sxtx|mul)$/.test(op))
|
||||
return "";
|
||||
|
||||
return ops;
|
||||
}
|
||||
}
|
||||
arm.Utils = Utils;
|
||||
|
||||
function normalizeNumber(n) {
|
||||
return n < 0 ? 0x100000000 + n : n;
|
||||
}
|
||||
|
||||
function decomposeOperand(s) {
|
||||
let type = null;
|
||||
let element = null;
|
||||
let consecutive = 0;
|
||||
let maskType = "";
|
||||
|
||||
const elementM = s.match(/\[#(\w+)\]$/);
|
||||
if (elementM) {
|
||||
element = elementM[1];
|
||||
s = s.substring(0, s.length - elementM[0].length);
|
||||
}
|
||||
|
||||
const typeM = s.match(/\.(\w+)$/);
|
||||
if (typeM) {
|
||||
type = typeM[1];
|
||||
s = s.substring(0, s.length - typeM[0].length);
|
||||
}
|
||||
|
||||
const maskM = s.match(/\/(M|Z|MZ)$/);
|
||||
if (maskM) {
|
||||
maskType = maskM[1];
|
||||
s = s.substring(0, s.length - maskM[0].length);
|
||||
}
|
||||
|
||||
if (s.endsWith("++")) {
|
||||
consecutive = 2;
|
||||
s = s.substring(0, s.length - 2);
|
||||
}
|
||||
else if (s.endsWith("+")) {
|
||||
consecutive = 1;
|
||||
s = s.substring(0, s.length - 1);
|
||||
}
|
||||
|
||||
let m = s.match(/==|\!=|>=|<=|\*/);
|
||||
let restrict = false;
|
||||
|
||||
if (m) {
|
||||
restrict = s.substring(m.index);
|
||||
s = s.substring(0, m.index);
|
||||
}
|
||||
|
||||
return {
|
||||
data : s,
|
||||
maskType : maskType,
|
||||
type : type,
|
||||
element : element,
|
||||
restrict : restrict,
|
||||
consecutive: consecutive
|
||||
};
|
||||
}
|
||||
|
||||
function splitOpcodeFields(s) {
|
||||
const arr = s.split("|");
|
||||
const out = [];
|
||||
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
const val = arr[i];
|
||||
if (/^[0-1A-Z]{2,}$/.test(val))
|
||||
out.push.apply(out, val.match(/([0-1]+)|[A-Z]/g));
|
||||
else
|
||||
out.push(val);
|
||||
}
|
||||
|
||||
return out.map((field)=>{return field.trim(); });
|
||||
}
|
||||
|
||||
// asmdb.aarch64.Operand
|
||||
// =====================
|
||||
|
||||
// ARM operand.
|
||||
class Operand extends base.Operand {
|
||||
constructor(def) {
|
||||
super(def);
|
||||
|
||||
// Register.
|
||||
this.sp = ""; // GP register stack access: ["", "WSP" or "SP"].
|
||||
this.mask = ""; // Masking specifier.
|
||||
}
|
||||
|
||||
hasMemModes() {
|
||||
return Object.keys(this.memModes).length !== 0;
|
||||
}
|
||||
|
||||
get name() {
|
||||
switch (this.type) {
|
||||
case "reg": return this.reg;
|
||||
case "mem": return this.mem;
|
||||
case "imm": return this.imm;
|
||||
case "rel": return this.rel;
|
||||
default : return "";
|
||||
}
|
||||
}
|
||||
|
||||
get scale() {
|
||||
if (this.restrict && this.restrict.startsWith("*"))
|
||||
return parseInt(this.restrict.substring(1), 10);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
arm.Operand = Operand;
|
||||
|
||||
// asmdb.aarch64.Instruction
|
||||
// =========================
|
||||
|
||||
function patternFromOperand(key) { return key; }
|
||||
|
||||
// ARM instruction.
|
||||
class Instruction extends base.Instruction {
|
||||
constructor(db, data) {
|
||||
super(db, data);
|
||||
|
||||
this.name = data.name;
|
||||
this.it = dict(); // THUMB's 'it' flags.
|
||||
this.apsr = dict();
|
||||
this.fpcsr = dict();
|
||||
this.calc = dict(); // Calculations required to generate opcode.
|
||||
this.immCond = []; // Immediate value conditions (array of conditions).
|
||||
|
||||
this._assignOperands(data.operands);
|
||||
this._assignOpcode(data.op);
|
||||
|
||||
for (let k in data) {
|
||||
if (k === "name" || k == "op" || k === "operands")
|
||||
continue;
|
||||
this._assignAttribute(k, data[k]);
|
||||
}
|
||||
|
||||
this._updateOperandsInfo();
|
||||
this._postProcess();
|
||||
}
|
||||
|
||||
_assignAttribute(key, value) {
|
||||
switch (key) {
|
||||
case "it":
|
||||
for (let it of value.split(" "))
|
||||
this.it[it.trim()] = true;
|
||||
break;
|
||||
|
||||
case "apsr":
|
||||
case "fpcsr":
|
||||
this._assignAttributeKeyValue(key, value);
|
||||
break;
|
||||
|
||||
case "imm":
|
||||
this.imm = exp.parse(value);
|
||||
break;
|
||||
|
||||
case "calc":
|
||||
for (let calcKey in value)
|
||||
this.calc[calcKey] = exp.parse(value[calcKey]);
|
||||
break;
|
||||
|
||||
default:
|
||||
super._assignAttribute(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
_assignAttributeKeyValue(name, content) {
|
||||
const attributes = content.trim().split(/[ ]+/);
|
||||
|
||||
for (let i = 0; i < attributes.length; i++) {
|
||||
const attr = attributes[i].trim();
|
||||
if (!attr)
|
||||
continue;
|
||||
|
||||
const eq = attr.indexOf("=");
|
||||
let key = eq === -1 ? attr : attr.substring(0, eq);
|
||||
let val = eq === -1 ? true : attr.substring(eq + 1);
|
||||
|
||||
// If the key contains "|" it's a definition of multiple attributes.
|
||||
if (key.indexOf("|") !== -1) {
|
||||
const dot = key.indexOf(".");
|
||||
|
||||
const base = dot === -1 ? "" : key.substring(0, dot + 1);
|
||||
const keys = (dot === -1 ? key : key.substring(dot + 1)).split("|");
|
||||
|
||||
for (let j = 0; j < keys.length; j++)
|
||||
this[name][base + keys[j]] = val;
|
||||
}
|
||||
else {
|
||||
this[name][key] = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_assignOperands(s) {
|
||||
if (!s) return;
|
||||
|
||||
// Split into individual operands and push them to `operands`.
|
||||
const arr = base.Parsing.splitOperands(s);
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
let def = arr[i].trim();
|
||||
const op = new Operand(def);
|
||||
|
||||
const sp = def.match(/^(\w+)\|(SP|WSP)$/);
|
||||
if (sp) {
|
||||
def = sp[1];
|
||||
op.sp = sp[2];
|
||||
}
|
||||
|
||||
const consecutive = def.match(/(\d+)x\{(.*)\}([+]?[+]?)/);
|
||||
if (consecutive)
|
||||
def = consecutive[2];
|
||||
|
||||
op.sign = false;
|
||||
op.element = null;
|
||||
op.shiftOp = "";
|
||||
op.shiftImm = null;
|
||||
op.shiftCond = "";
|
||||
|
||||
// Handle {optional} attribute.
|
||||
if (Parsing.isOptional(def)) {
|
||||
op.optional = true;
|
||||
def = Parsing.clearOptional(def);
|
||||
}
|
||||
|
||||
// Handle commutativity <-> symbol.
|
||||
if (Parsing.isCommutative(def)) {
|
||||
op.commutative = true;
|
||||
def = Parsing.clearCommutative(def);
|
||||
}
|
||||
|
||||
// Handle shift operation.
|
||||
let shiftOp = Utils.parseShiftOrExtendOp(def);
|
||||
if (shiftOp) {
|
||||
op.shiftOp = shiftOp;
|
||||
def = def.substring(shiftOp.length + 1);
|
||||
}
|
||||
|
||||
if (def.startsWith("[")) {
|
||||
op.type = "mem";
|
||||
op.memModes = dict();
|
||||
|
||||
op.base = null;
|
||||
op.index = null;
|
||||
op.offset = null;
|
||||
|
||||
let mem = def;
|
||||
let didHaveMemMode = false;
|
||||
|
||||
for (;;) {
|
||||
if (mem.endsWith("!")) {
|
||||
op.memModes.preIndex = true;
|
||||
mem = mem.substring(0, mem.length - 1);
|
||||
|
||||
didHaveMemMode = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (mem.endsWith("@")) {
|
||||
op.memModes.postIndex = true;
|
||||
mem = mem.substring(0, mem.length - 1);
|
||||
|
||||
didHaveMemMode = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (mem.endsWith("{!}")) {
|
||||
op.memModes.offset = true;
|
||||
op.memModes.preIndex = true;
|
||||
mem = mem.substring(0, mem.length - 3);
|
||||
|
||||
didHaveMemMode = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mem.endsWith("{@}")) {
|
||||
op.memModes.offset = true;
|
||||
op.memModes.postIndex = true;
|
||||
mem = mem.substring(0, mem.length - 3);
|
||||
|
||||
didHaveMemMode = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (!mem.endsWith("]"))
|
||||
FAIL(`Unknown memory operand '${mem}' in '${def}'`);
|
||||
|
||||
let parts = mem.substring(1, mem.length - 1).split(",").map(function(s) { return s.trim() });
|
||||
for (let i = 0; i < parts.length; i++) {
|
||||
const part = parts[i];
|
||||
|
||||
const m = part.match(/^\{(([a-z]+)(\|[a-z]+)*)\s+#(\w+)\s*(\*\s*\d+\s*)?\}$/);
|
||||
if (m) {
|
||||
op.shiftOp = m[1];
|
||||
op.shiftImm = m[2];
|
||||
if (m[3])
|
||||
op.shiftCond = m[3]
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i === 0) {
|
||||
op.base = dict();
|
||||
op.base.field = part;
|
||||
op.base.exp = null;
|
||||
|
||||
const m = part.match(/^([A-Za-z]\w*(?:\.\w+)?)/);
|
||||
if (m && m[1].length < part.length) {
|
||||
op.base.exp = exp.parse(part);
|
||||
op.base.field = m[1];
|
||||
}
|
||||
}
|
||||
else if (part.startsWith("#")) {
|
||||
let p = part.substring(1);
|
||||
let u = "1";
|
||||
|
||||
let offExp = null;
|
||||
let offMul = 1;
|
||||
|
||||
if (p.startsWith("+/-")) {
|
||||
u = "U";
|
||||
p = p.substring(3);
|
||||
}
|
||||
|
||||
const expMatch = p.match(/^([A-Za-z]\w*)==/);
|
||||
if (expMatch) {
|
||||
offExp = exp.parse(p);
|
||||
p = p.substring(0, expMatch[1].length);
|
||||
}
|
||||
|
||||
const mulMatch = p.match(/\s*\*\s*(\d+)$/);
|
||||
if (mulMatch) {
|
||||
offMul = parseInt(mulMatch[1]);
|
||||
p = p.substring(0, mulMatch.index);
|
||||
}
|
||||
|
||||
op.offset = dict();
|
||||
op.offset.field = p;
|
||||
op.offset.u = u;
|
||||
op.offset.exp = offExp;
|
||||
op.offset.mul = offMul;
|
||||
}
|
||||
else {
|
||||
let p = part;
|
||||
let u = "1";
|
||||
|
||||
if (p.startsWith("+/-")) {
|
||||
u = "U";
|
||||
p = p.substring(3);
|
||||
}
|
||||
|
||||
op.index = dict();
|
||||
op.index.field = p;
|
||||
op.index.u = u;
|
||||
|
||||
const m = p.match(/^([A-Za-z\|]\w*(?:\.\w+)?)/);
|
||||
if (m && m[1].length < p.length) {
|
||||
op.index.exp = exp.parse(p);
|
||||
op.index.field = m[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!op.hasMemModes() && (op.offset || op.index))
|
||||
op.memModes.offset = true;
|
||||
|
||||
op.mem = mem;
|
||||
}
|
||||
else if (def.startsWith("#")) {
|
||||
const obj = decomposeOperand(def);
|
||||
const imm = obj.data;
|
||||
|
||||
op.type = "imm";
|
||||
op.imm = imm.substring(1); // Immediate operand name.
|
||||
op.immSize = 0; // Immediate size in bits.
|
||||
op.restrict = obj.restrict; // Immediate condition.
|
||||
}
|
||||
else {
|
||||
// Some instructions use Reg! to specify that the register increments.
|
||||
if (def.endsWith("!")) {
|
||||
def = def.substring(0, def.length - 1)
|
||||
op.regInc = true
|
||||
}
|
||||
|
||||
const obj = decomposeOperand(def);
|
||||
const reg = obj.data;
|
||||
|
||||
const type = reg.substring(0, 1).toLowerCase();
|
||||
const info = FieldInfo[reg];
|
||||
|
||||
if (!info)
|
||||
FAIL(`Unknown register operand '${reg}' in '${def}'`);
|
||||
|
||||
op.type = info.list ? "reg-list" : "reg";
|
||||
op.reg = reg; // Register name (as specified in manual).
|
||||
op.regType = type; // Register type.
|
||||
op.regList = !!info.list; // Register list.
|
||||
op.maskType = obj.maskType; // Mask type.
|
||||
op.elementType = obj.type // Element type or t, ta, tb.
|
||||
op.read = info.read; // Register access (read).
|
||||
op.write = info.write; // Register access (write).
|
||||
op.element = obj.element; // Register element[] access.
|
||||
op.restrict = obj.restrict; // Register condition.
|
||||
op.consecutive = obj.consecutive;
|
||||
}
|
||||
|
||||
this.operands.push(op);
|
||||
|
||||
if (consecutive) {
|
||||
const count = parseInt(consecutive[1]);
|
||||
for (let n = 2; n <= count; n++) {
|
||||
const def = consecutive[3].replace(op.reg, op.reg + n);
|
||||
const opN = new Operand(def);
|
||||
opN.type = "reg";
|
||||
opN.reg = op.reg + n;
|
||||
opN.regType = op.regType;
|
||||
opN.read = op.read;
|
||||
opN.write = op.write;
|
||||
opN.element = op.element;
|
||||
opN.consecutive = consecutive[3].length;
|
||||
opN.artificial = true;
|
||||
this.operands.push(opN);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_assignOpcode(s) {
|
||||
this.opcodeString = s;
|
||||
|
||||
let opcodeIndex = 0;
|
||||
let opcodeValue = 0;
|
||||
|
||||
let patternMap = {};
|
||||
|
||||
// Split opcode into its fields.
|
||||
const arr = splitOpcodeFields(s);
|
||||
const dup = dict();
|
||||
|
||||
const fields = this.fields;
|
||||
const pattern = [];
|
||||
|
||||
const fieldMap = Object.create(null);
|
||||
for (let field of arr) {
|
||||
fieldMap[field] = true;
|
||||
}
|
||||
|
||||
for (let i = arr.length - 1; i >= 0; i--) {
|
||||
let key = arr[i].trim();
|
||||
let m;
|
||||
|
||||
if (/^[0-1]+$/.test(key)) {
|
||||
// This part of the opcode is RAW bits, they contribute to the `opcodeValue`.
|
||||
opcodeValue |= parseInt(key, 2) << opcodeIndex;
|
||||
opcodeIndex += key.length;
|
||||
pattern.unshift("_".repeat(key.length));
|
||||
}
|
||||
else {
|
||||
pattern.unshift(patternFromOperand(key));
|
||||
patternMap[patternFromOperand(key)] = true;
|
||||
|
||||
let size = 0;
|
||||
let mask = 0;
|
||||
let bits = 0;
|
||||
let from = -1;
|
||||
|
||||
let lbit = key.startsWith("'");
|
||||
let hbit = key.endsWith("'");
|
||||
|
||||
if ((m = key.match(/\[\s*(\d+)\s*\:\s*(\d+)\s*\]$/))) {
|
||||
const a = parseInt(m[1], 10);
|
||||
const b = parseInt(m[2], 10);
|
||||
if (a < b)
|
||||
FAIL(`Invalid bit range '${key}' in opcode '${s}'`);
|
||||
from = b;
|
||||
size = a - b + 1;
|
||||
mask = ((1 << size) - 1) << b;
|
||||
key = key.substring(0, m.index).trim();
|
||||
}
|
||||
else if ((m = key.match(/\[\s*(\d+)\s*\]$/))) {
|
||||
from = parseInt(m[1], 10);
|
||||
size = 1;
|
||||
mask = 1 << from;
|
||||
key = key.substring(0, m.index).trim();
|
||||
}
|
||||
else if ((m = key.match(/\:\s*(\d+)$/))) {
|
||||
size = parseInt(m[1], 10);
|
||||
bits = size;
|
||||
key = key.substring(0, m.index).trim();
|
||||
}
|
||||
else {
|
||||
const key_ = key;
|
||||
|
||||
if (lbit || hbit) {
|
||||
from = 0;
|
||||
|
||||
if (lbit && hbit)
|
||||
FAIL(`Couldn't recognize the format of '${key}' in opcode '${s}'`);
|
||||
|
||||
if (lbit) {
|
||||
key = key.substring(1);
|
||||
}
|
||||
|
||||
if (hbit) {
|
||||
key = key.substring(0, key.length - 1);
|
||||
from = 4;
|
||||
}
|
||||
|
||||
size = 1;
|
||||
}
|
||||
else if (FieldInfo[key]) {
|
||||
// Sizes of some standard fields can be assigned automatically.
|
||||
size = FieldInfo[key].bits;
|
||||
bits = size;
|
||||
|
||||
if (fieldMap["'" + key])
|
||||
from = 1;
|
||||
}
|
||||
else if (key.length === 1) {
|
||||
// Sizes of one-letter fields (like 'U', 'F', etc...) is 1 if not specified.
|
||||
size = 1;
|
||||
bits = 1;
|
||||
}
|
||||
else {
|
||||
FAIL(`Couldn't recognize the size of '${key}' in opcode '${s}'`);
|
||||
}
|
||||
|
||||
if (dup[key_] === true) {
|
||||
bits = 0;
|
||||
lbit = 0;
|
||||
hbit = 0;
|
||||
}
|
||||
else {
|
||||
dup[key_] = true;
|
||||
}
|
||||
}
|
||||
|
||||
let field = fields[key];
|
||||
if (!field) {
|
||||
field = {
|
||||
index: opcodeIndex,
|
||||
values: [],
|
||||
bits: 0,
|
||||
mask: 0,
|
||||
lbit: 0,
|
||||
hbit: 0 // Only 1 if a single quote (') was used.
|
||||
}
|
||||
fields[key] = field;
|
||||
}
|
||||
|
||||
if (from === -1)
|
||||
from = field.bits;
|
||||
|
||||
field.mask |= mask;
|
||||
field.bits += bits;
|
||||
field.lbit += lbit;
|
||||
field.hbit += hbit;
|
||||
field.values.push({
|
||||
index: opcodeIndex,
|
||||
from: from,
|
||||
size: size
|
||||
});
|
||||
|
||||
opcodeIndex += size;
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < pattern.length; i++)
|
||||
if (pattern[i] === 'U')
|
||||
pattern[i] = "_";
|
||||
|
||||
// Normalize all fields.
|
||||
for (let key in fields) {
|
||||
const field = fields[key];
|
||||
|
||||
// There should be either number of bits or mask, there shouldn't be both.
|
||||
if (!field.bits && !field.mask)
|
||||
FAIL(`Part '${key}' of opcode '${s}' contains neither size nor mask`);
|
||||
|
||||
if (field.bits && field.mask)
|
||||
FAIL(`Part '${key}' of opcode '${s}' contains both size and mask`);
|
||||
|
||||
if (field.bits)
|
||||
field.mask = ((1 << field.bits) - 1);
|
||||
else if (field.mask)
|
||||
field.bits = 32 - Math.clz32(field.mask);
|
||||
|
||||
// Handle field that used single-quote.
|
||||
if (field.lbit) {
|
||||
field.mask = (field.mask << 1) | 0x1;
|
||||
field.bits++;
|
||||
}
|
||||
|
||||
if (field.hbit) {
|
||||
field.mask |= 1 << field.bits;
|
||||
field.bits++;
|
||||
}
|
||||
|
||||
const op = this.operandByName(key);
|
||||
if (op && op.isImm())
|
||||
op.immSize = field.bits;
|
||||
}
|
||||
|
||||
// Check if the opcode value has the correct number of bits.
|
||||
if (opcodeIndex !== 32)
|
||||
FAIL(`The number of bits '${opcodeIndex}' used by the opcode '${s}' doesn't match 32`);
|
||||
this.opcodeValue = normalizeNumber(opcodeValue);
|
||||
}
|
||||
|
||||
_assignSpecificAttribute(key, value) {
|
||||
switch (key) {
|
||||
case "it": {
|
||||
const values = String(value).split("|");
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
const value = values[i];
|
||||
switch (value) {
|
||||
case "in" : this.it.IN = true; break;
|
||||
case "out" : this.it.OUT = true; break;
|
||||
case "any" : this.it.IN = true;
|
||||
this.it.OUT = true; break;
|
||||
case "last": this.it.LAST = true; break;
|
||||
case "def" : this.it.DEF = true; break;
|
||||
default:
|
||||
this.report(`${this.name}: Unhandled IT value '${value}'`);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
_postProcess() {}
|
||||
|
||||
operandByName(name) {
|
||||
const operands = this.operands;
|
||||
for (let i = 0; i < operands.length; i++) {
|
||||
const op = operands[i];
|
||||
if (op.name === name)
|
||||
return op;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
arm.Instruction = Instruction;
|
||||
|
||||
// asmdb.aarch64.ISA
|
||||
// =================
|
||||
|
||||
function mergeGroupData(data, group) {
|
||||
for (let k in group) {
|
||||
switch (k) {
|
||||
case "group":
|
||||
case "data":
|
||||
break;
|
||||
|
||||
case "ext":
|
||||
data[k] = (data[k] ? data[k] + " " : "") + group[k];
|
||||
break;
|
||||
|
||||
default:
|
||||
if (data[k] === undefined)
|
||||
data[k] = group[k]
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ISA extends base.ISA {
|
||||
constructor(data) {
|
||||
super(data);
|
||||
this.addData(data || NONE);
|
||||
}
|
||||
|
||||
_addInstructions(groups) {
|
||||
for (let group of groups) {
|
||||
for (let inst of group.data) {
|
||||
const sgn = Utils.splitInstructionSignature(inst.inst);
|
||||
const data = MapUtils.cloneExcept(inst, { "inst": true });
|
||||
|
||||
mergeGroupData(data, group)
|
||||
|
||||
for (let j = 0; j < sgn.names.length; j++) {
|
||||
data.name = sgn.names[j];
|
||||
data.operands = sgn.operands;
|
||||
if (j > 0)
|
||||
data.aliasOf = sgn.names[0];
|
||||
this._addInstruction(new Instruction(this, data));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
arm.ISA = ISA;
|
||||
|
||||
}).apply(this, typeof module === "object" && module && module.exports
|
||||
? [module, "exports"] : [this.asmdb || (this.asmdb = {}), "aarch64"]);
|
659
deps/asmjit/db/base.js
vendored
Normal file
@ -0,0 +1,659 @@
|
||||
// This file is part of AsmJit project <https://asmjit.com>
|
||||
//
|
||||
// See asmjit.h or LICENSE.md for license and copyright information
|
||||
// SPDX-License-Identifier: Zlib
|
||||
|
||||
(function($scope, $as) {
|
||||
"use strict";
|
||||
|
||||
function FAIL(msg) { throw new Error("[BASE] " + msg); }
|
||||
|
||||
// Import.
|
||||
const hasOwn = Object.prototype.hasOwnProperty;
|
||||
|
||||
const exp = $scope.exp ? $scope.exp : require("./exp.js");
|
||||
|
||||
|
||||
// Export.
|
||||
const base = $scope[$as] = Object.create(null);
|
||||
|
||||
base.exp = exp;
|
||||
|
||||
function dict(src) {
|
||||
const dst = Object.create(null);
|
||||
if (src)
|
||||
Object.assign(dst, src);
|
||||
return dst;
|
||||
}
|
||||
base.dict = dict;
|
||||
const NONE = base.NONE = Object.freeze(dict());
|
||||
|
||||
// asmdb.base.Symbols
|
||||
// ==================
|
||||
|
||||
const Symbols = Object.freeze({
|
||||
Commutative: '~'
|
||||
});
|
||||
base.Symbols = Symbols;
|
||||
|
||||
// asmdb.base.Parsing
|
||||
// ==================
|
||||
|
||||
// Namespace that provides functions related to text parsing.
|
||||
const Parsing = {
|
||||
// Get whether the string `s` representing an operand is <implicit>.
|
||||
isImplicit: function(s) { return s.startsWith("<") && s.endsWith(">"); },
|
||||
|
||||
// Clear <implicit> attribute from the given operand string `s`.
|
||||
clearImplicit: function(s) { return s.substring(1, s.length - 1); },
|
||||
|
||||
// Get whether the string `s` representing an operand is {optional}.
|
||||
isOptional: function(s) { return s.startsWith("{") && s.endsWith("}"); },
|
||||
|
||||
// Clear {optional} attribute from the given operand string `s`.
|
||||
clearOptional: function(s) { return s.substring(1, s.length - 1); },
|
||||
|
||||
// Get whether the string `s` representing an operand specifies commutativity.
|
||||
isCommutative: function(s) { return s.length > 0 && s.charAt(0) === Symbols.Commutative; },
|
||||
|
||||
// Clear commutative attribute from the given operand string `s`.
|
||||
clearCommutative: function(s) { return s.substring(1); },
|
||||
|
||||
// Matches a closing bracket in string `s` starting `from` the given index.
|
||||
// It behaves like `s.indexOf()`, but uses a counter and skips all nested
|
||||
// matches.
|
||||
matchClosingChar: function(s, from) {
|
||||
const len = s.length;
|
||||
const opening = s.charCodeAt(from);
|
||||
const closing = opening === 40 ? 31 : // ().
|
||||
opening === 60 ? 62 : // <>.
|
||||
opening === 91 ? 93 : // [].
|
||||
opening === 123 ? 125 : 0; // {}.
|
||||
|
||||
let i = from;
|
||||
let pending = 1;
|
||||
do {
|
||||
if (++i >= len)
|
||||
break;
|
||||
|
||||
const c = s.charCodeAt(i);
|
||||
pending += Number(c === opening);
|
||||
pending -= Number(c === closing);
|
||||
} while (pending);
|
||||
|
||||
return i;
|
||||
},
|
||||
|
||||
// Split instruction operands into an array containing each operand as a
|
||||
// trimmed string. This function is similar to `s.split(",")`, however,
|
||||
// it matches brackets inside the operands and won't just blindly split
|
||||
// the string based on "," token. If operand contains metadata or it's
|
||||
// an address it would still be split correctly.
|
||||
splitOperands: function(s) {
|
||||
const result = [];
|
||||
|
||||
s = s.trim();
|
||||
if (!s)
|
||||
return result;
|
||||
|
||||
let start = 0;
|
||||
let i = 0;
|
||||
let c = "";
|
||||
|
||||
for (;;) {
|
||||
if (i === s.length || (c = s[i]) === ",") {
|
||||
const op = s.substring(start, i).trim();
|
||||
if (!op)
|
||||
FAIL(`Found empty operand in '${s}'`);
|
||||
|
||||
result.push(op);
|
||||
if (i === s.length)
|
||||
return result;
|
||||
|
||||
start = ++i;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((c === "<" || c === ">") && i != start) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c === "[" || c === "{" || c === "(" || c === "<")
|
||||
i = base.Parsing.matchClosingChar(s, i);
|
||||
else
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
base.Parsing = Parsing;
|
||||
|
||||
// asmdb.base.MapUtils
|
||||
// ===================
|
||||
|
||||
const MapUtils = {
|
||||
cloneExcept(map, except) {
|
||||
const out = Object.create(null);
|
||||
for (let k in map) {
|
||||
if (k in except)
|
||||
continue
|
||||
out[k] = map[k];
|
||||
}
|
||||
return out;
|
||||
}
|
||||
};
|
||||
base.MapUtils = MapUtils;
|
||||
|
||||
// asmdb.base.Operand
|
||||
// ==================
|
||||
|
||||
const OperandFlags = Object.freeze({
|
||||
Optional : 0x00000001,
|
||||
Implicit : 0x00000002,
|
||||
Commutative: 0x00000004,
|
||||
ZExt : 0x00000008,
|
||||
ReadAccess : 0x00000010,
|
||||
WriteAccess: 0x00000020
|
||||
});
|
||||
base.OperandFlags = OperandFlags;
|
||||
|
||||
class Operand {
|
||||
constructor(data) {
|
||||
this.type = ""; // Type of the operand ("reg", "reg-list", "mem", "reg/mem", "imm", "rel").
|
||||
this.data = data; // The operand's data (possibly processed).
|
||||
this.flags = 0;
|
||||
|
||||
this.reg = ""; // Register operand's definition.
|
||||
this.mem = ""; // Memory operand's definition.
|
||||
this.imm = 0; // Immediate operand's size.
|
||||
this.rel = 0; // Relative displacement operand's size.
|
||||
|
||||
this.restrict = ""; // Operand is restricted (specific register or immediate value).
|
||||
this.read = false; // True if the operand is a read-op from reg/mem.
|
||||
this.write = false; // True if the operand is a write-op to reg/mem.
|
||||
|
||||
this.regType = ""; // Register operand's type.
|
||||
this.regIndexRel = 0; // Register index is relative to the previous register operand index (0 if not).
|
||||
this.memSize = -1; // Memory operand's size.
|
||||
this.immSign = ""; // Immediate sign (any / signed / unsigned).
|
||||
this.immValue = null; // Immediate value - `null` or `1` (only used by shift/rotate instructions).
|
||||
|
||||
this.rwxIndex = -1; // Read/Write (RWX) index.
|
||||
this.rwxWidth = -1; // Read/Write (RWX) width.
|
||||
}
|
||||
|
||||
_getFlag(flag) {
|
||||
return (this.flags & flag) != 0;
|
||||
}
|
||||
|
||||
_setFlag(flag, value) {
|
||||
this.flags = (this.flags & ~flag) | (value ? flag : 0);
|
||||
return this;
|
||||
}
|
||||
|
||||
get optional() { return this._getFlag(OperandFlags.Optional); }
|
||||
set optional(value) { this._setFlag(OperandFlags.Optional, value); }
|
||||
|
||||
get implicit() { return this._getFlag(OperandFlags.Implicit); }
|
||||
set implicit(value) { this._setFlag(OperandFlags.Implicit, value); }
|
||||
|
||||
get commutative() { return this._getFlag(OperandFlags.Commutative); }
|
||||
set commutative(value) { this._setFlag(OperandFlags.Commutative, value); }
|
||||
|
||||
get zext() { return this._getFlag(OperandFlags.ZExt); }
|
||||
set zext(value) { this._setFlag(OperandFlags.ZExt, value); }
|
||||
|
||||
toString() { return this.data; }
|
||||
|
||||
isReg() { return !!this.reg && this.type !== "reg-list"; }
|
||||
isMem() { return !!this.mem; }
|
||||
isImm() { return !!this.imm; }
|
||||
isRel() { return !!this.rel; }
|
||||
|
||||
isRegMem() { return this.reg && this.mem; }
|
||||
isRegOrMem() { return !!this.reg || !!this.mem; }
|
||||
|
||||
isRegList() { return this.type === "reg-list" }
|
||||
isPartialOp() { return false; }
|
||||
}
|
||||
base.Operand = Operand;
|
||||
|
||||
// asmdb.base.Instruction
|
||||
// ======================
|
||||
|
||||
// Defines interface and properties that each architecture dependent instruction
|
||||
// must provide even if that particular architecture doesn't use that feature(s).
|
||||
class Instruction {
|
||||
constructor(db) {
|
||||
Object.defineProperty(this, "db", { value: db });
|
||||
|
||||
this.name = ""; // Instruction name.
|
||||
this.arch = "ANY"; // Architecture.
|
||||
this.encoding = ""; // Encoding type.
|
||||
this.operands = []; // Instruction operands.
|
||||
|
||||
this.implicit = 0; // Indexes of all implicit operands (registers / memory).
|
||||
this.commutative = 0; // Indexes of all commutative operands.
|
||||
|
||||
this.opcodeString = ""; // Instruction opcode as specified in manual.
|
||||
this.opcodeValue = 0; // Instruction opcode as number (arch dependent).
|
||||
this.fields = dict(); // Information about each opcode field (arch dependent).
|
||||
this.operations = dict(); // Operations the instruction performs.
|
||||
|
||||
this.io = dict(); // Instruction input / output (CPU flags, states, and other registers).
|
||||
this.ext = dict(); // ISA extensions required by the instruction.
|
||||
this.category = dict(); // Instruction categories.
|
||||
|
||||
this.specialRegs = dict(); // Information about read/write to special registers.
|
||||
|
||||
this.altForm = false; // This is an alternative form, not needed to create a signature.
|
||||
this.volatile = false; // Instruction is volatile and should not be reordered.
|
||||
this.control = "none"; // Control flow type (none by default).
|
||||
this.privilege = ""; // Privilege-level required to execute the instruction.
|
||||
this.aliasOf = ""; // Instruction is an alias of another instruction
|
||||
}
|
||||
|
||||
get extArray() {
|
||||
const out = Object.keys(this.ext);
|
||||
out.sort();
|
||||
return out;
|
||||
}
|
||||
|
||||
get operandCount() {
|
||||
return this.operands.length;
|
||||
}
|
||||
|
||||
get minimumOperandCount() {
|
||||
const count = this.operands.length;
|
||||
for (let i = 0; i < count; i++) {
|
||||
if (this.operands[i].optional) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
_assignAttribute(key, value) {
|
||||
switch (key) {
|
||||
case "ext":
|
||||
case "io":
|
||||
case "category":
|
||||
return this._combineAttribute(key, value);
|
||||
|
||||
default:
|
||||
if (typeof this[key] === undefined)
|
||||
FAIL(`Cannot assign ${key}=${value}`);
|
||||
this[key] = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_combineAttribute(key, value) {
|
||||
if (typeof value === "string")
|
||||
value = value.split(" ");
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
for (let v of value) {
|
||||
let pKeys = v;
|
||||
let pValue = true;
|
||||
|
||||
const i = v.indexOf("=");
|
||||
if (i !== -1) {
|
||||
pValue = v.substring(i + 1);
|
||||
pKeys = v.substring(0, i).trim();
|
||||
}
|
||||
|
||||
for (let pk of pKeys.trim().split("|").map(function(s) { return s.trim(); })) {
|
||||
this[key][pk] = pValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (let k in value)
|
||||
this[key][k] = value[k];
|
||||
}
|
||||
}
|
||||
|
||||
_updateOperandsInfo() {
|
||||
this.implicit = 0;
|
||||
this.commutative = 0;
|
||||
|
||||
for (let i = 0; i < this.operands.length; i++) {
|
||||
const op = this.operands[i];
|
||||
|
||||
if (op.implicit) this.implicit |= (1 << i);
|
||||
if (op.commutative) this.commutative |= (1 << i);
|
||||
}
|
||||
}
|
||||
|
||||
isAlias() { return !!this.aliasOf; }
|
||||
isCommutative() { return this.commutative !== 0; }
|
||||
|
||||
hasImplicit() { return this.implicit !== 0; }
|
||||
|
||||
hasAttribute(name, matchValue) {
|
||||
const value = this[name];
|
||||
if (value === undefined)
|
||||
return false;
|
||||
|
||||
if (matchValue === undefined)
|
||||
return true;
|
||||
|
||||
return value === matchValue;
|
||||
}
|
||||
|
||||
report(msg) {
|
||||
console.log(`${this}: ${msg}`);
|
||||
}
|
||||
|
||||
toString() {
|
||||
return `${this.name} ${this.operands.join(", ")}`;
|
||||
}
|
||||
}
|
||||
base.Instruction = Instruction;
|
||||
|
||||
// asmdb.base.InstructionGroup
|
||||
// ===========================
|
||||
|
||||
// Instruction group is simply array of function that has some additional
|
||||
// functionality.
|
||||
class InstructionGroup extends Array {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
if (arguments.length === 1) {
|
||||
const a = arguments[0];
|
||||
if (Array.isArray(a)) {
|
||||
for (let i = 0; i < a.length; i++)
|
||||
this.push(a[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unionCpuFeatures(name) {
|
||||
const result = dict();
|
||||
for (let i = 0; i < this.length; i++) {
|
||||
const inst = this[i];
|
||||
const features = inst.ext;
|
||||
for (let k in features)
|
||||
result[k] = features[k];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
checkAttribute(key, value) {
|
||||
let n = 0;
|
||||
for (let i = 0; i < this.length; i++)
|
||||
n += Number(this[i][key] === value);
|
||||
return n;
|
||||
}
|
||||
}
|
||||
base.InstructionGroup = InstructionGroup;
|
||||
|
||||
const EmptyInstructionGroup = Object.freeze(new InstructionGroup());
|
||||
|
||||
// asmdb.base.ISA
|
||||
// ==============
|
||||
|
||||
class ISA {
|
||||
constructor() {
|
||||
this._instructions = null; // Instruction array (contains all instructions).
|
||||
this._instructionNames = null; // Instruction names (sorted), regenerated when needed.
|
||||
this._instructionMap = dict(); // Instruction name to `Instruction[]` mapping.
|
||||
this._aliases = dict(); // Instruction aliases.
|
||||
this._cpuLevels = dict(); // Architecture versions.
|
||||
this._extensions = dict(); // Architecture extensions.
|
||||
this._attributes = dict(); // Instruction attributes.
|
||||
this._specialRegs = dict(); // Special registers.
|
||||
this._shortcuts = dict(); // Shortcuts used by instructions metadata.
|
||||
this.stats = {
|
||||
insts : 0, // Number of all instructions.
|
||||
groups: 0 // Number of grouped instructions (having unique name).
|
||||
};
|
||||
}
|
||||
|
||||
get instructions() {
|
||||
let array = this._instructions;
|
||||
if (array === null) {
|
||||
array = [];
|
||||
const map = this.instructionMap;
|
||||
const names = this.instructionNames;
|
||||
for (let i = 0; i < names.length; i++)
|
||||
array.push.apply(array, map[names[i]]);
|
||||
this._instructions = array;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
get instructionNames() {
|
||||
let names = this._instructionNames;
|
||||
if (names === null) {
|
||||
names = Object.keys(this._instructionMap);
|
||||
names.sort();
|
||||
this._instructionNames = names;
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
get instructionMap() { return this._instructionMap; }
|
||||
get aliases() { return this._aliases; }
|
||||
get cpuLevels() { return this._cpuLevels; }
|
||||
get extensions() { return this._extensions; }
|
||||
get attributes() { return this._attributes; }
|
||||
get specialRegs() { return this._specialRegs; }
|
||||
get shortcuts() { return this._shortcuts; }
|
||||
|
||||
query(args, copy) {
|
||||
if (typeof args !== "object" || !args || Array.isArray(args))
|
||||
return this._queryByName(args, copy);
|
||||
|
||||
const filter = args.filter;
|
||||
if (filter)
|
||||
copy = false;
|
||||
|
||||
let result = this._queryByName(args.name, copy);
|
||||
if (filter)
|
||||
result = result.filter(filter, args.filterThis);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
_queryByName(name, copy) {
|
||||
let result = EmptyInstructionGroup;
|
||||
const map = this._instructionMap;
|
||||
|
||||
if (typeof name === "string") {
|
||||
const insts = map[name];
|
||||
if (insts) result = insts;
|
||||
return copy ? result.slice() : result;
|
||||
}
|
||||
|
||||
if (Array.isArray(name)) {
|
||||
const names = name;
|
||||
for (let i = 0; i < names.length; i++) {
|
||||
const insts = map[names[i]];
|
||||
if (!insts) continue;
|
||||
|
||||
if (result === EmptyInstructionGroup)
|
||||
result = new InstructionGroup();
|
||||
|
||||
for (let j = 0; j < insts.length; j++)
|
||||
result.push(insts[j]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
result = this.instructions;
|
||||
return copy ? result.slice() : result;
|
||||
}
|
||||
|
||||
forEachGroup(cb, thisArg) {
|
||||
const map = this._instructionMap;
|
||||
const names = this.instructionNames;
|
||||
|
||||
for (let i = 0; i < names.length; i++) {
|
||||
const name = names[i];
|
||||
cb.call(thisArg, name, map[name]);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
addData(data) {
|
||||
if (typeof data !== "object" || !data)
|
||||
FAIL("ISA.addData(): data argument must be object");
|
||||
|
||||
if (data.cpuLevels) this._addCpuLevels(data.cpuLevels);
|
||||
if (data.specialRegs) this._addSpecialRegs(data.specialRegs);
|
||||
if (data.shortcuts) this._addShortcuts(data.shortcuts);
|
||||
if (data.instructions) this._addInstructions(data.instructions);
|
||||
if (data.postproc) this._postProc(data.postproc);
|
||||
}
|
||||
|
||||
_postProc(groups) {
|
||||
for (let group of groups) {
|
||||
for (let iRule of group.instructions) {
|
||||
const names = iRule.inst.split(" ");
|
||||
for (let name of names) {
|
||||
const insts = this._instructionMap[name];
|
||||
if (!insts)
|
||||
FAIL(`Instruction ${name} referenced by '${group.group}' group doesn't exist`);
|
||||
|
||||
for (let k in iRule) {
|
||||
if (k === "inst" || k === "data")
|
||||
continue;
|
||||
for (let inst of insts) {
|
||||
inst._assignAttribute(k, iRule[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_addCpuLevels(items) {
|
||||
if (!Array.isArray(items))
|
||||
FAIL("Property 'cpuLevels' must be array");
|
||||
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const item = items[i];
|
||||
const name = item.name;
|
||||
|
||||
const obj = {
|
||||
name: name
|
||||
};
|
||||
|
||||
this._cpuLevels[name] = obj;
|
||||
}
|
||||
}
|
||||
|
||||
_addExtensions(items) {
|
||||
if (!Array.isArray(items))
|
||||
FAIL("Property 'extensions' must be array");
|
||||
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const item = items[i];
|
||||
const name = item.name;
|
||||
|
||||
const obj = {
|
||||
name: name,
|
||||
from: item.from || ""
|
||||
};
|
||||
|
||||
this._extensions[name] = obj;
|
||||
}
|
||||
}
|
||||
|
||||
_addAttributes(items) {
|
||||
if (!Array.isArray(items))
|
||||
FAIL("Property 'attributes' must be array");
|
||||
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const item = items[i];
|
||||
const name = item.name;
|
||||
const type = item.type;
|
||||
|
||||
if (!/^(?:flag|string|string\[\])$/.test(type))
|
||||
FAIL(`Unknown attribute type '${type}'`);
|
||||
|
||||
const obj = {
|
||||
name: name,
|
||||
type: type,
|
||||
doc : item.doc || ""
|
||||
};
|
||||
|
||||
this._attributes[name] = obj;
|
||||
}
|
||||
}
|
||||
|
||||
_addSpecialRegs(items) {
|
||||
if (!Array.isArray(items))
|
||||
FAIL("Property 'specialRegs' must be array");
|
||||
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const item = items[i];
|
||||
const name = item.name;
|
||||
|
||||
const obj = {
|
||||
name : name,
|
||||
group: item.group || name,
|
||||
doc : item.doc || ""
|
||||
};
|
||||
|
||||
this._specialRegs[name] = obj;
|
||||
}
|
||||
}
|
||||
|
||||
_addShortcuts(items) {
|
||||
if (!Array.isArray(items))
|
||||
FAIL("Property 'shortcuts' must be array");
|
||||
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const item = items[i];
|
||||
const name = item.name;
|
||||
const expand = item.expand;
|
||||
|
||||
if (!name || !expand)
|
||||
FAIL("Shortcut must contain 'name' and 'expand' properties");
|
||||
|
||||
const obj = {
|
||||
name : name,
|
||||
expand: expand,
|
||||
doc : item.doc || ""
|
||||
};
|
||||
|
||||
this._shortcuts[name] = obj;
|
||||
}
|
||||
}
|
||||
|
||||
_addInstructions(instructions) {
|
||||
FAIL("ISA._addInstructions() must be reimplemented");
|
||||
}
|
||||
|
||||
_addInstruction(inst) {
|
||||
let group;
|
||||
|
||||
if (hasOwn.call(this._instructionMap, inst.name)) {
|
||||
group = this._instructionMap[inst.name];
|
||||
}
|
||||
else {
|
||||
group = new InstructionGroup();
|
||||
this._instructionNames = null;
|
||||
this._instructionMap[inst.name] = group;
|
||||
this.stats.groups++;
|
||||
}
|
||||
|
||||
if (inst.aliasOf)
|
||||
this._aliases[inst.name] = inst.aliasOf;
|
||||
|
||||
group.push(inst);
|
||||
this.stats.insts++;
|
||||
this._instructions = null;
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
base.ISA = ISA;
|
||||
|
||||
}).apply(this, typeof module === "object" && module && module.exports
|
||||
? [module, "exports"] : [this.asmdb || (this.asmdb = {}), "base"]);
|
762
deps/asmjit/db/exp.js
vendored
Normal file
@ -0,0 +1,762 @@
|
||||
// This file is part of AsmJit project <https://asmjit.com>
|
||||
//
|
||||
// See asmjit.h or LICENSE.md for license and copyright information
|
||||
// SPDX-License-Identifier: Zlib
|
||||
|
||||
(function($scope, $as) {
|
||||
"use strict";
|
||||
|
||||
const hasOwn = Object.prototype.hasOwnProperty;
|
||||
|
||||
// Supported Operators
|
||||
// -------------------
|
||||
|
||||
const kUnaryOperators = {
|
||||
"-": {prec: 3, rtl : 1, emit: "-@1" },
|
||||
"~": {prec: 3, rtl : 1, emit: "~@1" },
|
||||
"!": {prec: 3, rtl : 1, emit: "!@1" }
|
||||
};
|
||||
|
||||
const kBinaryOperators = {
|
||||
"*" : { prec: 5, rtl : 0, emit: "@1 * @2" },
|
||||
"/" : { prec: 5, rtl : 0, emit: "@1 / @2" },
|
||||
"%" : { prec: 5, rtl : 0, emit: "@1 % @2" },
|
||||
"+" : { prec: 6, rtl : 0, emit: "@1 + @2" },
|
||||
"-" : { prec: 6, rtl : 0, emit: "@1 - @2" },
|
||||
">>": { prec: 7, rtl : 0, emit: "@1 >> @2" },
|
||||
"<<": { prec: 7, rtl : 0, emit: "@1 << @2" },
|
||||
"<" : { prec: 9, rtl : 0, emit: "@1 < @2" },
|
||||
">" : { prec: 9, rtl : 0, emit: "@1 > @2" },
|
||||
"<=": { prec: 9, rtl : 0, emit: "@1 <= @2" },
|
||||
">=": { prec: 9, rtl : 0, emit: "@1 >= @2" },
|
||||
"==": { prec:10, rtl : 0, emit: "@1 == @2" },
|
||||
"!=": { prec:10, rtl : 0, emit: "@1 != @2" },
|
||||
"&" : { prec:11, rtl : 0, emit: "@1 & @2" },
|
||||
"^" : { prec:12, rtl : 0, emit: "@1 ^ @2" },
|
||||
"|" : { prec:13, rtl : 0, emit: "@1 | @2" },
|
||||
"&&": { prec:14, rtl : 0, emit: "@1 && @2" },
|
||||
"||": { prec:15, rtl : 0, emit: "@1 || @2" },
|
||||
"?" : { prec:16, rtl : 0, emit: "@1 ? @2" },
|
||||
":" : { prec:16, rtl : 0, emit: "@1 : @2" }
|
||||
};
|
||||
|
||||
const kMaxOperatorLen = 4;
|
||||
|
||||
function rightAssociate(info, bPrec) {
|
||||
return info.prec > bPrec || (info.prec === bPrec && info.rtl);
|
||||
}
|
||||
|
||||
// Expression Error
|
||||
// ----------------
|
||||
|
||||
// Contains `message` and `position` members. If the `position` is not `-1` then it is
|
||||
// a zero-based index, which points to a first character of the token near the error.
|
||||
class ExpressionError extends Error {
|
||||
constructor(message, position) {
|
||||
super(message);
|
||||
this.name = "ExpressionError";
|
||||
this.message = message;
|
||||
this.position = position != null ? position : -1;
|
||||
}
|
||||
}
|
||||
|
||||
function throwTokenizerError(token) {
|
||||
throw new ExpressionError(`Unexpected token '${token.data}'`, token.position);
|
||||
}
|
||||
|
||||
function throwExpressionError(message, position) {
|
||||
throw new ExpressionError(message, position);
|
||||
}
|
||||
|
||||
// Expression Tree
|
||||
// ---------------
|
||||
|
||||
function mustEnclose(node) {
|
||||
return node.isUnary() ? node.child.isOperator() : node.isBinary() ? true : false;
|
||||
}
|
||||
|
||||
class ExpNode {
|
||||
constructor(type) { this.type = type; }
|
||||
|
||||
isImm() { return this.type === "imm"; }
|
||||
isVar() { return this.type === "var"; }
|
||||
isCall() { return this.type === "call"; }
|
||||
isUnary() { return this.type === "unary"; }
|
||||
isBinary() { return this.type === "binary"; }
|
||||
isOperator() { return this.type === "unary" || this.type === "binary"; }
|
||||
|
||||
info() { return null; }
|
||||
clone() { throw new Error("ExpNode.clone() must be overridden"); }
|
||||
evaluate(ctx) { throw new Error("ExpNode.evaluate() must be overridden"); }
|
||||
toString(ctx) { throw new Error("ExpNode.toString() must be overridden"); }
|
||||
}
|
||||
|
||||
class ImmNode extends ExpNode {
|
||||
constructor(imm) {
|
||||
super("imm");
|
||||
this.imm = imm || 0;
|
||||
}
|
||||
|
||||
clone() { return new ImmNode(this.imm); }
|
||||
evaluate(ctx) { return this.imm; }
|
||||
toString(ctx) { return ctx ? ctx.stringifyImmediate(this.imm) : String(this.imm); }
|
||||
}
|
||||
|
||||
class VarNode extends ExpNode {
|
||||
constructor(name) {
|
||||
super("var");
|
||||
this.name = name || "";
|
||||
}
|
||||
|
||||
clone() { return new VarNode(this.name); }
|
||||
evaluate(ctx) { return ctx.variable(this.name); }
|
||||
toString(ctx) { return ctx ? ctx.stringifyVariable(this.name) : String(this.name); }
|
||||
}
|
||||
|
||||
class CallNode extends ExpNode {
|
||||
constructor(name, args) {
|
||||
super("call");
|
||||
this.name = name || "";
|
||||
this.args = args || [];
|
||||
}
|
||||
|
||||
clone() {
|
||||
return new CallNode(this.name, this.args.map(function(arg) { return arg.clone(); }));
|
||||
}
|
||||
|
||||
evaluate(ctx) {
|
||||
const evaluatedArgs = this.args.map(function(arg) { return arg.evaluate(ctx); });
|
||||
return ctx.function(this.name, evaluatedArgs);
|
||||
}
|
||||
|
||||
toString(ctx) {
|
||||
if (this.name === "$bit") {
|
||||
return `((${this.args[0]} >> ${this.args[1]}) & 1)`;
|
||||
}
|
||||
else {
|
||||
let argsCode = this.args.map(function(arg) { return arg.toString(ctx); }).join(", ");
|
||||
if (ctx)
|
||||
return `${ctx.stringifyFunction(this.name)}(${argsCode})`;
|
||||
else
|
||||
return `${this.name}(${argsCode})`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class UnaryNode extends ExpNode {
|
||||
constructor(op, child) {
|
||||
if (!hasOwn.call(kUnaryOperators, op))
|
||||
throw new Error(`Invalid unary operator '${op}`);
|
||||
|
||||
super("unary");
|
||||
this.op = op;
|
||||
this.child = child || null;
|
||||
}
|
||||
|
||||
info() {
|
||||
return kUnaryOperators[this.op];
|
||||
}
|
||||
|
||||
clone() {
|
||||
return new UnaryNode(this.op, this.left ? this.left.clone() : null);
|
||||
}
|
||||
|
||||
evaluate(ctx) {
|
||||
const val = this.child.evaluate(ctx);
|
||||
switch (this.op) {
|
||||
case "-": return (-val);
|
||||
case "~": return (~val);
|
||||
case "!": return (val ? 0 : 1);
|
||||
default : return ctx.unary(this.op, val);
|
||||
}
|
||||
}
|
||||
|
||||
toString(ctx) {
|
||||
return this.info().emit.replace(/@1/g, () => {
|
||||
const node = this.child;
|
||||
const code = node.toString(ctx);
|
||||
return mustEnclose(node) ? `(${code})` : code;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class BinaryNode extends ExpNode {
|
||||
constructor(op, left, right) {
|
||||
if (!hasOwn.call(kBinaryOperators, op))
|
||||
throw new Error(`Invalid binary operator '${op}`);
|
||||
|
||||
super("binary");
|
||||
this.op = op || "";
|
||||
this.left = left || null;
|
||||
this.right = right || null;
|
||||
}
|
||||
|
||||
info() {
|
||||
return kBinaryOperators[this.op];
|
||||
}
|
||||
|
||||
clone() {
|
||||
return new BinaryNode(this.op, this.left ? this.left.clone() : null, this.right ? this.right.clone() : null);
|
||||
}
|
||||
|
||||
evaluate(ctx) {
|
||||
const left = this.left.evaluate(ctx);
|
||||
const right = this.right.evaluate(ctx);
|
||||
|
||||
switch (this.op) {
|
||||
case "-" : return left - right;
|
||||
case "+" : return left + right;
|
||||
case "*" : return left * right;
|
||||
case "/" : return (left / right)|0;
|
||||
case "%" : return (left % right)|0;
|
||||
case "&" : return left & right;
|
||||
case "|" : return left | right;
|
||||
case "^" : return left ^ right;
|
||||
case "<<": return left << right;
|
||||
case ">>": return left >> right;
|
||||
case "==": return left == right ? 1 : 0;
|
||||
case "!=": return left != right ? 1 : 0;
|
||||
case "<" : return left < right ? 1 : 0;
|
||||
case "<=": return left <= right ? 1 : 0;
|
||||
case ">" : return left > right ? 1 : 0;
|
||||
case ">=": return left >= right ? 1 : 0;
|
||||
case "&&": return left && right ? 1 : 0;
|
||||
case "||": return left || right ? 1 : 0;
|
||||
default : return ctx.binary(this.op, left, right);
|
||||
}
|
||||
}
|
||||
|
||||
toString(ctx) {
|
||||
return this.info().emit.replace(/@[1-2]/g, (p) => {
|
||||
const node = p === "@1" ? this.left : this.right;
|
||||
const code = node.toString(ctx);
|
||||
return mustEnclose(node) ? `(${code})` : code;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function Imm(imm) { return new ImmNode(imm); }
|
||||
function Var(name) { return new VarNode(name); }
|
||||
function Call(name, args) { return new CallNode(name, args); }
|
||||
function Unary(op, child) { return new UnaryNode(op, child); }
|
||||
function Binary(op, left, right) { return new BinaryNode(op, left, right); }
|
||||
|
||||
function Negate(child) { return Unary("-", child); }
|
||||
function BitNot(child) { return Unary("~", child); }
|
||||
|
||||
function Add(left, right) { return Binary("+", left, right); }
|
||||
function Sub(left, right) { return Binary("-", left, right); }
|
||||
function Mul(left, right) { return Binary("*", left, right); }
|
||||
function Div(left, right) { return Binary("/", left, right); }
|
||||
function Mod(left, right) { return Binary("%", left, right); }
|
||||
function Shl(left, right) { return Binary("<<", left, right); }
|
||||
function Shr(left, right) { return Binary(">>", left, right); }
|
||||
function BitAnd(left, right) { return Binary("&", left, right); }
|
||||
function BitOr(left, right) { return Binary("|", left, right); }
|
||||
function BitXor(left, right) { return Binary("^", left, right); }
|
||||
function Eq(left, right) { return Binary("==", left, right); }
|
||||
function Ne(left, right) { return Binary("!=", left, right); }
|
||||
function Lt(left, right) { return Binary("<", left, right); }
|
||||
function Le(left, right) { return Binary("<=", left, right); }
|
||||
function Gt(left, right) { return Binary(">", left, right); }
|
||||
function Ge(left, right) { return Binary(">=", left, right); }
|
||||
function And(left, right) { return Binary("&&", left, right); }
|
||||
function Or(left, right) { return Binary("||", left, right); }
|
||||
|
||||
|
||||
|
||||
// Expression Tokenizer
|
||||
// --------------------
|
||||
|
||||
const kCharNone = 0; // '_' - Character category - Invalid or <end>.
|
||||
const kCharSpace = 1; // 'S' - Character category - Space.
|
||||
const kCharAlpha = 2; // 'A' - Character category - Alpha [A-Za-z_].
|
||||
const kCharDigit = 3; // 'D' - Character category - Digit [0-9].
|
||||
const kCharPunct = 4; // '$' - Character category - Punctuation.
|
||||
|
||||
const Category = (function(_, S, A, D, $) {
|
||||
const Table = [
|
||||
_,_,_,_,_,_,_,_,_,S,S,S,S,S,_,_, // 000-015 |......... ..|
|
||||
_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_, // 016-031 |................|
|
||||
S,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$, // 032-047 | !"#$%&'()*+,-./|
|
||||
D,D,D,D,D,D,D,D,D,D,$,$,$,$,$,$, // 048-063 |0123456789:;<=>?|
|
||||
$,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A, // 064-079 |@ABCDEFGHIJKLMNO|
|
||||
A,A,A,A,A,A,A,A,A,A,A,$,$,$,$,A, // 080-095 |PQRSTUVWXYZ[\]^_|
|
||||
$,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A, // 096-111 |`abcdefghijklmno|
|
||||
A,A,A,A,A,A,A,A,A,A,A,$,$,$,$,_, // 112-127 |pqrstuvwxyz{|}~ |
|
||||
_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_, // 128-143 |................|
|
||||
_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_ // 144-159 |................|
|
||||
];
|
||||
const kTableLength = Table.length;
|
||||
|
||||
return function(c) {
|
||||
if (c < kTableLength)
|
||||
return Table[c];
|
||||
return kCharNone;
|
||||
};
|
||||
})(kCharNone, kCharSpace, kCharAlpha, kCharDigit, kCharPunct);
|
||||
|
||||
const kTokenNone = 0;
|
||||
const kTokenPunct = 1;
|
||||
const kTokenIdent = 2;
|
||||
const kTokenValue = 3;
|
||||
|
||||
function newToken(type, position, data, value) {
|
||||
return {
|
||||
type : type, // Token type, see `kToken...`.
|
||||
position: position, // Token position in expression's source.
|
||||
data : data, // Token data (content) as string.
|
||||
value : value // Token value (only if the token is a value).
|
||||
};
|
||||
}
|
||||
const NoToken = newToken(kTokenNone, -1, "<end>", null);
|
||||
|
||||
// Must be reset before it can be used, use `RegExp.lastIndex`.
|
||||
const reNumValue = /(?:(?:\d*\.\d+|\d+)(?:[E|e][+|-]?\d+)?)/g;
|
||||
|
||||
function parseHex(source, from) {
|
||||
let i = from;
|
||||
let number = 0;
|
||||
|
||||
while (i < source.length) {
|
||||
let c = source.charCodeAt(i);
|
||||
let n = 0;
|
||||
|
||||
if (c >= '0'.charCodeAt(0) && c <= '9'.charCodeAt(0)) {
|
||||
n = c - '0'.charCodeAt(0);
|
||||
}
|
||||
else if (c >= 'a'.charCodeAt(0) && c <= 'f'.charCodeAt(0)) {
|
||||
n = c - 'a'.charCodeAt(0) + 10;
|
||||
}
|
||||
else if (c >= 'A'.charCodeAt(0) && c <= 'F'.charCodeAt(0)) {
|
||||
n = c - 'A'.charCodeAt(0) + 10;
|
||||
}
|
||||
else if (c >= 'g'.charCodeAt(0) && c <= 'z'.charCodeAt(0) || c >= 'g'.charCodeAt(0) && c <= 'Z'.charCodeAt(0)) {
|
||||
throwExpressionError(`Invalid hex number 0x${source.substring(from, i + 1)}`);
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
|
||||
number = (number << 4) | n;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i === from)
|
||||
throwExpressionError(`Invalid number starting with 0x`);
|
||||
|
||||
return {
|
||||
number: number,
|
||||
end: i
|
||||
};
|
||||
}
|
||||
|
||||
function tokenize(source) {
|
||||
const len = source.length;
|
||||
const tokens = [];
|
||||
|
||||
let i = 0, j = 0; // Current index in `source` and temporary.
|
||||
let start = 0; // Current token start position.
|
||||
let data = ""; // Current token data (content) as string.
|
||||
let c, cat; // Current character code and category.
|
||||
|
||||
while (i < len) {
|
||||
c = source.charCodeAt(i);
|
||||
cat = Category(c);
|
||||
|
||||
if (cat === kCharSpace) {
|
||||
i++;
|
||||
}
|
||||
else if (cat === kCharDigit) {
|
||||
const n = tokens.length - 1;
|
||||
|
||||
// Hex number.
|
||||
if (c === '0'.charCodeAt(0) && i + 1 < len && source.charCodeAt(i + 1) === 'x'.charCodeAt(0)) {
|
||||
const status = parseHex(source, i + 2);
|
||||
tokens.push(newToken(kTokenValue, i, source.substring(i, status.end), status.number));
|
||||
i = status.end;
|
||||
}
|
||||
else {
|
||||
if (n >= 0 && tokens[n].data === "." && source[i - 1] === ".") {
|
||||
tokens.length = n;
|
||||
i--;
|
||||
}
|
||||
|
||||
reNumValue.lastIndex = i;
|
||||
data = reNumValue.exec(source)[0];
|
||||
|
||||
tokens.push(newToken(kTokenValue, i, data, parseFloat(data)));
|
||||
i += data.length;
|
||||
}
|
||||
}
|
||||
else if (cat === kCharAlpha) {
|
||||
start = i;
|
||||
while (++i < len && ((cat = Category(source.charCodeAt(i))) === kCharAlpha || cat === kCharDigit))
|
||||
continue;
|
||||
|
||||
data = source.substring(start, i);
|
||||
tokens.push(newToken(kTokenIdent, start, data, null));
|
||||
}
|
||||
else if (cat === kCharPunct) {
|
||||
start = i;
|
||||
while (++i < len && Category(source.charCodeAt(i)) === kCharPunct)
|
||||
continue;
|
||||
|
||||
data = source.substring(start, i);
|
||||
do {
|
||||
for (j = Math.min(i - start, kMaxOperatorLen); j > 0; j--) {
|
||||
const part = source.substr(start, j);
|
||||
if (hasOwn.call(kUnaryOperators, part) || hasOwn.call(kBinaryOperators, part) || j === 1) {
|
||||
tokens.push(newToken(kTokenPunct, start, part, null));
|
||||
start += j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (start < i);
|
||||
}
|
||||
else {
|
||||
throwExpressionError(`Unrecognized character '0x${c.toString(16)}'`, i);
|
||||
}
|
||||
}
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
// Expression Parser
|
||||
// -----------------
|
||||
|
||||
class Parser {
|
||||
constructor(tokens) {
|
||||
this.tokens = tokens;
|
||||
this.tIndex = 0;
|
||||
}
|
||||
|
||||
peek() { return this.tIndex < this.tokens.length ? this.tokens[this.tIndex ] : NoToken; }
|
||||
next() { return this.tIndex < this.tokens.length ? this.tokens[this.tIndex++] : NoToken; }
|
||||
skip() { this.tIndex++; return this; }
|
||||
back(token) { this.tIndex -= +(token !== NoToken); return this; }
|
||||
|
||||
parse() {
|
||||
// The root expression cannot be empty.
|
||||
let token = this.peek();
|
||||
if (token === NoToken)
|
||||
throwExpressionError("Expression cannot be empty", 0);
|
||||
|
||||
const exp = this.parseExpression();
|
||||
|
||||
// The root expression must reach the end of the input.
|
||||
token = this.peek();
|
||||
if (token !== NoToken)
|
||||
throwTokenizerError(token);
|
||||
|
||||
return exp;
|
||||
}
|
||||
|
||||
parseExpression() {
|
||||
const stack = [];
|
||||
let value = null;
|
||||
let token = null;
|
||||
|
||||
for (;;) {
|
||||
// The only case of value not being `null` is after ternary-if. In that
|
||||
// case the value was already parsed so we want to skip this section.
|
||||
if (value === null) {
|
||||
let unaryFirst = null;
|
||||
let unaryLast = null;
|
||||
|
||||
token = this.next();
|
||||
|
||||
// Parse a possible unary operator(s).
|
||||
if (token.type === kTokenPunct) {
|
||||
do {
|
||||
const opName = token.data;
|
||||
const opInfo = kUnaryOperators[opName];
|
||||
|
||||
if (!opInfo)
|
||||
break;
|
||||
|
||||
const node = Unary(opName);
|
||||
if (unaryLast)
|
||||
unaryLast.child = node;
|
||||
else
|
||||
unaryFirst = node;
|
||||
|
||||
unaryLast = node;
|
||||
token = this.next();
|
||||
} while (token.type === kTokenPunct);
|
||||
}
|
||||
|
||||
// Parse a value, variable, function call, or nested expression.
|
||||
if (token.type === kTokenValue) {
|
||||
value = Imm(token.value);
|
||||
}
|
||||
else if (token.type === kTokenIdent) {
|
||||
const name = token.data;
|
||||
const after = this.peek();
|
||||
|
||||
if (after.data === "(")
|
||||
value = this.parseCall(token.data);
|
||||
else if (after.data === "[")
|
||||
value = this.parseBitAccess(token.data);
|
||||
else
|
||||
value = Var(name);
|
||||
}
|
||||
else if (token.data === "(") {
|
||||
value = this.parseExpression();
|
||||
token = this.next();
|
||||
|
||||
if (token.data !== ")")
|
||||
throwTokenizerError(token);
|
||||
}
|
||||
else {
|
||||
throwTokenizerError(token);
|
||||
}
|
||||
|
||||
// Replace the value with the top-level unary operator, if parsed.
|
||||
if (unaryFirst) {
|
||||
unaryLast.child = value;
|
||||
value = unaryFirst;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse a possible binary operator - the loop must repeat, if present.
|
||||
token = this.peek();
|
||||
if (token.type === kTokenPunct && hasOwn.call(kBinaryOperators, token.data)) {
|
||||
const opName = token.data;
|
||||
if (opName === ":")
|
||||
break;
|
||||
|
||||
// Consume the token.
|
||||
this.skip();
|
||||
|
||||
const bNode = Binary(opName, null, null);
|
||||
|
||||
if (!stack.length) {
|
||||
bNode.left = value;
|
||||
stack.push(bNode);
|
||||
}
|
||||
else {
|
||||
let aNode = stack.pop();
|
||||
let aPrec = aNode.info().prec;
|
||||
let bPrec = bNode.info().prec;
|
||||
|
||||
if (aPrec > bPrec) {
|
||||
aNode.right = bNode;
|
||||
bNode.left = value;
|
||||
stack.push(aNode, bNode);
|
||||
}
|
||||
else {
|
||||
aNode.right = value;
|
||||
|
||||
// Advance to the top-most op that has less/equal precedence than `bPrec`.
|
||||
while (stack.length) {
|
||||
if (rightAssociate(aNode.info(), bPrec))
|
||||
break;
|
||||
aNode = stack.pop();
|
||||
}
|
||||
|
||||
if (!stack.length && !rightAssociate(aNode.info(), bPrec)) {
|
||||
bNode.left = aNode;
|
||||
stack.push(bNode);
|
||||
}
|
||||
else {
|
||||
const tmp = aNode.right;
|
||||
aNode.right = bNode;
|
||||
bNode.left = tmp;
|
||||
stack.push(aNode, bNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse "<cond> {ternary-if} <taken> {ternary-else} <not-taken>".
|
||||
if (opName === "?") {
|
||||
const ternLeft = this.parseExpression();
|
||||
const ternTok = this.next();
|
||||
|
||||
if (ternTok.data !== ":")
|
||||
throwExpressionError(`Unterminated ternary if '${token.data}'`, token.position);
|
||||
|
||||
const ternRight = this.parseExpression();
|
||||
value = Binary(opName, info, ternLeft, ternRight);
|
||||
}
|
||||
else {
|
||||
value = null;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (value === null)
|
||||
throwExpressionError("Invalid expression");
|
||||
|
||||
if (stack.length !== 0) {
|
||||
stack[stack.length - 1].right = value;
|
||||
value = stack[0];
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
parseCall(name) {
|
||||
const args = [];
|
||||
|
||||
let token = this.next();
|
||||
if (token.data !== "(")
|
||||
throwTokenizerError(token);
|
||||
|
||||
for (;;) {
|
||||
token = this.peek();
|
||||
if (token.data === ")")
|
||||
break;
|
||||
|
||||
if (args.length !== 0) {
|
||||
if (token.data !== ",")
|
||||
throwTokenizerError(token);
|
||||
this.skip();
|
||||
}
|
||||
|
||||
args.push(this.parseExpression());
|
||||
}
|
||||
|
||||
this.skip();
|
||||
return Call(name, args);
|
||||
}
|
||||
|
||||
parseBitAccess(name) {
|
||||
let token = this.next();
|
||||
if (token.data !== "[")
|
||||
throwTokenizerError(token);
|
||||
|
||||
token = this.next();
|
||||
if (token.type != kTokenValue)
|
||||
throwTokenizerError(token);
|
||||
|
||||
const index = token.value;
|
||||
|
||||
token = this.next();
|
||||
if (token.data !== "]")
|
||||
throwTokenizerError(token);
|
||||
|
||||
return Call("$bit", [Var(name), index]);
|
||||
}
|
||||
}
|
||||
|
||||
function parse(source) {
|
||||
const tokens = tokenize(source);
|
||||
return new Parser(tokens).parse();
|
||||
}
|
||||
|
||||
// Expression Visitors
|
||||
// -------------------
|
||||
|
||||
class Visitor {
|
||||
visit(node) {
|
||||
switch (node.type) {
|
||||
case "imm":
|
||||
case "var": {
|
||||
break;
|
||||
}
|
||||
|
||||
case "call": {
|
||||
for (let arg of node.args)
|
||||
this.visit(arg);
|
||||
break;
|
||||
}
|
||||
|
||||
case "unary": {
|
||||
if (node.child)
|
||||
this.visit(node.child);
|
||||
break;
|
||||
}
|
||||
|
||||
case "binary": {
|
||||
if (node.left)
|
||||
this.visit(node.left);
|
||||
if (node.right)
|
||||
this.visit(node.right);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
throw new Error(`Visitor.visit(): Unknown node type '${node.type}'`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Collector extends Visitor {
|
||||
constructor(nodeType, dst) {
|
||||
super();
|
||||
this.dict = dst || Object.create(null);
|
||||
this.nodeType = nodeType;
|
||||
}
|
||||
|
||||
visit(node) {
|
||||
if (node.type === this.nodeType) {
|
||||
if (hasOwn.call(this.dict, node.name))
|
||||
this.dict[node.name]++;
|
||||
else
|
||||
this.dict[node.name] = 1;
|
||||
}
|
||||
|
||||
super.visit(node);
|
||||
}
|
||||
}
|
||||
|
||||
function collectVars(node, dst) {
|
||||
const collector = new Collector("var", dst);
|
||||
collector.visit(node)
|
||||
return collector.dict;
|
||||
}
|
||||
|
||||
function collectCalls(node, dst) {
|
||||
const collector = new Collector("call", dst);
|
||||
collector.visit(node)
|
||||
return collector.dict;
|
||||
}
|
||||
|
||||
// Exports
|
||||
// -------
|
||||
|
||||
$scope[$as] = {
|
||||
Imm: Imm,
|
||||
Var: Var,
|
||||
Call: Call,
|
||||
Unary: Unary,
|
||||
Binary: Binary,
|
||||
|
||||
Negate: Negate,
|
||||
BitNot: BitNot,
|
||||
|
||||
Add: Add,
|
||||
Sub: Sub,
|
||||
Mul: Mul,
|
||||
Div: Div,
|
||||
Mod: Mod,
|
||||
Shl: Shl,
|
||||
Shr: Shr,
|
||||
BitAnd: BitAnd,
|
||||
BitOr: BitOr,
|
||||
BitXor: BitXor,
|
||||
Eq: Eq,
|
||||
Ne: Ne,
|
||||
Lt: Lt,
|
||||
Le: Le,
|
||||
Gt: Gt,
|
||||
Ge: Ge,
|
||||
And: And,
|
||||
Or: Or,
|
||||
|
||||
Visitor: Visitor,
|
||||
ExpressionError: ExpressionError,
|
||||
|
||||
parse: parse,
|
||||
collectVars: collectVars,
|
||||
collectCalls: collectCalls
|
||||
};
|
||||
|
||||
}).apply(this, typeof module === "object" && module && module.exports
|
||||
? [module, "exports"] : [this.asmdb || (this.asmdb = {}), "exp"]);
|