pax_global_header00006660000000000000000000000064140041152170014505gustar00rootroot0000000000000052 comment=e0f00666d90086bb245ae73abb6123d0e2c1b30b xtl-0.7.2/000077500000000000000000000000001400411521700123225ustar00rootroot00000000000000xtl-0.7.2/.appveyor.yml000066400000000000000000000026401400411521700147720ustar00rootroot00000000000000build: false platform: - x64 image: - Visual Studio 2017 - Visual Studio 2015 environment: matrix: - MINICONDA: C:\xtl-conda init: - "ECHO %MINICONDA%" - if "%APPVEYOR_BUILD_WORKER_IMAGE%" == "Visual Studio 2015" set VCVARPATH="C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" - if "%APPVEYOR_BUILD_WORKER_IMAGE%" == "Visual Studio 2015" set VCARGUMENT=%PLATFORM% - if "%APPVEYOR_BUILD_WORKER_IMAGE%" == "Visual Studio 2017" set VCVARPATH="C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat" - echo "%VCVARPATH% %VCARGUMENT%" - "%VCVARPATH% %VCARGUMENT%" - ps: if($env:Platform -eq "x64"){Start-FileDownload 'http://repo.continuum.io/miniconda/Miniconda3-latest-Windows-x86_64.exe' C:\Miniconda.exe; echo "Done"} - ps: if($env:Platform -eq "x86"){Start-FileDownload 'http://repo.continuum.io/miniconda/Miniconda3-latest-Windows-x86.exe' C:\Miniconda.exe; echo "Done"} - cmd: C:\Miniconda.exe /S /D=C:\xtl-conda - "set PATH=%MINICONDA%;%MINICONDA%\\Scripts;%MINICONDA%\\Library\\bin;%PATH%" install: - conda config --set always_yes yes --set changeps1 no - conda update -q conda - conda info -a - conda env create --file environment-dev.yml - CALL conda.bat activate xtl - cmake -G "NMake Makefiles" -D CMAKE_INSTALL_PREFIX=%MINICONDA%\\LIBRARY -DDOWNLOAD_GTEST=ON . - nmake test_xtl - cd test build_script: - .\test_xtl xtl-0.7.2/.azure-pipelines/000077500000000000000000000000001400411521700155145ustar00rootroot00000000000000xtl-0.7.2/.azure-pipelines/azure-pipelines-linux-clang.yml000066400000000000000000000025151400411521700235750ustar00rootroot00000000000000jobs: - job: 'Linux_0' strategy: matrix: clang_4: llvm_version: '4.0' clang_5: llvm_version: '5.0' clang_6: llvm_version: '6.0' clang_7: llvm_version: '7' clang_8: llvm_version: '8' clang_9: llvm_version: '9' pool: vmImage: ubuntu-16.04 variables: CC: clang-$(llvm_version) CXX: clang++-$(llvm_version) timeoutInMinutes: 360 steps: - script: | sudo add-apt-repository ppa:ubuntu-toolchain-r/test if [[ $(llvm_version) == '4.0' || $(llvm_version) == '5.0' ]]; then sudo apt-get update sudo apt-get --no-install-suggests --no-install-recommends install gcc-4.9 clang-$(llvm_version) else LLVM_VERSION=$(llvm_version) get -O - http://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - sudo add-apt-repository "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-$LLVM_VERSION main" sudo apt-get update sudo apt-get --no-install-suggests --no-install-recommends install clang-$(llvm_version) fi displayName: Install build toolchain - bash: echo "##vso[task.prependpath]$CONDA/bin" displayName: Add conda to PATH - template: unix-build.yml xtl-0.7.2/.azure-pipelines/azure-pipelines-linux-gcc.yml000066400000000000000000000016551400411521700232510ustar00rootroot00000000000000jobs: - job: 'Linux_1' strategy: matrix: gcc_4: gcc_version: '4.9' gcc_5: gcc_version: '5' gcc_6: gcc_version: '6' gcc_7: gcc_version: '7' gcc_8: gcc_version: '8' gcc_9: gcc_version: '9' pool: vmImage: ubuntu-16.04 variables: CC: gcc-$(gcc_version) CXX: g++-$(gcc_version) timeoutInMinutes: 360 steps: - script: | if [[ $(gcc_version) == '4.9' || $(gcc_version) == '6' ]]; then sudo add-apt-repository ppa:ubuntu-toolchain-r/test sudo apt-get update sudo apt-get --no-install-suggests --no-install-recommends install g++-$(gcc_version) fi displayName: Install build toolchain - bash: echo "##vso[task.prependpath]$CONDA/bin" displayName: Add conda to PATH - template: unix-build.yml xtl-0.7.2/.azure-pipelines/azure-pipelines-osx.yml000066400000000000000000000014261400411521700221650ustar00rootroot00000000000000jobs: - job: 'OSX' strategy: matrix: macOS_10_14: image_name: 'macOS-10.14' macOS_10_15: image_name: 'macOS-10.15' pool: vmImage: $(image_name) variables: CC: clang CXX: clang++ timeoutInMinutes: 360 steps: - script: | echo "Removing homebrew for Azure to avoid conflicts with conda" curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/uninstall > ~/uninstall_homebrew chmod +x ~/uninstall_homebrew ~/uninstall_homebrew -f -q displayName: Remove homebrew - bash: | echo "##vso[task.prependpath]$CONDA/bin" sudo chown -R $USER $CONDA displayName: Add conda to PATH - template: unix-build.yml xtl-0.7.2/.azure-pipelines/azure-pipelines-win.yml000066400000000000000000000055361400411521700221570ustar00rootroot00000000000000 jobs: - job: 'Windows_clangcl' pool: vmImage: 'vs2017-win2016' timeoutInMinutes: 360 steps: # Install Chocolatey (https://chocolatey.org/install#install-with-powershellexe) - powershell: | Set-ExecutionPolicy Bypass -Scope Process -Force iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1')) Write-Host "##vso[task.setvariable variable=PATH]$env:PATH" choco --version displayName: "Install Chocolatey" # Install Miniconda - script: | choco install miniconda3 --yes set PATH=C:\tools\miniconda3\Scripts;C:\tools\miniconda3;C:\tools\miniconda3\Library\bin;%PATH% echo '##vso[task.setvariable variable=PATH]%PATH%' set LIB=C:\tools\miniconda3\Library\lib;%LIB% echo '##vso[task.setvariable variable=LIB]%LIB%' conda --version displayName: "Install Miniconda" # Configure Miniconda - script: | conda config --set always_yes yes conda config --append channels conda-forge conda info displayName: "Configure Miniconda" # Create conda enviroment # Note: conda activate doesn't work here, because it creates a new shell! - script: | conda install cmake==3.14.0 ^ ninja ^ nlohmann_json ^ python=3.6 conda list displayName: "Install conda packages" # Install LLVM # Note: LLVM distributed by conda is too old - script: | choco install llvm --yes set PATH=C:\Program Files\LLVM\bin;%PATH% echo '##vso[task.setvariable variable=PATH]%PATH%' clang-cl --version displayName: "Install LLVM" # Configure - script: | setlocal EnableDelayedExpansion call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86_amd64 mkdir build & cd build cmake -G Ninja ^ -DCMAKE_BUILD_TYPE=Release ^ -DCMAKE_C_COMPILER=clang-cl ^ -DCMAKE_CXX_COMPILER=clang-cl ^ -DDOWNLOAD_GTEST=ON ^ $(Build.SourcesDirectory) displayName: "Configure xtl" workingDirectory: $(Build.BinariesDirectory) # Build - script: | call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86_amd64 cmake --build . ^ --config Release ^ --target test_xtl ^ -- -v displayName: "Build xtl" workingDirectory: $(Build.BinariesDirectory)/build # Test - script: | setlocal EnableDelayedExpansion cd test .\test_xtl displayName: "Test xtl" workingDirectory: $(Build.BinariesDirectory)/build/test xtl-0.7.2/.azure-pipelines/unix-build.yml000066400000000000000000000013311400411521700203150ustar00rootroot00000000000000steps: - script: | conda config --set always_yes yes --set changeps1 no conda update -q conda conda env create --file environment-dev.yml displayName: Install dependencies - script: | source activate xtl mkdir build cd build cmake -DDOWNLOAD_GTEST=ON $(Build.SourcesDirectory) displayName: Configure xtl workingDirectory: $(Build.BinariesDirectory) - script: | source activate xtl make -j2 test_xtl displayName: Build xtl workingDirectory: $(Build.BinariesDirectory)/build - script: | source activate xtl cd test ./test_xtl displayName: Test xtl workingDirectory: $(Build.BinariesDirectory)/build/test xtl-0.7.2/.github/000077500000000000000000000000001400411521700136625ustar00rootroot00000000000000xtl-0.7.2/.github/PULL_REQUEST_TEMPLATE.md000066400000000000000000000004141400411521700174620ustar00rootroot00000000000000# Checklist - The title and the commit message(s) are descriptive - Small commits made to fix your PR have been squashed to avoid history pollution - Tests have been added for new features or bug fixes - API of new functions and classes are documented # Description xtl-0.7.2/.gitignore000066400000000000000000000010301400411521700143040ustar00rootroot00000000000000# Prerequisites *.d # Compiled Object files *.slo *.lo *.o *.obj # Precompiled Headers *.gch *.pch # Compiled Dynamic libraries *.so *.dylib *.dll # Compiled Static libraries *.lai *.la *.a *.lib # Executables *.exe *.out *.app # Vim tmp files *.swp # Build directory build/ # Test build artefacts test/test_xtl test/CMakeCache.txt test/Makefile test/CMakeFiles/ test/cmake_install.cmake # Documentation build artefacts docs/CMakeCache.txt docs/xml/ docs/build/ # Jupyter artefacts .ipynb_checkpoints/ # Generated files *.pc xtl-0.7.2/.releash.py000066400000000000000000000013101400411521700143700ustar00rootroot00000000000000from releash import * gitpush = ReleaseTargetGitPush('upstream', 'master') xtl = add_package(path=".", name="xtl") version_xtl = VersionSourceAndTargetHpp(xtl, '{path}/include/xtl/xtl_config.hpp', prefix='XTL_VERSION_') gittag_xtl = ReleaseTargetGitTagVersion(version_source=version_xtl, prefix='', annotate=True) xtl.version_source = version_xtl xtl.version_targets.append(version_xtl) xtl.release_targets.append(gittag_xtl) xtl.release_targets.append(gitpush) source_tarball_filename = 'https://github.com/xtensor-stack/xtl/archive/{version}.tar.gz'.format(version=version_xtl) xtl.release_targets.append(ReleaseTargetCondaForge(xtl, '../xtl-feedstock', source_tarball_filename=source_tarball_filename)) xtl-0.7.2/CMakeLists.txt000066400000000000000000000136401400411521700150660ustar00rootroot00000000000000############################################################################ # Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht # # Copyright (c) QuantStack # # # # Distributed under the terms of the BSD 3-Clause License. # # # # The full license is in the file LICENSE, distributed with this software. # ############################################################################ cmake_minimum_required(VERSION 3.1) project(xtl) set(XTL_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include) # Versioning # =========== file(STRINGS "${XTL_INCLUDE_DIR}/xtl/xtl_config.hpp" xtl_version_defines REGEX "#define XTL_VERSION_(MAJOR|MINOR|PATCH)") foreach(ver ${xtl_version_defines}) if(ver MATCHES "#define XTL_VERSION_(MAJOR|MINOR|PATCH) +([^ ]+)$") set(XTL_VERSION_${CMAKE_MATCH_1} "${CMAKE_MATCH_2}" CACHE INTERNAL "") endif() endforeach() set(${PROJECT_NAME}_VERSION ${XTL_VERSION_MAJOR}.${XTL_VERSION_MINOR}.${XTL_VERSION_PATCH}) message(STATUS "xtl v${${PROJECT_NAME}_VERSION}") # Dependencies # ============ if(NOT TARGET nlohmann_json) find_package(nlohmann_json QUIET) endif() # Build # ===== set(XTL_HEADERS ${XTL_INCLUDE_DIR}/xtl/xany.hpp ${XTL_INCLUDE_DIR}/xtl/xbasic_fixed_string.hpp ${XTL_INCLUDE_DIR}/xtl/xbase64.hpp ${XTL_INCLUDE_DIR}/xtl/xclosure.hpp ${XTL_INCLUDE_DIR}/xtl/xcomplex.hpp ${XTL_INCLUDE_DIR}/xtl/xcomplex_sequence.hpp ${XTL_INCLUDE_DIR}/xtl/xspan.hpp ${XTL_INCLUDE_DIR}/xtl/xspan_impl.hpp ${XTL_INCLUDE_DIR}/xtl/xdynamic_bitset.hpp ${XTL_INCLUDE_DIR}/xtl/xfunctional.hpp ${XTL_INCLUDE_DIR}/xtl/xhalf_float.hpp ${XTL_INCLUDE_DIR}/xtl/xhalf_float_impl.hpp ${XTL_INCLUDE_DIR}/xtl/xhash.hpp ${XTL_INCLUDE_DIR}/xtl/xhierarchy_generator.hpp ${XTL_INCLUDE_DIR}/xtl/xiterator_base.hpp ${XTL_INCLUDE_DIR}/xtl/xjson.hpp ${XTL_INCLUDE_DIR}/xtl/xmasked_value_meta.hpp ${XTL_INCLUDE_DIR}/xtl/xmasked_value.hpp ${XTL_INCLUDE_DIR}/xtl/xmeta_utils.hpp ${XTL_INCLUDE_DIR}/xtl/xmultimethods.hpp ${XTL_INCLUDE_DIR}/xtl/xoptional_meta.hpp ${XTL_INCLUDE_DIR}/xtl/xoptional.hpp ${XTL_INCLUDE_DIR}/xtl/xoptional_sequence.hpp ${XTL_INCLUDE_DIR}/xtl/xplatform.hpp ${XTL_INCLUDE_DIR}/xtl/xproxy_wrapper.hpp ${XTL_INCLUDE_DIR}/xtl/xsequence.hpp ${XTL_INCLUDE_DIR}/xtl/xsystem.hpp ${XTL_INCLUDE_DIR}/xtl/xtl_config.hpp ${XTL_INCLUDE_DIR}/xtl/xtype_traits.hpp ${XTL_INCLUDE_DIR}/xtl/xvariant.hpp ${XTL_INCLUDE_DIR}/xtl/xvariant_impl.hpp ${XTL_INCLUDE_DIR}/xtl/xvisitor.hpp ) add_library(xtl INTERFACE) target_include_directories(xtl INTERFACE $ $) if(NOT (CMAKE_VERSION VERSION_LESS 3.15)) # CMake >= 3.15 set_target_properties(xtl PROPERTIES PUBLIC_HEADER "${XTL_HEADERS}") endif() target_compile_features(xtl INTERFACE cxx_std_14) option(BUILD_TESTS "xtl test suite" OFF) option(DOWNLOAD_GTEST "build gtest from downloaded sources" OFF) option(XTL_DISABLE_EXCEPTIONS "Disable C++ exceptions" OFF) if(DOWNLOAD_GTEST OR GTEST_SRC_DIR) set(BUILD_TESTS ON) endif() if(BUILD_TESTS) enable_testing() add_subdirectory(test) endif() # Installation # ============ include(GNUInstallDirs) include(CMakePackageConfigHelpers) if(CMAKE_VERSION VERSION_LESS 3.15) # CMake < 3.15 install(TARGETS xtl EXPORT ${PROJECT_NAME}-targets) else() install(TARGETS xtl EXPORT ${PROJECT_NAME}-targets PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}) endif() # Makes the project importable from the build directory export(EXPORT ${PROJECT_NAME}-targets FILE "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Targets.cmake") if(CMAKE_VERSION VERSION_LESS 3.15) # CMake < 3.15 install(FILES ${XTL_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/xtl) endif() set(XTL_CMAKECONFIG_INSTALL_DIR "${CMAKE_INSTALL_DATAROOTDIR}/cmake/${PROJECT_NAME}" CACHE STRING "install path for xtlConfig.cmake") configure_package_config_file(${PROJECT_NAME}Config.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" INSTALL_DESTINATION ${XTL_CMAKECONFIG_INSTALL_DIR}) # xtl is header-only and does not depend on the architecture. # Remove CMAKE_SIZEOF_VOID_P from xtlConfigVersion.cmake so that an xtlConfig.cmake # generated for a 64 bit target can be used for 32 bit targets and vice versa. set(_XTL_CMAKE_SIZEOF_VOID_P ${CMAKE_SIZEOF_VOID_P}) unset(CMAKE_SIZEOF_VOID_P) # ARCH_INDEPENDENT feature was introduced in cmake 3.14 if (${CMAKE_VERSION} VERSION_LESS "3.14.0") write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake VERSION ${${PROJECT_NAME}_VERSION} COMPATIBILITY AnyNewerVersion) else () write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake VERSION ${${PROJECT_NAME}_VERSION} COMPATIBILITY AnyNewerVersion ARCH_INDEPENDENT) endif () set(CMAKE_SIZEOF_VOID_P ${_XTL_CMAKE_SIZEOF_VOID_P}) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake DESTINATION ${XTL_CMAKECONFIG_INSTALL_DIR}) install(EXPORT ${PROJECT_NAME}-targets FILE ${PROJECT_NAME}Targets.cmake DESTINATION ${XTL_CMAKECONFIG_INSTALL_DIR}) configure_file(${PROJECT_NAME}.pc.in "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc" @ONLY) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig/") xtl-0.7.2/LICENSE000066400000000000000000000030541400411521700133310ustar00rootroot00000000000000BSD 3-Clause License Copyright (c) 2017, Sylvain Corlay, Johan Mabille and Wolf Vollprecht Copyright (c) 2017, QuantStack 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 the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. xtl-0.7.2/README.md000066400000000000000000000036221400411521700136040ustar00rootroot00000000000000# ![xtl](docs/source/xtl.svg) [![Appveyor](https://ci.appveyor.com/api/projects/status/wikc50xlb5rbrjy7?svg=true)](https://ci.appveyor.com/project/xtensor-stack/xtl) [![Azure](https://dev.azure.com/xtensor-stack/xtensor-stack/_apis/build/status/xtensor-stack.xtl?branchName=master)](https://dev.azure.com/xtensor-stack/xtensor-stack/_build/latest?definitionId=2&branchName=master) [![Documentation Status](http://readthedocs.org/projects/xtl/badge/?version=latest)](https://xtl.readthedocs.io/en/latest/?badge=latest) [![Join the Gitter Chat](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/QuantStack/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) Basic tools (containers, algorithms) used by other quantstack packages ## Installation ### Install from conda We provide a package for the conda package manager: ```bash conda install -c conda-forge xtl ``` ### Install from sources `xtl` is a header-only library. You can directly install it from the sources: ```bash cmake -D CMAKE_INSTALL_PREFIX=your_install_prefix make install ``` ## Documentation To get started with using `xtl`, check out the full documentation http://xtl.readthedocs.io/ ## Building the HTML documentation xtl's documentation is built with three tools - [doxygen](http://www.doxygen.org) - [sphinx](http://www.sphinx-doc.org) - [breathe](https://breathe.readthedocs.io) While doxygen must be installed separately, you can install breathe by typing ```bash pip install breathe ``` Breathe can also be installed with `conda` ```bash conda install -c conda-forge breathe ``` Finally, build the documentation with ```bash make html ``` from the `docs` subdirectory. ## License We use a shared copyright model that enables all contributors to maintain the copyright on their contributions. This software is licensed under the BSD-3-Clause license. See the [LICENSE](LICENSE) file for details. xtl-0.7.2/azure-pipelines.yml000066400000000000000000000004151400411521700161610ustar00rootroot00000000000000trigger: - master jobs: - template: ./.azure-pipelines/azure-pipelines-win.yml - template: ./.azure-pipelines/azure-pipelines-linux-clang.yml - template: ./.azure-pipelines/azure-pipelines-linux-gcc.yml - template: ./.azure-pipelines/azure-pipelines-osx.yml xtl-0.7.2/docs/000077500000000000000000000000001400411521700132525ustar00rootroot00000000000000xtl-0.7.2/docs/Doxyfile000066400000000000000000000004761400411521700147670ustar00rootroot00000000000000PROJECT_NAME = "xtl" XML_OUTPUT = xml INPUT = ../include GENERATE_LATEX = NO GENERATE_MAN = NO GENERATE_RTF = NO CASE_SENSE_NAMES = NO GENERATE_HTML = NO GENERATE_XML = YES RECURSIVE = YES QUIET = YES JAVADOC_AUTOBRIEF = YES WARN_IF_UNDOCUMENTED = NO xtl-0.7.2/docs/Makefile000066400000000000000000000152501400411521700147150ustar00rootroot00000000000000# You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build INKSCAPE = inkscape SED = sed PAPER = BUILDDIR = build # User-friendly check for sphinx-build ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) endif # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext api default: html help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " applehelp to make an Apple Help Book" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " xml to make Docutils-native XML files" @echo " pseudoxml to make pseudoxml-XML files for display purposes" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" @echo " coverage to run coverage check of the documentation (if enabled)" clean: rm -rf $(BUILDDIR)/* rm -rf xml html: doxygen $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: doxygen $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: doxygen $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: doxygen $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: doxygen $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: doxygen $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." epub: doxygen $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." tex-generation: doxygen $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex ${SED} -i.old -e 's/{\([^}]*\)}.svg/\1-svg.pdf/' $(BUILDDIR)/latex/xtl.tex (cd $(BUILDDIR)/latex/;\ for i in *.svg; do\ name=`basename $$i .svg`;\ ${INKSCAPE} -D -z --file=$$i --export-pdf=$$name-svg.pdf --export-latex; \ done) latex: tex-generation @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: tex-generation @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." latexpdfja: tex-generation @echo "Running LaTeX files through platex and dvipdfmx..." $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: doxygen $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: doxygen $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: doxygen $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: doxygen $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: doxygen $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: doxygen $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: doxygen $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: doxygen $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." coverage: doxygen $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage @echo "Testing of coverage in the sources finished, look at the " \ "results in $(BUILDDIR)/coverage/python.txt." xml: doxygen $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml @echo @echo "Build finished. The XML files are in $(BUILDDIR)/xml." pseudoxml: doxygen $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml @echo @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." xtl-0.7.2/docs/environment.yml000066400000000000000000000001151400411521700163360ustar00rootroot00000000000000name: xtl-docs channels: - conda-forge dependencies: - breathe==4.16.0 xtl-0.7.2/docs/make.bat000066400000000000000000000161651400411521700146700ustar00rootroot00000000000000@ECHO OFF REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set BUILDDIR=build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source set I18NSPHINXOPTS=%SPHINXOPTS% source if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. singlehtml to make a single large HTML file echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. devhelp to make HTML files and a Devhelp project echo. epub to make an epub echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. text to make text files echo. man to make manual pages echo. texinfo to make Texinfo files echo. gettext to make PO message catalogs echo. changes to make an overview over all changed/added/deprecated items echo. xml to make Docutils-native XML files echo. pseudoxml to make pseudoxml-XML files for display purposes echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled echo. coverage to run coverage check of the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) REM Check if sphinx-build is available and fallback to Python version if any %SPHINXBUILD% 1>NUL 2>NUL if errorlevel 9009 goto sphinx_python goto sphinx_ok :sphinx_python set SPHINXBUILD=python -m sphinx.__init__ %SPHINXBUILD% 2> nul if errorlevel 9009 ( echo. echo.The 'sphinx-build' command was not found. Make sure you have Sphinx echo.installed, then set the SPHINXBUILD environment variable to point echo.to the full path of the 'sphinx-build' executable. Alternatively you echo.may add the Sphinx directory to PATH. echo. echo.If you don't have Sphinx installed, grab it from echo.http://sphinx-doc.org/ exit /b 1 ) :sphinx_ok if "%1" == "html" ( doxygen %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. goto end ) if "%1" == "singlehtml" ( %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in %BUILDDIR%/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: echo.^> qcollectiongenerator %BUILDDIR%\qthelp\packagename.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\packagename.ghc goto end ) if "%1" == "devhelp" ( %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp if errorlevel 1 exit /b 1 echo. echo.Build finished. goto end ) if "%1" == "epub" ( %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub if errorlevel 1 exit /b 1 echo. echo.Build finished. The epub file is in %BUILDDIR%/epub. goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex if errorlevel 1 exit /b 1 echo. echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdf" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf cd %~dp0 echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdfja" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf-ja cd %~dp0 echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "text" ( %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text if errorlevel 1 exit /b 1 echo. echo.Build finished. The text files are in %BUILDDIR%/text. goto end ) if "%1" == "man" ( %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man if errorlevel 1 exit /b 1 echo. echo.Build finished. The manual pages are in %BUILDDIR%/man. goto end ) if "%1" == "texinfo" ( %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo if errorlevel 1 exit /b 1 echo. echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. goto end ) if "%1" == "gettext" ( %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale if errorlevel 1 exit /b 1 echo. echo.Build finished. The message catalogs are in %BUILDDIR%/locale. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes if errorlevel 1 exit /b 1 echo. echo.The overview file is in %BUILDDIR%/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck if errorlevel 1 exit /b 1 echo. echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest if errorlevel 1 exit /b 1 echo. echo.Testing of doctests in the sources finished, look at the ^ results in %BUILDDIR%/doctest/output.txt. goto end ) if "%1" == "coverage" ( %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage if errorlevel 1 exit /b 1 echo. echo.Testing of coverage in the sources finished, look at the ^ results in %BUILDDIR%/coverage/python.txt. goto end ) if "%1" == "xml" ( %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml if errorlevel 1 exit /b 1 echo. echo.Build finished. The XML files are in %BUILDDIR%/xml. goto end ) if "%1" == "pseudoxml" ( %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml if errorlevel 1 exit /b 1 echo. echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. goto end ) :end xtl-0.7.2/docs/source/000077500000000000000000000000001400411521700145525ustar00rootroot00000000000000xtl-0.7.2/docs/source/_static/000077500000000000000000000000001400411521700162005ustar00rootroot00000000000000xtl-0.7.2/docs/source/_static/main_stylesheet.css000066400000000000000000000000741400411521700221100ustar00rootroot00000000000000.wy-nav-content{ max-width: 1000px; margin: auto; } xtl-0.7.2/docs/source/basic_types.rst000066400000000000000000000060021400411521700176070ustar00rootroot00000000000000.. Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht Distributed under the terms of the BSD 3-Clause License. The full license is in the file LICENSE, distributed with this software. Basic types =========== any --- `xtl::any` is a backport of the C++17 class `std::any`. The class describes a type-safe container for single values of any type: .. code:: #include #include "xtl/xany.hpp" xtl::any a = 1; std::cout << a.type().name() << ": " << xtl::any_cast(a) << std::endl; // => i: 1 try { std::cout << xtl::any_cast(a) << std::endl; } catch(const xtl::bad_any_cast& e) { std::cout << e.what() << std::endl; } // => bad any_cast a.reset(); std::cout << std::boolalpha << a.empty() << std::endl; // => true The API of `xtl::any` is the same as that of `std::any`. Full documentation can be found on `cppreference `_. xbasic_fixed_string ------------------- TODO xcomplex -------- `xcomplex` is the equivalent to `std::complex`, where the real ang imaginary part can be stored either as values, or as references. Therefore, it can be used as a proxy on real values already initialized. This is particularly interesting for storing real and imaginary parts in different containers, and gather them as complex values for computation. This allows optimzations (such as vectorization) on the real and imgaginary values. .. code:: #include #include #include "xtl/xcomplex.hpp" std::vector arg1_real = { 1., 2.}; std::vector arg1_imag = { 3., 4.}; std::vector arg2_real = { 2., 4.}; std::vector arg2_real = { 1., 3.}; std::vector res_real(2); std::vector res_imag(2); using complex = xtl::xcomplex; using const_complex = xtl::xcomplex; for (size_t i = 0; i < 2; ++i) { complex res(res_real[i], res_img[i]); res = const_complex(arg1_real, arg1_imag) * const_complex(arg2_real, arg2_imag); std::cout << "res = (" << res.real(), << ", " << res.imag() << std::endl; } The API of `xtl::xcomplex` is the same as that of `std::complex`, with the ability to store values as references. Full documentation can be found on `cppreference `_. half_float ---------- The `half_cloat` class implements an IEEE-conformant half-precision floating-point type with the usual arithmetic operators and conversions. It is implicitly convertible from single-precision floating-point, which makes expressions and fnuctions with mixed-type operands to be of the most precise operand type. .. code:: #include 3.14 0.6.21 ------ - CMake: Modernized GTest integration - Add support for ``xtl::endianness`` 0.6.20 ------ - Added xtraits for future simple specialization - Added half_float implementation 0.6.19 ------ - Improved ``mpl::contains`` implementation - Added ``are_equivalent_sequences`` - Various minor improvements 0.6.18 ------ - Relaxed dimension constraint on multidispatcher - Replaced throw with XTL_THROW to support disabling exceptions 0.6.17 ------ - Implemented ``index_of`` for ``mpl::vector`` - Implemented multimethods pattern - Implemented visitor pattern 0.6.16 ------ - Fixed mpark variant inclusion guards - Add a serialiser for xvariant to json - Removed capture all by reference 0.6.15 ------ - Renamed mpark variant header inclusion guard 0.6.14 ------ - Implemented value iterator for map containers 0.6.13 ------ - mpark/variant small change for CUDA 10.2 workaround - Switched the documentation build to QuantStack channel - Refactored CI 0.6.12 ------ - NVCC CUDA compiler compatibility - Wrapped call to ``find_package`` 0.6.11 ------ - Avoids C++20 "requires" keyword 0.6.10 ------ - Set up xtl target's public headers - CMake: adding C++14 standard to target 0.6.9 ----- - Implemented stepping iterators 0.6.8 ----- - Fixed murmur implementation for x86 platform 0.6.7 ----- - Specialized ``promote_type`` for ``std::complex`` 0.6.6 ----- - Fixed ``promote_type`` for ``std::chrono::time_point`` - Update README for Conan installation instructions 0.6.5 ----- - Add supports for clang-cl compiler - Fix cmake command - Fix compiler error with clang-cl compiler 0.6.4 ----- - Fixed forward type 0.6.3 ----- - Fix constness issue in xtl's implementation of std::any. 0.6.2 ----- - Allows xtl to build with -fno-exceptions - Added ``constify`` and ``constify_t`` - Added ``size_t`` overloads for random access iterators 0.6.1 ----- - Latex does not know how to include svg - Added ``XTL_REQUIRES_IMPL`` macro - Removed warnings 0.6.0 ----- - Standalone build of xtl tests - Moved ``xmasked_value`` from `xtensor` - Moved ``promote_type`` from `xtensor` - Disabled ``xoptional`` methods for ``xmasked_value`` - Implemented ``select`` - ``make_sequence`` from ``initializer_list`` 0.5.4 ----- - Implementation of mpl::unique - Prevent installation of gtest artifact 0.5.3 ----- - upgraded to mpark/variant 1.4.0 - implemented concepts - implemented split of type lists 0.5.2 ----- - fixed C++11 compatibility in xjson.hpp 0.5.1 ----- - reverse order of initialization of optional - fixup mime type rendering of fixed string - closure wrapper assignment fixed 0.5.0 ----- - Serialization and deserialization of fixed strings - Inequality comparisons removed from bidirectional iterator base - Simplified forward sequence - Fixed forward sequence - Removed warnings - const reference getter for variant holding non const references - xget on rvalue fixed - Added storage option to fixed string - Added missing entries of header files in CMakeLists.txt - Refactored xdynamic_bitset - Fixed forwrad sequence for non resizable types - Removed meta pop-back 0.4.16 ------ - meta find_if implementation - Enable CTest and CMake cleanup - Make nlohmann_json optional in the tests, exported C++14 requirements 0.4.15 ------ - Value types in const closures are not const qualified anymore, to allow move - Added third template parameter to forward_sequence that allows for true forwarding of sequences 0.4.14 ------ - Fixed typo in 'xtl.pc.in' - Removed -march=native from systems that do not support in CMakeLists - Added hash.verification result for big-endian systemss - Fixed common_optional_impl - Implemented xeus-cling mime_bundle_repr for xoptional, xcomplex and xfixed_string 0.4.13 ------ - CMake call to find_package with nlohmann_json is QUIET - Fix typo in xoptional swap - Added pkgconfig support 0.4.12 ------ - operator overload fixes for xcomplex 0.4.11 ------ - add missing `` header in xcomplex - fix xcomplex isnan test 0.4.10 ------ - `xcomplex` implementation - `xcomplex_sequence` implementation 0.4.9 ----- - return type of `static_if` fixed 0.4.8 ----- - support for JSON serialization of xoptionals 0.4.7 ----- - support for uninitialized `make_sequence` 0.4.6 ----- - remove an unused file. - support for overloaded lambdas 0.4.5 ----- - xget for variant on xclosure_wrapper 0.4.4 ----- - bug fix in any - hierarchy generators 0.4.3 ----- - missing near integers functions for `xoptional` - `xoptional` compilation issue fixed 0.4.2 ----- - added missing operators for xoptional - removed compiler warning if cpp_exceptions already defined 0.4.1 ----- - Bug fix in move semantics for xoptional free functions (`value` and `has_value`) - Use `static_if` instead of regular `if` to remove gcc-6 warning. - Document installation with the Spack package manager. - Fix complex operators with closure wrappers. - Integrate upstream fix for the variant implementation. 0.4.0 ----- - Migration to modern target-based cmake 0.3.9 ----- - Bug fix in the computing of hashes for 32 bit platforms - Fixing warnings 0.3.8 ----- - Improvements and fixes in base iterators (common iterator tag) 0.3.7 ----- - Fixes in `xoptional`. 0.3.6 ----- - Addition of base iterators for linear containers, and associative containers. 0.3.5 ----- - Addition of `value` and `has_value` free functions. - Bug fix in comparison operator for `xclosure_wrapper`. 0.3.4 ----- - Better semantics for assignment operators in `xoptional`. - Addition of `static_if` in `xtl::mpl`. - Addition of `xtl::identity` functor in xfunctional. 0.3.3 ----- - Work around Visual Studio compiler bug in `xoptional_proxy`. 0.3.2 ----- - Improvement of xoptional value semantics (explicit constructors when underlying value type not implicitely constructable) 0.3.1 ----- - Fixes in closure wrapper semantics 0.3.0 ----- - Improve optional sequence - Use dynamic bitset in optional vector - Added base64encode and base64decode 0.2.11 ------ - Added dynamic bitset 0.2.10 ------ - Added meta programming tools 0.2.9 ----- - Added variant implementation 0.2.8 ----- - Added proxy wrapper for pointer semantics. 0.2.7 ----- - Added implementation for closure pointer 0.2.6 ----- - Added base class for random access iterators 0.2.5 ----- - Added closure wrappers 0.2.4 ----- - Added implementation of std::any 0.2.3 ----- - Fixed bug in fixed-size string hashing 0.2.2 ----- - Added the hashing of fixed-size strings 0.2.1 ----- - Fixed-size strings - Fixup issue with ambiguous overload of operator<< 0.2.0 ----- - Moving features from xtensor (xcomplex, xoptional, xsequence, xtypetraits) xtl-0.7.2/docs/source/cmake.svg000066400000000000000000000425311400411521700163600ustar00rootroot00000000000000 image/svg+xml xtl-0.7.2/docs/source/conda.svg000066400000000000000000000034151400411521700163620ustar00rootroot00000000000000xtl-0.7.2/docs/source/conf.py000066400000000000000000000014751400411521700160600ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- import os import subprocess on_rtd = os.environ.get('READTHEDOCS', None) == 'True' if on_rtd: subprocess.call('cd ..; doxygen', shell=True) import sphinx_rtd_theme html_theme = "sphinx_rtd_theme" html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] def setup(app): app.add_stylesheet("main_stylesheet.css") extensions = ['breathe'] breathe_projects = { 'xtl': '../xml' } templates_path = ['_templates'] html_static_path = ['_static'] source_suffix = '.rst' master_doc = 'index' project = 'xtl' copyright = '2017, Johan Mabille and Sylvain Corlay' author = 'Johan Mabille and Sylvain Corlay' html_logo = 'quantstack-white.svg' exclude_patterns = [] highlight_language = 'c++' pygments_style = 'sphinx' todo_include_todos = False htmlhelp_basename = 'xtldoc' xtl-0.7.2/docs/source/containers.rst000066400000000000000000000006751400411521700174610ustar00rootroot00000000000000.. Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht Distributed under the terms of the BSD 3-Clause License. The full license is in the file LICENSE, distributed with this software. Containers ========== xcomplex_sequence ----------------- TODO xdynamic_bitset --------------- TODO xiterator_base -------------- TODO xoptional_sequence ------------------ TODO xsequence --------- TODO xspan ----- TODO xtl-0.7.2/docs/source/debian.svg000066400000000000000000000153171400411521700165240ustar00rootroot00000000000000 ]> xtl-0.7.2/docs/source/design_patterns.rst000066400000000000000000000005351400411521700205000ustar00rootroot00000000000000.. Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht Distributed under the terms of the BSD 3-Clause License. The full license is in the file LICENSE, distributed with this software. Design Patterns =============== Hierarchy Generator ------------------- TODO Multimethods ------------ TODO Visitor ------- TODO xtl-0.7.2/docs/source/index.rst000066400000000000000000000020511400411521700164110ustar00rootroot00000000000000.. Copyright (c) 2017, Johan Mabille and Sylvain Corlay Distributed under the terms of the BSD 3-Clause License. The full license is in the file LICENSE, distributed with this software. .. image:: xtl.svg :alt: xtl Basic tools (containers, algorithms) used by other quantstack packages Introduction ------------ `xtl` gathers generic purpose algorithms and containers that are used by the `xtensor` stack and the `xeus` stack. Some of the features are C++14 backport of C++17 classes and algorithms, such as `variant` or `any`. Licensing --------- We use a shared copyright model that enables all contributors to maintain the copyright on their contributions. This software is licensed under the BSD-3-Clause license. See the LICENSE file for details. .. toctree:: :caption: INSTALLATION :maxdepth: 2 installation changelog .. toctree:: :caption: USAGE :maxdepth: 2 basic_types containers meta_programming design_patterns miscellaneous .. toctree:: :caption: DEVELOPER ZONE build-options releasing xtl-0.7.2/docs/source/installation.rst000066400000000000000000000032521400411521700200070ustar00rootroot00000000000000.. Copyright (c) 2017, Johan Mabille and Sylvain Corlay Distributed under the terms of the BSD 3-Clause License. The full license is in the file LICENSE, distributed with this software. .. raw:: html Installation ============ Although ``xtl`` is a header-only library, we provide standardized means to install it, with package managers or with cmake. Besides the xtl headers, all these methods place the ``cmake`` project configuration file in the right location so that third-party projects can use cmake's ``find_package`` to locate xtl headers. .. image:: conda.svg Using the conda package ----------------------- A package for xtl is available on the conda package manager. .. code:: conda install -c conda-forge xtl .. image:: spack.svg Using the Spack package ----------------------- A package for xtl is available on the Spack package manager. .. code:: spack install xtl spack load xtl .. image:: cmake.svg From source with cmake ---------------------- You can also install ``xtl`` from source with cmake. On Unix platforms, from the source directory: .. code:: mkdir build cd build cmake -DCMAKE_INSTALL_PREFIX=/path/to/prefix .. make install On Windows platforms, from the source directory: .. code:: mkdir build cd build cmake -G "NMake Makefiles" -DCMAKE_INSTALL_PREFIX=/path/to/prefix .. nmake nmake install See the section of the documentation on :doc:`build-options`, for more details on how to cmake options. xtl-0.7.2/docs/source/meta_programming.rst000066400000000000000000000005201400411521700206310ustar00rootroot00000000000000.. Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht Distributed under the terms of the BSD 3-Clause License. The full license is in the file LICENSE, distributed with this software. Meta Programming ================ xclosure -------- TODO xtype_traits ------------ TODO type vector ----------- TODO xtl-0.7.2/docs/source/miscellaneous.rst000066400000000000000000000005121400411521700201450ustar00rootroot00000000000000.. Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht Distributed under the terms of the BSD 3-Clause License. The full license is in the file LICENSE, distributed with this software. Miscellaneous ============= Base 64 encoding ---------------- TODO xhash ----- TODO endianness ---------- TODO xtl-0.7.2/docs/source/quantstack-white.svg000066400000000000000000000116361400411521700205760ustar00rootroot00000000000000 image/svg+xmlxtl-0.7.2/docs/source/releasing.rst000066400000000000000000000024761400411521700172660ustar00rootroot00000000000000.. Copyright (c) 2017, Johan Mabille and Sylvain Corlay Distributed under the terms of the BSD 3-Clause License. The full license is in the file LICENSE, distributed with this software. Releasing xtl ============= Releasing a new version ----------------------- From the relevant branch of xtl - Make sure that you are in sync with the master branch of the upstream remote. - In file ``xtl_config.hpp``, set the macros for ``XTL_VERSION_MAJOR``, ``XTL_VERSION_MINOR`` and ``XTL_VERSION_PATCH`` to the desired values. - In file ``README.md``, modify the binder link to point to the new release. - Stage the changes (``git add``), commit the changes (``git commit``) and add a tag of the form ``Major.minor.patch``. It is important to not add any other content to the tag name. - Push the new commit and tag to the main repository. (``git push``, and ``git push --tags``) Updating the conda-forge recipe ------------------------------- xtl has been packaged for the conda package manager. Once the new tag has been pushed on GitHub, edit the conda-forge recipe for xtl in the following fashion: - Update the version number to the new ``Major.minor.patch``. - Set the build number to ``0``. - Update the hash of the source tarball. - Check for the versions of the dependencies. - Optionally, rerender the conda-forge feedstock. xtl-0.7.2/docs/source/spack.svg000066400000000000000000000046711400411521700164040ustar00rootroot00000000000000 xtl-0.7.2/docs/source/xtl.svg000066400000000000000000000106311400411521700161030ustar00rootroot00000000000000 image/svg+xml xtl-0.7.2/environment-dev.yml000066400000000000000000000001161400411521700161630ustar00rootroot00000000000000name: xtl channels: - conda-forge dependencies: - cmake - nlohmann_json xtl-0.7.2/include/000077500000000000000000000000001400411521700137455ustar00rootroot00000000000000xtl-0.7.2/include/xtl/000077500000000000000000000000001400411521700145545ustar00rootroot00000000000000xtl-0.7.2/include/xtl/xany.hpp000066400000000000000000000416501400411521700162520ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) Sylvain Corlay and Johan Mabille and Wolf Vollprecht * * Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XTL_ANY_HPP #define XTL_ANY_HPP #include #include #include #include "xtl/xmeta_utils.hpp" namespace xtl { /************************************** * Implementation of C++17's std::any * **************************************/ // Copyright (c) 2016 Denilson das Mercês Amorim // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) class bad_any_cast : public std::bad_cast { public: const char* what() const noexcept override { return "bad any cast"; } }; namespace detail { inline static void check_any_cast(const void* p) { if (p == nullptr) { #if defined(XTL_NO_EXCEPTIONS) std::fprintf(stderr, "bad_any_cast\n"); std::terminate(); #else throw bad_any_cast(); #endif } } } // namespace detail class any final { public: /// Constructs an object of type any with an empty state. any() : vtable(nullptr) { } /// Constructs an object of type any with an equivalent state as other. any(const any& rhs) : vtable(rhs.vtable) { if (!rhs.empty()) { rhs.vtable->copy(rhs.storage, this->storage); } } /// Constructs an object of type any with a state equivalent to the original state of other. /// rhs is left in a valid but otherwise unspecified state. any(any&& rhs) noexcept : vtable(rhs.vtable) { if (!rhs.empty()) { rhs.vtable->move(rhs.storage, this->storage); rhs.vtable = nullptr; } } /// Same effect as this->clear(). ~any() { this->clear(); } /// Constructs an object of type any that contains an object of type T direct-initialized with std::forward(value). /// /// T shall satisfy the CopyConstructible requirements, otherwise the program is ill-formed. /// This is because an `any` may be copy constructed into another `any` at any time, so a copy should always be allowed. template ::type, any>::value>::type> any(ValueType&& value) { static_assert(std::is_copy_constructible::type>::value, "T shall satisfy the CopyConstructible requirements."); this->construct(std::forward(value)); } /// Has the same effect as any(rhs).swap(*this). No effects if an exception is thrown. any& operator=(const any& rhs) { any(rhs).swap(*this); return *this; } /// Has the same effect as any(std::move(rhs)).swap(*this). /// /// The state of *this is equivalent to the original state of rhs and rhs is left in a valid /// but otherwise unspecified state. any& operator=(any&& rhs) noexcept { any(std::move(rhs)).swap(*this); return *this; } /// Has the same effect as any(std::forward(value)).swap(*this). No effect if a exception is thrown. /// /// T shall satisfy the CopyConstructible requirements, otherwise the program is ill-formed. /// This is because an `any` may be copy constructed into another `any` at any time, so a copy should always be allowed. template ::type, any>::value>::type> any& operator=(ValueType&& value) { static_assert(std::is_copy_constructible::type>::value, "T shall satisfy the CopyConstructible requirements."); any(std::forward(value)).swap(*this); return *this; } /// If not empty, destroys the contained object. void clear() noexcept { if (!empty()) { this->vtable->destroy(storage); this->vtable = nullptr; } } /// C++17 equivalent of clear void reset() noexcept { clear(); } /// Returns true if *this has no contained object, otherwise false. bool empty() const noexcept { return this->vtable == nullptr; } /// C++17 equivalent of !empty() bool has_value() const noexcept { return !empty(); } /// If *this has a contained object of type T, typeid(T); otherwise typeid(void). const std::type_info& type() const noexcept { return empty() ? typeid(void) : this->vtable->type(); } /// Exchange the states of *this and rhs. void swap(any& rhs) noexcept { if (this->vtable != rhs.vtable) { any tmp(std::move(rhs)); // move from *this to rhs. rhs.vtable = this->vtable; if (this->vtable != nullptr) { this->vtable->move(this->storage, rhs.storage); //this->vtable = nullptr; -- uneeded, see below } // move from tmp (previously rhs) to *this. this->vtable = tmp.vtable; if (tmp.vtable != nullptr) { tmp.vtable->move(tmp.storage, this->storage); tmp.vtable = nullptr; } } else // same types { if (this->vtable != nullptr) this->vtable->swap(this->storage, rhs.storage); } } private: // Storage and Virtual Method Table union storage_union { using stack_storage_t = typename std::aligned_storage<2 * sizeof(void*), std::alignment_of::value>::type; void* dynamic; stack_storage_t stack; // 2 words for e.g. shared_ptr }; /// Base VTable specification. struct vtable_type { // Note: The caller is responssible for doing .vtable = nullptr after destructful operations // such as destroy() and/or move(). /// The type of the object this vtable is for. const std::type_info& (*type)() noexcept; /// Destroys the object in the union. /// The state of the union after this call is unspecified, caller must ensure not to use src anymore. void (*destroy)(storage_union&) noexcept; /// Copies the **inner** content of the src union into the yet unitialized dest union. /// As such, both inner objects will have the same state, but on separate memory locations. void (*copy)(const storage_union& src, storage_union& dest); /// Moves the storage from src to the yet unitialized dest union. /// The state of src after this call is unspecified, caller must ensure not to use src anymore. void (*move)(storage_union& src, storage_union& dest) noexcept; /// Exchanges the storage between lhs and rhs. void (*swap)(storage_union& lhs, storage_union& rhs) noexcept; }; /// VTable for dynamically allocated storage. template struct vtable_dynamic { static const std::type_info& type() noexcept { return typeid(T); } static void destroy(storage_union& storage) noexcept { //assert(reinterpret_cast(storage.dynamic)); delete reinterpret_cast(storage.dynamic); } static void copy(const storage_union& src, storage_union& dest) { dest.dynamic = new T(*reinterpret_cast(src.dynamic)); } static void move(storage_union& src, storage_union& dest) noexcept { dest.dynamic = src.dynamic; src.dynamic = nullptr; } static void swap(storage_union& lhs, storage_union& rhs) noexcept { // just exchage the storage pointers. std::swap(lhs.dynamic, rhs.dynamic); } }; /// VTable for stack allocated storage. template struct vtable_stack { static const std::type_info& type() noexcept { return typeid(T); } static void destroy(storage_union& storage) noexcept { reinterpret_cast(&storage.stack)->~T(); } static void copy(const storage_union& src, storage_union& dest) { new (&dest.stack) T(reinterpret_cast(src.stack)); } static void move(storage_union& src, storage_union& dest) noexcept { // one of the conditions for using vtable_stack is a nothrow move constructor, // so this move constructor will never throw a exception. new (&dest.stack) T(std::move(reinterpret_cast(src.stack))); destroy(src); } static void swap(storage_union& lhs, storage_union& rhs) noexcept { storage_union tmp_storage; move(rhs, tmp_storage); move(lhs, rhs); move(tmp_storage, lhs); } }; /// Whether the type T must be dynamically allocated or can be stored on the stack. template struct requires_allocation : std::integral_constant::value // N4562 �6.3/3 [any.class] && sizeof(T) <= sizeof(storage_union::stack) && std::alignment_of::value <= std::alignment_of::value)> { }; /// Returns the pointer to the vtable of the type T. template static vtable_type* vtable_for_type() { using VTableType = typename std::conditional::value, vtable_dynamic, vtable_stack>::type; static vtable_type table = { VTableType::type, VTableType::destroy, VTableType::copy, VTableType::move, VTableType::swap, }; return &table; } protected: template friend const T* any_cast(const any* operand) noexcept; template friend T* any_cast(any* operand) noexcept; /// Same effect as is_same(this->type(), t); bool is_typed(const std::type_info& t) const { return is_same(this->type(), t); } /// Checks if two type infos are the same. /// /// If ANY_IMPL_FAST_TYPE_INFO_COMPARE is defined, checks only the address of the /// type infos, otherwise does an actual comparision. Checking addresses is /// only a valid approach when there's no interaction with outside sources /// (other shared libraries and such). static bool is_same(const std::type_info& a, const std::type_info& b) { #ifdef ANY_IMPL_FAST_TYPE_INFO_COMPARE return &a == &b; #else return a == b; #endif } /// Casts (with no type_info checks) the storage pointer as const T*. template const T* cast() const noexcept { return requires_allocation::type>::value ? reinterpret_cast(storage.dynamic) : reinterpret_cast(&storage.stack); } /// Casts (with no type_info checks) the storage pointer as T*. template T* cast() noexcept { return requires_allocation::type>::value ? reinterpret_cast(storage.dynamic) : reinterpret_cast(&storage.stack); } private: storage_union storage; // on offset(0) so no padding for align vtable_type* vtable; /// Chooses between stack and dynamic allocation for the type decay_t, /// assigns the correct vtable, and constructs the object on our storage. template void construct(ValueType&& value) { using T = typename std::decay::type; this->vtable = vtable_for_type(); return xtl::mpl::static_if::value>([&](auto self) { self(*this).storage.dynamic = new T(std::forward(value)); }, /*else*/ [&](auto self) { new (&self(*this).storage.stack) T(std::forward(value)); }); } }; namespace detail { template inline ValueType any_cast_move_if_true(typename std::remove_reference::type* p, std::true_type) { return std::move(*p); } template inline ValueType any_cast_move_if_true(typename std::remove_reference::type* p, std::false_type) { return *p; } } /// Performs *any_cast>>(&operand), or throws bad_any_cast on failure. template inline ValueType any_cast(const any& operand) { auto p = any_cast::type>::type>(&operand); detail::check_any_cast(p); return *p; } /// Performs *any_cast>(&operand), or throws bad_any_cast on failure. template inline ValueType any_cast(any& operand) { auto p = any_cast::type>(&operand); detail::check_any_cast(p); return *p; } /// /// If ANY_IMPL_ANYCAST_MOVEABLE is not defined, does as N4562 specifies: /// Performs *any_cast>(&operand), or throws bad_any_cast on failure. /// /// If ANY_IMPL_ANYCAST_MOVEABLE is defined, does as LWG Defect 2509 specifies: /// If ValueType is MoveConstructible and isn't a lvalue reference, performs /// std::move(*any_cast>(&operand)), otherwise /// *any_cast>(&operand). Throws bad_any_cast on failure. /// template inline ValueType any_cast(any&& operand) { #ifdef ANY_IMPL_ANY_CAST_MOVEABLE // https://cplusplus.github.io/LWG/lwg-active.html#2509 using can_move = std::integral_constant::value && !std::is_lvalue_reference::value>; #else using can_move = std::false_type; #endif auto p = any_cast::type>(&operand); detail::check_any_cast(p); return detail::any_cast_move_if_true(p, can_move()); } /// If operand != nullptr && operand->type() == typeid(ValueType), a pointer to the object /// contained by operand, otherwise nullptr. template inline const T* any_cast(const any* operand) noexcept { if (operand == nullptr || !operand->is_typed(typeid(T))) return nullptr; else return operand->cast(); } /// If operand != nullptr && operand->type() == typeid(ValueType), a pointer to the object /// contained by operand, otherwise nullptr. template inline T* any_cast(any* operand) noexcept { if (operand == nullptr || !operand->is_typed(typeid(T))) return nullptr; else return operand->cast(); } } namespace std { inline void swap(xtl::any& lhs, xtl::any& rhs) noexcept { lhs.swap(rhs); } } #endif xtl-0.7.2/include/xtl/xbase64.hpp000066400000000000000000000044411400411521700165440ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) Sylvain Corlay and Johan Mabille and Wolf Vollprecht * * Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XTL_BASE64_HPP #define XTL_BASE64_HPP #include #include #include #include "xsequence.hpp" namespace xtl { inline std::string base64decode(const std::string& input) { std::array T; T.fill(-1); for (std::size_t i = 0; i < 64; ++i) { T[std::size_t("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i])] = int(i); } std::string output; int val = 0; int valb = -8; for (char c : input) { if (T[std::size_t(c)] == -1) { break; } val = (val << 6) + T[std::size_t(c)]; valb += 6; if (valb >= 0) { output.push_back(char((val >> valb) & 0xFF)); valb -= 8; } } return output; } inline std::string base64encode(const std::string& input) { std::string output; int val = 0; int valb = -6; for (char sc : input) { unsigned char c = static_cast(sc); val = (val << 8) + c; valb += 8; while (valb >= 0) { output.push_back("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(val >> valb) & 0x3F]); valb -= 6; } } if (valb > -6) { output.push_back("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[((val << 8) >> (valb + 8)) & 0x3F]); } while (output.size() % 4) { output.push_back('='); } return output; } } #endif xtl-0.7.2/include/xtl/xbasic_fixed_string.hpp000066400000000000000000003047431400411521700213160ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) Sylvain Corlay and Johan Mabille and Wolf Vollprecht * * Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XTL_BASIC_FIXED_STRING_HPP #define XTL_BASIC_FIXED_STRING_HPP #include #include #include #include #include #include #include #ifdef __CLING__ #include #endif #include "xhash.hpp" #include "xtl_config.hpp" namespace xtl { namespace string_policy { template struct silent_error; template struct throwing_error; } /*********************** * xbasic_fixed_string * ***********************/ enum storage_options { buffer = 1 << 0, pointer = 1 << 1, store_size = 1 << 2, is_const = 1 << 3 }; template class EP = string_policy::silent_error, class TR = std::char_traits> class xbasic_fixed_string; template class EP, class TR> std::basic_ostream& operator<<(std::basic_ostream& os, const xbasic_fixed_string& str); template class EP, class TR> std::basic_istream& operator>>(std::basic_istream& is, xbasic_fixed_string& str); template using xbasic_string_view = xbasic_fixed_string; namespace detail { template struct select_storage; template struct fixed_small_string_storage_impl; template struct fixed_small_string_storage_impl { static_assert(N <= (1u << (8 * sizeof(T))), "small string"); fixed_small_string_storage_impl() { set_size(0); } fixed_small_string_storage_impl(T ptr[N], std::size_t size) : m_buffer(ptr) { m_buffer[N - 1] = N - size; } T* buffer() { return m_buffer; } const T* buffer() const { return m_buffer; } std::size_t size() const { // Don't use std::make_unsinged_t here, this should remain C++11 compatible using unsigned_type = typename std::make_unsigned::type; return N - reinterpret_cast(m_buffer)[N - 1]; } void set_size(std::size_t sz) { assert(sz < N && "setting a small size"); // Don't use std::make_unsinged_t here, this should remain C++11 compatible using unsigned_type = typename std::make_unsigned::type; reinterpret_cast(m_buffer)[N - 1] = static_cast(N - sz); m_buffer[sz] = '\0'; } void adjust_size(std::ptrdiff_t val) { assert(size() + val >= 0 && "adjusting to positive size"); set_size(static_cast(static_cast(size()) + val)); } T m_buffer[N]; }; template struct fixed_string_storage_impl { fixed_string_storage_impl() = default; fixed_string_storage_impl(T ptr, std::size_t size) : m_buffer(ptr), m_size(size) { } T& buffer() { return m_buffer; } const T& buffer() const { return m_buffer; } std::size_t size() const { return m_size; } void set_size(std::size_t sz) { m_size = sz; m_buffer[sz] = '\0'; } void adjust_size(std::ptrdiff_t val) { m_size += std::size_t(val); m_buffer[m_size] = '\0'; } T m_buffer; std::size_t m_size; }; template struct fixed_string_external_storage_impl { fixed_string_external_storage_impl() = default; fixed_string_external_storage_impl(T ptr, std::ptrdiff_t/*size*/) { m_buffer = ptr; } T& buffer() { return m_buffer; } const T& buffer() const { return m_buffer; } void set_size(std::size_t sz) { m_buffer[sz] = '\0'; } void adjust_size(std::ptrdiff_t val) { m_buffer[size() + val] = '\0'; } std::size_t size() const { return std::strlen(m_buffer); } T m_buffer; }; template struct select_fixed_storage { using type = fixed_string_storage_impl; }; template struct select_fixed_storage { using type = fixed_small_string_storage_impl; }; template <> struct select_storage { template using type = typename select_fixed_storage::type; }; template <> struct select_storage { template using type = fixed_string_external_storage_impl; }; } template class EP, class TR> class xbasic_fixed_string { public: using traits_type = TR; using value_type = CT; using size_type = std::size_t; using difference_type = std::ptrdiff_t; using storage_type = typename detail::select_storage::template type; using reference = value_type&; using const_reference = const value_type&; using pointer = value_type*; using const_pointer = const value_type*; using iterator = pointer; using const_iterator = const_pointer; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; static const size_type npos; using self_type = xbasic_fixed_string; using initializer_type = std::initializer_list; using string_type = std::basic_string; using error_policy = EP; xbasic_fixed_string(); explicit xbasic_fixed_string(size_type count, value_type ch); explicit xbasic_fixed_string(const self_type& other, size_type pos, size_type count = npos); explicit xbasic_fixed_string(const string_type& other); explicit xbasic_fixed_string(const string_type& other, size_type pos, size_type count = npos); xbasic_fixed_string(const_pointer s, size_type count); xbasic_fixed_string(const_pointer s); xbasic_fixed_string(initializer_type ilist); template xbasic_fixed_string(InputIt first, InputIt last); operator string_type() const; ~xbasic_fixed_string() = default; xbasic_fixed_string(const self_type&) = default; xbasic_fixed_string(self_type&&) = default; self_type& operator=(const self_type&) = default; self_type& operator=(self_type&&) = default; self_type& operator=(const_pointer s); self_type& operator=(value_type ch); self_type& operator=(initializer_type ilist); self_type& operator=(const string_type& str); self_type& assign(size_type count, value_type ch); self_type& assign(const self_type& other, size_type pos, size_type count = npos); self_type& assign(const_pointer s, size_type count); self_type& assign(const_pointer s); self_type& assign(initializer_type ilist); template self_type& assign(InputIt first, InputIt last); self_type& assign(const self_type& rhs); self_type& assign(self_type&& rhs); self_type& assign(const string_type& str); self_type& assign(const string_type& other, size_type pos, size_type count = npos); reference at(size_type pos); const_reference at(size_type pos) const; reference operator[](size_type pos); const_reference operator[](size_type pos) const; reference front(); const_reference front() const; reference back(); const_reference back() const; pointer data() noexcept; const_pointer data() const noexcept; const_pointer c_str() const noexcept; iterator begin() noexcept; iterator end() noexcept; const_iterator begin() const noexcept; const_iterator end() const noexcept; const_iterator cbegin() const noexcept; const_iterator cend() const noexcept; reverse_iterator rbegin() noexcept; reverse_iterator rend() noexcept; const_reverse_iterator rbegin() const noexcept; const_reverse_iterator rend() const noexcept; const_reverse_iterator crbegin() const noexcept; const_reverse_iterator crend() const noexcept; bool empty() const noexcept; size_type size() const noexcept; size_type length() const noexcept; size_type max_size() const noexcept; void clear() noexcept; void push_back(value_type ch); void pop_back(); self_type substr(size_type pos = 0, size_type count = npos) const; size_type copy(pointer dest, size_type count, size_type pos = 0) const; void resize(size_type count); void resize(size_type count, value_type ch); void swap(self_type& rhs) noexcept; self_type& insert(size_type index, size_type count, value_type ch); self_type& insert(size_type index, const_pointer s); self_type& insert(size_type index, const_pointer s, size_type count); self_type& insert(size_type index, const self_type& str); self_type& insert(size_type index, const self_type& str, size_type index_str, size_type count = npos); self_type& insert(size_type index, const string_type& str); self_type& insert(size_type index, const string_type& str, size_type index_str, size_type count = npos); iterator insert(const_iterator pos, value_type ch); iterator insert(const_iterator pos, size_type count, value_type ch); iterator insert(const_iterator pos, initializer_type ilist); template iterator insert(const_iterator pos, InputIt first, InputIt last); self_type& erase(size_type index = 0, size_type count = npos); iterator erase(const_iterator position); iterator erase(const_iterator first, const_iterator last); self_type& append(size_type count, value_type ch); self_type& append(const self_type& str); self_type& append(const self_type& str, size_type pos, size_type count = npos); self_type& append(const string_type& str); self_type& append(const string_type& str, size_type pos, size_type count = npos); self_type& append(const_pointer s, size_type count); self_type& append(const_pointer s); self_type& append(initializer_type ilist); template self_type& append(InputIt first, InputIt last); self_type& operator+=(const self_type& str); self_type& operator+=(const string_type& str); self_type& operator+=(value_type ch); self_type& operator+=(const_pointer s); self_type& operator+=(initializer_type ilist); int compare(const self_type& str) const noexcept; int compare(size_type pos1, size_type count1, const self_type& str) const; int compare(size_type pos1, size_type count1, const self_type& str, size_type pos2, size_type count2 = npos) const; int compare(const string_type& str) const noexcept; int compare(size_type pos1, size_type count1, const string_type& str) const; int compare(size_type pos1, size_type count1, const string_type& str, size_type pos2, size_type count2 = npos) const; int compare(const_pointer s) const noexcept; int compare(size_type pos1, size_type count1, const_pointer s) const; int compare(size_type pos1, size_type count1, const_pointer s, size_type count2) const; self_type& replace(size_type pos, size_type count, const self_type& str); self_type& replace(const_iterator first, const_iterator last, const self_type& str); self_type& replace(size_type pos1, size_type count1, const self_type& str, size_type pos2, size_type count2 = npos); self_type& replace(size_type pos, size_type count, const string_type& str); self_type& replace(const_iterator first, const_iterator last, const string_type& str); self_type& replace(size_type pos1, size_type count1, const string_type& str, size_type pos2, size_type count2 = npos); self_type& replace(size_type pos, size_type count, const_pointer cstr, size_type count2); self_type& replace(const_iterator first, const_iterator last, const_pointer cstr, size_type count2); self_type& replace(size_type pos, size_type count, const_pointer cstr); self_type& replace(const_iterator first, const_iterator last, const_pointer cstr); self_type& replace(size_type pos, size_type count, size_type count2, value_type ch); self_type& replace(const_iterator first, const_iterator last, size_type count2, value_type ch); self_type& replace(const_iterator first, const_iterator last, initializer_type ilist); template self_type& replace(const_iterator first, const_iterator last, InputIt first2, InputIt last2); size_type find(const self_type& str, size_type pos = 0) const noexcept; size_type find(const string_type& str, size_type pos = 0) const noexcept; size_type find(const_pointer s, size_type pos, size_type count) const; size_type find(const_pointer s, size_type pos = 0) const; size_type find(value_type ch, size_type pos = 0) const; size_type rfind(const self_type& str, size_type pos = npos) const noexcept; size_type rfind(const string_type& str, size_type pos = npos) const noexcept; size_type rfind(const_pointer s, size_type pos, size_type count) const; size_type rfind(const_pointer s, size_type pos = npos) const; size_type rfind(value_type ch, size_type pos = npos) const; size_type find_first_of(const self_type& str, size_type pos = 0) const noexcept; size_type find_first_of(const string_type& str, size_type pos = 0) const noexcept; size_type find_first_of(const_pointer s, size_type pos, size_type count) const; size_type find_first_of(const_pointer s, size_type pos = 0) const; size_type find_first_of(value_type ch, size_type pos = 0) const; size_type find_first_not_of(const self_type& str, size_type pos = 0) const noexcept; size_type find_first_not_of(const string_type& str, size_type pos = 0) const noexcept; size_type find_first_not_of(const_pointer s, size_type pos, size_type count) const; size_type find_first_not_of(const_pointer s, size_type pos = 0) const; size_type find_first_not_of(value_type ch, size_type pos = 0) const; size_type find_last_of(const self_type& str, size_type pos = 0) const noexcept; size_type find_last_of(const string_type& str, size_type pos = 0) const noexcept; size_type find_last_of(const_pointer s, size_type pos, size_type count) const; size_type find_last_of(const_pointer s, size_type pos = 0) const; size_type find_last_of(value_type ch, size_type pos = 0) const; size_type find_last_not_of(const self_type& str, size_type pos = npos) const noexcept; size_type find_last_not_of(const string_type& str, size_type pos = npos) const noexcept; size_type find_last_not_of(const_pointer s, size_type pos, size_type count) const; size_type find_last_not_of(const_pointer s, size_type pos = npos) const; size_type find_last_not_of(value_type ch, size_type pos = npos) const; private: int compare_impl(const_pointer s1, size_type count1, const_pointer s2, size_type count2) const noexcept; void update_null_termination() noexcept; void check_index(size_type pos, size_type size, const char* what) const; void check_index_strict(size_type pos, size_type size, const char* what) const; storage_type m_storage; }; template class EP, class TR> const typename xbasic_fixed_string::size_type xbasic_fixed_string::npos = std::basic_string::npos; template using xfixed_string = xbasic_fixed_string; template using xwfixed_string = xbasic_fixed_string; template using xu16fixed_string = xbasic_fixed_string; template using xu32fixed_string = xbasic_fixed_string; /************************** * Concatenation operator * **************************/ template class EP, class TR> xbasic_fixed_string operator+(const xbasic_fixed_string& lhs, const xbasic_fixed_string& rhs); template class EP, class TR> xbasic_fixed_string operator+(const xbasic_fixed_string& lhs, const CT* rhs); template class EP, class TR> xbasic_fixed_string operator+(const xbasic_fixed_string& lhs, CT rhs); template class EP, class TR> xbasic_fixed_string operator+(const CT* lhs, const xbasic_fixed_string& rhs); template class EP, class TR> xbasic_fixed_string operator+(CT lhs, const xbasic_fixed_string& rhs); template class EP, class TR> xbasic_fixed_string operator+(const xbasic_fixed_string&& lhs, const xbasic_fixed_string& rhs); template class EP, class TR> xbasic_fixed_string operator+(const xbasic_fixed_string& lhs, const xbasic_fixed_string&& rhs); template class EP, class TR> xbasic_fixed_string operator+(const xbasic_fixed_string&& lhs, const xbasic_fixed_string&& rhs); template class EP, class TR> xbasic_fixed_string operator+(const xbasic_fixed_string&& lhs, const CT* rhs); template class EP, class TR> xbasic_fixed_string operator+(const xbasic_fixed_string&& lhs, CT rhs); template class EP, class TR> xbasic_fixed_string operator+(const CT* lhs, const xbasic_fixed_string&& rhs); template class EP, class TR> xbasic_fixed_string operator+(CT lhs, const xbasic_fixed_string&& rhs); /************************ * Comparison operators * ************************/ template class EP, class TR> bool operator==(const xbasic_fixed_string& lhs, const xbasic_fixed_string& rhs) noexcept; template class EP, class TR> bool operator==(const xbasic_fixed_string& lhs, const CT* rhs) noexcept; template class EP, class TR> bool operator==(const CT* lhs, const xbasic_fixed_string& rhs) noexcept; template class EP, class TR> bool operator==(const xbasic_fixed_string& lhs, const std::basic_string& rhs) noexcept; template class EP, class TR> bool operator==(const std::basic_string& lhs, const xbasic_fixed_string& rhs) noexcept; template class EP, class TR> bool operator!=(const xbasic_fixed_string& lhs, const xbasic_fixed_string& rhs) noexcept; template class EP, class TR> bool operator!=(const xbasic_fixed_string& lhs, const CT* rhs) noexcept; template class EP, class TR> bool operator!=(const CT* lhs, const xbasic_fixed_string& rhs) noexcept; template class EP, class TR> bool operator!=(const xbasic_fixed_string& lhs, const std::basic_string& rhs) noexcept; template class EP, class TR> bool operator!=(const std::basic_string& lhs, const xbasic_fixed_string& rhs) noexcept; template class EP, class TR> bool operator<(const xbasic_fixed_string& lhs, const xbasic_fixed_string& rhs) noexcept; template class EP, class TR> bool operator<(const xbasic_fixed_string& lhs, const CT* rhs) noexcept; template class EP, class TR> bool operator<(const CT* lhs, const xbasic_fixed_string& rhs) noexcept; template class EP, class TR> bool operator<(const xbasic_fixed_string& lhs, const std::basic_string& rhs) noexcept; template class EP, class TR> bool operator<(const std::basic_string& lhs, const xbasic_fixed_string& rhs) noexcept; template class EP, class TR> bool operator<=(const xbasic_fixed_string& lhs, const xbasic_fixed_string& rhs) noexcept; template class EP, class TR> bool operator<=(const xbasic_fixed_string& lhs, const CT* rhs) noexcept; template class EP, class TR> bool operator<=(const CT* lhs, const xbasic_fixed_string& rhs) noexcept; template class EP, class TR> bool operator<=(const xbasic_fixed_string& lhs, const std::basic_string& rhs) noexcept; template class EP, class TR> bool operator<=(const std::basic_string& lhs, const xbasic_fixed_string& rhs) noexcept; template class EP, class TR> bool operator>(const xbasic_fixed_string& lhs, const xbasic_fixed_string& rhs) noexcept; template class EP, class TR> bool operator>(const xbasic_fixed_string& lhs, const CT* rhs) noexcept; template class EP, class TR> bool operator>(const CT* lhs, const xbasic_fixed_string& rhs) noexcept; template class EP, class TR> bool operator>(const xbasic_fixed_string& lhs, const std::basic_string& rhs) noexcept; template class EP, class TR> bool operator>(const std::basic_string& lhs, const xbasic_fixed_string& rhs) noexcept; template class EP, class TR> bool operator>=(const xbasic_fixed_string& lhs, const xbasic_fixed_string& rhs) noexcept; template class EP, class TR> bool operator>=(const xbasic_fixed_string& lhs, const CT* rhs) noexcept; template class EP, class TR> bool operator>=(const CT* lhs, const xbasic_fixed_string& rhs) noexcept; template class EP, class TR> bool operator>=(const xbasic_fixed_string& lhs, const std::basic_string& rhs) noexcept; template class EP, class TR> bool operator>=(const std::basic_string& lhs, const xbasic_fixed_string& rhs) noexcept; template class EP, class TR> void swap(xbasic_fixed_string& lhs, xbasic_fixed_string& rhs); /****************************** * Input / output declaration * ******************************/ template class EP, class TR> std::basic_istream& getline(std::basic_istream& input, xbasic_fixed_string& str, CT delim); template class EP, class TR> std::basic_istream& getline(std::basic_istream&& input, xbasic_fixed_string& str, CT delim); template class EP, class TR> std::basic_istream& getline(std::basic_istream& input, xbasic_fixed_string& str); template class EP, class TR> std::basic_istream& getline(std::basic_istream&& input, xbasic_fixed_string& str); } // namespace xtl namespace std { template class EP, class TR> struct hash<::xtl::xbasic_fixed_string> { using argument_type = ::xtl::xbasic_fixed_string; using result_type = std::size_t; inline result_type operator()(const argument_type& arg) const { return ::xtl::hash_bytes(arg.data(), arg.size(), static_cast(0xc70f6907UL)); } }; } // namespace std namespace xtl { /******************************** * xbasic_fixed_string policies * ********************************/ namespace string_policy { template struct silent_error { inline static std::size_t check_size(std::size_t size) { return size; } inline static std::size_t check_add(std::size_t size1, std::size_t size2) { return size1 + size2; } }; template struct throwing_error { inline static std::size_t check_size(std::size_t size) { if (size > N) { std::ostringstream oss; oss << "Invalid size (" << size << ") for xbasic_fixed_string - maximal size: " << N; #if defined(XTL_NO_EXCEPTIONS) std::fprintf(stderr, "%s\n", oss.str().c_str()); std::terminate(); #else throw std::length_error(oss.str()); #endif } return size; } inline static std::size_t check_add(std::size_t size1, std::size_t size2) { return check_size(size1 + size2); } }; } // string_policy /************************************** * xbasic_fixed_string implementation * **************************************/ /**************** * Constructors * ****************/ template class EP, class TR> inline xbasic_fixed_string::xbasic_fixed_string() : m_storage() { } template class EP, class TR> inline xbasic_fixed_string::xbasic_fixed_string(size_type count, value_type ch) : m_storage() { assign(count, ch); } template class EP, class TR> inline xbasic_fixed_string::xbasic_fixed_string(const self_type& other, size_type pos, size_type count) : m_storage() { assign(other, pos, count); } template class EP, class TR> inline xbasic_fixed_string::xbasic_fixed_string(const string_type& other) : m_storage() { assign(other); } template class EP, class TR> inline xbasic_fixed_string::xbasic_fixed_string(const string_type& other, size_type pos, size_type count) : m_storage() { assign(other, pos, count); } template class EP, class TR> inline xbasic_fixed_string::xbasic_fixed_string(const_pointer s, size_type count) : m_storage() { assign(s, count); } template class EP, class TR> inline xbasic_fixed_string::xbasic_fixed_string(const_pointer s) : m_storage() { assign(s); } template class EP, class TR> inline xbasic_fixed_string::xbasic_fixed_string(initializer_type ilist) : m_storage() { assign(ilist); } template class EP, class TR> template inline xbasic_fixed_string::xbasic_fixed_string(InputIt first, InputIt last) : m_storage() { assign(first, last); } template class EP, class TR> inline xbasic_fixed_string::operator string_type() const { return string_type(data()); } /************** * Assignment * **************/ template class EP, class TR> inline auto xbasic_fixed_string::operator=(const_pointer s) -> self_type& { return assign(s); } template class EP, class TR> inline auto xbasic_fixed_string::operator=(value_type ch) -> self_type& { return assign(size_type(1), ch); } template class EP, class TR> inline auto xbasic_fixed_string::operator=(initializer_type ilist) -> self_type& { return assign(ilist); } template class EP, class TR> inline auto xbasic_fixed_string::operator=(const string_type& str) -> self_type& { return assign(str); } template class EP, class TR> inline auto xbasic_fixed_string::assign(size_type count, value_type ch) -> self_type& { m_storage.set_size(error_policy::check_size(count)); traits_type::assign(data(), count, ch); return *this; } template class EP, class TR> inline auto xbasic_fixed_string::assign(const self_type& other, size_type pos, size_type count) -> self_type& { check_index_strict(pos, other.size(), "xbasic_fixed_string::assign"); size_type copy_count = std::min(other.size() - pos, count); m_storage.set_size(error_policy::check_size(copy_count)); traits_type::copy(data(), other.data() + pos, copy_count); return *this; } template class EP, class TR> inline auto xbasic_fixed_string::assign(const_pointer s, size_type count) -> self_type& { m_storage.set_size(error_policy::check_size(count)); traits_type::copy(data(), s, count); return *this; } template class EP, class TR> inline auto xbasic_fixed_string::assign(const_pointer s) -> self_type& { std::size_t ssize = traits_type::length(s); return assign(s, ssize); } template class EP, class TR> inline auto xbasic_fixed_string::assign(initializer_type ilist) -> self_type& { return assign(ilist.begin(), ilist.end()); } template class EP, class TR> template inline auto xbasic_fixed_string::assign(InputIt first, InputIt last) -> self_type& { m_storage.set_size(error_policy::check_size(static_cast(std::distance(first, last)))); std::copy(first, last, data()); return *this; } template class EP, class TR> inline auto xbasic_fixed_string::assign(const self_type& rhs) -> self_type& { if (this != &rhs) { m_storage.set_size(rhs.size()); traits_type::copy(data(), rhs.data(), rhs.size()); } return *this; } template class EP, class TR> inline auto xbasic_fixed_string::assign(self_type&& rhs) -> self_type& { if (this != &rhs) { m_storage.set_size(rhs.size()); traits_type::copy(data(), rhs.data(), rhs.size()); } return *this; } template class EP, class TR> inline auto xbasic_fixed_string::assign(const string_type& other) -> self_type& { return assign(other.c_str()); } template class EP, class TR> inline auto xbasic_fixed_string::assign(const string_type& other, size_type pos, size_type count) -> self_type& { return assign(other.c_str() + pos, std::min(count, other.size() - pos)); } /****************** * Element access * ******************/ template class EP, class TR> inline auto xbasic_fixed_string::at(size_type pos) -> reference { check_index(pos, size(), "basic_fixed_string::at"); return this->operator[](pos); } template class EP, class TR> inline auto xbasic_fixed_string::at(size_type pos) const -> const_reference { check_index(pos, size(), "basic_fixed_string::at"); return this->operator[](pos); } template class EP, class TR> inline auto xbasic_fixed_string::operator[](size_type pos) -> reference { return data()[pos]; } template class EP, class TR> inline auto xbasic_fixed_string::operator[](size_type pos) const -> const_reference { return data()[pos]; } template class EP, class TR> inline auto xbasic_fixed_string::front() -> reference { return this->operator[](0); } template class EP, class TR> inline auto xbasic_fixed_string::front() const -> const_reference { return this->operator[](0); } template class EP, class TR> inline auto xbasic_fixed_string::back() -> reference { return this->operator[](size() - 1); } template class EP, class TR> inline auto xbasic_fixed_string::back() const -> const_reference { return this->operator[](size() - 1); } template class EP, class TR> inline auto xbasic_fixed_string::data() noexcept -> pointer { return m_storage.buffer(); } template class EP, class TR> inline auto xbasic_fixed_string::data() const noexcept -> const_pointer { return m_storage.buffer(); } template class EP, class TR> inline auto xbasic_fixed_string::c_str() const noexcept -> const_pointer { return m_storage.buffer(); } /************* * Iterators * *************/ template class EP, class TR> inline auto xbasic_fixed_string::begin() noexcept -> iterator { return data(); } template class EP, class TR> inline auto xbasic_fixed_string::end() noexcept -> iterator { return data() + size(); } template class EP, class TR> inline auto xbasic_fixed_string::begin() const noexcept -> const_iterator { return cbegin(); } template class EP, class TR> inline auto xbasic_fixed_string::end() const noexcept -> const_iterator { return cend(); } template class EP, class TR> inline auto xbasic_fixed_string::cbegin() const noexcept -> const_iterator { return data(); } template class EP, class TR> inline auto xbasic_fixed_string::cend() const noexcept -> const_iterator { return data() + size(); } template class EP, class TR> inline auto xbasic_fixed_string::rbegin() noexcept -> reverse_iterator { return reverse_iterator(end()); } template class EP, class TR> inline auto xbasic_fixed_string::rend() noexcept -> reverse_iterator { return reverse_iterator(begin()); } template class EP, class TR> inline auto xbasic_fixed_string::rbegin() const noexcept -> const_reverse_iterator { return const_reverse_iterator(end()); } template class EP, class TR> inline auto xbasic_fixed_string::rend() const noexcept -> const_reverse_iterator { return const_reverse_iterator(begin()); } template class EP, class TR> inline auto xbasic_fixed_string::crbegin() const noexcept -> const_reverse_iterator { return const_reverse_iterator(end()); } template class EP, class TR> inline auto xbasic_fixed_string::crend() const noexcept -> const_reverse_iterator { return const_reverse_iterator(begin()); } /************ * Capacity * ************/ template class EP, class TR> inline bool xbasic_fixed_string::empty() const noexcept { return size() == 0; } template class EP, class TR> inline auto xbasic_fixed_string::size() const noexcept -> size_type { return m_storage.size(); } template class EP, class TR> inline auto xbasic_fixed_string::length() const noexcept -> size_type { return m_storage.size(); } template class EP, class TR> inline auto xbasic_fixed_string::max_size() const noexcept -> size_type { return N; } /************** * Operations * **************/ template class EP, class TR> inline void xbasic_fixed_string::clear() noexcept { m_storage.set_size(0); } template class EP, class TR> inline void xbasic_fixed_string::push_back(value_type ch) { error_policy::check_add(size(), size_type(1)); data()[size()] = ch; m_storage.adjust_size(+1); } template class EP, class TR> inline void xbasic_fixed_string::pop_back() { m_storage.adjust_size(-1); } template class EP, class TR> inline auto xbasic_fixed_string::substr(size_type pos, size_type count) const -> self_type { return self_type(*this, pos, count); } template class EP, class TR> inline auto xbasic_fixed_string::copy(pointer dest, size_type count, size_type pos) const -> size_type { check_index_strict(pos, size(), "xbasic_fixed_string::copy"); size_type nb_copied = std::min(count, size() - pos); traits_type::copy(dest, data() + pos, nb_copied); return nb_copied; } template class EP, class TR> inline void xbasic_fixed_string::resize(size_type count) { resize(count, value_type(' ')); // need to initialize with some value != \0 } template class EP, class TR> inline void xbasic_fixed_string::resize(size_type count, value_type ch) { size_type old_size = size(); m_storage.set_size(error_policy::check_size(count)); if (old_size < size()) { traits_type::assign(data() + old_size, size() - old_size, ch); } } template class EP, class TR> inline void xbasic_fixed_string::swap(self_type& rhs) noexcept { self_type tmp(std::move(rhs)); rhs = std::move(*this); *this = std::move(tmp); } /********** * insert * **********/ template class EP, class TR> auto xbasic_fixed_string::insert(size_type index, size_type count, value_type ch) -> self_type& { check_index_strict(index, size(), "xbasic_fixed_string::insert"); size_type old_size = size(); m_storage.set_size(error_policy::check_add(size(), count)); std::copy_backward(data() + index, data() + old_size, end()); traits_type::assign(data() + index, count, ch); return *this; } template class EP, class TR> inline auto xbasic_fixed_string::insert(size_type index, const_pointer s) -> self_type& { return insert(index, s, traits_type::length(s)); } template class EP, class TR> auto xbasic_fixed_string::insert(size_type index, const_pointer s, size_type count) -> self_type& { check_index_strict(index, size(), "xbasic_fixed_string::insert"); size_type old_size = size(); m_storage.set_size(error_policy::check_add(size(), count)); std::copy_backward(data() + index, data() + old_size, end()); traits_type::copy(data() + index, s, count); return *this; } template class EP, class TR> inline auto xbasic_fixed_string::insert(size_type index, const self_type& str) -> self_type& { return insert(index, str.data(), str.size()); } template class EP, class TR> inline auto xbasic_fixed_string::insert(size_type index, const self_type& str, size_type index_str, size_type count) -> self_type& { check_index_strict(index_str, str.size(), "xbasic_fixed_string::insert"); return insert(index, str.data() + index_str, std::min(count, str.size() - index_str)); } template class EP, class TR> inline auto xbasic_fixed_string::insert(size_type index, const string_type& str) -> self_type& { return insert(index, str.c_str(), str.size()); } template class EP, class TR> inline auto xbasic_fixed_string::insert(size_type index, const string_type& str, size_type index_str, size_type count) -> self_type& { check_index_strict(index_str, str.size(), "xbasic_fixed_string::insert"); return insert(index, str.c_str() + index_str, std::min(count, str.size() - index_str)); } template class EP, class TR> inline auto xbasic_fixed_string::insert(const_iterator pos, value_type ch) -> iterator { return insert(pos, size_type(1), ch); } template class EP, class TR> inline auto xbasic_fixed_string::insert(const_iterator pos, size_type count, value_type ch) -> iterator { if (cbegin() <= pos && pos < cend()) { size_type index = static_cast(pos - cbegin()); insert(index, count, ch); return const_cast(pos); } return end(); } template class EP, class TR> inline auto xbasic_fixed_string::insert(const_iterator pos, initializer_type ilist) -> iterator { return insert(pos, ilist.begin(), ilist.end()); } template class EP, class TR> template auto xbasic_fixed_string::insert(const_iterator pos, InputIt first, InputIt last) -> iterator { if (cbegin() <= pos && pos < cend()) { size_type index = static_cast(pos - cbegin()); size_type count = static_cast(std::distance(first, last)); size_type old_size = size(); m_storage.set_size(error_policy::check_add(size(), count)); std::copy_backward(data() + index, data() + old_size, end()); std::copy(first, last, data() + index); return begin() + index; } return end(); } /********* * erase * *********/ template class EP, class TR> auto xbasic_fixed_string::erase(size_type index, size_type count) -> self_type& { check_index_strict(index, size(), "xbasic_fixed_string::erase"); size_type erase_count = std::min(count, size() - index); // cannot use traits_type::copy because of overlapping std::copy(data() + index + erase_count, data() + size(), data() + index); m_storage.adjust_size(-static_cast(erase_count)); return *this; } template class EP, class TR> inline auto xbasic_fixed_string::erase(const_iterator position) -> iterator { return erase(position, position + 1); } template class EP, class TR> auto xbasic_fixed_string::erase(const_iterator first, const_iterator last) -> iterator { if (cbegin() <= first && first < cend()) { const_iterator adapted_last = std::min(last, cend()); size_type erase_count = static_cast(adapted_last - first); // cannot use traits_type::copy because of overlapping std::copy(adapted_last, cend(), iterator(first)); m_storage.adjust_size(-static_cast(erase_count)); return const_cast(first); } return end(); } /********** * append * **********/ template class EP, class TR> inline auto xbasic_fixed_string::append(size_type count, value_type ch) -> self_type& { size_type old_size = m_storage.size(); m_storage.set_size(error_policy::check_add(size(), count)); traits_type::assign(data() + old_size, count, ch); return *this; } template class EP, class TR> inline auto xbasic_fixed_string::append(const self_type& str) -> self_type& { return append(str.data(), str.size()); } template class EP, class TR> inline auto xbasic_fixed_string::append(const self_type& str, size_type pos, size_type count) -> self_type& { check_index_strict(pos, str.size(), "xbasic_fixed_string::append"); return append(str.data() + pos, std::min(count, str.size() - pos)); } template class EP, class TR> inline auto xbasic_fixed_string::append(const string_type& str) -> self_type& { return append(str.c_str(), str.size()); } template class EP, class TR> inline auto xbasic_fixed_string::append(const string_type& str, size_type pos, size_type count) -> self_type& { check_index_strict(pos, str.size(), "xbasic_fixed_string::append"); return append(str.c_str() + pos, std::min(count, str.size() - pos)); } template class EP, class TR> inline auto xbasic_fixed_string::append(const_pointer s, size_type count) -> self_type& { size_type old_size = m_storage.size(); m_storage.set_size(error_policy::check_add(size(), count)); traits_type::copy(data() + old_size, s, count); return *this; } template class EP, class TR> inline auto xbasic_fixed_string::append(const_pointer s) -> self_type& { return append(s, traits_type::length(s)); } template class EP, class TR> inline auto xbasic_fixed_string::append(initializer_type ilist) -> self_type& { return append(ilist.begin(), ilist.end()); } template class EP, class TR> template inline auto xbasic_fixed_string::append(InputIt first, InputIt last) -> self_type& { size_type count = static_cast(std::distance(first, last)); size_type old_size = m_storage.size(); m_storage.set_size(error_policy::check_add(size(), count)); std::copy(first, last, data() + old_size); return *this; } template class EP, class TR> inline auto xbasic_fixed_string::operator+=(const self_type& str) -> self_type& { return append(str); } template class EP, class TR> inline auto xbasic_fixed_string::operator+=(const string_type& str) -> self_type& { return append(str); } template class EP, class TR> inline auto xbasic_fixed_string::operator+=(value_type ch) -> self_type& { return append(size_type(1), ch); } template class EP, class TR> inline auto xbasic_fixed_string::operator+=(const_pointer s) -> self_type& { return append(s); } template class EP, class TR> inline auto xbasic_fixed_string::operator+=(initializer_type ilist) -> self_type& { return append(ilist); } /*********** * compare * ***********/ template class EP, class TR> inline int xbasic_fixed_string::compare(const self_type& str) const noexcept { return compare_impl(data(), size(), str.data(), str.size()); } template class EP, class TR> inline int xbasic_fixed_string::compare(size_type pos1, size_type count1, const self_type& str) const { check_index_strict(pos1, size(), "xbasic_fixed_string::compare"); return compare_impl(data() + pos1, std::min(count1, size() - pos1), str.data(), str.size()); } template class EP, class TR> inline int xbasic_fixed_string::compare(size_type pos1, size_type count1, const self_type& str, size_type pos2, size_type count2) const { check_index_strict(pos1, size(), "xbasic_fixed_string::compare"); check_index_strict(pos2, str.size(), "xbasic_fixed_string::compare"); return compare_impl(data() + pos1, std::min(count1, size() - pos1), str.data() + pos2, std::min(count2, str.size() - pos2)); } template class EP, class TR> inline int xbasic_fixed_string::compare(const string_type& str) const noexcept { return compare_impl(data(), size(), str.data(), str.size()); } template class EP, class TR> inline int xbasic_fixed_string::compare(size_type pos1, size_type count1, const string_type& str) const { check_index_strict(pos1, size(), "xbasic_fixed_string::compare"); return compare_impl(data() + pos1, std::min(count1, size() - pos1), str.data(), str.size()); } template class EP, class TR> inline int xbasic_fixed_string::compare(size_type pos1, size_type count1, const string_type& str, size_type pos2, size_type count2) const { check_index_strict(pos1, size(), "xbasic_fixed_string::compare"); check_index_strict(pos2, str.size(), "xbasic_fixed_string::compare"); return compare_impl(data() + pos1, std::min(count1, size() - pos1), str.data() + pos2, std::min(count2, str.size() - pos2)); } template class EP, class TR> inline int xbasic_fixed_string::compare(const_pointer s) const noexcept { return compare_impl(data(), size(), s, traits_type::length(s)); } template class EP, class TR> int xbasic_fixed_string::compare(size_type pos1, size_type count1, const_pointer s) const { return compare(pos1, count1, s, traits_type::length(s)); } template class EP, class TR> int xbasic_fixed_string::compare(size_type pos1, size_type count1, const_pointer s, size_type count2) const { check_index_strict(pos1, size(), "xbasic_fixed_string::compare"); return compare_impl(data() + pos1, std::min(count1, size() - pos1), s, count2); } /*********** * replace * ***********/ template class EP, class TR> inline auto xbasic_fixed_string::replace(size_type pos, size_type count, const self_type& str) -> self_type& { return replace(pos, count, str.data(), str.size()); } template class EP, class TR> inline auto xbasic_fixed_string::replace(const_iterator first, const_iterator last, const self_type& str) -> self_type& { return replace(first, last, str.data(), str.size()); } template class EP, class TR> inline auto xbasic_fixed_string::replace(size_type pos1, size_type count1, const self_type& str, size_type pos2, size_type count2) -> self_type& { check_index_strict(pos2, str.size(), "xbasic_fixed_string::replace"); return replace(pos1, count1, str.data() + pos2, std::min(count2, str.size() - pos2)); } template class EP, class TR> inline auto xbasic_fixed_string::replace(size_type pos, size_type count, const string_type& str) -> self_type& { return replace(pos, count, str.data(), str.size()); } template class EP, class TR> inline auto xbasic_fixed_string::replace(const_iterator first, const_iterator last, const string_type& str) -> self_type& { return replace(first, last, str.data(), str.size()); } template class EP, class TR> inline auto xbasic_fixed_string::replace(size_type pos1, size_type count1, const string_type& str, size_type pos2, size_type count2) -> self_type& { check_index_strict(pos2, str.size(), "xbasic_fixed_string::replace"); return replace(pos1, count1, str.data() + pos2, std::min(count2, str.size() - pos2)); } template class EP, class TR> auto xbasic_fixed_string::replace(size_type pos, size_type count, const_pointer cstr, size_type count2) -> self_type& { check_index_strict(pos, size(), "xbasic_fixed_string::replace"); size_type erase_count = std::min(count, size() - pos); size_type new_size = error_policy::check_add(size() - erase_count, count2); if (erase_count > count2) { traits_type::copy(data() + pos, cstr, count2); std::copy(cbegin() + pos + erase_count, cend(), data() + pos + count2); m_storage.set_size(new_size); } else if (erase_count < count2) { std::copy_backward(cbegin() + pos + erase_count, cend(), data() + new_size); traits_type::copy(data() + pos, cstr, count2); m_storage.set_size(new_size); } else { traits_type::copy(data() + pos, cstr, count2); } return *this; } template class EP, class TR> inline auto xbasic_fixed_string::replace(const_iterator first, const_iterator last, const_pointer cstr, size_type count2) -> self_type& { if (cbegin() <= first && first < last && last <= cend()) { size_type pos = static_cast(first - cbegin()); size_type count = static_cast(last - first); return replace(pos, count, cstr, count2); } return *this; } template class EP, class TR> inline auto xbasic_fixed_string::replace(size_type pos, size_type count, const_pointer cstr) -> self_type& { return replace(pos, count, cstr, traits_type::length(cstr)); } template class EP, class TR> inline auto xbasic_fixed_string::replace(const_iterator first, const_iterator last, const_pointer cstr) -> self_type& { return replace(first, last, cstr, traits_type::length(cstr)); } template class EP, class TR> inline auto xbasic_fixed_string::replace(size_type pos, size_type count, size_type count2, value_type ch) -> self_type& { check_index_strict(pos, size(), "xbasic_fixed_string::replace"); size_type erase_count = std::min(count, size() - pos); size_type new_size = error_policy::check_add(size() - erase_count, count2); if (erase_count > count2) { traits_type::assign(data() + pos, count2, ch); std::copy(cbegin() + pos + erase_count, cend(), data() + pos + count2); m_storage.set_size(new_size); } else if (erase_count < count2) { std::copy_backward(cbegin() + pos + erase_count, cend(), data() + new_size); traits_type::assign(data() + pos, count2, ch); m_storage.set_size(new_size); } else { traits_type::assign(data() + pos, count2, ch); } return *this; } template class EP, class TR> inline auto xbasic_fixed_string::replace(const_iterator first, const_iterator last, size_type count2, value_type ch) -> self_type& { if (cbegin() <= first && first < last && last <= cend()) { size_type pos = static_cast(first - cbegin()); size_type count = static_cast(last - first); return replace(pos, count, count2, ch); } return *this; } template class EP, class TR> inline auto xbasic_fixed_string::replace(const_iterator first, const_iterator last, initializer_type ilist) -> self_type& { return replace(first, last, ilist.begin(), ilist.end()); } template class EP, class TR> template inline auto xbasic_fixed_string::replace(const_iterator first, const_iterator last, InputIt first2, InputIt last2) -> self_type& { if (cbegin() <= first && first < last && last <= cend()) { size_type pos = static_cast(first - cbegin()); size_type erase_count = static_cast(last - first); size_type count2 = static_cast(std::distance(first2, last2)); size_type new_size = error_policy::check_add(size() - erase_count, count2); if (erase_count > count2) { std::copy(first2, last2, data() + pos); std::copy(cbegin() + pos + erase_count, cend(), data() + pos + count2); m_storage.set_size(new_size); } else if (erase_count < count2) { std::copy_backward(cbegin() + pos + erase_count, cend(), data() + new_size); std::copy(first2, last2, data() + pos); m_storage.set_size(new_size); } else { std::copy(first2, last2, data() + pos); } } return *this; } /******** * find * ********/ template class EP, class TR> inline auto xbasic_fixed_string::find(const self_type& str, size_type pos) const noexcept -> size_type { return find(str.data(), pos, str.size()); } template class EP, class TR> inline auto xbasic_fixed_string::find(const string_type& str, size_type pos) const noexcept -> size_type { return find(str.data(), pos, str.size()); } template class EP, class TR> auto xbasic_fixed_string::find(const_pointer s, size_type pos, size_type count) const -> size_type { if (count == size_type(0) && pos <= size()) { return pos; } size_type nm; if (pos < size() && count <= (nm = size() - pos)) { const_pointer uptr, vptr; for (nm -= count - 1, vptr = data() + pos; (uptr = traits_type::find(vptr, nm, *s)) != 0; nm -= size_type(uptr - vptr) + 1ul, vptr = uptr + 1ul) { if (traits_type::compare(uptr, s, count) == 0) { return size_type(uptr - data()); } } } return npos; } template class EP, class TR> inline auto xbasic_fixed_string::find(const_pointer s, size_type pos) const -> size_type { return find(s, pos, traits_type::length(s)); } template class EP, class TR> inline auto xbasic_fixed_string::find(value_type ch, size_type pos) const -> size_type { return find((const_pointer)(&ch), pos, size_type(1)); } /********* * rfind * *********/ template class EP, class TR> inline auto xbasic_fixed_string::rfind(const self_type& str, size_type pos) const noexcept -> size_type { return rfind(str.data(), pos, str.size()); } template class EP, class TR> inline auto xbasic_fixed_string::rfind(const string_type& str, size_type pos) const noexcept -> size_type { return rfind(str.data(), pos, str.size()); } template class EP, class TR> auto xbasic_fixed_string::rfind(const_pointer s, size_type pos, size_type count) const -> size_type { if (count == 0) { return std::min(pos, size()); } if (count <= size()) { const_pointer uptr = data() + std::min(pos, size() - count); for (;; --uptr) { if (traits_type::eq(*uptr, *s) && traits_type::compare(uptr, s, count) == 0) { return size_type(uptr - data()); } else if (uptr == data()) { break; } } } return npos; } template class EP, class TR> inline auto xbasic_fixed_string::rfind(const_pointer s, size_type pos) const -> size_type { return rfind(s, pos, traits_type::length(s)); } template class EP, class TR> inline auto xbasic_fixed_string::rfind(value_type ch, size_type pos) const -> size_type { return rfind((const_pointer)(&ch), pos, size_type(1)); } /***************** * find_first_of * *****************/ template class EP, class TR> inline auto xbasic_fixed_string::find_first_of(const self_type& str, size_type pos) const noexcept -> size_type { return find_first_of(str.data(), pos, str.size()); } template class EP, class TR> inline auto xbasic_fixed_string::find_first_of(const string_type& str, size_type pos) const noexcept -> size_type { return find_first_of(str.data(), pos, str.size()); } template class EP, class TR> auto xbasic_fixed_string::find_first_of(const_pointer s, size_type pos, size_type count) const -> size_type { if (size_type(0) < count && pos < size()) { const_pointer vptr = data() + size(); for (const_pointer uptr = data() + pos; uptr < vptr; ++uptr) { if (traits_type::find(s, count, *uptr) != 0) { return size_type(uptr - data()); } } } return npos; } template class EP, class TR> inline auto xbasic_fixed_string::find_first_of(const_pointer s, size_type pos) const -> size_type { return find_first_of(s, pos, traits_type::length(s)); } template class EP, class TR> inline auto xbasic_fixed_string::find_first_of(value_type ch, size_type pos) const -> size_type { return find_first_of((const_pointer)(&ch), pos, size_type(1)); } /********************* * find_first_not_of * *********************/ template class EP, class TR> inline auto xbasic_fixed_string::find_first_not_of(const self_type& str, size_type pos) const noexcept -> size_type { return find_first_not_of(str.data(), pos, str.size()); } template class EP, class TR> inline auto xbasic_fixed_string::find_first_not_of(const string_type& str, size_type pos) const noexcept -> size_type { return find_first_not_of(str.data(), pos, str.size()); } template class EP, class TR> auto xbasic_fixed_string::find_first_not_of(const_pointer s, size_type pos, size_type count) const -> size_type { if (pos < size()) { const_pointer vptr = data() + size(); for (const_pointer uptr = data() + pos; uptr < vptr; ++uptr) { if (traits_type::find(s, count, *uptr) == 0) { return size_type(uptr - data()); } } } return npos; } template class EP, class TR> inline auto xbasic_fixed_string::find_first_not_of(const_pointer s, size_type pos) const -> size_type { return find_first_not_of(s, pos, traits_type::length(s)); } template class EP, class TR> inline auto xbasic_fixed_string::find_first_not_of(value_type ch, size_type pos) const -> size_type { return find_first_not_of((const_pointer)(&ch), pos, size_type(1)); } /**************** * find_last_of * ****************/ template class EP, class TR> inline auto xbasic_fixed_string::find_last_of(const self_type& str, size_type pos) const noexcept -> size_type { return find_last_of(str.data(), pos, str.size()); } template class EP, class TR> inline auto xbasic_fixed_string::find_last_of(const string_type& str, size_type pos) const noexcept -> size_type { return find_last_of(str.data(), pos, str.size()); } template class EP, class TR> auto xbasic_fixed_string::find_last_of(const_pointer s, size_type pos, size_type count) const -> size_type { if (size_type(0) < count && size_type(0) < size()) { const_pointer uptr = data() + std::min(pos, size() - 1); for (;; --uptr) { if (traits_type::find(s, count, *uptr) != 0) { return size_type(uptr - data()); } else if (uptr == data()) { break; } } } return npos; } template class EP, class TR> inline auto xbasic_fixed_string::find_last_of(const_pointer s, size_type pos) const -> size_type { return find_last_of(s, pos, traits_type::length(s)); } template class EP, class TR> inline auto xbasic_fixed_string::find_last_of(value_type ch, size_type pos) const -> size_type { return find_last_of((const_pointer)(&ch), pos, size_type(1)); } /******************** * find_last_not_of * ********************/ template class EP, class TR> inline auto xbasic_fixed_string::find_last_not_of(const self_type& str, size_type pos) const noexcept -> size_type { return find_last_not_of(str.data(), pos, str.size()); } template class EP, class TR> inline auto xbasic_fixed_string::find_last_not_of(const string_type& str, size_type pos) const noexcept -> size_type { return find_last_not_of(str.data(), pos, str.size()); } template class EP, class TR> auto xbasic_fixed_string::find_last_not_of(const_pointer s, size_type pos, size_type count) const -> size_type { if (size_type(0) < size()) { const_pointer uptr = data() + std::min(pos, size() - 1); for (;; --uptr) { if (traits_type::find(s, count, *uptr) == 0) { return size_type(uptr - data()); } else if (uptr == data()) { break; } } } return npos; } template class EP, class TR> inline auto xbasic_fixed_string::find_last_not_of(const_pointer s, size_type pos) const -> size_type { return find_last_not_of(s, pos, traits_type::length(s)); } template class EP, class TR> inline auto xbasic_fixed_string::find_last_not_of(value_type ch, size_type pos) const -> size_type { return find_last_not_of((const_pointer)(&ch), pos, size_type(1)); } /******************* * Private methods * *******************/ template class EP, class TR> int xbasic_fixed_string::compare_impl(const_pointer s1, size_type count1, const_pointer s2, size_type count2) const noexcept { size_type rlen = std::min(count1, count2); int res = traits_type::compare(s1, s2, rlen); if (res == 0) { return count1 < count2 ? -1 : (count1 > count2 ? 1 : 0); } else { return res; } } template class EP, class TR> inline void xbasic_fixed_string::update_null_termination() noexcept { data()[size()] = '\0'; } template class EP, class TR> void xbasic_fixed_string::check_index(size_type pos, size_type size, const char* what) const { if (pos >= size) { #if defined(XTL_NO_EXCEPTIONS) std::fprintf(stderr, "%s\n", what); std::terminate(); #else throw std::out_of_range(what); #endif } } template class EP, class TR> void xbasic_fixed_string::check_index_strict(size_type pos, size_type size, const char* what) const { check_index(pos, size + 1, what); } /************************** * Concatenation operator * **************************/ template class EP, class TR> inline xbasic_fixed_string operator+(const xbasic_fixed_string& lhs, const xbasic_fixed_string& rhs) { xbasic_fixed_string res(lhs); return res += rhs; } template class EP, class TR> inline xbasic_fixed_string operator+(const xbasic_fixed_string& lhs, const CT* rhs) { xbasic_fixed_string res(lhs); return res += rhs; } template class EP, class TR> inline xbasic_fixed_string operator+(const xbasic_fixed_string& lhs, CT rhs) { xbasic_fixed_string res(lhs); return res += rhs; } template class EP, class TR> inline xbasic_fixed_string operator+(const CT* lhs, const xbasic_fixed_string& rhs) { xbasic_fixed_string res(lhs); return res += rhs; } template class EP, class TR> inline xbasic_fixed_string operator+(CT lhs, const xbasic_fixed_string& rhs) { using size_type = typename xbasic_fixed_string::size_type; xbasic_fixed_string res(size_type(1), lhs); return res += rhs; } template class EP, class TR> inline xbasic_fixed_string operator+(const xbasic_fixed_string&& lhs, const xbasic_fixed_string& rhs) { xbasic_fixed_string res(std::move(lhs)); return res += rhs; } template class EP, class TR> inline xbasic_fixed_string operator+(const xbasic_fixed_string& lhs, const xbasic_fixed_string&& rhs) { xbasic_fixed_string res(lhs); return res += std::move(rhs); } template class EP, class TR> inline xbasic_fixed_string operator+(const xbasic_fixed_string&& lhs, const xbasic_fixed_string&& rhs) { xbasic_fixed_string res(std::move(lhs)); return res += std::move(rhs); } template class EP, class TR> inline xbasic_fixed_string operator+(const xbasic_fixed_string&& lhs, const CT* rhs) { xbasic_fixed_string res(std::move(lhs)); return res += rhs; } template class EP, class TR> inline xbasic_fixed_string operator+(const xbasic_fixed_string&& lhs, CT rhs) { xbasic_fixed_string res(std::move(lhs)); return res += rhs; } template class EP, class TR> inline xbasic_fixed_string operator+(const CT* lhs, const xbasic_fixed_string&& rhs) { xbasic_fixed_string res(lhs); return res += std::move(rhs); } template class EP, class TR> inline xbasic_fixed_string operator+(CT lhs, const xbasic_fixed_string&& rhs) { using size_type = typename xbasic_fixed_string::size_type; xbasic_fixed_string res(size_type(1), lhs); return res += std::move(rhs); } /************************ * Comparison operators * ************************/ template class EP, class TR> inline bool operator==(const xbasic_fixed_string& lhs, const xbasic_fixed_string& rhs) noexcept { return lhs.compare(rhs) == 0; } template class EP, class TR> inline bool operator==(const xbasic_fixed_string& lhs, const CT* rhs) noexcept { return lhs.compare(rhs) == 0; } template class EP, class TR> inline bool operator==(const CT* lhs, const xbasic_fixed_string& rhs) noexcept { return rhs == lhs; } template class EP, class TR> inline bool operator==(const xbasic_fixed_string& lhs, const std::basic_string& rhs) noexcept { return lhs == rhs.c_str(); } template class EP, class TR> inline bool operator==(const std::basic_string& lhs, const xbasic_fixed_string& rhs) noexcept { return lhs.c_str() == rhs; } template class EP, class TR> inline bool operator!=(const xbasic_fixed_string& lhs, const xbasic_fixed_string& rhs) noexcept { return lhs.compare(rhs) != 0; } template class EP, class TR> inline bool operator!=(const xbasic_fixed_string& lhs, const CT* rhs) noexcept { return lhs.compare(rhs) != 0; } template class EP, class TR> inline bool operator!=(const CT* lhs, const xbasic_fixed_string& rhs) noexcept { return rhs != lhs; } template class EP, class TR> inline bool operator!=(const xbasic_fixed_string& lhs, const std::basic_string& rhs) noexcept { return lhs != rhs.c_str(); } template class EP, class TR> inline bool operator!=(const std::basic_string& lhs, const xbasic_fixed_string& rhs) noexcept { return lhs.c_str() != rhs; } template class EP, class TR> inline bool operator<(const xbasic_fixed_string& lhs, const xbasic_fixed_string& rhs) noexcept { return lhs.compare(rhs) < 0; } template class EP, class TR> inline bool operator<(const xbasic_fixed_string& lhs, const CT* rhs) noexcept { return lhs.compare(rhs) < 0; } template class EP, class TR> inline bool operator<(const CT* lhs, const xbasic_fixed_string& rhs) noexcept { return rhs > lhs; } template class EP, class TR> inline bool operator<(const xbasic_fixed_string& lhs, const std::basic_string& rhs) noexcept { return lhs < rhs.c_str(); } template class EP, class TR> inline bool operator<(const std::basic_string& lhs, const xbasic_fixed_string& rhs) noexcept { return lhs.c_str() < rhs; } template class EP, class TR> inline bool operator<=(const xbasic_fixed_string& lhs, const xbasic_fixed_string& rhs) noexcept { return lhs.compare(rhs) <= 0; } template class EP, class TR> inline bool operator<=(const xbasic_fixed_string& lhs, const CT* rhs) noexcept { return lhs.compare(rhs) <= 0; } template class EP, class TR> inline bool operator<=(const CT* lhs, const xbasic_fixed_string& rhs) noexcept { return rhs >= lhs; } template class EP, class TR> inline bool operator<=(const xbasic_fixed_string& lhs, const std::basic_string& rhs) noexcept { return lhs <= rhs.c_str(); } template class EP, class TR> inline bool operator<=(const std::basic_string& lhs, const xbasic_fixed_string& rhs) noexcept { return lhs.c_str() <= rhs; } template class EP, class TR> inline bool operator>(const xbasic_fixed_string& lhs, const xbasic_fixed_string& rhs) noexcept { return lhs.compare(rhs) > 0; } template class EP, class TR> inline bool operator>(const xbasic_fixed_string& lhs, const CT* rhs) noexcept { return lhs.compare(rhs) > 0; } template class EP, class TR> inline bool operator>(const CT* lhs, const xbasic_fixed_string& rhs) noexcept { return rhs < lhs; } template class EP, class TR> inline bool operator>(const xbasic_fixed_string& lhs, const std::basic_string& rhs) noexcept { return lhs > rhs.c_str(); } template class EP, class TR> inline bool operator>(const std::basic_string& lhs, const xbasic_fixed_string& rhs) noexcept { return lhs.c_str() > rhs; } template class EP, class TR> inline bool operator>=(const xbasic_fixed_string& lhs, const xbasic_fixed_string& rhs) noexcept { return lhs.compare(rhs) >= 0; } template class EP, class TR> inline bool operator>=(const xbasic_fixed_string& lhs, const CT* rhs) noexcept { return lhs.compare(rhs) >= 0; } template class EP, class TR> inline bool operator>=(const CT* lhs, const xbasic_fixed_string& rhs) noexcept { return rhs <= lhs; } template class EP, class TR> inline bool operator>=(const xbasic_fixed_string& lhs, const std::basic_string& rhs) noexcept { return lhs >= rhs.c_str(); } template class EP, class TR> inline bool operator>=(const std::basic_string& lhs, const xbasic_fixed_string& rhs) noexcept { return lhs.c_str() >= rhs; } template class EP, class TR> inline void swap(xbasic_fixed_string& lhs, xbasic_fixed_string& rhs) { lhs.swap(rhs); } /****************** * Input / output * ******************/ template class EP, class TR> inline std::basic_ostream& operator<<(std::basic_ostream& os, const xbasic_fixed_string& str) { os << str.c_str(); return os; } #ifdef __CLING__ template class EP, class TR> nlohmann::json mime_bundle_repr(const xbasic_fixed_string& str) { auto bundle = nlohmann::json::object(); bundle["text/plain"] = str.c_str(); return bundle; } #endif template class EP, class TR> inline std::basic_istream& operator>>(std::basic_istream& is, xbasic_fixed_string& str) { // Not optimal std::string tmp; is >> tmp; str = tmp.c_str(); return is; } template class EP, class TR> inline std::basic_istream& getline(std::basic_istream& input, xbasic_fixed_string& str, CT delim) { std::string tmp; auto& ret = std::getline(input, tmp, delim); str = tmp; return ret; } template class EP, class TR> inline std::basic_istream& getline(std::basic_istream&& input, xbasic_fixed_string& str, CT delim) { std::string tmp; auto& ret = std::getline(std::move(input), tmp, delim); str = tmp; return ret; } template class EP, class TR> inline std::basic_istream& getline(std::basic_istream& input, xbasic_fixed_string& str) { std::string tmp; auto& ret = std::getline(input, tmp); str = tmp; return ret; } template class EP, class TR> inline std::basic_istream& getline(std::basic_istream&& input, xbasic_fixed_string& str) { std::string tmp; auto& ret = std::getline(std::move(input), tmp); str = tmp; return ret; } } #endif // xtl xtl-0.7.2/include/xtl/xclosure.hpp000066400000000000000000000306071400411521700171370ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) Sylvain Corlay and Johan Mabille and Wolf Vollprecht * * Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XTL_CLOSURE_HPP #define XTL_CLOSURE_HPP #include #include #include #include "xtl_config.hpp" namespace xtl { #ifdef __cpp_lib_as_const using std::as_const; #else template constexpr std::add_const_t& as_const(T& t) noexcept { return t; } template constexpr std::add_const_t& as_const(T&& t) noexcept = delete; #endif /**************** * closure_type * ****************/ template struct closure_type { using underlying_type = std::conditional_t>::value, const std::decay_t, std::decay_t>; using type = typename std::conditional::value, underlying_type&, underlying_type>::type; }; template using closure_type_t = typename closure_type::type; template struct const_closure_type { using underlying_type = std::decay_t; using type = typename std::conditional::value, std::add_const_t&, underlying_type>::type; }; template using const_closure_type_t = typename const_closure_type::type; /**************************** * ptr_closure_closure_type * ****************************/ template struct ptr_closure_type { using underlying_type = std::conditional_t>::value, const std::decay_t, std::decay_t>; using type = std::conditional_t::value, underlying_type*, underlying_type>; }; template using ptr_closure_type_t = typename ptr_closure_type::type; template struct const_ptr_closure_type { using underlying_type = const std::decay_t; using type = std::conditional_t::value, underlying_type*, underlying_type>; }; template using const_ptr_closure_type_t = typename const_ptr_closure_type::type; /******************** * xclosure_wrapper * ********************/ template class xclosure_wrapper { public: using self_type = xclosure_wrapper; using closure_type = CT; using const_closure_type = std::add_const_t; using value_type = std::decay_t; using reference = std::conditional_t< std::is_const>::value, const value_type&, value_type& >; using pointer = std::conditional_t< std::is_const>::value, const value_type*, value_type* >; xclosure_wrapper(value_type&& e); xclosure_wrapper(reference e); xclosure_wrapper(const self_type& rhs) = default; xclosure_wrapper(self_type&& rhs) = default; self_type& operator=(const self_type& rhs); self_type& operator=(self_type&& rhs); template self_type& operator=(T&&); operator closure_type() noexcept; operator const_closure_type() const noexcept; std::add_lvalue_reference_t get() & noexcept; std::add_lvalue_reference_t> get() const & noexcept; closure_type get() && noexcept; pointer operator&() noexcept; bool equal(const self_type& rhs) const; void swap(self_type& rhs); private: using storing_type = ptr_closure_type_t; storing_type m_wrappee; template std::enable_if_t::value, std::add_lvalue_reference_t>> deref(T val) const; template std::enable_if_t::value, std::add_lvalue_reference_t> deref(T& val) const; template std::enable_if_t::value, T> get_pointer(T val) const; template std::enable_if_t::value, std::add_pointer_t> get_pointer(T& val) const; template std::enable_if_t::value, T> get_storage_init(CTA&& e) const; template std::enable_if_t::value, T> get_storage_init(CTA&& e) const; }; // TODO: remove this (backward compatibility) template using closure_wrapper = xclosure_wrapper; /******************** * xclosure_pointer * ********************/ template class xclosure_pointer { public: using self_type = xclosure_pointer; using closure_type = CT; using value_type = std::decay_t; using reference = std::conditional_t< std::is_const>::value, const value_type&, value_type& >; using const_reference = const value_type&; using pointer = std::conditional_t< std::is_const>::value, const value_type*, value_type* >; xclosure_pointer(value_type&& e); xclosure_pointer(reference e); reference operator*() noexcept; const_reference operator*() const noexcept; pointer operator->() const noexcept; private: using storing_type = closure_type_t; storing_type m_wrappee; }; /*********************************** * xclosure_wrapper implementation * ***********************************/ template inline xclosure_wrapper::xclosure_wrapper(value_type&& e) : m_wrappee(get_storage_init(std::move(e))) { } template inline xclosure_wrapper::xclosure_wrapper(reference e) : m_wrappee(get_storage_init(e)) { } template inline auto xclosure_wrapper::operator=(const self_type& rhs) -> self_type& { deref(m_wrappee) = deref(rhs.m_wrappee); return *this; } template inline auto xclosure_wrapper::operator=(self_type&& rhs) -> self_type& { swap(rhs); return *this; } template template inline auto xclosure_wrapper::operator=(T&& t) -> self_type& { deref(m_wrappee) = std::forward(t); return *this; } template inline xclosure_wrapper::operator typename xclosure_wrapper::closure_type() noexcept { return deref(m_wrappee); } template inline xclosure_wrapper::operator typename xclosure_wrapper::const_closure_type() const noexcept { return deref(m_wrappee); } template inline auto xclosure_wrapper::get() & noexcept -> std::add_lvalue_reference_t { return deref(m_wrappee); } template inline auto xclosure_wrapper::get() const & noexcept -> std::add_lvalue_reference_t> { return deref(m_wrappee); } template inline auto xclosure_wrapper::get() && noexcept -> closure_type { return deref(m_wrappee); } template inline auto xclosure_wrapper::operator&() noexcept -> pointer { return get_pointer(m_wrappee); } template template inline std::enable_if_t::value, std::add_lvalue_reference_t>> xclosure_wrapper::deref(T val) const { return *val; } template template inline std::enable_if_t::value, std::add_lvalue_reference_t> xclosure_wrapper::deref(T& val) const { return val; } template template inline std::enable_if_t::value, T> xclosure_wrapper::get_pointer(T val) const { return val; } template template inline std::enable_if_t::value, std::add_pointer_t> xclosure_wrapper::get_pointer(T& val) const { return &val; } template template inline std::enable_if_t::value, T> xclosure_wrapper::get_storage_init(CTA&& e) const { return &e; } template template inline std::enable_if_t::value, T> xclosure_wrapper::get_storage_init(CTA&& e) const { return e; } template inline bool xclosure_wrapper::equal(const self_type& rhs) const { return deref(m_wrappee) == rhs.deref(rhs.m_wrappee); } template inline void xclosure_wrapper::swap(self_type& rhs) { using std::swap; swap(deref(m_wrappee), deref(rhs.m_wrappee)); } template inline bool operator==(const xclosure_wrapper& lhs, const xclosure_wrapper& rhs) { return lhs.equal(rhs); } template inline bool operator!=(const xclosure_wrapper& lhs, const xclosure_wrapper& rhs) { return !(lhs == rhs); } template inline void swap(xclosure_wrapper& lhs, xclosure_wrapper& rhs) { lhs.swap(rhs); } /*********************************** * xclosure_pointer implementation * ***********************************/ template inline xclosure_pointer::xclosure_pointer(value_type&& e) : m_wrappee(std::move(e)) { } template inline xclosure_pointer::xclosure_pointer(reference e) : m_wrappee(e) { } template inline auto xclosure_pointer::operator*() noexcept -> reference { return m_wrappee; } template inline auto xclosure_pointer::operator*() const noexcept -> const_reference { return m_wrappee; } template inline auto xclosure_pointer::operator->() const noexcept -> pointer { return const_cast(std::addressof(m_wrappee)); } /***************************** * closure and const_closure * *****************************/ template inline decltype(auto) closure(T&& t) { return xclosure_wrapper>(std::forward(t)); } template inline decltype(auto) const_closure(T&& t) { return xclosure_wrapper>(std::forward(t)); } /******************************************** * closure_pointer et const_closure_pointer * ********************************************/ template inline auto closure_pointer(T&& t) { return xclosure_pointer>(std::forward(t)); } template inline auto const_closure_pointer(T&& t) { return xclosure_pointer>(std::forward(t)); } } #endif xtl-0.7.2/include/xtl/xcomplex.hpp000066400000000000000000001350551400411521700171350ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) Sylvain Corlay and Johan Mabille and Wolf Vollprecht * * Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XTL_COMPLEX_HPP #define XTL_COMPLEX_HPP #if !defined(_MSC_VER) #include using std::copysign; #endif #include #include #include #include #include #include #include #ifdef __CLING__ #include #endif #include "xclosure.hpp" #include "xtl_config.hpp" #include "xtype_traits.hpp" namespace xtl { template class xcomplex; /************** * is_complex * **************/ namespace detail { template struct is_complex : std::false_type { }; template struct is_complex> : std::true_type { }; } template struct is_complex { static constexpr bool value = detail::is_complex>::value; }; /*************** * is_xcomplex * ***************/ namespace detail { template struct is_xcomplex : std::false_type { }; template struct is_xcomplex> : std::true_type { }; } template struct is_xcomplex { static constexpr bool value = detail::is_xcomplex>::value; }; /****************** * is_gen_complex * ******************/ template using is_gen_complex = disjunction>, is_xcomplex>>; /**************************** * enable / disable complex * ****************************/ template using disable_xcomplex = std::enable_if_t::value, R>; template using enable_xcomplex = std::enable_if_t::value, R>; /***************** * enable_scalar * *****************/ template using enable_scalar = std::enable_if_t::value, R>; /******************* * common_xcomplex * *******************/ template struct common_xcomplex { using type = xcomplex, std::common_type_t, ieee1 || ieee2>; }; template using common_xcomplex_t = typename common_xcomplex::type; /********************** * temporary_xcomplex * **********************/ template struct temporary_xcomplex { using type = xcomplex, std::decay_t, ieee>; }; template using temporary_xcomplex_t = typename temporary_xcomplex::type; /************ * xcomplex * ************/ template class xcomplex { public: static_assert(std::is_same, std::decay_t>::value, "closure types must have the same value type"); using value_type = std::common_type_t; using self_type = xcomplex; using temporary_type = temporary_xcomplex_t; using real_reference = std::add_lvalue_reference_t; using real_const_reference = std::add_lvalue_reference_t>; using real_rvalue_reference = std::conditional_t::value, apply_cv_t&, value_type>; using real_rvalue_const_reference = std::conditional_t::value, const value_type&, value_type>; using imag_reference = std::add_lvalue_reference_t; using imag_const_reference = std::add_lvalue_reference_t>; using imag_rvalue_reference = std::conditional_t::value, apply_cv_t&, value_type>; using imag_rvalue_const_reference = std::conditional_t::value, const value_type&, value_type>; constexpr xcomplex() noexcept : m_real(), m_imag() { } template >, std::is_constructible, std::is_convertible >::value, bool > = true> constexpr xcomplex(OCTR&& re) noexcept : m_real(std::forward(re)), m_imag() { } template >, std::is_constructible, negation> >::value, bool > = true> explicit constexpr xcomplex(OCTR&& re) noexcept : m_real(std::forward(re)), m_imag() { } template explicit constexpr xcomplex(OCTR&& re, OCTI&& im) noexcept : m_real(std::forward(re)), m_imag(std::forward(im)) { } template explicit constexpr xcomplex(const xcomplex& rhs) noexcept : m_real(rhs.real()), m_imag(rhs.imag()) { } template explicit constexpr xcomplex(xcomplex&& rhs) noexcept : m_real(std::move(rhs).real()), m_imag(std::move(rhs).imag()) { } template constexpr xcomplex(const std::complex& rhs) noexcept : m_real(rhs.real()), m_imag(rhs.imag()) { } template constexpr xcomplex(std::complex&& rhs) noexcept : m_real(std::move(rhs).real()), m_imag(std::move(rhs).imag()) { } template disable_xcomplex operator=(OCTR&& rhs) noexcept; template self_type& operator=(const xcomplex& rhs) noexcept; template self_type& operator=(xcomplex&& rhs) noexcept; operator std::complex>() const noexcept; template self_type& operator+=(const xcomplex& rhs) noexcept; template self_type& operator-=(const xcomplex& rhs) noexcept; template self_type& operator*=(const xcomplex& rhs) noexcept; template self_type& operator/=(const xcomplex& rhs) noexcept; template disable_xcomplex operator+=(const T& rhs) noexcept; template disable_xcomplex operator-=(const T& rhs) noexcept; template disable_xcomplex operator*=(const T& rhs) noexcept; template disable_xcomplex operator/=(const T& rhs) noexcept; real_reference real() & noexcept; real_rvalue_reference real() && noexcept; constexpr real_const_reference real() const & noexcept; constexpr real_rvalue_const_reference real() const && noexcept; imag_reference imag() & noexcept; imag_rvalue_reference imag() && noexcept; constexpr imag_const_reference imag() const & noexcept; constexpr imag_rvalue_const_reference imag() const && noexcept; xclosure_pointer operator&() & noexcept; xclosure_pointer operator&() const & noexcept; xclosure_pointer operator&() && noexcept; private: CTR m_real; CTI m_imag; }; /********************** * xcomplex operators * **********************/ template bool operator==(const xcomplex& lhs, const xcomplex& rhs) noexcept; template bool operator!=(const xcomplex& lhs, const xcomplex& rhs) noexcept; template std::basic_ostream& operator<<(std::basic_ostream& out, const xcomplex& c) noexcept; template temporary_xcomplex_t operator+(const xcomplex& rhs) noexcept; template temporary_xcomplex_t operator-(const xcomplex& rhs) noexcept; template common_xcomplex_t operator+(const xcomplex& lhs, const xcomplex& rhs) noexcept; template enable_scalar> operator+(const xcomplex& lhs, const T& rhs) noexcept; template enable_scalar> operator+(const T& lhs, const xcomplex& rhs) noexcept; template common_xcomplex_t operator-(const xcomplex& lhs, const xcomplex& rhs) noexcept; template enable_scalar> operator-(const xcomplex& lhs, const T& rhs) noexcept; template enable_scalar> operator-(const T& lhs, const xcomplex& rhs) noexcept; template common_xcomplex_t operator*(const xcomplex& lhs, const xcomplex& rhs) noexcept; template enable_scalar> operator*(const xcomplex& lhs, const T& rhs) noexcept; template enable_scalar> operator*(const T& lhs, const xcomplex& rhs) noexcept; template common_xcomplex_t operator/(const xcomplex& lhs, const xcomplex& rhs) noexcept; template enable_scalar> operator/(const xcomplex& lhs, const T& rhs) noexcept; template enable_scalar> operator/(const T& lhs, const xcomplex& rhs) noexcept; /***************** * real and imag * *****************/ template decltype(auto) real(E&& e) noexcept; template decltype(auto) imag(E&& e) noexcept; /*************************** * xcomplex free functions * ***************************/ template typename xcomplex::value_type abs(const xcomplex& rhs); template typename xcomplex::value_type arg(const xcomplex& rhs); template typename xcomplex::value_type norm(const xcomplex& rhs); template temporary_xcomplex_t conj(const xcomplex& rhs); template temporary_xcomplex_t proj(const xcomplex& rhs); /********************************** * xcomplex exponential functions * **********************************/ template temporary_xcomplex_t exp(const xcomplex& rhs); template temporary_xcomplex_t log(const xcomplex& rhs); template temporary_xcomplex_t log10(const xcomplex& rhs); /**************************** * xcomplex power functions * ****************************/ template common_xcomplex_t pow(const xcomplex& x, const xcomplex& y); template enable_scalar> pow(const xcomplex& x, const T& y); template enable_scalar> pow(const T& x, const xcomplex& y); template temporary_xcomplex_t sqrt(const xcomplex& x); /************************************ * xcomplex trigonometric functions * ************************************/ template temporary_xcomplex_t sin(const xcomplex& x); template temporary_xcomplex_t cos(const xcomplex& x); template temporary_xcomplex_t tan(const xcomplex& x); template temporary_xcomplex_t asin(const xcomplex& x); template temporary_xcomplex_t acos(const xcomplex& x); template temporary_xcomplex_t atan(const xcomplex& x); /********************************* * xcomplex hyperbolic functions * *********************************/ template temporary_xcomplex_t sinh(const xcomplex& x); template temporary_xcomplex_t cosh(const xcomplex& x); template temporary_xcomplex_t tanh(const xcomplex& x); template temporary_xcomplex_t asinh(const xcomplex& x); template temporary_xcomplex_t acosh(const xcomplex& x); template temporary_xcomplex_t atanh(const xcomplex& x); /*************************** * xcomplex implementation * ***************************/ template template inline auto xcomplex::operator=(OCTR&& rhs) noexcept -> disable_xcomplex { m_real = std::forward(rhs); m_imag = std::decay_t(); return *this; } template template inline auto xcomplex::operator=(const xcomplex& rhs) noexcept -> self_type& { m_real = rhs.m_real; m_imag = rhs.m_imag; return *this; } template template inline auto xcomplex::operator=(xcomplex&& rhs) noexcept -> self_type& { m_real = std::move(rhs.m_real); m_imag = std::move(rhs.m_imag); return *this; } template inline xcomplex::operator std::complex>() const noexcept { return std::complex>(m_real, m_imag); } template template inline auto xcomplex::operator+=(const xcomplex& rhs) noexcept -> self_type& { m_real += rhs.m_real; m_imag += rhs.m_imag; return *this; } template template inline auto xcomplex::operator-=(const xcomplex& rhs) noexcept -> self_type& { m_real -= rhs.m_real; m_imag -= rhs.m_imag; return *this; } namespace detail { template struct xcomplex_multiplier { template static auto mul(const xcomplex& lhs, const xcomplex& rhs) { using return_type = temporary_xcomplex_t; using value_type = typename return_type::value_type; value_type a = lhs.real(); value_type b = lhs.imag(); value_type c = rhs.real(); value_type d = rhs.imag(); return return_type(a*c - b*d, a*d + b*c); } template static auto div(const xcomplex& lhs, const xcomplex& rhs) { using return_type = temporary_xcomplex_t; using value_type = typename return_type::value_type; value_type a = lhs.real(); value_type b = lhs.imag(); value_type c = rhs.real(); value_type d = rhs.imag(); value_type e = c*c + d*d; return return_type((c*a + d*b) / e, (c*b - d*a) / e); } }; template <> struct xcomplex_multiplier { template static auto mul(const xcomplex& lhs, const xcomplex& rhs) { using return_type = temporary_xcomplex_t; using value_type = typename return_type::value_type; value_type a = lhs.real(); value_type b = lhs.imag(); value_type c = rhs.real(); value_type d = rhs.imag(); value_type ac = a * c; value_type bd = b * d; value_type ad = a * d; value_type bc = b * c; value_type x = ac - bd; value_type y = ad + bc; if (std::isnan(x) && std::isnan(y)) { bool recalc = false; if (std::isinf(a) || std::isinf(b)) { a = copysign(std::isinf(a) ? value_type(1) : value_type(0), a); b = copysign(std::isinf(b) ? value_type(1) : value_type(0), b); if (std::isnan(c)) { c = copysign(value_type(0), c); } if (std::isnan(d)) { d = copysign(value_type(0), d); } recalc = true; } if (std::isinf(c) || std::isinf(d)) { c = copysign(std::isinf(c) ? value_type(1) : value_type(0), c); d = copysign(std::isinf(c) ? value_type(1) : value_type(0), d); if (std::isnan(a)) { a = copysign(value_type(0), a); } if (std::isnan(b)) { b = copysign(value_type(0), b); } recalc = true; } if (!recalc && (std::isinf(ac) || std::isinf(bd) || std::isinf(ad) || std::isinf(bc))) { if (std::isnan(a)) { a = copysign(value_type(0), a); } if (std::isnan(b)) { b = copysign(value_type(0), b); } if (std::isnan(c)) { c = copysign(value_type(0), c); } if (std::isnan(d)) { d = copysign(value_type(0), d); } recalc = true; } if (recalc) { x = std::numeric_limits::infinity() * (a * c - b * d); y = std::numeric_limits::infinity() * (a * d + b * c); } } return return_type(x, y); } template static auto div(const xcomplex& lhs, const xcomplex& rhs) { using return_type = temporary_xcomplex_t; using value_type = typename return_type::value_type; value_type a = lhs.real(); value_type b = lhs.imag(); value_type c = rhs.real(); value_type d = rhs.imag(); value_type logbw = std::logb(std::fmax(std::fabs(c), std::fabs(d))); int ilogbw = 0; if (std::isfinite(logbw)) { ilogbw = static_cast(logbw); c = std::scalbn(c, -ilogbw); d = std::scalbn(d, -ilogbw); } value_type denom = c*c + d*d; value_type x = std::scalbn((a*c + b*d) / denom, -ilogbw); value_type y = std::scalbn((b*c - a*d) / denom, -ilogbw); if (std::isnan(x) && std::isnan(y)) { if ((denom == value_type(0)) && (!std::isnan(a) || !std::isnan(b))) { x = copysign(std::numeric_limits::infinity(), c) * a; y = copysign(std::numeric_limits::infinity(), c) * b; } else if ((std::isinf(a) || std::isinf(b)) && std::isfinite(c) && std::isfinite(d)) { a = copysign(std::isinf(a) ? value_type(1) : value_type(0), a); b = copysign(std::isinf(b) ? value_type(1) : value_type(0), b); x = std::numeric_limits::infinity() * (a*c + b*d); y = std::numeric_limits::infinity() * (b*c - a*d); } else if (std::isinf(logbw) && logbw > value_type(0) && std::isfinite(a) && std::isfinite(b)) { c = copysign(std::isinf(c) ? value_type(1) : value_type(0), c); d = copysign(std::isinf(d) ? value_type(1) : value_type(0), d); x = value_type(0) * (a*c + b*d); y = value_type(0) * (b*c - a*d); } } return std::complex(x, y); } }; } template template inline auto xcomplex::operator*=(const xcomplex& rhs) noexcept -> self_type& { *this = detail::xcomplex_multiplier::mul(*this, rhs); return *this; } template template inline auto xcomplex::operator/=(const xcomplex& rhs) noexcept -> self_type& { *this = detail::xcomplex_multiplier::div(*this, rhs); return *this; } template template inline auto xcomplex::operator+=(const T& rhs) noexcept -> disable_xcomplex { m_real += rhs; return *this; } template template inline auto xcomplex::operator-=(const T& rhs) noexcept -> disable_xcomplex { m_real -= rhs; return *this; } template template inline auto xcomplex::operator*=(const T& rhs) noexcept -> disable_xcomplex { m_real *= rhs; m_imag *= rhs; return *this; } template template inline auto xcomplex::operator/=(const T& rhs) noexcept -> disable_xcomplex { m_real /= rhs; m_imag /= rhs; return *this; } template auto xcomplex::real() & noexcept -> real_reference { return m_real; } template auto xcomplex::real() && noexcept -> real_rvalue_reference { return m_real; } template constexpr auto xcomplex::real() const & noexcept -> real_const_reference { return m_real; } template constexpr auto xcomplex::real() const && noexcept -> real_rvalue_const_reference { return m_real; } template auto xcomplex::imag() & noexcept -> imag_reference { return m_imag; } template auto xcomplex::imag() && noexcept -> imag_rvalue_reference { return m_imag; } template constexpr auto xcomplex::imag() const & noexcept -> imag_const_reference { return m_imag; } template constexpr auto xcomplex::imag() const && noexcept -> imag_rvalue_const_reference { return m_imag; } template inline auto xcomplex::operator&() & noexcept -> xclosure_pointer { return xclosure_pointer(*this); } template inline auto xcomplex::operator&() const & noexcept -> xclosure_pointer { return xclosure_pointer(*this); } template inline auto xcomplex::operator&() && noexcept -> xclosure_pointer { return xclosure_pointer(std::move(*this)); } /************************************* * xcomplex operators implementation * *************************************/ template inline bool operator==(const xcomplex& lhs, const xcomplex& rhs) noexcept { return lhs.real() == rhs.real() && lhs.imag() == rhs.imag(); } template inline bool operator!=(const xcomplex& lhs, const xcomplex& rhs) noexcept { return !(lhs == rhs); } template inline std::basic_ostream& operator<<(std::basic_ostream& out, const xcomplex& c) noexcept { out << "(" << c.real() << "," << c.imag() << ")"; return out; } #ifdef __CLING__ template nlohmann::json mime_bundle_repr(const xcomplex& c) { auto bundle = nlohmann::json::object(); std::stringstream tmp; tmp << c; bundle["text/plain"] = tmp.str(); return bundle; } #endif template inline temporary_xcomplex_t operator+(const xcomplex& rhs) noexcept { return rhs; } template inline temporary_xcomplex_t operator-(const xcomplex& rhs) noexcept { return temporary_xcomplex_t(-rhs.real(), -rhs.imag()); } template inline common_xcomplex_t operator+(const xcomplex& lhs, const xcomplex& rhs) noexcept { common_xcomplex_t res(lhs); res += rhs; return res; } template inline enable_scalar> operator+(const xcomplex& lhs, const T& rhs) noexcept { temporary_xcomplex_t res(lhs); res += rhs; return res; } template inline enable_scalar> operator+(const T& lhs, const xcomplex& rhs) noexcept { temporary_xcomplex_t res(lhs); res += rhs; return res; } template inline common_xcomplex_t operator-(const xcomplex& lhs, const xcomplex& rhs) noexcept { common_xcomplex_t res(lhs); res -= rhs; return res; } template inline enable_scalar> operator-(const xcomplex& lhs, const T& rhs) noexcept { temporary_xcomplex_t res(lhs); res -= rhs; return res; } template inline enable_scalar> operator-(const T& lhs, const xcomplex& rhs) noexcept { temporary_xcomplex_t res(lhs); res -= rhs; return res; } template inline common_xcomplex_t operator*(const xcomplex& lhs, const xcomplex& rhs) noexcept { common_xcomplex_t res(lhs); res *= rhs; return res; } template inline enable_scalar> operator*(const xcomplex& lhs, const T& rhs) noexcept { temporary_xcomplex_t res(lhs); res *= rhs; return res; } template inline enable_scalar> operator*(const T& lhs, const xcomplex& rhs) noexcept { temporary_xcomplex_t res(lhs); res *= rhs; return res; } template inline common_xcomplex_t operator/(const xcomplex& lhs, const xcomplex& rhs) noexcept { common_xcomplex_t res(lhs); res /= rhs; return res; } template inline enable_scalar> operator/(const xcomplex& lhs, const T& rhs) noexcept { temporary_xcomplex_t res(lhs); res /= rhs; return res; } template inline enable_scalar> operator/(const T& lhs, const xcomplex& rhs) noexcept { temporary_xcomplex_t res(lhs); res /= rhs; return res; } /*************************** * xcomplex free functions * ***************************/ template inline typename xcomplex::value_type abs(const xcomplex& rhs) { using value_type = typename xcomplex::value_type; return std::abs(std::complex(rhs)); } template inline typename xcomplex::value_type arg(const xcomplex& rhs) { using value_type = typename xcomplex::value_type; return std::arg(std::complex(rhs)); } template inline typename xcomplex::value_type norm(const xcomplex& rhs) { using value_type = typename xcomplex::value_type; return std::norm(std::complex(rhs)); } template inline temporary_xcomplex_t conj(const xcomplex& rhs) { using value_type = typename xcomplex::value_type; return std::conj(std::complex(rhs)); } template inline temporary_xcomplex_t proj(const xcomplex& rhs) { using value_type = typename xcomplex::value_type; return std::proj(std::complex(rhs)); } /************************************************* * xcomplex exponential functions implementation * *************************************************/ template inline temporary_xcomplex_t exp(const xcomplex& rhs) { using value_type = typename xcomplex::value_type; return std::exp(std::complex(rhs)); } template inline temporary_xcomplex_t log(const xcomplex& rhs) { using value_type = typename xcomplex::value_type; return std::log(std::complex(rhs)); } template inline temporary_xcomplex_t log10(const xcomplex& rhs) { using value_type = typename xcomplex::value_type; return std::log10(std::complex(rhs)); } /******************************************* * xcomplex power functions implementation * *******************************************/ template inline common_xcomplex_t pow(const xcomplex& x, const xcomplex& y) { using value_type1 = typename xcomplex::value_type; using value_type2 = typename xcomplex::value_type; return std::pow(std::complex(x), std::complex(y)); } template inline enable_scalar> pow(const xcomplex& x, const T& y) { using value_type = typename xcomplex::value_type; return std::pow(std::complex(x), y); } template inline enable_scalar> pow(const T& x, const xcomplex& y) { using value_type = typename xcomplex::value_type; return std::pow(x, std::complex(y)); } template inline temporary_xcomplex_t sqrt(const xcomplex& x) { using value_type = typename xcomplex::value_type; return std::sqrt(std::complex(x)); } /*************************************************** * xcomplex trigonometric functions implementation * ***************************************************/ template inline temporary_xcomplex_t sin(const xcomplex& x) { using value_type = typename temporary_xcomplex_t::value_type; return std::sin(std::complex(x)); } template inline temporary_xcomplex_t cos(const xcomplex& x) { using value_type = typename temporary_xcomplex_t::value_type; return std::cos(std::complex(x)); } template inline temporary_xcomplex_t tan(const xcomplex& x) { using value_type = typename temporary_xcomplex_t::value_type; return std::tan(std::complex(x)); } template inline temporary_xcomplex_t asin(const xcomplex& x) { using value_type = typename temporary_xcomplex_t::value_type; return std::asin(std::complex(x)); } template inline temporary_xcomplex_t acos(const xcomplex& x) { using value_type = typename temporary_xcomplex_t::value_type; return std::acos(std::complex(x)); } template inline temporary_xcomplex_t atan(const xcomplex& x) { using value_type = typename temporary_xcomplex_t::value_type; return std::atan(std::complex(x)); } /************************************************ * xcomplex hyperbolic functions implementation * ************************************************/ template inline temporary_xcomplex_t sinh(const xcomplex& x) { using value_type = typename temporary_xcomplex_t::value_type; return std::sinh(std::complex(x)); } template inline temporary_xcomplex_t cosh(const xcomplex& x) { using value_type = typename temporary_xcomplex_t::value_type; return std::cosh(std::complex(x)); } template inline temporary_xcomplex_t tanh(const xcomplex& x) { using value_type = typename temporary_xcomplex_t::value_type; return std::tanh(std::complex(x)); } template inline temporary_xcomplex_t asinh(const xcomplex& x) { using value_type = typename temporary_xcomplex_t::value_type; return std::asinh(std::complex(x)); } template inline temporary_xcomplex_t acosh(const xcomplex& x) { using value_type = typename temporary_xcomplex_t::value_type; return std::acosh(std::complex(x)); } template inline temporary_xcomplex_t atanh(const xcomplex& x) { using value_type = typename temporary_xcomplex_t::value_type; return std::atanh(std::complex(x)); } /********************************* * forward_offset implementation * *********************************/ namespace detail { template struct forward_type { using type = apply_cv_t; }; template struct forward_type { using type = apply_cv_t&; }; template using forward_type_t = typename forward_type::type; } template constexpr detail::forward_type_t forward_offset(T&& v) noexcept { using forward_type = detail::forward_type_t; using cv_value_type = std::remove_reference_t; using byte_type = apply_cv_t, char>; return static_cast( *reinterpret_cast( reinterpret_cast(&v) + I ) ); } /********************************************** * forward_real & forward_imag implementation * **********************************************/ // forward_real template auto forward_real(T&& v) -> std::enable_if_t::value, detail::forward_type_t> // real case -> forward { return static_cast>(v); } template auto forward_real(T&& v) -> std::enable_if_t::value, detail::forward_type_t::value_type>> // complex case -> forward the real part { return forward_offset::value_type, 0>(v); } template auto forward_real(T&& v) -> std::enable_if_t::value, decltype(std::forward(v).real())> { return std::forward(v).real(); } // forward_imag template auto forward_imag(T &&) -> std::enable_if_t::value, std::decay_t> // real case -> always return 0 by value { return 0; } template auto forward_imag(T&& v) -> std::enable_if_t::value, detail::forward_type_t::value_type>> // complex case -> forwards the imaginary part { using real_type = typename std::decay_t::value_type; return forward_offset(v); } template auto forward_imag(T&& v) -> std::enable_if_t::value, decltype(std::forward(v).imag())> { return std::forward(v).imag(); } /****************************** * real & imag implementation * ******************************/ template inline decltype(auto) real(E&& e) noexcept { return forward_real(std::forward(e)); } template inline decltype(auto) imag(E&& e) noexcept { return forward_imag(std::forward(e)); } /********************** * complex_value_type * **********************/ template struct complex_value_type { using type = T; }; template struct complex_value_type> { using type = T; }; template struct complex_value_type> { using type = xcomplex; }; template using complex_value_type_t = typename complex_value_type::type; /****************************************************** * operator overloads for complex and closure wrapper * *****************************************************/ template ::value, int> = 0> std::complex operator+(const std::complex& c, const T& t) { std::complex result(c); result += t; return result; } template ::value, int> = 0> std::complex operator+(const T& t, const std::complex& c) { std::complex result(t); result += c; return result; } template ::value, int> = 0> std::complex operator-(const std::complex& c, const T& t) { std::complex result(c); result -= t; return result; } template ::value, int> = 0> std::complex operator-(const T& t, const std::complex& c) { std::complex result(t); result -= c; return result; } template ::value, int> = 0> std::complex operator*(const std::complex& c, const T& t) { std::complex result(c); result *= t; return result; } template ::value, int> = 0> std::complex operator*(const T& t, const std::complex& c) { std::complex result(t); result *= c; return result; } template ::value, int> = 0> std::complex operator/(const std::complex& c, const T& t) { std::complex result(c); result /= t; return result; } template ::value, int> = 0> std::complex operator/(const T& t, const std::complex& c) { std::complex result(t); result /= c; return result; } } #endif xtl-0.7.2/include/xtl/xcomplex_sequence.hpp000066400000000000000000000434071400411521700210240ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * * Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XTL_XCOMPLEX_SEQUENCE_HPP #define XTL_XCOMPLEX_SEQUENCE_HPP #include #include #include #include "xclosure.hpp" #include "xcomplex.hpp" #include "xiterator_base.hpp" #include "xsequence.hpp" namespace xtl { /************************************ * Optimized 1-D xcomplex container * ************************************/ template class xcomplex_iterator; template class xcomplex_sequence { public: using container_type = C; using cvt = typename C::value_type; using value_type = xcomplex; using reference = xcomplex; using const_reference = xcomplex; using pointer = xclosure_pointer; using const_pointer = xclosure_pointer; using size_type = typename container_type::size_type; using difference_type = typename container_type::difference_type; using iterator = xcomplex_iterator; using const_iterator = xcomplex_iterator; using reverse_iterator = xcomplex_iterator; using const_reverse_iterator = xcomplex_iterator; bool empty() const noexcept; size_type size() const noexcept; size_type max_size() const noexcept; reference at(size_type i); const_reference at(size_type i) const; reference operator[](size_type i); const_reference operator[](size_type i) const; reference front(); const_reference front() const; reference back(); const_reference back() const; iterator begin() noexcept; iterator end() noexcept; const_iterator begin() const noexcept; const_iterator end() const noexcept; const_iterator cbegin() const noexcept; const_iterator cend() const noexcept; reverse_iterator rbegin() noexcept; reverse_iterator rend() noexcept; const_reverse_iterator rbegin() const noexcept; const_reverse_iterator rend() const noexcept; const_reverse_iterator crbegin() const noexcept; const_reverse_iterator crend() const noexcept; container_type real() && noexcept; container_type& real() & noexcept; const container_type& real() const & noexcept; container_type imag() && noexcept; container_type& imag() & noexcept; const container_type& imag() const & noexcept; protected: xcomplex_sequence() = default; xcomplex_sequence(size_type s); xcomplex_sequence(size_type s, const value_type& v); template xcomplex_sequence(size_type s, const xcomplex& v); xcomplex_sequence(std::initializer_list init); ~xcomplex_sequence() = default; xcomplex_sequence(const xcomplex_sequence&) = default; xcomplex_sequence& operator=(const xcomplex_sequence&) = default; xcomplex_sequence(xcomplex_sequence&&) = default; xcomplex_sequence& operator=(xcomplex_sequence&&) = default; container_type m_real; container_type m_imag; }; template bool operator==(const xcomplex_sequence& lhs, const xcomplex_sequence& rhs); template bool operator!=(const xcomplex_sequence& lhs, const xcomplex_sequence& rhs); /****************** * xcomplex_array * ******************/ template class xcomplex_array : public xcomplex_sequence, ieee_compliant> { public: using base_type = xcomplex_sequence, ieee_compliant>; using value_type = typename base_type::value_type; using size_type = typename base_type::size_type; xcomplex_array() = default; xcomplex_array(size_type s); xcomplex_array(size_type s, const value_type& v); template xcomplex_array(size_type s, const xcomplex& v); }; /******************* * xcomplex_vector * *******************/ template > class xcomplex_vector : public xcomplex_sequence, ieee_compliant> { public: using base_type = xcomplex_sequence, ieee_compliant>; using value_type = typename base_type::value_type; using size_type = typename base_type::size_type; xcomplex_vector() = default; xcomplex_vector(size_type s); xcomplex_vector(size_type s, const value_type& v); xcomplex_vector(std::initializer_list init); template xcomplex_vector(size_type s, const xcomplex& v); void resize(size_type); void resize(size_type, const value_type&); template void resize(size_type s, const xcomplex& v); }; /********************* * xcomplex_iterator * *********************/ template struct xcomplex_iterator_traits { using iterator_type = xcomplex_iterator; using value_type = xcomplex; using reference = xcomplex; using pointer = xclosure_pointer; using difference_type = typename IT::difference_type; }; template class xcomplex_iterator : public xrandom_access_iterator_base2> { public: using self_type = xcomplex_iterator; using base_type = xrandom_access_iterator_base2>; using value_type = typename base_type::value_type; using reference = typename base_type::reference; using pointer = typename base_type::pointer; using difference_type = typename base_type::difference_type; xcomplex_iterator() = default; xcomplex_iterator(IT it_real, IT it_imag); self_type& operator++(); self_type& operator--(); self_type& operator+=(difference_type n); self_type& operator-=(difference_type n); difference_type operator-(const self_type& rhs) const; reference operator*() const; pointer operator->() const; bool operator==(const self_type& rhs) const; private: IT m_it_real; IT m_it_imag; }; /************************************ * xcomplex_sequence implementation * ************************************/ template inline xcomplex_sequence::xcomplex_sequence(size_type s) : m_real(make_sequence(s)), m_imag(make_sequence(s)) { } template inline xcomplex_sequence::xcomplex_sequence(size_type s, const value_type& v) : m_real(make_sequence(s, v.real())), m_imag(make_sequence(s, v.imag())) { } template template inline xcomplex_sequence::xcomplex_sequence(size_type s, const xcomplex& v) : m_real(make_sequence(s, v.real())), m_imag(make_sequence(s, v.imag())) { } template inline xcomplex_sequence::xcomplex_sequence(std::initializer_list init) : m_real(make_sequence(init.size())), m_imag(make_sequence(init.size())) { std::transform(init.begin(), init.end(), m_real.begin(), [](const auto& v) { return v.real(); }); std::transform(init.begin(), init.end(), m_imag.begin(), [](const auto& v) { return v.imag(); }); } template inline bool xcomplex_sequence::empty() const noexcept { return m_real.empty(); } template inline auto xcomplex_sequence::size() const noexcept -> size_type { return m_real.size(); } template inline auto xcomplex_sequence::max_size() const noexcept -> size_type { return m_real.max_size(); } template inline auto xcomplex_sequence::at(size_type i) -> reference { return reference(m_real.at(i), m_imag.at(i)); } template inline auto xcomplex_sequence::at(size_type i) const -> const_reference { return const_reference(m_real.at(i), m_imag.at(i)); } template inline auto xcomplex_sequence::operator[](size_type i) -> reference { return reference(m_real[i], m_imag[i]); } template inline auto xcomplex_sequence::operator[](size_type i) const -> const_reference { return const_reference(m_real[i], m_imag[i]); } template inline auto xcomplex_sequence::front() -> reference { return reference(m_real.front(), m_imag.front()); } template inline auto xcomplex_sequence::front() const -> const_reference { return const_reference(m_real.front(), m_imag.front()); } template inline auto xcomplex_sequence::back() -> reference { return reference(m_real.back(), m_imag.back()); } template inline auto xcomplex_sequence::back() const -> const_reference { return const_reference(m_real.back(), m_imag.back()); } template inline auto xcomplex_sequence::begin() noexcept -> iterator { return iterator(m_real.begin(), m_imag.begin()); } template inline auto xcomplex_sequence::end() noexcept -> iterator { return iterator(m_real.end(), m_imag.end()); } template inline auto xcomplex_sequence::begin() const noexcept -> const_iterator { return cbegin(); } template inline auto xcomplex_sequence::end() const noexcept -> const_iterator { return cend(); } template inline auto xcomplex_sequence::cbegin() const noexcept -> const_iterator { return const_iterator(m_real.cbegin(), m_imag.cbegin()); } template inline auto xcomplex_sequence::cend() const noexcept -> const_iterator { return const_iterator(m_real.cend(), m_imag.cend()); } template inline auto xcomplex_sequence::rbegin() noexcept -> reverse_iterator { return reverse_iterator(m_real.rbegin(), m_imag.rbegin()); } template inline auto xcomplex_sequence::rend() noexcept -> reverse_iterator { return reverse_iterator(m_real.rend(), m_imag.rend()); } template inline auto xcomplex_sequence::rbegin() const noexcept -> const_reverse_iterator { return crbegin(); } template inline auto xcomplex_sequence::rend() const noexcept -> const_reverse_iterator { return crend(); } template inline auto xcomplex_sequence::crbegin() const noexcept -> const_reverse_iterator { return const_reverse_iterator(m_real.crbegin(), m_imag.crbegin()); } template inline auto xcomplex_sequence::crend() const noexcept -> const_reverse_iterator { return const_reverse_iterator(m_real.crend(), m_imag.crend()); } template inline auto xcomplex_sequence::real() && noexcept -> container_type { return m_real; } template inline auto xcomplex_sequence::real() & noexcept -> container_type& { return m_real; } template inline auto xcomplex_sequence::real() const & noexcept -> const container_type& { return m_real; } template inline auto xcomplex_sequence::imag() && noexcept -> container_type { return m_imag; } template inline auto xcomplex_sequence::imag() & noexcept -> container_type& { return m_imag; } template inline auto xcomplex_sequence::imag() const & noexcept -> const container_type& { return m_imag; } template inline bool operator==(const xcomplex_sequence& lhs, const xcomplex_sequence& rhs) { return lhs.real() == rhs.real() && lhs.imag() == rhs.imag(); } template inline bool operator!=(const xcomplex_sequence& lhs, const xcomplex_sequence& rhs) { return !(lhs == rhs); } /********************************* * xcomplex_array implementation * *********************************/ template inline xcomplex_array::xcomplex_array(size_type s) : base_type(s) { } template inline xcomplex_array::xcomplex_array(size_type s, const value_type& v) : base_type(s, v) { } template template inline xcomplex_array::xcomplex_array(size_type s, const xcomplex& v) : base_type(s, v) { } /********************************** * xcomplex_vector implementation * **********************************/ template inline xcomplex_vector::xcomplex_vector(size_type s) : base_type(s) { } template inline xcomplex_vector::xcomplex_vector(size_type s, const value_type& v) : base_type(s, v) { } template template inline xcomplex_vector::xcomplex_vector(size_type s, const xcomplex& v) : base_type(s, v) { } template inline xcomplex_vector::xcomplex_vector(std::initializer_list init) : base_type(init) { } template void xcomplex_vector::resize(size_type s) { this->m_real.resize(s); this->m_imag.resize(s); } template void xcomplex_vector::resize(size_type s, const value_type& v) { this->m_real.resize(s, v.real()); this->m_imag.resize(s, v.imag()); } template template inline void xcomplex_vector::resize(size_type s, const xcomplex& v) { this->m_real.resize(s, v.real()); this->m_imag.resize(s, v.imag()); } /************************************ * xcomplex_iterator implementation * ************************************/ template inline xcomplex_iterator::xcomplex_iterator(IT it_real, IT it_imag) : m_it_real(it_real), m_it_imag(it_imag) { } template inline auto xcomplex_iterator::operator++() -> self_type& { ++m_it_real; ++m_it_imag; return *this; } template inline auto xcomplex_iterator::operator--() -> self_type& { --m_it_real; --m_it_imag; return *this; } template inline auto xcomplex_iterator::operator+=(difference_type n) -> self_type& { m_it_real += n; m_it_imag += n; return *this; } template inline auto xcomplex_iterator::operator-=(difference_type n) -> self_type& { m_it_real -= n; m_it_imag -= n; return *this; } template inline auto xcomplex_iterator::operator-(const self_type& rhs) const -> difference_type { return m_it_real - rhs.m_it_real; } template inline auto xcomplex_iterator::operator*() const -> reference { return reference(*m_it_real, *m_it_imag); } template inline auto xcomplex_iterator::operator->() const -> pointer { return pointer(operator*()); } template inline bool xcomplex_iterator::operator==(const self_type& rhs) const { return m_it_real == rhs.m_it_real && m_it_imag == rhs.m_it_imag; } } #endif xtl-0.7.2/include/xtl/xdynamic_bitset.hpp000066400000000000000000001223661400411521700204650ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * * Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XDYNAMIC_BITSET_HPP #define XDYNAMIC_BITSET_HPP #include #include #include #include "xclosure.hpp" #include "xspan.hpp" #include "xiterator_base.hpp" #include "xtype_traits.hpp" namespace xtl { template class xbitset_reference; template class xbitset_iterator; /****************** * xdyamic_bitset * ******************/ template class xdynamic_bitset_base; template class xdynamic_bitset; template class xdynamic_bitset_view; template struct xdynamic_bitset_traits; template struct xdynamic_bitset_traits> { using storage_type = std::vector; using block_type = typename storage_type::value_type; }; template struct xdynamic_bitset_traits> { using storage_type = xtl::span; using block_type = typename storage_type::value_type; }; template struct container_internals; template struct container_internals> { using value_type = typename xtl::span::value_type; static_assert(xtl::is_scalar::value, ""); using allocator_type = std::allocator; using size_type = std::size_t; using difference_type = typename xtl::span::difference_type; }; template struct container_internals> { using value_type = X; static_assert(xtl::is_scalar::value, ""); using allocator_type = A; using size_type = typename std::vector::size_type; using difference_type = typename std::vector::difference_type; }; template class xdynamic_bitset_base { public: using self_type = xdynamic_bitset_base; using derived_class = B; using storage_type = typename xdynamic_bitset_traits::storage_type; using block_type = typename xdynamic_bitset_traits::block_type; using temporary_type = xdynamic_bitset>; using allocator_type = typename container_internals::allocator_type; using value_type = bool; using reference = xbitset_reference; using const_reference = xbitset_reference; using pointer = typename reference::pointer; using const_pointer = typename const_reference::pointer; using size_type = typename container_internals::size_type; using difference_type = typename storage_type::difference_type; using iterator = xbitset_iterator; using const_iterator = xbitset_iterator; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; using const_block_iterator = typename storage_type::const_iterator; bool empty() const noexcept; size_type size() const noexcept; void swap(self_type& rhs); reference at(size_type i); const_reference at(size_type i) const; reference operator[](size_type i); const_reference operator[](size_type i) const; reference front(); const_reference front() const; reference back(); const_reference back() const; iterator begin() noexcept; iterator end() noexcept; const_iterator begin() const noexcept; const_iterator end() const noexcept; const_iterator cbegin() const noexcept; const_iterator cend() const noexcept; reverse_iterator rbegin() noexcept; reverse_iterator rend() noexcept; const_reverse_iterator rbegin() const noexcept; const_reverse_iterator rend() const noexcept; const_reverse_iterator crbegin() const noexcept; const_reverse_iterator crend() const noexcept; const_block_iterator block_begin() const noexcept; const_block_iterator block_end() const noexcept; template self_type& operator&=(const xdynamic_bitset_base& rhs); template self_type& operator|=(const xdynamic_bitset_base& rhs); template self_type& operator^=(const xdynamic_bitset_base& rhs); temporary_type operator<<(size_type pos); self_type& operator<<=(size_type pos); temporary_type operator>>(size_type pos); self_type& operator>>=(size_type pos); self_type& set(); self_type& set(size_type pos, value_type value = true); self_type& reset(); self_type& reset(size_type pos); self_type& flip(); self_type& flip(size_type pos); bool all() const noexcept; bool any() const noexcept; bool none() const noexcept; size_type count() const noexcept; size_type block_count() const noexcept; block_type* data() noexcept; const block_type* data() const noexcept; template bool operator==(const xdynamic_bitset_base& rhs) const noexcept; template bool operator!=(const xdynamic_bitset_base& rhs) const noexcept; derived_class& derived_cast(); const derived_class& derived_cast() const; protected: xdynamic_bitset_base(const storage_type& buffer, std::size_t size); ~xdynamic_bitset_base() = default; xdynamic_bitset_base(const xdynamic_bitset_base& rhs) = default; xdynamic_bitset_base(xdynamic_bitset_base&& rhs) = default; xdynamic_bitset_base& operator=(const xdynamic_bitset_base& rhs) = default; xdynamic_bitset_base& operator=(xdynamic_bitset_base&& rhs) = default; size_type m_size; storage_type m_buffer; static constexpr std::size_t s_bits_per_block = CHAR_BIT * sizeof(block_type); size_type compute_block_count(size_type bits_count) const noexcept; size_type block_index(size_type pos) const noexcept; size_type bit_index(size_type pos) const noexcept; block_type bit_mask(size_type pos) const noexcept; size_type count_extra_bits() const noexcept; void zero_unused_bits(); private: // Make views and buffers friends template friend class xdynamic_bitset_base; }; // NOTE this view ZEROS out remaining bits! template class xdynamic_bitset_view : public xdynamic_bitset_base> { public: using base_class = xdynamic_bitset_base>; using storage_type = typename base_class::storage_type; using block_type = typename base_class::block_type; xdynamic_bitset_view(block_type* ptr, std::size_t size); xdynamic_bitset_view() = default; ~xdynamic_bitset_view() = default; xdynamic_bitset_view(const xdynamic_bitset_view& rhs) = default; xdynamic_bitset_view(xdynamic_bitset_view&& rhs) = default; xdynamic_bitset_view& operator=(const xdynamic_bitset_view& rhs) = default; xdynamic_bitset_view& operator=(xdynamic_bitset_view&& rhs) = default; void resize(std::size_t sz); }; namespace detail_bitset { template constexpr T integer_ceil(T n, T div) { return (n + div - T(1)) / div; } } template inline xdynamic_bitset_view::xdynamic_bitset_view(block_type* ptr, std::size_t size) : base_class(storage_type(ptr, detail_bitset::integer_ceil(size, base_class::s_bits_per_block)), size) { base_class::zero_unused_bits(); } template inline void xdynamic_bitset_view::resize(std::size_t sz) { if (sz != this->m_size) { #if defined(XTL_NO_EXCEPTIONS) std::fprintf(stderr, "cannot resize bitset_view\n"); std::terminate(); #else throw std::runtime_error("cannot resize bitset_view"); #endif } } template > class xdynamic_bitset; template auto operator~(const xdynamic_bitset_base& lhs); template auto operator&(const xdynamic_bitset_base& lhs, const xdynamic_bitset_base& rhs); template auto operator|(const xdynamic_bitset_base& lhs, const xdynamic_bitset_base& rhs); template auto operator^(const xdynamic_bitset_base& lhs, const xdynamic_bitset_base& rhs); template void swap(const xdynamic_bitset_base& lhs, const xdynamic_bitset_base& rhs); /********************* * xbitset_reference * *********************/ template class xbitset_reference { public: using self_type = xbitset_reference; using pointer = std::conditional_t, xclosure_pointer>; operator bool() const noexcept; xbitset_reference(const self_type&) = default; xbitset_reference(self_type&&) = default; self_type& operator=(const self_type&) noexcept; self_type& operator=(self_type&&) noexcept; self_type& operator=(bool) noexcept; bool operator~() const noexcept; self_type& operator&=(bool) noexcept; self_type& operator|=(bool) noexcept; self_type& operator^=(bool) noexcept; self_type& flip() noexcept; pointer operator&() noexcept; private: using block_type = typename xdynamic_bitset_traits::block_type; using closure_type = std::conditional_t; xbitset_reference(closure_type block, block_type pos); void assign(bool) noexcept; void set() noexcept; void reset() noexcept; closure_type m_block; const block_type m_mask; template friend class xbitset_reference; friend class xdynamic_bitset_base; }; /******************** * xbitset_iterator * ********************/ template class xbitset_iterator : public xrandom_access_iterator_base, typename xdynamic_bitset_base::value_type, typename xdynamic_bitset_base::difference_type, std::conditional_t::const_pointer, typename xdynamic_bitset_base::pointer>, std::conditional_t::const_reference, typename xdynamic_bitset_base::reference>> { public: using self_type = xbitset_iterator; using container_type = xdynamic_bitset_base; using value_type = typename container_type::value_type; using reference = std::conditional_t; using pointer = std::conditional_t; using size_type = typename container_type::size_type; using difference_type = typename container_type::difference_type; using base_type = xrandom_access_iterator_base; using container_reference = std::conditional_t; using container_pointer = std::conditional_t; xbitset_iterator() noexcept; xbitset_iterator(container_reference c, size_type index) noexcept; self_type& operator++(); self_type& operator--(); self_type& operator+=(difference_type n); self_type& operator-=(difference_type n); difference_type operator-(const self_type& rhs) const; reference operator*() const; pointer operator->() const; bool operator==(const self_type& rhs) const; bool operator<(const self_type& rhs) const; private: container_pointer p_container; size_type m_index; }; template class xdynamic_bitset : public xdynamic_bitset_base> { public: using allocator_type = Allocator; using storage_type = std::vector; using base_type = xdynamic_bitset_base>; using self_type = xdynamic_bitset; using block_type = B; using reference = typename base_type::reference; using const_reference = typename base_type::const_reference; using pointer = typename reference::pointer; using const_pointer = typename const_reference::pointer; using size_type = typename storage_type::size_type; using difference_type = typename storage_type::difference_type; using iterator = xbitset_iterator; using const_iterator = xbitset_iterator; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; using base_type::base_type; using base_type::begin; using base_type::cbegin; using base_type::end; using base_type::cend; using base_type::rbegin; using base_type::rend; using base_type::size; xdynamic_bitset(); explicit xdynamic_bitset(const allocator_type& allocator); xdynamic_bitset(size_type count, bool b, const allocator_type& alloc = allocator_type()); explicit xdynamic_bitset(size_type count, const allocator_type& alloc = allocator_type()); xdynamic_bitset(std::initializer_list init, const allocator_type& alloc = allocator_type()); template xdynamic_bitset(BlockInputIt first, BlockInputIt last, const allocator_type& alloc = allocator_type()); xdynamic_bitset(const xdynamic_bitset& rhs); // Allow creation from views for e.g. temporary creation template xdynamic_bitset(const xdynamic_bitset_base& rhs); ~xdynamic_bitset() = default; xdynamic_bitset(xdynamic_bitset&& rhs) = default; xdynamic_bitset& operator=(const xdynamic_bitset& rhs) = default; xdynamic_bitset& operator=(xdynamic_bitset&& rhs) = default; void assign(size_type count, bool b); template void assign(BlockInputIt first, BlockInputIt last); void assign(std::initializer_list init); size_type max_size() const noexcept; void reserve(size_type new_cap); size_type capacity() const noexcept; allocator_type get_allocator() const; void resize(size_type size, bool b = false); void clear() noexcept; void push_back(bool b); void pop_back(); }; /********************************** * xdynamic_bitset implementation * **********************************/ template inline xdynamic_bitset::xdynamic_bitset() : base_type(storage_type(), size_type(0)) { } template inline xdynamic_bitset::xdynamic_bitset(const allocator_type& allocator) : base_type(storage_type(allocator), size_type(0)) { } template inline xdynamic_bitset::xdynamic_bitset(size_type count, bool b, const allocator_type& alloc) : base_type(storage_type(this->compute_block_count(count), b ? ~block_type(0) : block_type(0), alloc), count) { this->zero_unused_bits(); } template inline xdynamic_bitset::xdynamic_bitset(size_type count, const allocator_type& alloc) : base_type(storage_type(this->compute_block_count(count), block_type(0), alloc), count) { } template template inline xdynamic_bitset::xdynamic_bitset(BlockInputIt first, BlockInputIt last, const allocator_type& alloc) : base_type(storage_type(first, last, alloc), size_type(std::distance(first, last)) * base_type::s_bits_per_block) { } template inline xdynamic_bitset::xdynamic_bitset(std::initializer_list init, const allocator_type& alloc) : xdynamic_bitset(init.size(), alloc) { std::copy(init.begin(), init.end(), begin()); } template inline xdynamic_bitset::xdynamic_bitset(const xdynamic_bitset& rhs) : base_type(storage_type(rhs.block_begin(), rhs.block_end()), rhs.size()) { } template template inline xdynamic_bitset::xdynamic_bitset(const xdynamic_bitset_base& rhs) : base_type(storage_type(rhs.block_begin(), rhs.block_end()), rhs.size()) { } template inline void xdynamic_bitset::assign(size_type count, bool b) { resize(count); b ? this->set() : this->reset(); } template template inline void xdynamic_bitset::assign(BlockInputIt first, BlockInputIt last) { resize(size_type(std::distance(first, last)) * base_type::s_bits_per_block); std::copy(first, last, this->m_buffer.begin()); } template inline void xdynamic_bitset::assign(std::initializer_list init) { resize(init.size()); std::copy(init.begin(), init.end(), begin()); } template inline auto xdynamic_bitset::get_allocator() const -> allocator_type { return base_type::m_buffer.get_allocator(); } template inline bool xdynamic_bitset_base::empty() const noexcept { return m_size == 0; } template inline auto xdynamic_bitset_base::size() const noexcept -> size_type { return m_size; } template inline auto xdynamic_bitset::max_size() const noexcept -> size_type { return base_type::m_buffer.max_size() * base_type::s_bits_per_block; } template inline void xdynamic_bitset::reserve(size_type new_cap) { base_type::m_buffer.reserve(this->compute_block_count(new_cap)); } template inline auto xdynamic_bitset::capacity() const noexcept -> size_type { return base_type::m_buffer.capacity() * base_type::s_bits_per_block; } template inline void xdynamic_bitset::resize(size_type asize, bool b) { size_type old_block_count = base_type::block_count(); size_type new_block_count = base_type::compute_block_count(asize); block_type value = b ? ~block_type(0) : block_type(0); if (new_block_count != old_block_count) { base_type::m_buffer.resize(new_block_count, value); } if (b && asize > base_type::m_size) { size_type extra_bits = base_type::count_extra_bits(); if (extra_bits > 0) { base_type::m_buffer[old_block_count - 1] |= (value << extra_bits); } } base_type::m_size = asize; base_type::zero_unused_bits(); } template inline void xdynamic_bitset::clear() noexcept { base_type::m_buffer.clear(); base_type::m_size = size_type(0); } template inline void xdynamic_bitset::push_back(bool b) { size_type s = size(); resize(s + 1); this->set(s, b); } template inline void xdynamic_bitset::pop_back() { size_type old_block_count = base_type::m_buffer.size(); size_type new_block_count = base_type::compute_block_count(base_type::m_size - 1); if (new_block_count != old_block_count) { base_type::m_buffer.pop_back(); } --base_type::m_size; base_type::zero_unused_bits(); } template inline void xdynamic_bitset_base::swap(self_type& rhs) { using std::swap; swap(m_buffer, rhs.m_buffer); swap(m_size, rhs.m_size); } template inline auto xdynamic_bitset_base::at(size_type i) -> reference { // TODO add real check, remove m_buffer.at ... return reference(m_buffer.at(block_index(i)), bit_index(i)); } template inline auto xdynamic_bitset_base::at(size_type i) const -> const_reference { // TODO add real check, remove m_buffer.at ... return const_reference(m_buffer.at(block_index(i)), bit_index(i)); } template inline auto xdynamic_bitset_base::operator[](size_type i) -> reference { return reference(m_buffer[block_index(i)], bit_index(i)); } template inline auto xdynamic_bitset_base::operator[](size_type i) const -> const_reference { return const_reference(m_buffer[block_index(i)], bit_index(i)); } template inline auto xdynamic_bitset_base::front() -> reference { return (*this)[0]; } template inline auto xdynamic_bitset_base::front() const -> const_reference { return (*this)[0]; } template inline auto xdynamic_bitset_base::back() -> reference { return (*this)[m_size - 1]; } template inline auto xdynamic_bitset_base::back() const -> const_reference { return (*this)[m_size - 1]; } template inline auto xdynamic_bitset_base::begin() noexcept -> iterator { return iterator(*this, size_type(0)); } template inline auto xdynamic_bitset_base::end() noexcept -> iterator { return iterator(*this, size()); } template inline auto xdynamic_bitset_base::begin() const noexcept -> const_iterator { return cbegin(); } template inline auto xdynamic_bitset_base::end() const noexcept -> const_iterator { return cend(); } template inline auto xdynamic_bitset_base::cbegin() const noexcept -> const_iterator { return const_iterator(*this, size_type(0)); } template inline auto xdynamic_bitset_base::cend() const noexcept -> const_iterator { return const_iterator(*this, size()); } template inline auto xdynamic_bitset_base::rbegin() noexcept -> reverse_iterator { return reverse_iterator(end()); } template inline auto xdynamic_bitset_base::rend() noexcept -> reverse_iterator { return reverse_iterator(begin()); } template inline auto xdynamic_bitset_base::rbegin() const noexcept -> const_reverse_iterator { return crbegin(); } template inline auto xdynamic_bitset_base::rend() const noexcept -> const_reverse_iterator { return crend(); } template inline auto xdynamic_bitset_base::crbegin() const noexcept -> const_reverse_iterator { return const_reverse_iterator(cend()); } template inline auto xdynamic_bitset_base::crend() const noexcept -> const_reverse_iterator { return const_reverse_iterator(cbegin()); } template inline auto xdynamic_bitset_base::block_begin() const noexcept -> const_block_iterator { return m_buffer.begin(); } template inline auto xdynamic_bitset_base::block_end() const noexcept -> const_block_iterator { return m_buffer.end(); } template template inline auto xdynamic_bitset_base::operator&=(const xdynamic_bitset_base& rhs) -> self_type& { size_type size = block_count(); for (size_type i = 0; i < size; ++i) { m_buffer[i] &= rhs.m_buffer[i]; } return *this; } template template inline auto xdynamic_bitset_base::operator|=(const xdynamic_bitset_base& rhs) -> self_type& { size_type size = block_count(); for (size_type i = 0; i < size; ++i) { m_buffer[i] |= rhs.m_buffer[i]; } return *this; } template template inline auto xdynamic_bitset_base::operator^=(const xdynamic_bitset_base& rhs) -> self_type& { size_type size = block_count(); for (size_type i = 0; i < size; ++i) { m_buffer[i] ^= rhs.m_buffer[i]; } return *this; } template inline auto xdynamic_bitset_base::operator<<(size_type pos) -> temporary_type { temporary_type tmp(this->derived_cast()); tmp <<= pos; return tmp; } template inline auto xdynamic_bitset_base::operator<<=(size_type pos) -> self_type& { if (pos >= m_size) { return reset(); } if (pos > 0) { size_type last = block_count() - 1; size_type div = pos / s_bits_per_block; size_type r = bit_index(pos); block_type* b = &m_buffer[0]; if (r != 0) { size_type rs = s_bits_per_block - r; for (size_type i = last - div; i > 0; --i) { b[i + div] = (b[i] << r) | (b[i - 1] >> rs); } b[div] = b[0] << r; } else { for (size_type i = last - div; i > 0; --i) { b[i + div] = b[i]; } b[div] = b[0]; } std::fill_n(m_buffer.begin(), div, block_type(0)); zero_unused_bits(); } return *this; } template inline auto xdynamic_bitset_base::operator>>(size_type pos) -> temporary_type { temporary_type tmp(this->derived_cast()); tmp >>= pos; return tmp; } template inline auto xdynamic_bitset_base::operator>>=(size_type pos) -> self_type& { if (pos >= m_size) { return reset(); } if (pos > 0) { size_type last = block_count() - 1; size_type div = pos / s_bits_per_block; size_type r = bit_index(pos); block_type* b = &m_buffer[0]; if (r != 0) { size_type ls = s_bits_per_block - r; for (size_type i = div; i < last; ++i) { b[i - div] = (b[i] >> r) | (b[i + 1] << ls); } b[last - div] = b[last] >> r; } else { for (size_type i = div; i <= last; ++i) { b[i - div] = b[i]; } } std::fill_n(m_buffer.begin() + static_cast(block_count() - div), div, block_type(0)); } return *this; } template inline auto xdynamic_bitset_base::set() -> self_type& { std::fill(m_buffer.begin(), m_buffer.end(), ~block_type(0)); zero_unused_bits(); return *this; } template inline auto xdynamic_bitset_base::set(size_type pos, value_type value) -> self_type& { if (value) { m_buffer[block_index(pos)] |= bit_mask(pos); } else { reset(pos); } return *this; } template inline auto xdynamic_bitset_base::reset() -> self_type& { std::fill(m_buffer.begin(), m_buffer.end(), block_type(0)); return *this; } template inline auto xdynamic_bitset_base::reset(size_type pos) -> self_type& { m_buffer[block_index(pos)] &= ~bit_mask(pos); return *this; } template inline auto xdynamic_bitset_base::flip() -> self_type& { size_type size = block_count(); for (size_type i = 0; i < size; ++i) { m_buffer[i] = ~m_buffer[i]; } zero_unused_bits(); return *this; } template inline auto xdynamic_bitset_base::flip(size_type pos) -> self_type& { m_buffer[block_index(pos)] ^= bit_mask(pos); return *this; } template inline bool xdynamic_bitset_base::all() const noexcept { if (empty()) return true; size_type extra_bits = count_extra_bits(); constexpr block_type all_ones = ~block_type(0); size_type size = extra_bits != 0 ? block_count() - 1 : block_count(); for (size_type i = 0; i < size; ++i) { if (m_buffer[i] != all_ones) return false; } if (extra_bits != 0) { block_type mask = ~(~block_type(0) << extra_bits); if (m_buffer.back() != mask) return false; } return true; } template inline bool xdynamic_bitset_base::any() const noexcept { size_type size = block_count(); for (size_type i = 0; i < size; ++i) { if (m_buffer[i]) return true; } return false; } template inline bool xdynamic_bitset_base::none() const noexcept { return !any(); } template inline auto xdynamic_bitset_base::count() const noexcept -> size_type { static constexpr unsigned char table[] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 }; size_type res = 0; const unsigned char* p = static_cast(static_cast(&m_buffer[0])); size_type length = m_buffer.size() * sizeof(block_type); for (size_type i = 0; i < length; ++i, ++p) { res += table[*p]; } return res; } template inline auto xdynamic_bitset_base::block_count() const noexcept -> size_type { return m_buffer.size(); } template inline auto xdynamic_bitset_base::data() noexcept -> block_type* { return m_buffer.data(); } template inline auto xdynamic_bitset_base::data() const noexcept -> const block_type* { return m_buffer.data(); } template template inline bool xdynamic_bitset_base::operator==(const xdynamic_bitset_base& rhs) const noexcept { bool is_equal = m_size == rhs.m_size; if (!is_equal) { return false; } // we know that block type of lhs & rhs is the same auto n_blocks = block_count(); for (std::size_t i = 0; i < n_blocks; ++i) { if (m_buffer[i] != rhs.m_buffer[i]) { return false; } } return true; } template template inline bool xdynamic_bitset_base::operator!=(const xdynamic_bitset_base& rhs) const noexcept { return !(*this == rhs); } template inline auto xdynamic_bitset_base::derived_cast() -> derived_class& { return *(reinterpret_cast(this)); } template inline auto xdynamic_bitset_base::derived_cast() const -> const derived_class& { return *(reinterpret_cast(this)); } template inline xdynamic_bitset_base::xdynamic_bitset_base(const storage_type& buffer, std::size_t size) : m_size(size), m_buffer(buffer) { } template inline auto xdynamic_bitset_base::compute_block_count(size_type bits_count) const noexcept -> size_type { return bits_count / s_bits_per_block + static_cast(bits_count % s_bits_per_block != 0); } template inline auto xdynamic_bitset_base::block_index(size_type pos) const noexcept -> size_type { return pos / s_bits_per_block; } template inline auto xdynamic_bitset_base::bit_index(size_type pos) const noexcept -> size_type { return pos % s_bits_per_block; } template inline auto xdynamic_bitset_base::bit_mask(size_type pos) const noexcept -> block_type { return block_type(1) << bit_index(pos); } template inline auto xdynamic_bitset_base::count_extra_bits() const noexcept -> size_type { return bit_index(size()); } template inline void xdynamic_bitset_base::zero_unused_bits() { size_type extra_bits = count_extra_bits(); if (extra_bits != 0) { m_buffer.back() &= ~(~block_type(0) << extra_bits); } } template inline auto operator~(const xdynamic_bitset_base& lhs) { using temporary_type = typename xdynamic_bitset_base::temporary_type; temporary_type res(lhs.derived_cast()); res.flip(); return res; } template inline auto operator&(const xdynamic_bitset_base& lhs, const xdynamic_bitset_base& rhs) { using temporary_type = typename xdynamic_bitset_base::temporary_type; temporary_type res(lhs.derived_cast()); res &= rhs; return res; } template inline auto operator|(const xdynamic_bitset_base& lhs, const xdynamic_bitset_base& rhs) { using temporary_type = typename xdynamic_bitset_base::temporary_type; temporary_type res(lhs.derived_cast()); res |= rhs; return res; } template inline auto operator^(const xdynamic_bitset_base& lhs, const xdynamic_bitset_base& rhs) { using temporary_type = typename xdynamic_bitset_base::temporary_type; temporary_type res(lhs.derived_cast()); res ^= rhs; return res; } template inline void swap(const xdynamic_bitset_base& lhs, const xdynamic_bitset_base& rhs) { return lhs.swap(rhs); } /************************************ * xbitset_reference implementation * ************************************/ template inline xbitset_reference::xbitset_reference(closure_type block, block_type pos) : m_block(block), m_mask(block_type(1) << pos) { } template inline xbitset_reference::operator bool() const noexcept { return (m_block & m_mask) != 0; } template inline auto xbitset_reference::operator=(const self_type& rhs) noexcept -> self_type& { assign(rhs); return *this; } template inline auto xbitset_reference::operator=(self_type&& rhs) noexcept -> self_type& { assign(rhs); return *this; } template inline auto xbitset_reference::operator=(bool rhs) noexcept -> self_type& { assign(rhs); return *this; } template inline bool xbitset_reference::operator~() const noexcept { return (m_block & m_mask) == 0; } template inline auto xbitset_reference::operator&=(bool rhs) noexcept -> self_type& { if (!rhs) { reset(); } return *this; } template inline auto xbitset_reference::operator|=(bool rhs) noexcept -> self_type& { if (rhs) { set(); } return *this; } template inline auto xbitset_reference::operator^=(bool rhs) noexcept -> self_type& { return rhs ? flip() : *this; } template inline auto xbitset_reference::flip() noexcept -> self_type& { m_block ^= m_mask; return *this; } template inline auto xbitset_reference::operator&() noexcept -> pointer { return pointer(*this); } template inline void xbitset_reference::assign(bool rhs) noexcept { rhs ? set() : reset(); } template inline void xbitset_reference::set() noexcept { m_block |= m_mask; } template inline void xbitset_reference::reset() noexcept { m_block &= ~m_mask; } /*********************************** * xbitset_iterator implementation * ***********************************/ template inline xbitset_iterator::xbitset_iterator() noexcept : p_container(nullptr), m_index(0) { } template inline xbitset_iterator::xbitset_iterator(container_reference c, size_type index) noexcept : p_container(&c), m_index(index) { } template inline auto xbitset_iterator::operator++() -> self_type& { ++m_index; return *this; } template inline auto xbitset_iterator::operator--() -> self_type& { --m_index; return *this; } template inline auto xbitset_iterator::operator+=(difference_type n) -> self_type& { difference_type res = static_cast(m_index) + n; m_index = static_cast(res); return *this; } template inline auto xbitset_iterator::operator-=(difference_type n) -> self_type& { difference_type res = static_cast(m_index) - n; m_index = static_cast(res); return *this; } template inline auto xbitset_iterator::operator-(const self_type& rhs) const -> difference_type { return difference_type(m_index - rhs.m_index); } template inline auto xbitset_iterator::operator*() const -> reference { return (*p_container)[m_index]; } template inline auto xbitset_iterator::operator->() const -> pointer { return &(operator*()); } template inline bool xbitset_iterator::operator==(const self_type& rhs) const { return p_container == rhs.p_container && m_index == rhs.m_index; } template inline bool xbitset_iterator::operator<(const self_type& rhs) const { return p_container == rhs.p_container && m_index < rhs.m_index; } } #endif xtl-0.7.2/include/xtl/xfunctional.hpp000066400000000000000000000025021400411521700176160ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * * Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XTL_FUNCTIONAL_HPP #define XTL_FUNCTIONAL_HPP #include #include "xtl_config.hpp" #include "xtype_traits.hpp" namespace xtl { /*************************** * identity implementation * ***************************/ struct identity { template T&& operator()(T&& x) const { return std::forward(x); } }; /************************* * select implementation * *************************/ template )> inline std::common_type_t select(const B& cond, const T1& v1, const T2& v2) noexcept { return cond ? v1 : v2; } } #endif xtl-0.7.2/include/xtl/xhalf_float.hpp000066400000000000000000000021571400411521700175610ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * * Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XTL_XHALF_FLOAT_HPP #define XTL_XHALF_FLOAT_HPP #include "xtype_traits.hpp" #include "xhalf_float_impl.hpp" namespace xtl { using half_float = half_float::half; template <> struct is_scalar : std::true_type { }; template <> struct is_arithmetic : std::true_type { }; template <> struct is_signed : std::true_type { }; template <> struct is_floating_point : std::true_type { }; } #endif xtl-0.7.2/include/xtl/xhalf_float_impl.hpp000066400000000000000000006117011400411521700206030ustar00rootroot00000000000000// half - IEEE 754-based half-precision floating-point library. // // Copyright (c) 2012-2019 Christian Rau // Copyright (c) 2020 0xBYTESHIFT // // 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. /// \file /// Main header file for half-precision functionality. #pragma once #define HALF_TWOS_COMPLEMENT_INT 1 // any error throwing C++ exceptions? #if defined(HALF_ERRHANDLING_THROW_INVALID) || defined(HALF_ERRHANDLING_THROW_DIVBYZERO) || defined(HALF_ERRHANDLING_THROW_OVERFLOW) || defined(HALF_ERRHANDLING_THROW_UNDERFLOW) || defined(HALF_ERRHANDLING_THROW_INEXACT) #define HALF_ERRHANDLING_THROWS 1 #endif // any error handling enabled? #define HALF_ERRHANDLING (HALF_ERRHANDLING_FLAGS||HALF_ERRHANDLING_ERRNO||HALF_ERRHANDLING_FENV||HALF_ERRHANDLING_THROWS) #if HALF_ERRHANDLING #define HALF_UNUSED_NOERR(name) name #else #define HALF_UNUSED_NOERR(name) #endif // support constexpr #if HALF_ERRHANDLING #define constexpr_NOERR #else #define constexpr_NOERR constexpr #endif #include #include #include #include #include #include #include #include #include #include #include #include #if HALF_ERRHANDLING_ERRNO #include #endif #include #include #ifndef HALF_ENABLE_F16C_INTRINSICS /// Enable F16C intruction set intrinsics. /// Defining this to 1 enables the use of [F16C compiler intrinsics](https://en.wikipedia.org/wiki/F16C) for converting between /// half-precision and single-precision values which may result in improved performance. This will not perform additional checks /// for support of the F16C instruction set, so an appropriate target platform is required when enabling this feature. /// /// Unless predefined it will be enabled automatically when the `__F16C__` symbol is defined, which some compilers do on supporting platforms. #define HALF_ENABLE_F16C_INTRINSICS __F16C__ #endif #if HALF_ENABLE_F16C_INTRINSICS #include #endif #ifndef HALF_ERRHANDLING_OVERFLOW_TO_INEXACT /// Raise INEXACT exception on overflow. /// Defining this to 1 (default) causes overflow errors to automatically raise inexact exceptions in addition. /// These will be raised after any possible handling of the underflow exception. #define HALF_ERRHANDLING_OVERFLOW_TO_INEXACT 1 #endif #ifndef HALF_ERRHANDLING_UNDERFLOW_TO_INEXACT /// Raise INEXACT exception on underflow. /// Defining this to 1 (default) causes underflow errors to automatically raise inexact exceptions in addition. /// These will be raised after any possible handling of the underflow exception. /// /// **Note:** This will actually cause underflow (and the accompanying inexact) exceptions to be raised *only* when the result /// is inexact, while if disabled bare underflow errors will be raised for *any* (possibly exact) subnormal result. #define HALF_ERRHANDLING_UNDERFLOW_TO_INEXACT 1 #endif /// Default rounding mode. /// This specifies the rounding mode used for all conversions between [half](\ref half_float::half)s and more precise types /// (unless using half_cast() and specifying the rounding mode directly) as well as in arithmetic operations and mathematical /// functions. It can be redefined (before including half.hpp) to one of the standard rounding modes using their respective /// constants or the equivalent values of /// [std::float_round_style](https://en.cppreference.com/w/cpp/types/numeric_limits/float_round_style): /// /// `std::float_round_style` | value | rounding /// ---------------------------------|-------|------------------------- /// `std::round_indeterminate` | -1 | fastest /// `std::round_toward_zero` | 0 | toward zero /// `std::round_to_nearest` | 1 | to nearest (default) /// `std::round_toward_infinity` | 2 | toward positive infinity /// `std::round_toward_neg_infinity` | 3 | toward negative infinity /// /// By default this is set to `1` (`std::round_to_nearest`), which rounds results to the nearest representable value. It can even /// be set to [std::numeric_limits::round_style](https://en.cppreference.com/w/cpp/types/numeric_limits/round_style) to synchronize /// the rounding mode with that of the built-in single-precision implementation (which is likely `std::round_to_nearest`, though). #ifndef HALF_ROUND_STYLE #define HALF_ROUND_STYLE 1 // = std::round_to_nearest #endif /// Value signaling overflow. /// In correspondence with `HUGE_VAL[F|L]` from `` this symbol expands to a positive value signaling the overflow of an /// operation, in particular it just evaluates to positive infinity. /// /// **See also:** Documentation for [HUGE_VAL](https://en.cppreference.com/w/cpp/numeric/math/HUGE_VAL) #define HUGE_VALH std::numeric_limits::infinity() /// Fast half-precision fma function. /// This symbol is defined if the fma() function generally executes as fast as, or faster than, a separate /// half-precision multiplication followed by an addition, which is always the case. /// /// **See also:** Documentation for [FP_FAST_FMA](https://en.cppreference.com/w/cpp/numeric/math/fma) #define FP_FAST_FMAH 1 /// Half rounding mode. /// In correspondence with `FLT_ROUNDS` from `` this symbol expands to the rounding mode used for /// half-precision operations. It is an alias for [HALF_ROUND_STYLE](\ref HALF_ROUND_STYLE). /// /// **See also:** Documentation for [FLT_ROUNDS](https://en.cppreference.com/w/cpp/types/climits/FLT_ROUNDS) #define HLF_ROUNDS HALF_ROUND_STYLE #ifndef FP_ILOGB0 #define FP_ILOGB0 INT_MIN #endif #ifndef FP_ILOGBNAN #define FP_ILOGBNAN INT_MAX #endif #ifndef FP_SUBNORMAL #define FP_SUBNORMAL 0 #endif #ifndef FP_ZERO #define FP_ZERO 1 #endif #ifndef FP_NAN #define FP_NAN 2 #endif #ifndef FP_INFINITE #define FP_INFINITE 3 #endif #ifndef FP_NORMAL #define FP_NORMAL 4 #endif #if !defined(FE_ALL_EXCEPT) #define FE_INVALID 0x10 #define FE_DIVBYZERO 0x08 #define FE_OVERFLOW 0x04 #define FE_UNDERFLOW 0x02 #define FE_INEXACT 0x01 #define FE_ALL_EXCEPT (FE_INVALID|FE_DIVBYZERO|FE_OVERFLOW|FE_UNDERFLOW|FE_INEXACT) #endif /// Main namespace for half-precision functionality. /// This namespace contains all the functionality provided by the library. namespace half_float { class half; /// Library-defined half-precision literals. /// Import this namespace to enable half-precision floating-point literals: /// ~~~~{.cpp} /// using namespace half_float::literal; /// half_float::half = 4.2_h; /// ~~~~ namespace literal { half operator "" _h(long double); } /// \internal /// \brief Implementation details. namespace detail { /// Conditional type. template struct conditional : std::conditional {}; /// Helper for tag dispatching. template struct bool_type : std::integral_constant {}; using std::true_type; using std::false_type; /// Type traits for floating-point types. template struct is_float : std::is_floating_point {}; /// Type traits for floating-point bits. template struct bits { using type = unsigned char; }; template struct bits : bits {}; template struct bits : bits {}; template struct bits : bits {}; /// Unsigned integer of (at least) 16 bits width. using uint16 = std::uint_least16_t; /// Fastest unsigned integer of (at least) 32 bits width. using uint32 = std::uint_fast32_t; /// Fastest signed integer of (at least) 32 bits width. using int32 = std::int_fast32_t; /// Unsigned integer of (at least) 32 bits width. template<> struct bits { using type = std::uint_least32_t; }; /// Unsigned integer of (at least) 64 bits width. template<> struct bits { using type = std::uint_least64_t; }; template using bits_t = typename bits::type; #ifdef HALF_ARITHMETIC_TYPE /// Type to use for arithmetic computations and mathematic functions internally. typedef HALF_ARITHMETIC_TYPE internal_t; #endif /// Tag type for binary construction. struct binary_t {}; /// Tag for binary construction. constexpr binary_t binary = binary_t(); /// \name Implementation defined classification and arithmetic /// \{ /// Check for infinity. /// \tparam T argument type (builtin floating-point type) /// \param arg value to query /// \retval true if infinity /// \retval false else template bool builtin_isinf(T arg) { return std::isinf(arg); } /// Check for NaN. /// \tparam T argument type (builtin floating-point type) /// \param arg value to query /// \retval true if not a number /// \retval false else template bool builtin_isnan(T arg) { return std::isnan(arg); } /// Check sign. /// \tparam T argument type (builtin floating-point type) /// \param arg value to query /// \retval true if signbit set /// \retval false else template bool builtin_signbit(T arg) { return std::signbit(arg); } /// Platform-independent sign mask. /// \param arg integer value in two's complement /// \retval -1 if \a arg negative /// \retval 0 if \a arg positive inline uint32 sign_mask(uint32 arg) { static const int N = std::numeric_limits::digits - 1; #if HALF_TWOS_COMPLEMENT_INT return static_cast(arg) >> N; #else return -((arg>>N)&1); #endif } /// Platform-independent arithmetic right shift. /// \param arg integer value in two's complement /// \param i shift amount (at most 31) /// \return \a arg right shifted for \a i bits with possible sign extension inline uint32 arithmetic_shift(uint32 arg, int i) { #if HALF_TWOS_COMPLEMENT_INT return static_cast(arg) >> i; #else return static_cast(arg)/(static_cast(1)<>(std::numeric_limits::digits-1))&1); #endif } /// \} /// \name Error handling /// \{ /// Internal exception flags. /// \return reference to global exception flags inline int& errflags() { thread_local int flags = 0; return flags; } /// Raise floating-point exception. /// \param flags exceptions to raise /// \param cond condition to raise exceptions for inline void raise(int HALF_UNUSED_NOERR(flags), bool HALF_UNUSED_NOERR(cond) = true) { #if HALF_ERRHANDLING if(!cond) return; #if HALF_ERRHANDLING_FLAGS errflags() |= flags; #endif #if HALF_ERRHANDLING_ERRNO if(flags & FE_INVALID) errno = EDOM; else if(flags & (FE_DIVBYZERO|FE_OVERFLOW|FE_UNDERFLOW)) errno = ERANGE; #endif #if HALF_ERRHANDLING_FENV std::feraiseexcept(flags); #endif #ifdef HALF_ERRHANDLING_THROW_INVALID if(flags & FE_INVALID) throw std::domain_error(HALF_ERRHANDLING_THROW_INVALID); #endif #ifdef HALF_ERRHANDLING_THROW_DIVBYZERO if(flags & FE_DIVBYZERO) throw std::domain_error(HALF_ERRHANDLING_THROW_DIVBYZERO); #endif #ifdef HALF_ERRHANDLING_THROW_OVERFLOW if(flags & FE_OVERFLOW) throw std::overflow_error(HALF_ERRHANDLING_THROW_OVERFLOW); #endif #ifdef HALF_ERRHANDLING_THROW_UNDERFLOW if(flags & FE_UNDERFLOW) throw std::underflow_error(HALF_ERRHANDLING_THROW_UNDERFLOW); #endif #ifdef HALF_ERRHANDLING_THROW_INEXACT if(flags & FE_INEXACT) throw std::range_error(HALF_ERRHANDLING_THROW_INEXACT); #endif #if HALF_ERRHANDLING_UNDERFLOW_TO_INEXACT if((flags & FE_UNDERFLOW) && !(flags & FE_INEXACT)) raise(FE_INEXACT); #endif #if HALF_ERRHANDLING_OVERFLOW_TO_INEXACT if((flags & FE_OVERFLOW) && !(flags & FE_INEXACT)) raise(FE_INEXACT); #endif #endif } /// Check and signal for any NaN. /// \param x first half-precision value to check /// \param y second half-precision value to check /// \retval true if either \a x or \a y is NaN /// \retval false else /// \exception FE_INVALID if \a x or \a y is NaN inline constexpr_NOERR bool compsignal(unsigned int x, unsigned int y) { #if HALF_ERRHANDLING raise(FE_INVALID, (x&0x7FFF)>0x7C00 || (y&0x7FFF)>0x7C00); #endif return (x&0x7FFF) > 0x7C00 || (y&0x7FFF) > 0x7C00; } /// Signal and silence signaling NaN. /// \param nan half-precision NaN value /// \return quiet NaN /// \exception FE_INVALID if \a nan is signaling NaN inline constexpr_NOERR unsigned int signal(unsigned int nan) { #if HALF_ERRHANDLING raise(FE_INVALID, !(nan&0x200)); #endif return nan | 0x200; } /// Signal and silence signaling NaNs. /// \param x first half-precision value to check /// \param y second half-precision value to check /// \return quiet NaN /// \exception FE_INVALID if \a x or \a y is signaling NaN inline constexpr_NOERR unsigned int signal(unsigned int x, unsigned int y) { #if HALF_ERRHANDLING raise(FE_INVALID, ((x&0x7FFF)>0x7C00 && !(x&0x200)) || ((y&0x7FFF)>0x7C00 && !(y&0x200))); #endif return ((x&0x7FFF)>0x7C00) ? (x|0x200) : (y|0x200); } /// Signal and silence signaling NaNs. /// \param x first half-precision value to check /// \param y second half-precision value to check /// \param z third half-precision value to check /// \return quiet NaN /// \exception FE_INVALID if \a x, \a y or \a z is signaling NaN inline constexpr_NOERR unsigned int signal(unsigned int x, unsigned int y, unsigned int z) { #if HALF_ERRHANDLING raise(FE_INVALID, ((x&0x7FFF)>0x7C00 && !(x&0x200)) || ((y&0x7FFF)>0x7C00 && !(y&0x200)) || ((z&0x7FFF)>0x7C00 && !(z&0x200))); #endif return ((x&0x7FFF)>0x7C00) ? (x|0x200) : ((y&0x7FFF)>0x7C00) ? (y|0x200) : (z|0x200); } /// Select value or signaling NaN. /// \param x preferred half-precision value /// \param y ignored half-precision value except for signaling NaN /// \return \a y if signaling NaN, \a x otherwise /// \exception FE_INVALID if \a y is signaling NaN inline constexpr_NOERR unsigned int select(unsigned int x, unsigned int HALF_UNUSED_NOERR(y)) { #if HALF_ERRHANDLING return (((y&0x7FFF)>0x7C00) && !(y&0x200)) ? signal(y) : x; #else return x; #endif } /// Raise domain error and return NaN. /// return quiet NaN /// \exception FE_INVALID inline constexpr_NOERR unsigned int invalid() { #if HALF_ERRHANDLING raise(FE_INVALID); #endif return 0x7FFF; } /// Raise pole error and return infinity. /// \param sign half-precision value with sign bit only /// \return half-precision infinity with sign of \a sign /// \exception FE_DIVBYZERO inline constexpr_NOERR unsigned int pole(unsigned int sign = 0) { #if HALF_ERRHANDLING raise(FE_DIVBYZERO); #endif return sign | 0x7C00; } /// Check value for underflow. /// \param arg non-zero half-precision value to check /// \return \a arg /// \exception FE_UNDERFLOW if arg is subnormal inline constexpr_NOERR unsigned int check_underflow(unsigned int arg) { #if HALF_ERRHANDLING && !HALF_ERRHANDLING_UNDERFLOW_TO_INEXACT raise(FE_UNDERFLOW, !(arg&0x7C00)); #endif return arg; } /// \} /// \name Conversion and rounding /// \{ /// Half-precision overflow. /// \tparam R rounding mode to use /// \param sign half-precision value with sign bit only /// \return rounded overflowing half-precision value /// \exception FE_OVERFLOW template constexpr_NOERR unsigned int overflow(unsigned int sign = 0) { #if HALF_ERRHANDLING raise(FE_OVERFLOW); #endif return (R==std::round_toward_infinity) ? (sign+0x7C00-(sign>>15)) : (R==std::round_toward_neg_infinity) ? (sign+0x7BFF+(sign>>15)) : (R==std::round_toward_zero) ? (sign|0x7BFF) : (sign|0x7C00); } /// Half-precision underflow. /// \tparam R rounding mode to use /// \param sign half-precision value with sign bit only /// \return rounded underflowing half-precision value /// \exception FE_UNDERFLOW template constexpr_NOERR unsigned int underflow(unsigned int sign = 0) { #if HALF_ERRHANDLING raise(FE_UNDERFLOW); #endif return (R==std::round_toward_infinity) ? (sign+1-(sign>>15)) : (R==std::round_toward_neg_infinity) ? (sign+(sign>>15)) : sign; } /// Round half-precision number. /// \tparam R rounding mode to use /// \tparam I `true` to always raise INEXACT exception, `false` to raise only for rounded results /// \param value finite half-precision number to round /// \param g guard bit (most significant discarded bit) /// \param s sticky bit (or of all but the most significant discarded bits) /// \return rounded half-precision value /// \exception FE_OVERFLOW on overflows /// \exception FE_UNDERFLOW on underflows /// \exception FE_INEXACT if value had to be rounded or \a I is `true` template constexpr_NOERR unsigned int rounded(unsigned int value, int g, int s) { #if HALF_ERRHANDLING value += (R==std::round_to_nearest) ? (g&(s|value)) : (R==std::round_toward_infinity) ? (~(value>>15)&(g|s)) : (R==std::round_toward_neg_infinity) ? ((value>>15)&(g|s)) : 0; if((value&0x7C00) == 0x7C00) raise(FE_OVERFLOW); else if(value & 0x7C00) raise(FE_INEXACT, I || (g|s)!=0); else raise(FE_UNDERFLOW, !(HALF_ERRHANDLING_UNDERFLOW_TO_INEXACT) || I || (g|s)!=0); return value; #else return (R==std::round_to_nearest) ? (value+(g&(s|value))) : (R==std::round_toward_infinity) ? (value+(~(value>>15)&(g|s))) : (R==std::round_toward_neg_infinity) ? (value+((value>>15)&(g|s))) : value; #endif } /// Round half-precision number to nearest integer value. /// \tparam R rounding mode to use /// \tparam E `true` for round to even, `false` for round away from zero /// \tparam I `true` to raise INEXACT exception (if inexact), `false` to never raise it /// \param value half-precision value to round /// \return half-precision bits for nearest integral value /// \exception FE_INVALID for signaling NaN /// \exception FE_INEXACT if value had to be rounded and \a I is `true` template unsigned int integral(unsigned int value) { unsigned int abs = value & 0x7FFF; if(abs < 0x3C00) { raise(FE_INEXACT, I); return ((R==std::round_to_nearest) ? (0x3C00&-static_cast(abs>=(0x3800+E))) : (R==std::round_toward_infinity) ? (0x3C00&-(~(value>>15)&(abs!=0))) : (R==std::round_toward_neg_infinity) ? (0x3C00&-static_cast(value>0x8000)) : 0) | (value&0x8000); } if(abs >= 0x6400) return (abs>0x7C00) ? signal(value) : value; unsigned int exp = 25 - (abs>>10), mask = (1<>exp)&E)) : (R==std::round_toward_infinity) ? (mask&((value>>15)-1)) : (R==std::round_toward_neg_infinity) ? (mask&-(value>>15)) : 0) + value) & ~mask; } /// Convert fixed point to half-precision floating-point. /// \tparam R rounding mode to use /// \tparam F number of fractional bits (at least 11) /// \tparam S `true` for signed, `false` for unsigned /// \tparam N `true` for additional normalization step, `false` if already normalized to 1.F /// \tparam I `true` to always raise INEXACT exception, `false` to raise only for rounded results /// \param m mantissa in Q1.F fixed point format /// \param exp exponent /// \param sign half-precision value with sign bit only /// \param s sticky bit (or of all but the most significant already discarded bits) /// \return value converted to half-precision /// \exception FE_OVERFLOW on overflows /// \exception FE_UNDERFLOW on underflows /// \exception FE_INEXACT if value had to be rounded or \a I is `true` template unsigned int fixed2half(uint32 m, int exp = 14, unsigned int sign = 0, int s = 0) { if(S) { uint32 msign = sign_mask(m); m = (m^msign) - msign; sign = msign & 0x8000; } if(N) for(; m<(static_cast(1)<(sign+(m>>(F-10-exp)), (m>>(F-11-exp))&1, s|((m&((static_cast(1)<<(F-11-exp))-1))!=0)); return rounded(sign+(exp<<10)+(m>>(F-10)), (m>>(F-11))&1, s|((m&((static_cast(1)<<(F-11))-1))!=0)); } /// Convert IEEE single-precision to half-precision. /// Credit for this goes to [Jeroen van der Zijp](ftp://ftp.fox-toolkit.org/pub/fasthalffloatconversion.pdf). /// \tparam R rounding mode to use /// \param value single-precision value to convert /// \return rounded half-precision value /// \exception FE_OVERFLOW on overflows /// \exception FE_UNDERFLOW on underflows /// \exception FE_INEXACT if value had to be rounded template unsigned int float2half_impl(float value, true_type) { #if HALF_ENABLE_F16C_INTRINSICS return _mm_cvtsi128_si32(_mm_cvtps_ph(_mm_set_ss(value), (R==std::round_to_nearest) ? _MM_FROUND_TO_NEAREST_INT : (R==std::round_toward_zero) ? _MM_FROUND_TO_ZERO : (R==std::round_toward_infinity) ? _MM_FROUND_TO_POS_INF : (R==std::round_toward_neg_infinity) ? _MM_FROUND_TO_NEG_INF : _MM_FROUND_CUR_DIRECTION)); #else bits_t fbits; std::memcpy(&fbits, &value, sizeof(float)); #if 1 unsigned int sign = (fbits>>16) & 0x8000; fbits &= 0x7FFFFFFF; if(fbits >= 0x7F800000) return sign | 0x7C00 | ((fbits>0x7F800000) ? (0x200|((fbits>>13)&0x3FF)) : 0); if(fbits >= 0x47800000) return overflow(sign); if(fbits >= 0x38800000) return rounded(sign|(((fbits>>23)-112)<<10)|((fbits>>13)&0x3FF), (fbits>>12)&1, (fbits&0xFFF)!=0); if(fbits >= 0x33000000) { int i = 125 - (fbits>>23); fbits = (fbits&0x7FFFFF) | 0x800000; return rounded(sign|(fbits>>(i+1)), (fbits>>i)&1, (fbits&((static_cast(1)<(sign); return sign; #else static const uint16 base_table[512] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, 0x0100, 0x0200, 0x0400, 0x0800, 0x0C00, 0x1000, 0x1400, 0x1800, 0x1C00, 0x2000, 0x2400, 0x2800, 0x2C00, 0x3000, 0x3400, 0x3800, 0x3C00, 0x4000, 0x4400, 0x4800, 0x4C00, 0x5000, 0x5400, 0x5800, 0x5C00, 0x6000, 0x6400, 0x6800, 0x6C00, 0x7000, 0x7400, 0x7800, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7BFF, 0x7C00, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8001, 0x8002, 0x8004, 0x8008, 0x8010, 0x8020, 0x8040, 0x8080, 0x8100, 0x8200, 0x8400, 0x8800, 0x8C00, 0x9000, 0x9400, 0x9800, 0x9C00, 0xA000, 0xA400, 0xA800, 0xAC00, 0xB000, 0xB400, 0xB800, 0xBC00, 0xC000, 0xC400, 0xC800, 0xCC00, 0xD000, 0xD400, 0xD800, 0xDC00, 0xE000, 0xE400, 0xE800, 0xEC00, 0xF000, 0xF400, 0xF800, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFBFF, 0xFC00 }; static const unsigned char shift_table[256] = { 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 13 }; int sexp = fbits >> 23, exp = sexp & 0xFF, i = shift_table[exp]; fbits &= 0x7FFFFF; uint32 m = (fbits|((exp!=0)<<23)) & -static_cast(exp!=0xFF); return rounded(base_table[sexp]+(fbits>>i), (m>>(i-1))&1, (((static_cast(1)<<(i-1))-1)&m)!=0); #endif #endif } /// Convert IEEE double-precision to half-precision. /// \tparam R rounding mode to use /// \param value double-precision value to convert /// \return rounded half-precision value /// \exception FE_OVERFLOW on overflows /// \exception FE_UNDERFLOW on underflows /// \exception FE_INEXACT if value had to be rounded template unsigned int float2half_impl(double value, true_type) { #if HALF_ENABLE_F16C_INTRINSICS if(R == std::round_indeterminate) return _mm_cvtsi128_si32(_mm_cvtps_ph(_mm_cvtpd_ps(_mm_set_sd(value)), _MM_FROUND_CUR_DIRECTION)); #endif bits_t dbits; std::memcpy(&dbits, &value, sizeof(double)); uint32 hi = dbits >> 32, lo = dbits & 0xFFFFFFFF; unsigned int sign = (hi>>16) & 0x8000; hi &= 0x7FFFFFFF; if(hi >= 0x7FF00000) return sign | 0x7C00 | ((dbits&0xFFFFFFFFFFFFF) ? (0x200|((hi>>10)&0x3FF)) : 0); if(hi >= 0x40F00000) return overflow(sign); if(hi >= 0x3F100000) return rounded(sign|(((hi>>20)-1008)<<10)|((hi>>10)&0x3FF), (hi>>9)&1, ((hi&0x1FF)|lo)!=0); if(hi >= 0x3E600000) { int i = 1018 - (hi>>20); hi = (hi&0xFFFFF) | 0x100000; return rounded(sign|(hi>>(i+1)), (hi>>i)&1, ((hi&((static_cast(1)<(sign); return sign; } /// Convert non-IEEE floating-point to half-precision. /// \tparam R rounding mode to use /// \tparam T source type (builtin floating-point type) /// \param value floating-point value to convert /// \return rounded half-precision value /// \exception FE_OVERFLOW on overflows /// \exception FE_UNDERFLOW on underflows /// \exception FE_INEXACT if value had to be rounded template unsigned int float2half_impl(T value, ...) { unsigned int hbits = static_cast(builtin_signbit(value)) << 15; if(value == T()) return hbits; if(builtin_isnan(value)) return hbits | 0x7FFF; if(builtin_isinf(value)) return hbits | 0x7C00; int exp; std::frexp(value, &exp); if(exp > 16) return overflow(hbits); if(exp < -13) value = std::ldexp(value, 25); else { value = std::ldexp(value, 12-exp); hbits |= ((exp+13)<<10); } T ival, frac = std::modf(value, &ival); int m = std::abs(static_cast(ival)); return rounded(hbits+(m>>1), m&1, frac!=T()); } /// Convert floating-point to half-precision. /// \tparam R rounding mode to use /// \tparam T source type (builtin floating-point type) /// \param value floating-point value to convert /// \return rounded half-precision value /// \exception FE_OVERFLOW on overflows /// \exception FE_UNDERFLOW on underflows /// \exception FE_INEXACT if value had to be rounded template unsigned int float2half(T value) { return float2half_impl(value, bool_type::is_iec559&&sizeof(bits_t)==sizeof(T)>()); } template unsigned int float2half(T value) { return float2half_impl<(std::float_round_style)(HALF_ROUND_STYLE)>(value, bool_type::is_iec559&&sizeof(bits_t)==sizeof(T)>()); } /// Convert integer to half-precision floating-point. /// \tparam R rounding mode to use /// \tparam T type to convert (builtin integer type) /// \param value integral value to convert /// \return rounded half-precision value /// \exception FE_OVERFLOW on overflows /// \exception FE_INEXACT if value had to be rounded template unsigned int int2half(T value) { unsigned int bits = static_cast(value<0) << 15; if(!value) return bits; if(bits) value = -value; if(value > 0xFFFF) return overflow(bits); unsigned int m = static_cast(value), exp = 24; for(; m<0x400; m<<=1,--exp) ; for(; m>0x7FF; m>>=1,++exp) ; bits |= (exp<<10) + m; return (exp>24) ? rounded(bits, (value>>(exp-25))&1, (((1<<(exp-25))-1)&value)!=0) : bits; } /// Convert half-precision to IEEE single-precision. /// Credit for this goes to [Jeroen van der Zijp](ftp://ftp.fox-toolkit.org/pub/fasthalffloatconversion.pdf). /// \param value half-precision value to convert /// \return single-precision value inline float half2float_impl(unsigned int value, float, true_type) { #if HALF_ENABLE_F16C_INTRINSICS return _mm_cvtss_f32(_mm_cvtph_ps(_mm_cvtsi32_si128(value))); #else #if 0 bits_t fbits = static_cast>(value&0x8000) << 16; int abs = value & 0x7FFF; if(abs) { fbits |= 0x38000000 << static_cast(abs>=0x7C00); for(; abs<0x400; abs<<=1,fbits-=0x800000) ; fbits += static_cast>(abs) << 13; } #else static const bits_t mantissa_table[2048] = { 0x00000000, 0x33800000, 0x34000000, 0x34400000, 0x34800000, 0x34A00000, 0x34C00000, 0x34E00000, 0x35000000, 0x35100000, 0x35200000, 0x35300000, 0x35400000, 0x35500000, 0x35600000, 0x35700000, 0x35800000, 0x35880000, 0x35900000, 0x35980000, 0x35A00000, 0x35A80000, 0x35B00000, 0x35B80000, 0x35C00000, 0x35C80000, 0x35D00000, 0x35D80000, 0x35E00000, 0x35E80000, 0x35F00000, 0x35F80000, 0x36000000, 0x36040000, 0x36080000, 0x360C0000, 0x36100000, 0x36140000, 0x36180000, 0x361C0000, 0x36200000, 0x36240000, 0x36280000, 0x362C0000, 0x36300000, 0x36340000, 0x36380000, 0x363C0000, 0x36400000, 0x36440000, 0x36480000, 0x364C0000, 0x36500000, 0x36540000, 0x36580000, 0x365C0000, 0x36600000, 0x36640000, 0x36680000, 0x366C0000, 0x36700000, 0x36740000, 0x36780000, 0x367C0000, 0x36800000, 0x36820000, 0x36840000, 0x36860000, 0x36880000, 0x368A0000, 0x368C0000, 0x368E0000, 0x36900000, 0x36920000, 0x36940000, 0x36960000, 0x36980000, 0x369A0000, 0x369C0000, 0x369E0000, 0x36A00000, 0x36A20000, 0x36A40000, 0x36A60000, 0x36A80000, 0x36AA0000, 0x36AC0000, 0x36AE0000, 0x36B00000, 0x36B20000, 0x36B40000, 0x36B60000, 0x36B80000, 0x36BA0000, 0x36BC0000, 0x36BE0000, 0x36C00000, 0x36C20000, 0x36C40000, 0x36C60000, 0x36C80000, 0x36CA0000, 0x36CC0000, 0x36CE0000, 0x36D00000, 0x36D20000, 0x36D40000, 0x36D60000, 0x36D80000, 0x36DA0000, 0x36DC0000, 0x36DE0000, 0x36E00000, 0x36E20000, 0x36E40000, 0x36E60000, 0x36E80000, 0x36EA0000, 0x36EC0000, 0x36EE0000, 0x36F00000, 0x36F20000, 0x36F40000, 0x36F60000, 0x36F80000, 0x36FA0000, 0x36FC0000, 0x36FE0000, 0x37000000, 0x37010000, 0x37020000, 0x37030000, 0x37040000, 0x37050000, 0x37060000, 0x37070000, 0x37080000, 0x37090000, 0x370A0000, 0x370B0000, 0x370C0000, 0x370D0000, 0x370E0000, 0x370F0000, 0x37100000, 0x37110000, 0x37120000, 0x37130000, 0x37140000, 0x37150000, 0x37160000, 0x37170000, 0x37180000, 0x37190000, 0x371A0000, 0x371B0000, 0x371C0000, 0x371D0000, 0x371E0000, 0x371F0000, 0x37200000, 0x37210000, 0x37220000, 0x37230000, 0x37240000, 0x37250000, 0x37260000, 0x37270000, 0x37280000, 0x37290000, 0x372A0000, 0x372B0000, 0x372C0000, 0x372D0000, 0x372E0000, 0x372F0000, 0x37300000, 0x37310000, 0x37320000, 0x37330000, 0x37340000, 0x37350000, 0x37360000, 0x37370000, 0x37380000, 0x37390000, 0x373A0000, 0x373B0000, 0x373C0000, 0x373D0000, 0x373E0000, 0x373F0000, 0x37400000, 0x37410000, 0x37420000, 0x37430000, 0x37440000, 0x37450000, 0x37460000, 0x37470000, 0x37480000, 0x37490000, 0x374A0000, 0x374B0000, 0x374C0000, 0x374D0000, 0x374E0000, 0x374F0000, 0x37500000, 0x37510000, 0x37520000, 0x37530000, 0x37540000, 0x37550000, 0x37560000, 0x37570000, 0x37580000, 0x37590000, 0x375A0000, 0x375B0000, 0x375C0000, 0x375D0000, 0x375E0000, 0x375F0000, 0x37600000, 0x37610000, 0x37620000, 0x37630000, 0x37640000, 0x37650000, 0x37660000, 0x37670000, 0x37680000, 0x37690000, 0x376A0000, 0x376B0000, 0x376C0000, 0x376D0000, 0x376E0000, 0x376F0000, 0x37700000, 0x37710000, 0x37720000, 0x37730000, 0x37740000, 0x37750000, 0x37760000, 0x37770000, 0x37780000, 0x37790000, 0x377A0000, 0x377B0000, 0x377C0000, 0x377D0000, 0x377E0000, 0x377F0000, 0x37800000, 0x37808000, 0x37810000, 0x37818000, 0x37820000, 0x37828000, 0x37830000, 0x37838000, 0x37840000, 0x37848000, 0x37850000, 0x37858000, 0x37860000, 0x37868000, 0x37870000, 0x37878000, 0x37880000, 0x37888000, 0x37890000, 0x37898000, 0x378A0000, 0x378A8000, 0x378B0000, 0x378B8000, 0x378C0000, 0x378C8000, 0x378D0000, 0x378D8000, 0x378E0000, 0x378E8000, 0x378F0000, 0x378F8000, 0x37900000, 0x37908000, 0x37910000, 0x37918000, 0x37920000, 0x37928000, 0x37930000, 0x37938000, 0x37940000, 0x37948000, 0x37950000, 0x37958000, 0x37960000, 0x37968000, 0x37970000, 0x37978000, 0x37980000, 0x37988000, 0x37990000, 0x37998000, 0x379A0000, 0x379A8000, 0x379B0000, 0x379B8000, 0x379C0000, 0x379C8000, 0x379D0000, 0x379D8000, 0x379E0000, 0x379E8000, 0x379F0000, 0x379F8000, 0x37A00000, 0x37A08000, 0x37A10000, 0x37A18000, 0x37A20000, 0x37A28000, 0x37A30000, 0x37A38000, 0x37A40000, 0x37A48000, 0x37A50000, 0x37A58000, 0x37A60000, 0x37A68000, 0x37A70000, 0x37A78000, 0x37A80000, 0x37A88000, 0x37A90000, 0x37A98000, 0x37AA0000, 0x37AA8000, 0x37AB0000, 0x37AB8000, 0x37AC0000, 0x37AC8000, 0x37AD0000, 0x37AD8000, 0x37AE0000, 0x37AE8000, 0x37AF0000, 0x37AF8000, 0x37B00000, 0x37B08000, 0x37B10000, 0x37B18000, 0x37B20000, 0x37B28000, 0x37B30000, 0x37B38000, 0x37B40000, 0x37B48000, 0x37B50000, 0x37B58000, 0x37B60000, 0x37B68000, 0x37B70000, 0x37B78000, 0x37B80000, 0x37B88000, 0x37B90000, 0x37B98000, 0x37BA0000, 0x37BA8000, 0x37BB0000, 0x37BB8000, 0x37BC0000, 0x37BC8000, 0x37BD0000, 0x37BD8000, 0x37BE0000, 0x37BE8000, 0x37BF0000, 0x37BF8000, 0x37C00000, 0x37C08000, 0x37C10000, 0x37C18000, 0x37C20000, 0x37C28000, 0x37C30000, 0x37C38000, 0x37C40000, 0x37C48000, 0x37C50000, 0x37C58000, 0x37C60000, 0x37C68000, 0x37C70000, 0x37C78000, 0x37C80000, 0x37C88000, 0x37C90000, 0x37C98000, 0x37CA0000, 0x37CA8000, 0x37CB0000, 0x37CB8000, 0x37CC0000, 0x37CC8000, 0x37CD0000, 0x37CD8000, 0x37CE0000, 0x37CE8000, 0x37CF0000, 0x37CF8000, 0x37D00000, 0x37D08000, 0x37D10000, 0x37D18000, 0x37D20000, 0x37D28000, 0x37D30000, 0x37D38000, 0x37D40000, 0x37D48000, 0x37D50000, 0x37D58000, 0x37D60000, 0x37D68000, 0x37D70000, 0x37D78000, 0x37D80000, 0x37D88000, 0x37D90000, 0x37D98000, 0x37DA0000, 0x37DA8000, 0x37DB0000, 0x37DB8000, 0x37DC0000, 0x37DC8000, 0x37DD0000, 0x37DD8000, 0x37DE0000, 0x37DE8000, 0x37DF0000, 0x37DF8000, 0x37E00000, 0x37E08000, 0x37E10000, 0x37E18000, 0x37E20000, 0x37E28000, 0x37E30000, 0x37E38000, 0x37E40000, 0x37E48000, 0x37E50000, 0x37E58000, 0x37E60000, 0x37E68000, 0x37E70000, 0x37E78000, 0x37E80000, 0x37E88000, 0x37E90000, 0x37E98000, 0x37EA0000, 0x37EA8000, 0x37EB0000, 0x37EB8000, 0x37EC0000, 0x37EC8000, 0x37ED0000, 0x37ED8000, 0x37EE0000, 0x37EE8000, 0x37EF0000, 0x37EF8000, 0x37F00000, 0x37F08000, 0x37F10000, 0x37F18000, 0x37F20000, 0x37F28000, 0x37F30000, 0x37F38000, 0x37F40000, 0x37F48000, 0x37F50000, 0x37F58000, 0x37F60000, 0x37F68000, 0x37F70000, 0x37F78000, 0x37F80000, 0x37F88000, 0x37F90000, 0x37F98000, 0x37FA0000, 0x37FA8000, 0x37FB0000, 0x37FB8000, 0x37FC0000, 0x37FC8000, 0x37FD0000, 0x37FD8000, 0x37FE0000, 0x37FE8000, 0x37FF0000, 0x37FF8000, 0x38000000, 0x38004000, 0x38008000, 0x3800C000, 0x38010000, 0x38014000, 0x38018000, 0x3801C000, 0x38020000, 0x38024000, 0x38028000, 0x3802C000, 0x38030000, 0x38034000, 0x38038000, 0x3803C000, 0x38040000, 0x38044000, 0x38048000, 0x3804C000, 0x38050000, 0x38054000, 0x38058000, 0x3805C000, 0x38060000, 0x38064000, 0x38068000, 0x3806C000, 0x38070000, 0x38074000, 0x38078000, 0x3807C000, 0x38080000, 0x38084000, 0x38088000, 0x3808C000, 0x38090000, 0x38094000, 0x38098000, 0x3809C000, 0x380A0000, 0x380A4000, 0x380A8000, 0x380AC000, 0x380B0000, 0x380B4000, 0x380B8000, 0x380BC000, 0x380C0000, 0x380C4000, 0x380C8000, 0x380CC000, 0x380D0000, 0x380D4000, 0x380D8000, 0x380DC000, 0x380E0000, 0x380E4000, 0x380E8000, 0x380EC000, 0x380F0000, 0x380F4000, 0x380F8000, 0x380FC000, 0x38100000, 0x38104000, 0x38108000, 0x3810C000, 0x38110000, 0x38114000, 0x38118000, 0x3811C000, 0x38120000, 0x38124000, 0x38128000, 0x3812C000, 0x38130000, 0x38134000, 0x38138000, 0x3813C000, 0x38140000, 0x38144000, 0x38148000, 0x3814C000, 0x38150000, 0x38154000, 0x38158000, 0x3815C000, 0x38160000, 0x38164000, 0x38168000, 0x3816C000, 0x38170000, 0x38174000, 0x38178000, 0x3817C000, 0x38180000, 0x38184000, 0x38188000, 0x3818C000, 0x38190000, 0x38194000, 0x38198000, 0x3819C000, 0x381A0000, 0x381A4000, 0x381A8000, 0x381AC000, 0x381B0000, 0x381B4000, 0x381B8000, 0x381BC000, 0x381C0000, 0x381C4000, 0x381C8000, 0x381CC000, 0x381D0000, 0x381D4000, 0x381D8000, 0x381DC000, 0x381E0000, 0x381E4000, 0x381E8000, 0x381EC000, 0x381F0000, 0x381F4000, 0x381F8000, 0x381FC000, 0x38200000, 0x38204000, 0x38208000, 0x3820C000, 0x38210000, 0x38214000, 0x38218000, 0x3821C000, 0x38220000, 0x38224000, 0x38228000, 0x3822C000, 0x38230000, 0x38234000, 0x38238000, 0x3823C000, 0x38240000, 0x38244000, 0x38248000, 0x3824C000, 0x38250000, 0x38254000, 0x38258000, 0x3825C000, 0x38260000, 0x38264000, 0x38268000, 0x3826C000, 0x38270000, 0x38274000, 0x38278000, 0x3827C000, 0x38280000, 0x38284000, 0x38288000, 0x3828C000, 0x38290000, 0x38294000, 0x38298000, 0x3829C000, 0x382A0000, 0x382A4000, 0x382A8000, 0x382AC000, 0x382B0000, 0x382B4000, 0x382B8000, 0x382BC000, 0x382C0000, 0x382C4000, 0x382C8000, 0x382CC000, 0x382D0000, 0x382D4000, 0x382D8000, 0x382DC000, 0x382E0000, 0x382E4000, 0x382E8000, 0x382EC000, 0x382F0000, 0x382F4000, 0x382F8000, 0x382FC000, 0x38300000, 0x38304000, 0x38308000, 0x3830C000, 0x38310000, 0x38314000, 0x38318000, 0x3831C000, 0x38320000, 0x38324000, 0x38328000, 0x3832C000, 0x38330000, 0x38334000, 0x38338000, 0x3833C000, 0x38340000, 0x38344000, 0x38348000, 0x3834C000, 0x38350000, 0x38354000, 0x38358000, 0x3835C000, 0x38360000, 0x38364000, 0x38368000, 0x3836C000, 0x38370000, 0x38374000, 0x38378000, 0x3837C000, 0x38380000, 0x38384000, 0x38388000, 0x3838C000, 0x38390000, 0x38394000, 0x38398000, 0x3839C000, 0x383A0000, 0x383A4000, 0x383A8000, 0x383AC000, 0x383B0000, 0x383B4000, 0x383B8000, 0x383BC000, 0x383C0000, 0x383C4000, 0x383C8000, 0x383CC000, 0x383D0000, 0x383D4000, 0x383D8000, 0x383DC000, 0x383E0000, 0x383E4000, 0x383E8000, 0x383EC000, 0x383F0000, 0x383F4000, 0x383F8000, 0x383FC000, 0x38400000, 0x38404000, 0x38408000, 0x3840C000, 0x38410000, 0x38414000, 0x38418000, 0x3841C000, 0x38420000, 0x38424000, 0x38428000, 0x3842C000, 0x38430000, 0x38434000, 0x38438000, 0x3843C000, 0x38440000, 0x38444000, 0x38448000, 0x3844C000, 0x38450000, 0x38454000, 0x38458000, 0x3845C000, 0x38460000, 0x38464000, 0x38468000, 0x3846C000, 0x38470000, 0x38474000, 0x38478000, 0x3847C000, 0x38480000, 0x38484000, 0x38488000, 0x3848C000, 0x38490000, 0x38494000, 0x38498000, 0x3849C000, 0x384A0000, 0x384A4000, 0x384A8000, 0x384AC000, 0x384B0000, 0x384B4000, 0x384B8000, 0x384BC000, 0x384C0000, 0x384C4000, 0x384C8000, 0x384CC000, 0x384D0000, 0x384D4000, 0x384D8000, 0x384DC000, 0x384E0000, 0x384E4000, 0x384E8000, 0x384EC000, 0x384F0000, 0x384F4000, 0x384F8000, 0x384FC000, 0x38500000, 0x38504000, 0x38508000, 0x3850C000, 0x38510000, 0x38514000, 0x38518000, 0x3851C000, 0x38520000, 0x38524000, 0x38528000, 0x3852C000, 0x38530000, 0x38534000, 0x38538000, 0x3853C000, 0x38540000, 0x38544000, 0x38548000, 0x3854C000, 0x38550000, 0x38554000, 0x38558000, 0x3855C000, 0x38560000, 0x38564000, 0x38568000, 0x3856C000, 0x38570000, 0x38574000, 0x38578000, 0x3857C000, 0x38580000, 0x38584000, 0x38588000, 0x3858C000, 0x38590000, 0x38594000, 0x38598000, 0x3859C000, 0x385A0000, 0x385A4000, 0x385A8000, 0x385AC000, 0x385B0000, 0x385B4000, 0x385B8000, 0x385BC000, 0x385C0000, 0x385C4000, 0x385C8000, 0x385CC000, 0x385D0000, 0x385D4000, 0x385D8000, 0x385DC000, 0x385E0000, 0x385E4000, 0x385E8000, 0x385EC000, 0x385F0000, 0x385F4000, 0x385F8000, 0x385FC000, 0x38600000, 0x38604000, 0x38608000, 0x3860C000, 0x38610000, 0x38614000, 0x38618000, 0x3861C000, 0x38620000, 0x38624000, 0x38628000, 0x3862C000, 0x38630000, 0x38634000, 0x38638000, 0x3863C000, 0x38640000, 0x38644000, 0x38648000, 0x3864C000, 0x38650000, 0x38654000, 0x38658000, 0x3865C000, 0x38660000, 0x38664000, 0x38668000, 0x3866C000, 0x38670000, 0x38674000, 0x38678000, 0x3867C000, 0x38680000, 0x38684000, 0x38688000, 0x3868C000, 0x38690000, 0x38694000, 0x38698000, 0x3869C000, 0x386A0000, 0x386A4000, 0x386A8000, 0x386AC000, 0x386B0000, 0x386B4000, 0x386B8000, 0x386BC000, 0x386C0000, 0x386C4000, 0x386C8000, 0x386CC000, 0x386D0000, 0x386D4000, 0x386D8000, 0x386DC000, 0x386E0000, 0x386E4000, 0x386E8000, 0x386EC000, 0x386F0000, 0x386F4000, 0x386F8000, 0x386FC000, 0x38700000, 0x38704000, 0x38708000, 0x3870C000, 0x38710000, 0x38714000, 0x38718000, 0x3871C000, 0x38720000, 0x38724000, 0x38728000, 0x3872C000, 0x38730000, 0x38734000, 0x38738000, 0x3873C000, 0x38740000, 0x38744000, 0x38748000, 0x3874C000, 0x38750000, 0x38754000, 0x38758000, 0x3875C000, 0x38760000, 0x38764000, 0x38768000, 0x3876C000, 0x38770000, 0x38774000, 0x38778000, 0x3877C000, 0x38780000, 0x38784000, 0x38788000, 0x3878C000, 0x38790000, 0x38794000, 0x38798000, 0x3879C000, 0x387A0000, 0x387A4000, 0x387A8000, 0x387AC000, 0x387B0000, 0x387B4000, 0x387B8000, 0x387BC000, 0x387C0000, 0x387C4000, 0x387C8000, 0x387CC000, 0x387D0000, 0x387D4000, 0x387D8000, 0x387DC000, 0x387E0000, 0x387E4000, 0x387E8000, 0x387EC000, 0x387F0000, 0x387F4000, 0x387F8000, 0x387FC000, 0x38000000, 0x38002000, 0x38004000, 0x38006000, 0x38008000, 0x3800A000, 0x3800C000, 0x3800E000, 0x38010000, 0x38012000, 0x38014000, 0x38016000, 0x38018000, 0x3801A000, 0x3801C000, 0x3801E000, 0x38020000, 0x38022000, 0x38024000, 0x38026000, 0x38028000, 0x3802A000, 0x3802C000, 0x3802E000, 0x38030000, 0x38032000, 0x38034000, 0x38036000, 0x38038000, 0x3803A000, 0x3803C000, 0x3803E000, 0x38040000, 0x38042000, 0x38044000, 0x38046000, 0x38048000, 0x3804A000, 0x3804C000, 0x3804E000, 0x38050000, 0x38052000, 0x38054000, 0x38056000, 0x38058000, 0x3805A000, 0x3805C000, 0x3805E000, 0x38060000, 0x38062000, 0x38064000, 0x38066000, 0x38068000, 0x3806A000, 0x3806C000, 0x3806E000, 0x38070000, 0x38072000, 0x38074000, 0x38076000, 0x38078000, 0x3807A000, 0x3807C000, 0x3807E000, 0x38080000, 0x38082000, 0x38084000, 0x38086000, 0x38088000, 0x3808A000, 0x3808C000, 0x3808E000, 0x38090000, 0x38092000, 0x38094000, 0x38096000, 0x38098000, 0x3809A000, 0x3809C000, 0x3809E000, 0x380A0000, 0x380A2000, 0x380A4000, 0x380A6000, 0x380A8000, 0x380AA000, 0x380AC000, 0x380AE000, 0x380B0000, 0x380B2000, 0x380B4000, 0x380B6000, 0x380B8000, 0x380BA000, 0x380BC000, 0x380BE000, 0x380C0000, 0x380C2000, 0x380C4000, 0x380C6000, 0x380C8000, 0x380CA000, 0x380CC000, 0x380CE000, 0x380D0000, 0x380D2000, 0x380D4000, 0x380D6000, 0x380D8000, 0x380DA000, 0x380DC000, 0x380DE000, 0x380E0000, 0x380E2000, 0x380E4000, 0x380E6000, 0x380E8000, 0x380EA000, 0x380EC000, 0x380EE000, 0x380F0000, 0x380F2000, 0x380F4000, 0x380F6000, 0x380F8000, 0x380FA000, 0x380FC000, 0x380FE000, 0x38100000, 0x38102000, 0x38104000, 0x38106000, 0x38108000, 0x3810A000, 0x3810C000, 0x3810E000, 0x38110000, 0x38112000, 0x38114000, 0x38116000, 0x38118000, 0x3811A000, 0x3811C000, 0x3811E000, 0x38120000, 0x38122000, 0x38124000, 0x38126000, 0x38128000, 0x3812A000, 0x3812C000, 0x3812E000, 0x38130000, 0x38132000, 0x38134000, 0x38136000, 0x38138000, 0x3813A000, 0x3813C000, 0x3813E000, 0x38140000, 0x38142000, 0x38144000, 0x38146000, 0x38148000, 0x3814A000, 0x3814C000, 0x3814E000, 0x38150000, 0x38152000, 0x38154000, 0x38156000, 0x38158000, 0x3815A000, 0x3815C000, 0x3815E000, 0x38160000, 0x38162000, 0x38164000, 0x38166000, 0x38168000, 0x3816A000, 0x3816C000, 0x3816E000, 0x38170000, 0x38172000, 0x38174000, 0x38176000, 0x38178000, 0x3817A000, 0x3817C000, 0x3817E000, 0x38180000, 0x38182000, 0x38184000, 0x38186000, 0x38188000, 0x3818A000, 0x3818C000, 0x3818E000, 0x38190000, 0x38192000, 0x38194000, 0x38196000, 0x38198000, 0x3819A000, 0x3819C000, 0x3819E000, 0x381A0000, 0x381A2000, 0x381A4000, 0x381A6000, 0x381A8000, 0x381AA000, 0x381AC000, 0x381AE000, 0x381B0000, 0x381B2000, 0x381B4000, 0x381B6000, 0x381B8000, 0x381BA000, 0x381BC000, 0x381BE000, 0x381C0000, 0x381C2000, 0x381C4000, 0x381C6000, 0x381C8000, 0x381CA000, 0x381CC000, 0x381CE000, 0x381D0000, 0x381D2000, 0x381D4000, 0x381D6000, 0x381D8000, 0x381DA000, 0x381DC000, 0x381DE000, 0x381E0000, 0x381E2000, 0x381E4000, 0x381E6000, 0x381E8000, 0x381EA000, 0x381EC000, 0x381EE000, 0x381F0000, 0x381F2000, 0x381F4000, 0x381F6000, 0x381F8000, 0x381FA000, 0x381FC000, 0x381FE000, 0x38200000, 0x38202000, 0x38204000, 0x38206000, 0x38208000, 0x3820A000, 0x3820C000, 0x3820E000, 0x38210000, 0x38212000, 0x38214000, 0x38216000, 0x38218000, 0x3821A000, 0x3821C000, 0x3821E000, 0x38220000, 0x38222000, 0x38224000, 0x38226000, 0x38228000, 0x3822A000, 0x3822C000, 0x3822E000, 0x38230000, 0x38232000, 0x38234000, 0x38236000, 0x38238000, 0x3823A000, 0x3823C000, 0x3823E000, 0x38240000, 0x38242000, 0x38244000, 0x38246000, 0x38248000, 0x3824A000, 0x3824C000, 0x3824E000, 0x38250000, 0x38252000, 0x38254000, 0x38256000, 0x38258000, 0x3825A000, 0x3825C000, 0x3825E000, 0x38260000, 0x38262000, 0x38264000, 0x38266000, 0x38268000, 0x3826A000, 0x3826C000, 0x3826E000, 0x38270000, 0x38272000, 0x38274000, 0x38276000, 0x38278000, 0x3827A000, 0x3827C000, 0x3827E000, 0x38280000, 0x38282000, 0x38284000, 0x38286000, 0x38288000, 0x3828A000, 0x3828C000, 0x3828E000, 0x38290000, 0x38292000, 0x38294000, 0x38296000, 0x38298000, 0x3829A000, 0x3829C000, 0x3829E000, 0x382A0000, 0x382A2000, 0x382A4000, 0x382A6000, 0x382A8000, 0x382AA000, 0x382AC000, 0x382AE000, 0x382B0000, 0x382B2000, 0x382B4000, 0x382B6000, 0x382B8000, 0x382BA000, 0x382BC000, 0x382BE000, 0x382C0000, 0x382C2000, 0x382C4000, 0x382C6000, 0x382C8000, 0x382CA000, 0x382CC000, 0x382CE000, 0x382D0000, 0x382D2000, 0x382D4000, 0x382D6000, 0x382D8000, 0x382DA000, 0x382DC000, 0x382DE000, 0x382E0000, 0x382E2000, 0x382E4000, 0x382E6000, 0x382E8000, 0x382EA000, 0x382EC000, 0x382EE000, 0x382F0000, 0x382F2000, 0x382F4000, 0x382F6000, 0x382F8000, 0x382FA000, 0x382FC000, 0x382FE000, 0x38300000, 0x38302000, 0x38304000, 0x38306000, 0x38308000, 0x3830A000, 0x3830C000, 0x3830E000, 0x38310000, 0x38312000, 0x38314000, 0x38316000, 0x38318000, 0x3831A000, 0x3831C000, 0x3831E000, 0x38320000, 0x38322000, 0x38324000, 0x38326000, 0x38328000, 0x3832A000, 0x3832C000, 0x3832E000, 0x38330000, 0x38332000, 0x38334000, 0x38336000, 0x38338000, 0x3833A000, 0x3833C000, 0x3833E000, 0x38340000, 0x38342000, 0x38344000, 0x38346000, 0x38348000, 0x3834A000, 0x3834C000, 0x3834E000, 0x38350000, 0x38352000, 0x38354000, 0x38356000, 0x38358000, 0x3835A000, 0x3835C000, 0x3835E000, 0x38360000, 0x38362000, 0x38364000, 0x38366000, 0x38368000, 0x3836A000, 0x3836C000, 0x3836E000, 0x38370000, 0x38372000, 0x38374000, 0x38376000, 0x38378000, 0x3837A000, 0x3837C000, 0x3837E000, 0x38380000, 0x38382000, 0x38384000, 0x38386000, 0x38388000, 0x3838A000, 0x3838C000, 0x3838E000, 0x38390000, 0x38392000, 0x38394000, 0x38396000, 0x38398000, 0x3839A000, 0x3839C000, 0x3839E000, 0x383A0000, 0x383A2000, 0x383A4000, 0x383A6000, 0x383A8000, 0x383AA000, 0x383AC000, 0x383AE000, 0x383B0000, 0x383B2000, 0x383B4000, 0x383B6000, 0x383B8000, 0x383BA000, 0x383BC000, 0x383BE000, 0x383C0000, 0x383C2000, 0x383C4000, 0x383C6000, 0x383C8000, 0x383CA000, 0x383CC000, 0x383CE000, 0x383D0000, 0x383D2000, 0x383D4000, 0x383D6000, 0x383D8000, 0x383DA000, 0x383DC000, 0x383DE000, 0x383E0000, 0x383E2000, 0x383E4000, 0x383E6000, 0x383E8000, 0x383EA000, 0x383EC000, 0x383EE000, 0x383F0000, 0x383F2000, 0x383F4000, 0x383F6000, 0x383F8000, 0x383FA000, 0x383FC000, 0x383FE000, 0x38400000, 0x38402000, 0x38404000, 0x38406000, 0x38408000, 0x3840A000, 0x3840C000, 0x3840E000, 0x38410000, 0x38412000, 0x38414000, 0x38416000, 0x38418000, 0x3841A000, 0x3841C000, 0x3841E000, 0x38420000, 0x38422000, 0x38424000, 0x38426000, 0x38428000, 0x3842A000, 0x3842C000, 0x3842E000, 0x38430000, 0x38432000, 0x38434000, 0x38436000, 0x38438000, 0x3843A000, 0x3843C000, 0x3843E000, 0x38440000, 0x38442000, 0x38444000, 0x38446000, 0x38448000, 0x3844A000, 0x3844C000, 0x3844E000, 0x38450000, 0x38452000, 0x38454000, 0x38456000, 0x38458000, 0x3845A000, 0x3845C000, 0x3845E000, 0x38460000, 0x38462000, 0x38464000, 0x38466000, 0x38468000, 0x3846A000, 0x3846C000, 0x3846E000, 0x38470000, 0x38472000, 0x38474000, 0x38476000, 0x38478000, 0x3847A000, 0x3847C000, 0x3847E000, 0x38480000, 0x38482000, 0x38484000, 0x38486000, 0x38488000, 0x3848A000, 0x3848C000, 0x3848E000, 0x38490000, 0x38492000, 0x38494000, 0x38496000, 0x38498000, 0x3849A000, 0x3849C000, 0x3849E000, 0x384A0000, 0x384A2000, 0x384A4000, 0x384A6000, 0x384A8000, 0x384AA000, 0x384AC000, 0x384AE000, 0x384B0000, 0x384B2000, 0x384B4000, 0x384B6000, 0x384B8000, 0x384BA000, 0x384BC000, 0x384BE000, 0x384C0000, 0x384C2000, 0x384C4000, 0x384C6000, 0x384C8000, 0x384CA000, 0x384CC000, 0x384CE000, 0x384D0000, 0x384D2000, 0x384D4000, 0x384D6000, 0x384D8000, 0x384DA000, 0x384DC000, 0x384DE000, 0x384E0000, 0x384E2000, 0x384E4000, 0x384E6000, 0x384E8000, 0x384EA000, 0x384EC000, 0x384EE000, 0x384F0000, 0x384F2000, 0x384F4000, 0x384F6000, 0x384F8000, 0x384FA000, 0x384FC000, 0x384FE000, 0x38500000, 0x38502000, 0x38504000, 0x38506000, 0x38508000, 0x3850A000, 0x3850C000, 0x3850E000, 0x38510000, 0x38512000, 0x38514000, 0x38516000, 0x38518000, 0x3851A000, 0x3851C000, 0x3851E000, 0x38520000, 0x38522000, 0x38524000, 0x38526000, 0x38528000, 0x3852A000, 0x3852C000, 0x3852E000, 0x38530000, 0x38532000, 0x38534000, 0x38536000, 0x38538000, 0x3853A000, 0x3853C000, 0x3853E000, 0x38540000, 0x38542000, 0x38544000, 0x38546000, 0x38548000, 0x3854A000, 0x3854C000, 0x3854E000, 0x38550000, 0x38552000, 0x38554000, 0x38556000, 0x38558000, 0x3855A000, 0x3855C000, 0x3855E000, 0x38560000, 0x38562000, 0x38564000, 0x38566000, 0x38568000, 0x3856A000, 0x3856C000, 0x3856E000, 0x38570000, 0x38572000, 0x38574000, 0x38576000, 0x38578000, 0x3857A000, 0x3857C000, 0x3857E000, 0x38580000, 0x38582000, 0x38584000, 0x38586000, 0x38588000, 0x3858A000, 0x3858C000, 0x3858E000, 0x38590000, 0x38592000, 0x38594000, 0x38596000, 0x38598000, 0x3859A000, 0x3859C000, 0x3859E000, 0x385A0000, 0x385A2000, 0x385A4000, 0x385A6000, 0x385A8000, 0x385AA000, 0x385AC000, 0x385AE000, 0x385B0000, 0x385B2000, 0x385B4000, 0x385B6000, 0x385B8000, 0x385BA000, 0x385BC000, 0x385BE000, 0x385C0000, 0x385C2000, 0x385C4000, 0x385C6000, 0x385C8000, 0x385CA000, 0x385CC000, 0x385CE000, 0x385D0000, 0x385D2000, 0x385D4000, 0x385D6000, 0x385D8000, 0x385DA000, 0x385DC000, 0x385DE000, 0x385E0000, 0x385E2000, 0x385E4000, 0x385E6000, 0x385E8000, 0x385EA000, 0x385EC000, 0x385EE000, 0x385F0000, 0x385F2000, 0x385F4000, 0x385F6000, 0x385F8000, 0x385FA000, 0x385FC000, 0x385FE000, 0x38600000, 0x38602000, 0x38604000, 0x38606000, 0x38608000, 0x3860A000, 0x3860C000, 0x3860E000, 0x38610000, 0x38612000, 0x38614000, 0x38616000, 0x38618000, 0x3861A000, 0x3861C000, 0x3861E000, 0x38620000, 0x38622000, 0x38624000, 0x38626000, 0x38628000, 0x3862A000, 0x3862C000, 0x3862E000, 0x38630000, 0x38632000, 0x38634000, 0x38636000, 0x38638000, 0x3863A000, 0x3863C000, 0x3863E000, 0x38640000, 0x38642000, 0x38644000, 0x38646000, 0x38648000, 0x3864A000, 0x3864C000, 0x3864E000, 0x38650000, 0x38652000, 0x38654000, 0x38656000, 0x38658000, 0x3865A000, 0x3865C000, 0x3865E000, 0x38660000, 0x38662000, 0x38664000, 0x38666000, 0x38668000, 0x3866A000, 0x3866C000, 0x3866E000, 0x38670000, 0x38672000, 0x38674000, 0x38676000, 0x38678000, 0x3867A000, 0x3867C000, 0x3867E000, 0x38680000, 0x38682000, 0x38684000, 0x38686000, 0x38688000, 0x3868A000, 0x3868C000, 0x3868E000, 0x38690000, 0x38692000, 0x38694000, 0x38696000, 0x38698000, 0x3869A000, 0x3869C000, 0x3869E000, 0x386A0000, 0x386A2000, 0x386A4000, 0x386A6000, 0x386A8000, 0x386AA000, 0x386AC000, 0x386AE000, 0x386B0000, 0x386B2000, 0x386B4000, 0x386B6000, 0x386B8000, 0x386BA000, 0x386BC000, 0x386BE000, 0x386C0000, 0x386C2000, 0x386C4000, 0x386C6000, 0x386C8000, 0x386CA000, 0x386CC000, 0x386CE000, 0x386D0000, 0x386D2000, 0x386D4000, 0x386D6000, 0x386D8000, 0x386DA000, 0x386DC000, 0x386DE000, 0x386E0000, 0x386E2000, 0x386E4000, 0x386E6000, 0x386E8000, 0x386EA000, 0x386EC000, 0x386EE000, 0x386F0000, 0x386F2000, 0x386F4000, 0x386F6000, 0x386F8000, 0x386FA000, 0x386FC000, 0x386FE000, 0x38700000, 0x38702000, 0x38704000, 0x38706000, 0x38708000, 0x3870A000, 0x3870C000, 0x3870E000, 0x38710000, 0x38712000, 0x38714000, 0x38716000, 0x38718000, 0x3871A000, 0x3871C000, 0x3871E000, 0x38720000, 0x38722000, 0x38724000, 0x38726000, 0x38728000, 0x3872A000, 0x3872C000, 0x3872E000, 0x38730000, 0x38732000, 0x38734000, 0x38736000, 0x38738000, 0x3873A000, 0x3873C000, 0x3873E000, 0x38740000, 0x38742000, 0x38744000, 0x38746000, 0x38748000, 0x3874A000, 0x3874C000, 0x3874E000, 0x38750000, 0x38752000, 0x38754000, 0x38756000, 0x38758000, 0x3875A000, 0x3875C000, 0x3875E000, 0x38760000, 0x38762000, 0x38764000, 0x38766000, 0x38768000, 0x3876A000, 0x3876C000, 0x3876E000, 0x38770000, 0x38772000, 0x38774000, 0x38776000, 0x38778000, 0x3877A000, 0x3877C000, 0x3877E000, 0x38780000, 0x38782000, 0x38784000, 0x38786000, 0x38788000, 0x3878A000, 0x3878C000, 0x3878E000, 0x38790000, 0x38792000, 0x38794000, 0x38796000, 0x38798000, 0x3879A000, 0x3879C000, 0x3879E000, 0x387A0000, 0x387A2000, 0x387A4000, 0x387A6000, 0x387A8000, 0x387AA000, 0x387AC000, 0x387AE000, 0x387B0000, 0x387B2000, 0x387B4000, 0x387B6000, 0x387B8000, 0x387BA000, 0x387BC000, 0x387BE000, 0x387C0000, 0x387C2000, 0x387C4000, 0x387C6000, 0x387C8000, 0x387CA000, 0x387CC000, 0x387CE000, 0x387D0000, 0x387D2000, 0x387D4000, 0x387D6000, 0x387D8000, 0x387DA000, 0x387DC000, 0x387DE000, 0x387E0000, 0x387E2000, 0x387E4000, 0x387E6000, 0x387E8000, 0x387EA000, 0x387EC000, 0x387EE000, 0x387F0000, 0x387F2000, 0x387F4000, 0x387F6000, 0x387F8000, 0x387FA000, 0x387FC000, 0x387FE000 }; static const bits_t exponent_table[64] = { 0x00000000, 0x00800000, 0x01000000, 0x01800000, 0x02000000, 0x02800000, 0x03000000, 0x03800000, 0x04000000, 0x04800000, 0x05000000, 0x05800000, 0x06000000, 0x06800000, 0x07000000, 0x07800000, 0x08000000, 0x08800000, 0x09000000, 0x09800000, 0x0A000000, 0x0A800000, 0x0B000000, 0x0B800000, 0x0C000000, 0x0C800000, 0x0D000000, 0x0D800000, 0x0E000000, 0x0E800000, 0x0F000000, 0x47800000, 0x80000000, 0x80800000, 0x81000000, 0x81800000, 0x82000000, 0x82800000, 0x83000000, 0x83800000, 0x84000000, 0x84800000, 0x85000000, 0x85800000, 0x86000000, 0x86800000, 0x87000000, 0x87800000, 0x88000000, 0x88800000, 0x89000000, 0x89800000, 0x8A000000, 0x8A800000, 0x8B000000, 0x8B800000, 0x8C000000, 0x8C800000, 0x8D000000, 0x8D800000, 0x8E000000, 0x8E800000, 0x8F000000, 0xC7800000 }; static const unsigned short offset_table[64] = { 0, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 0, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024 }; bits_t fbits = mantissa_table[offset_table[value>>10]+(value&0x3FF)] + exponent_table[value>>10]; #endif float out; std::memcpy(&out, &fbits, sizeof(float)); return out; #endif } /// Convert half-precision to IEEE double-precision. /// \param value half-precision value to convert /// \return double-precision value inline double half2float_impl(unsigned int value, double, true_type) { #if HALF_ENABLE_F16C_INTRINSICS return _mm_cvtsd_f64(_mm_cvtps_pd(_mm_cvtph_ps(_mm_cvtsi32_si128(value)))); #else uint32 hi = static_cast(value&0x8000) << 16; unsigned int abs = value & 0x7FFF; if(abs) { hi |= 0x3F000000 << static_cast(abs>=0x7C00); for(; abs<0x400; abs<<=1,hi-=0x100000) ; hi += static_cast(abs) << 10; } bits_t dbits = static_cast>(hi) << 32; double out; std::memcpy(&out, &dbits, sizeof(double)); return out; #endif } /// Convert half-precision to non-IEEE floating-point. /// \tparam T type to convert to (builtin integer type) /// \param value half-precision value to convert /// \return floating-point value template T half2float_impl(unsigned int value, T, ...) { T out; unsigned int abs = value & 0x7FFF; if(abs > 0x7C00) out = (std::numeric_limits::has_signaling_NaN && !(abs&0x200)) ? std::numeric_limits::signaling_NaN() : std::numeric_limits::has_quiet_NaN ? std::numeric_limits::quiet_NaN() : T(); else if(abs == 0x7C00) out = std::numeric_limits::has_infinity ? std::numeric_limits::infinity() : std::numeric_limits::max(); else if(abs > 0x3FF) out = std::ldexp(static_cast((abs&0x3FF)|0x400), (abs>>10)-25); else out = std::ldexp(static_cast(abs), -24); return (value&0x8000) ? -out : out; } /// Convert half-precision to floating-point. /// \tparam T type to convert to (builtin integer type) /// \param value half-precision value to convert /// \return floating-point value template T half2float(unsigned int value) { return half2float_impl(value, T(), bool_type::is_iec559&&sizeof(bits_t)==sizeof(T)>()); } /// Convert half-precision floating-point to integer. /// \tparam R rounding mode to use /// \tparam E `true` for round to even, `false` for round away from zero /// \tparam I `true` to raise INEXACT exception (if inexact), `false` to never raise it /// \tparam T type to convert to (buitlin integer type with at least 16 bits precision, excluding any implicit sign bits) /// \param value half-precision value to convert /// \return rounded integer value /// \exception FE_INVALID if value is not representable in type \a T /// \exception FE_INEXACT if value had to be rounded and \a I is `true` template T half2int(unsigned int value) { unsigned int abs = value & 0x7FFF; if(abs >= 0x7C00) { raise(FE_INVALID); return (value&0x8000) ? std::numeric_limits::min() : std::numeric_limits::max(); } if(abs < 0x3800) { raise(FE_INEXACT, I); return (R==std::round_toward_infinity) ? T(~(value>>15)&(abs!=0)) : (R==std::round_toward_neg_infinity) ? -T(value>0x8000) : T(); } int exp = 25 - (abs>>10); unsigned int m = (value&0x3FF) | 0x400; int32 i = static_cast((exp<=0) ? (m<<-exp) : ((m+( (R==std::round_to_nearest) ? ((1<<(exp-1))-(~(m>>exp)&E)) : (R==std::round_toward_infinity) ? (((1<>15)-1)) : (R==std::round_toward_neg_infinity) ? (((1<>15)) : 0))>>exp)); if((!std::numeric_limits::is_signed && (value&0x8000)) || (std::numeric_limits::digits<16 && ((value&0x8000) ? (-i::min()) : (i>std::numeric_limits::max())))) raise(FE_INVALID); else if(I && exp > 0 && (m&((1<((value&0x8000) ? -i : i); } /// \} /// \name Mathematics /// \{ /// upper part of 64-bit multiplication. /// \tparam R rounding mode to use /// \param x first factor /// \param y second factor /// \return upper 32 bit of \a x * \a y template uint32 mulhi(uint32 x, uint32 y) { uint32 xy = (x>>16) * (y&0xFFFF), yx = (x&0xFFFF) * (y>>16), c = (xy&0xFFFF) + (yx&0xFFFF) + (((x&0xFFFF)*(y&0xFFFF))>>16); return (x>>16)*(y>>16) + (xy>>16) + (yx>>16) + (c>>16) + ((R==std::round_to_nearest) ? ((c>>15)&1) : (R==std::round_toward_infinity) ? ((c&0xFFFF)!=0) : 0); } /// 64-bit multiplication. /// \param x first factor /// \param y second factor /// \return upper 32 bit of \a x * \a y rounded to nearest inline uint32 multiply64(uint32 x, uint32 y) { return static_cast((static_cast(x)*static_cast(y)+0x80000000)>>32); } /// 64-bit division. /// \param x upper 32 bit of dividend /// \param y divisor /// \param s variable to store sticky bit for rounding /// \return (\a x << 32) / \a y inline uint32 divide64(uint32 x, uint32 y, int &s) { unsigned long long xx = static_cast(x) << 32; return s = (xx%y!=0), static_cast(xx/y); } /// Half precision positive modulus. /// \tparam Q `true` to compute full quotient, `false` else /// \tparam R `true` to compute signed remainder, `false` for positive remainder /// \param x first operand as positive finite half-precision value /// \param y second operand as positive finite half-precision value /// \param quo adress to store quotient at, `nullptr` if \a Q `false` /// \return modulus of \a x / \a y template unsigned int mod(unsigned int x, unsigned int y, int *quo = NULL) { unsigned int q = 0; if(x > y) { int absx = x, absy = y, expx = 0, expy = 0; for(; absx<0x400; absx<<=1,--expx) ; for(; absy<0x400; absy<<=1,--expy) ; expx += absx >> 10; expy += absy >> 10; int mx = (absx&0x3FF) | 0x400, my = (absy&0x3FF) | 0x400; for(int d=expx-expy; d; --d) { if(!Q && mx == my) return 0; if(mx >= my) { mx -= my; q += Q; } mx <<= 1; q <<= static_cast(Q); } if(!Q && mx == my) return 0; if(mx >= my) { mx -= my; ++q; } if(Q) { q &= (1<<(std::numeric_limits::digits-1)) - 1; if(!mx) return *quo = q, 0; } for(; mx<0x400; mx<<=1,--expy) ; x = (expy>0) ? ((expy<<10)|(mx&0x3FF)) : (mx>>(1-expy)); } if(R) { unsigned int a, b; if(y < 0x800) { a = (x<0x400) ? (x<<1) : (x+0x400); b = y; } else { a = x; b = y - 0x400; } if(a > b || (a == b && (q&1))) { int exp = (y>>10) + (y<=0x3FF), d = exp - (x>>10) - (x<=0x3FF); int m = (((y&0x3FF)|((y>0x3FF)<<10))<<1) - (((x&0x3FF)|((x>0x3FF)<<10))<<(1-d)); for(; m<0x800 && exp>1; m<<=1,--exp) ; x = 0x8000 + ((exp-1)<<10) + (m>>1); q += Q; } } if(Q) *quo = q; return x; } /// Fixed point square root. /// \tparam F number of fractional bits /// \param r radicand in Q1.F fixed point format /// \param exp exponent /// \return square root as Q1.F/2 template uint32 sqrt(uint32 &r, int &exp) { int i = exp & 1; r <<= i; exp = (exp-i) / 2; uint32 m = 0; for(uint32 bit=static_cast(1)<>=2) { if(r < m+bit) m >>= 1; else { r -= m + bit; m = (m>>1) + bit; } } return m; } /// Fixed point binary exponential. /// This uses the BKM algorithm in E-mode. /// \param m exponent in [0,1) as Q0.31 /// \param n number of iterations (at most 32) /// \return 2 ^ \a m as Q1.31 inline uint32 exp2(uint32 m, unsigned int n = 32) { static const uint32 logs[] = { 0x80000000, 0x4AE00D1D, 0x2934F098, 0x15C01A3A, 0x0B31FB7D, 0x05AEB4DD, 0x02DCF2D1, 0x016FE50B, 0x00B84E23, 0x005C3E10, 0x002E24CA, 0x001713D6, 0x000B8A47, 0x0005C53B, 0x0002E2A3, 0x00017153, 0x0000B8AA, 0x00005C55, 0x00002E2B, 0x00001715, 0x00000B8B, 0x000005C5, 0x000002E3, 0x00000171, 0x000000B9, 0x0000005C, 0x0000002E, 0x00000017, 0x0000000C, 0x00000006, 0x00000003, 0x00000001 }; if(!m) return 0x80000000; uint32 mx = 0x80000000, my = 0; for(unsigned int i=1; i> i; } } return mx; } /// Fixed point binary logarithm. /// This uses the BKM algorithm in L-mode. /// \param m mantissa in [1,2) as Q1.30 /// \param n number of iterations (at most 32) /// \return log2(\a m) as Q0.31 inline uint32 log2(uint32 m, unsigned int n = 32) { static const uint32 logs[] = { 0x80000000, 0x4AE00D1D, 0x2934F098, 0x15C01A3A, 0x0B31FB7D, 0x05AEB4DD, 0x02DCF2D1, 0x016FE50B, 0x00B84E23, 0x005C3E10, 0x002E24CA, 0x001713D6, 0x000B8A47, 0x0005C53B, 0x0002E2A3, 0x00017153, 0x0000B8AA, 0x00005C55, 0x00002E2B, 0x00001715, 0x00000B8B, 0x000005C5, 0x000002E3, 0x00000171, 0x000000B9, 0x0000005C, 0x0000002E, 0x00000017, 0x0000000C, 0x00000006, 0x00000003, 0x00000001 }; if(m == 0x40000000) return 0; uint32 mx = 0x40000000, my = 0; for(unsigned int i=1; i>i); if(mz <= m) { mx = mz; my += logs[i]; } } return my; } /// Fixed point sine and cosine. /// This uses the CORDIC algorithm in rotation mode. /// \param mz angle in [-pi/2,pi/2] as Q1.30 /// \param n number of iterations (at most 31) /// \return sine and cosine of \a mz as Q1.30 inline std::pair sincos(uint32 mz, unsigned int n = 31) { static const uint32 angles[] = { 0x3243F6A9, 0x1DAC6705, 0x0FADBAFD, 0x07F56EA7, 0x03FEAB77, 0x01FFD55C, 0x00FFFAAB, 0x007FFF55, 0x003FFFEB, 0x001FFFFD, 0x00100000, 0x00080000, 0x00040000, 0x00020000, 0x00010000, 0x00008000, 0x00004000, 0x00002000, 0x00001000, 0x00000800, 0x00000400, 0x00000200, 0x00000100, 0x00000080, 0x00000040, 0x00000020, 0x00000010, 0x00000008, 0x00000004, 0x00000002, 0x00000001 }; uint32 mx = 0x26DD3B6A, my = 0; for(unsigned int i=0; i0x3FF)<<10); int exp = (abs>>10) + (abs<=0x3FF) - 15; if(abs < 0x3A48) return k = 0, m << (exp+20); unsigned long long y = m * 0xA2F9836E4E442, mask = (1ULL<<(62-exp)) - 1, yi = (y+(mask>>1)) & ~mask, f = y - yi; uint32 sign = -static_cast(f>>63); k = static_cast(yi>>(62-exp)); return (multiply64(static_cast((sign ? -f : f)>>(31-exp)), 0xC90FDAA2)^sign) - sign; } /// Get arguments for atan2 function. /// \param abs half-precision floating-point value /// \return \a abs and sqrt(1 - \a abs^2) as Q0.30 inline std::pair atan2_args(unsigned int abs) { int exp = -15; for(; abs<0x400; abs<<=1,--exp) ; exp += abs >> 10; uint32 my = ((abs&0x3FF)|0x400) << 5, r = my * my; int rexp = 2 * exp; r = 0x40000000 - ((rexp>-31) ? ((r>>-rexp)|((r&((static_cast(1)<<-rexp)-1))!=0)) : 1); for(rexp=0; r<0x40000000; r<<=1,--rexp) ; uint32 mx = sqrt<30>(r, rexp); int d = exp - rexp; if(d < 0) return std::make_pair((d<-14) ? ((my>>(-d-14))+((my>>(-d-15))&1)) : (my<<(14+d)), (mx<<14)+(r<<13)/mx); if(d > 0) return std::make_pair(my<<14, (d>14) ? ((mx>>(d-14))+((mx>>(d-15))&1)) : ((d==14) ? mx : ((mx<<(14-d))+(r<<(13-d))/mx))); return std::make_pair(my<<13, (mx<<13)+(r<<12)/mx); } /// Get exponentials for hyperbolic computation /// \param abs half-precision floating-point value /// \param exp variable to take unbiased exponent of larger result /// \param n number of BKM iterations (at most 32) /// \return exp(abs) and exp(-\a abs) as Q1.31 with same exponent inline std::pair hyperbolic_args(unsigned int abs, int &exp, unsigned int n = 32) { uint32 mx = detail::multiply64(static_cast((abs&0x3FF)+((abs>0x3FF)<<10))<<21, 0xB8AA3B29), my; int e = (abs>>10) + (abs<=0x3FF); if(e < 14) { exp = 0; mx >>= 14 - e; } else { exp = mx >> (45-e); mx = (mx<<(e-14)) & 0x7FFFFFFF; } mx = exp2(mx, n); int d = exp << 1, s; if(mx > 0x80000000) { my = divide64(0x80000000, mx, s); my |= s; ++d; } else my = mx; return std::make_pair(mx, (d<31) ? ((my>>d)|((my&((static_cast(1)< unsigned int exp2_post(uint32 m, int exp, bool esign, unsigned int sign = 0) { int s = 0; if(esign) { if(m > 0x80000000) { m = divide64(0x80000000, m, s); ++exp; } if(exp > 25) return underflow(sign); else if(exp == 25) return rounded(sign, 1, (m&0x7FFFFFFF)!=0); exp = -exp; } else if(exp > 15) return overflow(sign); return fixed2half(m, exp+14, sign, s); } /// Postprocessing for binary logarithm. /// \tparam R rounding mode to use /// \tparam L logarithm for base transformation as Q1.31 /// \param m fractional part of logarithm as Q0.31 /// \param ilog signed integer part of logarithm /// \param exp biased exponent of result /// \param sign sign bit of result /// \return value base-transformed and converted to half-precision /// \exception FE_OVERFLOW on overflows /// \exception FE_UNDERFLOW on underflows /// \exception FE_INEXACT if no other exception occurred template unsigned int log2_post(uint32 m, int ilog, int exp, unsigned int sign = 0) { uint32 msign = sign_mask(ilog); m = (((static_cast(ilog)<<27)+(m>>4))^msign) - msign; if(!m) return 0; for(; m<0x80000000; m<<=1,--exp) ; int i = m >= L, s; exp += i; m >>= 1 + i; sign ^= msign & 0x8000; if(exp < -11) return underflow(sign); m = divide64(m, L, s); return fixed2half(m, exp, sign, 1); } /// Hypotenuse square root and postprocessing. /// \tparam R rounding mode to use /// \param r mantissa as Q2.30 /// \param exp unbiased exponent /// \return square root converted to half-precision /// \exception FE_OVERFLOW on overflows /// \exception FE_UNDERFLOW on underflows /// \exception FE_INEXACT if value had to be rounded template unsigned int hypot_post(uint32 r, int exp) { int i = r >> 31; if((exp+=i) > 46) return overflow(); if(exp < -34) return underflow(); r = (r>>i) | (r&i); uint32 m = sqrt<30>(r, exp+=15); return fixed2half(m, exp-1, 0, r!=0); } /// Division and postprocessing for tangents. /// \tparam R rounding mode to use /// \param my dividend as Q1.31 /// \param mx divisor as Q1.31 /// \param exp biased exponent of result /// \param sign sign bit of result /// \return quotient converted to half-precision /// \exception FE_OVERFLOW on overflows /// \exception FE_UNDERFLOW on underflows /// \exception FE_INEXACT if no other exception occurred template unsigned int tangent_post(uint32 my, uint32 mx, int exp, unsigned int sign = 0) { int i = my >= mx, s; exp += i; if(exp > 29) return overflow(sign); if(exp < -11) return underflow(sign); uint32 m = divide64(my>>(i+1), mx, s); return fixed2half(m, exp, sign, s); } /// Area function and postprocessing. /// This computes the value directly in Q2.30 using the representation `asinh|acosh(x) = log(x+sqrt(x^2+|-1))`. /// \tparam R rounding mode to use /// \tparam S `true` for asinh, `false` for acosh /// \param arg half-precision argument /// \return asinh|acosh(\a arg) converted to half-precision /// \exception FE_OVERFLOW on overflows /// \exception FE_UNDERFLOW on underflows /// \exception FE_INEXACT if no other exception occurred template unsigned int area(unsigned int arg) { int abs = arg & 0x7FFF, expx = (abs>>10) + (abs<=0x3FF) - 15, expy = -15, ilog, i; uint32 mx = static_cast((abs&0x3FF)|((abs>0x3FF)<<10)) << 20, my, r; for(; abs<0x400; abs<<=1,--expy) ; expy += abs >> 10; r = ((abs&0x3FF)|0x400) << 5; r *= r; i = r >> 31; expy = 2*expy + i; r >>= i; if(S) { if(expy < 0) { r = 0x40000000 + ((expy>-30) ? ((r>>-expy)|((r&((static_cast(1)<<-expy)-1))!=0)) : 1); expy = 0; } else { r += 0x40000000 >> expy; i = r >> 31; r = (r>>i) | (r&i); expy += i; } } else { r -= 0x40000000 >> expy; for(; r<0x40000000; r<<=1,--expy) ; } my = sqrt<30>(r, expy); my = (my<<15) + (r<<14)/my; if(S) { mx >>= expy - expx; ilog = expy; } else { my >>= expx - expy; ilog = expx; } my += mx; i = my >> 31; static const int G = S && (R==std::round_to_nearest); return log2_post(log2(my>>i, 26+S+G)+(G<<3), ilog+i, 17, arg&(static_cast(S)<<15)); } /// Class for 1.31 unsigned floating-point computation struct f31 { /// Constructor. /// \param mant mantissa as 1.31 /// \param e exponent constexpr f31(uint32 mant, int e) : m(mant), exp(e) {} /// Constructor. /// \param abs unsigned half-precision value f31(unsigned int abs) : exp(-15) { for(; abs<0x400; abs<<=1,--exp) ; m = static_cast((abs&0x3FF)|0x400) << 21; exp += (abs>>10); } /// Addition operator. /// \param a first operand /// \param b second operand /// \return \a a + \a b friend f31 operator+(f31 a, f31 b) { if(b.exp > a.exp) std::swap(a, b); int d = a.exp - b.exp; uint32 m = a.m + ((d<32) ? (b.m>>d) : 0); int i = (m&0xFFFFFFFF) < a.m; return f31(((m+i)>>i)|0x80000000, a.exp+i); } /// Subtraction operator. /// \param a first operand /// \param b second operand /// \return \a a - \a b friend f31 operator-(f31 a, f31 b) { int d = a.exp - b.exp, exp = a.exp; uint32 m = a.m - ((d<32) ? (b.m>>d) : 0); if(!m) return f31(0, -32); for(; m<0x80000000; m<<=1,--exp) ; return f31(m, exp); } /// Multiplication operator. /// \param a first operand /// \param b second operand /// \return \a a * \a b friend f31 operator*(f31 a, f31 b) { uint32 m = multiply64(a.m, b.m); int i = m >> 31; return f31(m<<(1-i), a.exp + b.exp + i); } /// Division operator. /// \param a first operand /// \param b second operand /// \return \a a / \a b friend f31 operator/(f31 a, f31 b) { int i = a.m >= b.m, s; uint32 m = divide64((a.m+i)>>i, b.m, s); return f31(m, a.exp - b.exp + i - 1); } uint32 m; ///< mantissa as 1.31. int exp; ///< exponent. }; /// Error function and postprocessing. /// This computes the value directly in Q1.31 using the approximations given /// [here](https://en.wikipedia.org/wiki/Error_function#Approximation_with_elementary_functions). /// \tparam R rounding mode to use /// \tparam C `true` for comlementary error function, `false` else /// \param arg half-precision function argument /// \return approximated value of error function in half-precision /// \exception FE_OVERFLOW on overflows /// \exception FE_UNDERFLOW on underflows /// \exception FE_INEXACT if no other exception occurred template unsigned int erf(unsigned int arg) { unsigned int abs = arg & 0x7FFF, sign = arg & 0x8000; f31 x(abs), x2 = x * x * f31(0xB8AA3B29, 0), t = f31(0x80000000, 0) / (f31(0x80000000, 0)+f31(0xA7BA054A, -2)*x), t2 = t * t; f31 e = ((f31(0x87DC2213, 0)*t2+f31(0xB5F0E2AE, 0))*t2+f31(0x82790637, -2)-(f31(0xBA00E2B8, 0)*t2+f31(0x91A98E62, -2))*t) * t / ((x2.exp<0) ? f31(exp2((x2.exp>-32) ? (x2.m>>-x2.exp) : 0, 30), 0) : f31(exp2((x2.m<>(31-x2.exp))); return (!C || sign) ? fixed2half(0x80000000-(e.m>>(C-e.exp)), 14+C, sign&(C-1U)) : (e.exp<-25) ? underflow() : fixed2half(e.m>>1, e.exp+14, 0, e.m&1); } /// Gamma function and postprocessing. /// This approximates the value of either the gamma function or its logarithm directly in Q1.31. /// \tparam R rounding mode to use /// \tparam L `true` for lograithm of gamma function, `false` for gamma function /// \param arg half-precision floating-point value /// \return lgamma/tgamma(\a arg) in half-precision /// \exception FE_OVERFLOW on overflows /// \exception FE_UNDERFLOW on underflows /// \exception FE_INEXACT if \a arg is not a positive integer template unsigned int gamma(unsigned int arg) { /* static const double p[] ={ 2.50662827563479526904, 225.525584619175212544, -268.295973841304927459, 80.9030806934622512966, -5.00757863970517583837, 0.0114684895434781459556 }; double t = arg + 4.65, s = p[0]; for(unsigned int i=0; i<5; ++i) s += p[i+1] / (arg+i); return std::log(s) + (arg-0.5)*std::log(t) - t; */ static const f31 pi(0xC90FDAA2, 1), lbe(0xB8AA3B29, 0); unsigned int abs = arg & 0x7FFF, sign = arg & 0x8000; bool bsign = sign != 0; f31 z(abs), x = sign ? (z+f31(0x80000000, 0)) : z, t = x + f31(0x94CCCCCD, 2), s = f31(0xA06C9901, 1) + f31(0xBBE654E2, -7)/(x+f31(0x80000000, 2)) + f31(0xA1CE6098, 6)/(x+f31(0x80000000, 1)) + f31(0xE1868CB7, 7)/x - f31(0x8625E279, 8)/(x+f31(0x80000000, 0)) - f31(0xA03E158F, 2)/(x+f31(0xC0000000, 1)); int i = (s.exp>=2) + (s.exp>=4) + (s.exp>=8) + (s.exp>=16); s = f31((static_cast(s.exp)<<(31-i))+(log2(s.m>>1, 28)>>i), i) / lbe; if(x.exp != -1 || x.m != 0x80000000) { i = (t.exp>=2) + (t.exp>=4) + (t.exp>=8); f31 l = f31((static_cast(t.exp)<<(31-i))+(log2(t.m>>1, 30)>>i), i) / lbe; s = (x.exp<-1) ? (s-(f31(0x80000000, -1)-x)*l) : (s+(x-f31(0x80000000, -1))*l); } s = x.exp ? (s-t) : (t-s); if(bsign) { if(z.exp >= 0) { sign &= (L|((z.m>>(31-z.exp))&1)) - 1; for(z=f31((z.m<<(1+z.exp))&0xFFFFFFFF, -1); z.m<0x80000000; z.m<<=1,--z.exp) ; } if(z.exp == -1) z = f31(0x80000000, 0) - z; if(z.exp < -1) { z = z * pi; z.m = sincos(z.m>>(1-z.exp), 30).first; for(z.exp=1; z.m<0x80000000; z.m<<=1,--z.exp) ; } else z = f31(0x80000000, 0); } if(L) { if(bsign) { f31 l(0x92868247, 0); if(z.exp < 0) { uint32 m = log2((z.m+1)>>1, 27); z = f31(-((static_cast(z.exp)<<26)+(m>>5)), 5); for(; z.m<0x80000000; z.m<<=1,--z.exp) ; l = l + z / lbe; } sign = static_cast(x.exp&&(l.exp(x.exp==0) << 15; if(s.exp < -24) return underflow(sign); if(s.exp > 15) return overflow(sign); } } else { s = s * lbe; uint32 m; if(s.exp < 0) { m = s.m >> -s.exp; s.exp = 0; } else { m = (s.m<>(31-s.exp)); } s.m = exp2(m, 27); if(!x.exp) s = f31(0x80000000, 0) / s; if(bsign) { if(z.exp < 0) s = s * z; s = pi / s; if(s.exp < -24) return underflow(sign); } else if(z.exp > 0 && !(z.m&((1<<(31-z.exp))-1))) return ((s.exp+14)<<10) + (s.m>>21); if(s.exp > 15) return overflow(sign); } return fixed2half(s.m, s.exp+14, sign); } /// \} template struct half_caster; } /// Half-precision floating-point type. /// This class implements an IEEE-conformant half-precision floating-point type with the usual arithmetic /// operators and conversions. It is implicitly convertible to single-precision floating-point, which makes artihmetic /// expressions and functions with mixed-type operands to be of the most precise operand type. /// /// According to the C++98/03 definition, the half type is not a POD type. But according to C++11's less strict and /// extended definitions it is both a standard layout type and a trivially copyable type (even if not a POD type), which /// means it can be standard-conformantly copied using raw binary copies. But in this context some more words about the /// actual size of the type. Although the half is representing an IEEE 16-bit type, it does not neccessarily have to be of /// exactly 16-bits size. But on any reasonable implementation the actual binary representation of this type will most /// probably not ivolve any additional "magic" or padding beyond the simple binary representation of the underlying 16-bit /// IEEE number, even if not strictly guaranteed by the standard. But even then it only has an actual size of 16 bits if /// your C++ implementation supports an unsigned integer type of exactly 16 bits width. But this should be the case on /// nearly any reasonable platform. /// /// So if your C++ implementation is not totally exotic or imposes special alignment requirements, it is a reasonable /// assumption that the data of a half is just comprised of the 2 bytes of the underlying IEEE representation. class half { public: /// \name Construction and assignment /// \{ /// Default constructor. /// This initializes the half to 0. Although this does not match the builtin types' default-initialization semantics /// and may be less efficient than no initialization, it is needed to provide proper value-initialization semantics. constexpr half() noexcept : data_() {} /// Conversion constructor. /// \param rhs float to convert /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding //explicit half(float rhs) : data_(static_cast(detail::float2half(rhs))) {} /// Conversion constructor. /// \param rhs float to convert /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding template half(T rhs) : data_(static_cast(detail::float2half(static_cast(rhs)))) {} /// Conversion to single-precision. /// \return single precision value representing expression value operator float() const { return detail::half2float(data_); } /// Assignment operator. /// \param rhs single-precision value to copy from /// \return reference to this half /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding half& operator=(const float &rhs) { data_ = static_cast(detail::float2half(rhs)); return *this; } template half& operator=(const T &rhs) { return *this = static_cast(rhs); } /// \} /// \name Arithmetic updates /// \{ /// Arithmetic assignment. /// \tparam T type of concrete half expression /// \param rhs half expression to add /// \return reference to this half /// \exception FE_... according to operator+(half,half) half& operator+=(half rhs) { return *this = *this + rhs; } /// Arithmetic assignment. /// \tparam T type of concrete half expression /// \param rhs half expression to subtract /// \return reference to this half /// \exception FE_... according to operator-(half,half) half& operator-=(half rhs) { return *this = *this - rhs; } /// Arithmetic assignment. /// \tparam T type of concrete half expression /// \param rhs half expression to multiply with /// \return reference to this half /// \exception FE_... according to operator*(half,half) half& operator*=(half rhs) { return *this = *this * rhs; } /// Arithmetic assignment. /// \tparam T type of concrete half expression /// \param rhs half expression to divide by /// \return reference to this half /// \exception FE_... according to operator/(half,half) half& operator/=(half rhs) { return *this = *this / rhs; } /* /// Arithmetic assignment. /// \param rhs single-precision value to add /// \return reference to this half /// \exception FE_... according to operator=() half& operator+=(float rhs) { return *this = *this + rhs; } /// Arithmetic assignment. /// \param rhs single-precision value to subtract /// \return reference to this half /// \exception FE_... according to operator=() half& operator-=(float rhs) { return *this = *this - rhs; } /// Arithmetic assignment. /// \param rhs single-precision value to multiply with /// \return reference to this half /// \exception FE_... according to operator=() half& operator*=(float rhs) { return *this = *this * rhs; } /// Arithmetic assignment. /// \param rhs single-precision value to divide by /// \return reference to this half /// \exception FE_... according to operator=() half& operator/=(float rhs) { return *this = *this / rhs; } */ /// \} /// \name Increment and decrement /// \{ /// Prefix increment. /// \return incremented half value /// \exception FE_... according to operator+(half,half) half& operator++() { return *this = *this + half(detail::binary, 0x3C00); } /// Prefix decrement. /// \return decremented half value /// \exception FE_... according to operator-(half,half) half& operator--() { return *this = *this + half(detail::binary, 0xBC00); } /// Postfix increment. /// \return non-incremented half value /// \exception FE_... according to operator+(half,half) half operator++(int) { half out(*this); ++*this; return out; } /// Postfix decrement. /// \return non-decremented half value /// \exception FE_... according to operator-(half,half) half operator--(int) { half out(*this); --*this; return out; } /// \} detail::uint16 get_data()const{ return data_; } private: /// Rounding mode to use static const std::float_round_style round_style = (std::float_round_style)(HALF_ROUND_STYLE); /// Constructor. /// \param bits binary representation to set half to constexpr half(detail::binary_t, unsigned int bits) noexcept : data_(static_cast(bits)) {} /// Internal binary representation detail::uint16 data_; friend constexpr_NOERR bool operator==(half, half); template friend constexpr_NOERR bool operator==(half, T); template friend constexpr_NOERR bool operator==(T, half); friend constexpr_NOERR bool operator!=(half, half); template friend constexpr_NOERR bool operator!=(half, T); template friend constexpr_NOERR bool operator!=(T, half); friend constexpr_NOERR bool operator<(half, half); template friend constexpr_NOERR bool operator<(half, T); template friend constexpr_NOERR bool operator<(T, half); friend constexpr_NOERR bool operator>(half, half); template friend constexpr_NOERR bool operator>(half, T); template friend constexpr_NOERR bool operator>(T, half); friend constexpr_NOERR bool operator<=(half, half); template friend constexpr_NOERR bool operator<=(half, T); template friend constexpr_NOERR bool operator<=(T, half); friend constexpr_NOERR bool operator>=(half, half); template friend constexpr_NOERR bool operator>=(half, T); template friend constexpr_NOERR bool operator>=(T, half); friend constexpr half operator+(half); friend constexpr half operator-(half); friend half operator+(half, half); template friend half operator+(half, T); template friend half operator+(T, half); friend half operator-(half, half); template friend half operator-(half, T); template friend half operator-(T, half); friend half operator*(half, half); template friend half operator*(half, T); template friend half operator*(T, half); friend half operator/(half, half); template friend half operator/(half, T); template friend half operator/(T, half); template friend std::basic_ostream& operator<<(std::basic_ostream&, half); template friend std::basic_istream& operator>>(std::basic_istream&, half&); friend constexpr half fabs(half); friend half fmod(half, half); friend half remainder(half, half); friend half remquo(half, half, int*); friend half fma(half, half, half); friend constexpr_NOERR half fmax(half, half); friend constexpr_NOERR half fmin(half, half); friend half fdim(half, half); friend half nanh(const char*); friend half exp(half); friend half exp2(half); friend half expm1(half); friend half log(half); friend half log10(half); friend half log2(half); friend half log1p(half); friend half sqrt(half); friend half cbrt(half); friend half hypot(half, half); friend half hypot(half, half, half); friend half pow(half, half); friend void sincos(half, half*, half*); friend half sin(half); friend half cos(half); friend half tan(half); friend half asin(half); friend half acos(half); friend half atan(half); friend half atan2(half, half); friend half sinh(half); friend half cosh(half); friend half tanh(half); friend half asinh(half); friend half acosh(half); friend half atanh(half); friend half erf(half); friend half erfc(half); friend half lgamma(half); friend half tgamma(half); friend half ceil(half); friend half floor(half); friend half trunc(half); friend half round(half); friend long lround(half); friend half rint(half); friend long lrint(half); friend half nearbyint(half); friend long long llround(half); friend long long llrint(half); friend half frexp(half, int*); friend half scalbln(half, long); friend half modf(half, half*); friend int ilogb(half); friend half logb(half); friend half nextafter(half, half); friend half nexttoward(half, long double); friend constexpr half copysign(half, half); friend constexpr int fpclassify(half); friend constexpr bool isfinite(half); friend constexpr bool isinf(half); friend constexpr bool isnan(half); friend constexpr bool isnormal(half); friend constexpr bool signbit(half); friend constexpr bool isgreater(half, half); friend constexpr bool isgreaterequal(half, half); friend constexpr bool isless(half, half); friend constexpr bool islessequal(half, half); friend constexpr bool islessgreater(half, half); template friend struct detail::half_caster; friend class std::numeric_limits; friend struct std::hash; friend half literal::operator "" _h(long double); }; namespace literal { /// Half literal. /// While this returns a properly rounded half-precision value, half literals can unfortunately not be constant /// expressions due to rather involved conversions. So don't expect this to be a literal literal without involving /// conversion operations at runtime. It is a convenience feature, not a performance optimization. /// \param value literal value /// \return half with of given value (possibly rounded) /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding inline half operator "" _h(long double value) { return half(detail::binary, detail::float2half(value)); } } namespace detail { /// Helper class for half casts. /// This class template has to be specialized for all valid cast arguments to define an appropriate static /// `cast` member function and a corresponding `type` member denoting its return type. /// \tparam T destination type /// \tparam U source type /// \tparam R rounding mode to use template struct half_caster {}; template struct half_caster { static_assert(std::is_arithmetic::value, "half_cast from non-arithmetic type unsupported"); static half cast(U arg) { return cast_impl(arg, is_float()); }; private: static half cast_impl(U arg, true_type) { return half(binary, float2half(arg)); } static half cast_impl(U arg, false_type) { return half(binary, int2half(arg)); } }; template struct half_caster { static_assert(std::is_arithmetic::value, "half_cast to non-arithmetic type unsupported"); static T cast(half arg) { return cast_impl(arg, is_float()); } private: static T cast_impl(half arg, true_type) { return half2float(arg.data_); } static T cast_impl(half arg, false_type) { return half2int(arg.data_); } }; template struct half_caster { static half cast(half arg) { return arg; } }; } } /// Extensions to the C++ standard library. namespace std { /// Numeric limits for half-precision floats. /// **See also:** Documentation for [std::numeric_limits](https://en.cppreference.com/w/cpp/types/numeric_limits) template<> class numeric_limits { public: /// Is template specialization. static constexpr bool is_specialized = true; /// Supports signed values. static constexpr bool is_signed = true; /// Is not an integer type. static constexpr bool is_integer = false; /// Is not exact. static constexpr bool is_exact = false; /// Doesn't provide modulo arithmetic. static constexpr bool is_modulo = false; /// Has a finite set of values. static constexpr bool is_bounded = true; /// IEEE conformant. static constexpr bool is_iec559 = true; /// Supports infinity. static constexpr bool has_infinity = true; /// Supports quiet NaNs. static constexpr bool has_quiet_NaN = true; /// Supports signaling NaNs. static constexpr bool has_signaling_NaN = true; /// Supports subnormal values. static constexpr float_denorm_style has_denorm = denorm_present; /// Supports no denormalization detection. static constexpr bool has_denorm_loss = false; #if HALF_ERRHANDLING_THROWS static constexpr bool traps = true; #else /// Traps only if [HALF_ERRHANDLING_THROW_...](\ref HALF_ERRHANDLING_THROW_INVALID) is acitvated. static constexpr bool traps = false; #endif /// Does not support no pre-rounding underflow detection. static constexpr bool tinyness_before = false; /// Rounding mode. static constexpr float_round_style round_style = half_float::half::round_style; /// Significant digits. static constexpr int digits = 11; /// Significant decimal digits. static constexpr int digits10 = 3; /// Required decimal digits to represent all possible values. static constexpr int max_digits10 = 5; /// Number base. static constexpr int radix = 2; /// One more than smallest exponent. static constexpr int min_exponent = -13; /// Smallest normalized representable power of 10. static constexpr int min_exponent10 = -4; /// One more than largest exponent static constexpr int max_exponent = 16; /// Largest finitely representable power of 10. static constexpr int max_exponent10 = 4; /// Smallest positive normal value. static constexpr half_float::half min() noexcept { return half_float::half(half_float::detail::binary, 0x0400); } /// Smallest finite value. static constexpr half_float::half lowest() noexcept { return half_float::half(half_float::detail::binary, 0xFBFF); } /// Largest finite value. static constexpr half_float::half max() noexcept { return half_float::half(half_float::detail::binary, 0x7BFF); } /// Difference between 1 and next representable value. static constexpr half_float::half epsilon() noexcept { return half_float::half(half_float::detail::binary, 0x1400); } /// Maximum rounding error in ULP (units in the last place). static constexpr half_float::half round_error() noexcept { return half_float::half(half_float::detail::binary, (round_style==std::round_to_nearest) ? 0x3800 : 0x3C00); } /// Positive infinity. static constexpr half_float::half infinity() noexcept { return half_float::half(half_float::detail::binary, 0x7C00); } /// Quiet NaN. static constexpr half_float::half quiet_NaN() noexcept { return half_float::half(half_float::detail::binary, 0x7FFF); } /// Signaling NaN. static constexpr half_float::half signaling_NaN() noexcept { return half_float::half(half_float::detail::binary, 0x7DFF); } /// Smallest positive subnormal value. static constexpr half_float::half denorm_min() noexcept { return half_float::half(half_float::detail::binary, 0x0001); } }; /// Hash function for half-precision floats. /// **See also:** Documentation for [std::hash](https://en.cppreference.com/w/cpp/utility/hash) template<> struct hash { /// Type of function argument. typedef half_float::half argument_type; /// Function return type. typedef size_t result_type; /// Compute hash function. /// \param arg half to hash /// \return hash value result_type operator()(argument_type arg) const { return hash()(arg.data_&-static_cast(arg.data_!=0x8000)); } }; } namespace half_float { /// \anchor compop /// \name Comparison operators /// \{ /// Comparison for equality. /// \param x first operand /// \param y second operand /// \retval true if operands equal /// \retval false else /// \exception FE_INVALID if \a x or \a y is NaN inline constexpr_NOERR bool operator==(half x, half y) { return !detail::compsignal(x.data_, y.data_) && (x.data_==y.data_ || !((x.data_|y.data_)&0x7FFF)); } template inline constexpr_NOERR bool operator==(half x, T y) { return x == static_cast(y); } template inline constexpr_NOERR bool operator==(T x, half y) { return static_cast(x) == y; } /// Comparison for inequality. /// \param x first operand /// \param y second operand /// \retval true if operands not equal /// \retval false else /// \exception FE_INVALID if \a x or \a y is NaN inline constexpr_NOERR bool operator!=(half x, half y) { return detail::compsignal(x.data_, y.data_) || (x.data_!=y.data_ && ((x.data_|y.data_)&0x7FFF)); } template inline constexpr_NOERR bool operator!=(half x, T y) { return x != static_cast(y); } template inline constexpr_NOERR bool operator!=(T x, half y) { return static_cast(x) != y; } /// Comparison for less than. /// \param x first operand /// \param y second operand /// \retval true if \a x less than \a y /// \retval false else /// \exception FE_INVALID if \a x or \a y is NaN inline constexpr_NOERR bool operator<(half x, half y) { return !detail::compsignal(x.data_, y.data_) && ((x.data_^(0x8000|(0x8000-(x.data_>>15))))+(x.data_>>15)) < ((y.data_^(0x8000|(0x8000-(y.data_>>15))))+(y.data_>>15)); } template inline constexpr_NOERR bool operator<(half x, T y) { return x < static_cast(y); } template inline constexpr_NOERR bool operator<(T x, half y) { return static_cast(x) < y; } /// Comparison for greater than. /// \param x first operand /// \param y second operand /// \retval true if \a x greater than \a y /// \retval false else /// \exception FE_INVALID if \a x or \a y is NaN inline constexpr_NOERR bool operator>(half x, half y) { return !detail::compsignal(x.data_, y.data_) && ((x.data_^(0x8000|(0x8000-(x.data_>>15))))+(x.data_>>15)) > ((y.data_^(0x8000|(0x8000-(y.data_>>15))))+(y.data_>>15)); } template inline constexpr_NOERR bool operator>(half x, T y) { return x > static_cast(y); } template inline constexpr_NOERR bool operator>(T x, half y) { return static_cast(x) > y; } /// Comparison for less equal. /// \param x first operand /// \param y second operand /// \retval true if \a x less equal \a y /// \retval false else /// \exception FE_INVALID if \a x or \a y is NaN inline constexpr_NOERR bool operator<=(half x, half y) { return !detail::compsignal(x.data_, y.data_) && ((x.data_^(0x8000|(0x8000-(x.data_>>15))))+(x.data_>>15)) <= ((y.data_^(0x8000|(0x8000-(y.data_>>15))))+(y.data_>>15)); } template inline constexpr_NOERR bool operator<=(half x, T y) { return x <= static_cast(y); } template inline constexpr_NOERR bool operator<=(T x, half y) { return static_cast(x) <= y; } /// Comparison for greater equal. /// \param x first operand /// \param y second operand /// \retval true if \a x greater equal \a y /// \retval false else /// \exception FE_INVALID if \a x or \a y is NaN inline constexpr_NOERR bool operator>=(half x, half y) { return !detail::compsignal(x.data_, y.data_) && ((x.data_^(0x8000|(0x8000-(x.data_>>15))))+(x.data_>>15)) >= ((y.data_^(0x8000|(0x8000-(y.data_>>15))))+(y.data_>>15)); } template inline constexpr_NOERR bool operator>=(half x, T y) { return x >= static_cast(y); } template inline constexpr_NOERR bool operator>=(T x, half y) { return static_cast(x) >= y; } /// \} /// \anchor arithmetics /// \name Arithmetic operators /// \{ /// Identity. /// \param arg operand /// \return unchanged operand inline constexpr half operator+(half arg) { return arg; } /// Negation. /// \param arg operand /// \return negated operand inline constexpr half operator-(half arg) { return half(detail::binary, arg.data_^0x8000); } /// Addition. /// This operation is exact to rounding for all rounding modes. /// \param x left operand /// \param y right operand /// \return sum of half expressions /// \exception FE_INVALID if \a x and \a y are infinities with different signs or signaling NaNs /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding inline half operator+(half x, half y) { #ifdef HALF_ARITHMETIC_TYPE return half(detail::binary, detail::float2half(detail::half2float(x.data_)+detail::half2float(y.data_))); #else int absx = x.data_ & 0x7FFF, absy = y.data_ & 0x7FFF; bool sub = ((x.data_^y.data_)&0x8000) != 0; if(absx >= 0x7C00 || absy >= 0x7C00) return half(detail::binary, (absx>0x7C00 || absy>0x7C00) ? detail::signal(x.data_, y.data_) : (absy!=0x7C00) ? x.data_ : (sub && absx==0x7C00) ? detail::invalid() : y.data_); if(!absx) return absy ? y : half(detail::binary, (half::round_style==std::round_toward_neg_infinity) ? (x.data_|y.data_) : (x.data_&y.data_)); if(!absy) return x; unsigned int sign = ((sub && absy>absx) ? y.data_ : x.data_) & 0x8000; if(absy > absx) std::swap(absx, absy); int exp = (absx>>10) + (absx<=0x3FF), d = exp - (absy>>10) - (absy<=0x3FF), mx = ((absx&0x3FF)|((absx>0x3FF)<<10)) << 3, my; if(d < 13) { my = ((absy&0x3FF)|((absy>0x3FF)<<10)) << 3; my = (my>>d) | ((my&((1<(half::round_style==std::round_toward_neg_infinity)<<15); for(; mx<0x2000 && exp>1; mx<<=1,--exp) ; } else { mx += my; int i = mx >> 14; if((exp+=i) > 30) return half(detail::binary, detail::overflow(sign)); mx = (mx>>i) | (mx&i); } return half(detail::binary, detail::rounded(sign+((exp-1)<<10)+(mx>>3), (mx>>2)&1, (mx&0x3)!=0)); #endif } template inline half operator+(half x, T y) { return x + static_cast(y); } template inline half operator+(T x, half y) { return static_cast(x) + y; } /// Subtraction. /// This operation is exact to rounding for all rounding modes. /// \param x left operand /// \param y right operand /// \return difference of half expressions /// \exception FE_INVALID if \a x and \a y are infinities with equal signs or signaling NaNs /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding inline half operator-(half x, half y) { #ifdef HALF_ARITHMETIC_TYPE return half(detail::binary, detail::float2half(detail::half2float(x.data_)-detail::half2float(y.data_))); #else return x + (-y); #endif } template inline half operator-(half x, T y) { return x - static_cast(y); } template inline half operator-(T x, half y) { return static_cast(x) - y; } /// Multiplication. /// This operation is exact to rounding for all rounding modes. /// \param x left operand /// \param y right operand /// \return product of half expressions /// \exception FE_INVALID if multiplying 0 with infinity or if \a x or \a y is signaling NaN /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding inline half operator*(half x, half y) { #ifdef HALF_ARITHMETIC_TYPE return half(detail::binary, detail::float2half(detail::half2float(x.data_)*detail::half2float(y.data_))); #else int absx = x.data_ & 0x7FFF, absy = y.data_ & 0x7FFF, exp = -16; unsigned int sign = (x.data_^y.data_) & 0x8000; if(absx >= 0x7C00 || absy >= 0x7C00) return half(detail::binary, (absx>0x7C00 || absy>0x7C00) ? detail::signal(x.data_, y.data_) : ((absx==0x7C00 && !absy)||(absy==0x7C00 && !absx)) ? detail::invalid() : (sign|0x7C00)); if(!absx || !absy) return half(detail::binary, sign); for(; absx<0x400; absx<<=1,--exp) ; for(; absy<0x400; absy<<=1,--exp) ; detail::uint32 m = static_cast((absx&0x3FF)|0x400) * static_cast((absy&0x3FF)|0x400); int i = m >> 21, s = m & i; exp += (absx>>10) + (absy>>10) + i; if(exp > 29) return half(detail::binary, detail::overflow(sign)); else if(exp < -11) return half(detail::binary, detail::underflow(sign)); return half(detail::binary, detail::fixed2half(m>>i, exp, sign, s)); #endif } template inline half operator*(half x, T y) { return x * static_cast(y); } template inline half operator*(T x, half y) { return static_cast(x) * y; } /// Division. /// This operation is exact to rounding for all rounding modes. /// \param x left operand /// \param y right operand /// \return quotient of half expressions /// \exception FE_INVALID if dividing 0s or infinities with each other or if \a x or \a y is signaling NaN /// \exception FE_DIVBYZERO if dividing finite value by 0 /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding inline half operator/(half x, half y) { #ifdef HALF_ARITHMETIC_TYPE return half(detail::binary, detail::float2half(detail::half2float(x.data_)/detail::half2float(y.data_))); #else int absx = x.data_ & 0x7FFF, absy = y.data_ & 0x7FFF, exp = 14; unsigned int sign = (x.data_^y.data_) & 0x8000; if(absx >= 0x7C00 || absy >= 0x7C00) return half(detail::binary, (absx>0x7C00 || absy>0x7C00) ? detail::signal(x.data_, y.data_) : (absx==absy) ? detail::invalid() : (sign|((absx==0x7C00) ? 0x7C00 : 0))); if(!absx) return half(detail::binary, absy ? sign : detail::invalid()); if(!absy) return half(detail::binary, detail::pole(sign)); for(; absx<0x400; absx<<=1,--exp) ; for(; absy<0x400; absy<<=1,++exp) ; detail::uint32 mx = (absx&0x3FF) | 0x400, my = (absy&0x3FF) | 0x400; int i = mx < my; exp += (absx>>10) - (absy>>10) - i; if(exp > 29) return half(detail::binary, detail::overflow(sign)); else if(exp < -11) return half(detail::binary, detail::underflow(sign)); mx <<= 12 + i; my <<= 1; return half(detail::binary, detail::fixed2half(mx/my, exp, sign, mx%my!=0)); #endif } template inline half operator/(half x, T y) { return x / static_cast(y); } template inline half operator/(T x, half y) { return static_cast(x) / y; } /// \} /// \anchor streaming /// \name Input and output /// \{ /// Output operator. /// This uses the built-in functionality for streaming out floating-point numbers. /// \param out output stream to write into /// \param arg half expression to write /// \return reference to output stream template std::basic_ostream& operator<<(std::basic_ostream &out, half arg) { #ifdef HALF_ARITHMETIC_TYPE return out << detail::half2float(arg.data_); #else return out << detail::half2float(arg.data_); #endif } /// Input operator. /// This uses the built-in functionality for streaming in floating-point numbers, specifically double precision floating /// point numbers (unless overridden with [HALF_ARITHMETIC_TYPE](\ref HALF_ARITHMETIC_TYPE)). So the input string is first /// rounded to double precision using the underlying platform's current floating-point rounding mode before being rounded /// to half-precision using the library's half-precision rounding mode. /// \param in input stream to read from /// \param arg half to read into /// \return reference to input stream /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding template std::basic_istream& operator>>(std::basic_istream &in, half &arg) { #ifdef HALF_ARITHMETIC_TYPE detail::internal_t f; #else double f; #endif if(in >> f) arg.data_ = detail::float2half(f); return in; } /// \} /// \anchor basic /// \name Basic mathematical operations /// \{ /// Absolute value. /// **See also:** Documentation for [std::fabs](https://en.cppreference.com/w/cpp/numeric/math/fabs). /// \param arg operand /// \return absolute value of \a arg inline constexpr half fabs(half arg) { return half(detail::binary, arg.data_&0x7FFF); } /// Absolute value. /// **See also:** Documentation for [std::abs](https://en.cppreference.com/w/cpp/numeric/math/fabs). /// \param arg operand /// \return absolute value of \a arg inline constexpr half abs(half arg) { return fabs(arg); } /// Remainder of division. /// **See also:** Documentation for [std::fmod](https://en.cppreference.com/w/cpp/numeric/math/fmod). /// \param x first operand /// \param y second operand /// \return remainder of floating-point division. /// \exception FE_INVALID if \a x is infinite or \a y is 0 or if \a x or \a y is signaling NaN inline half fmod(half x, half y) { unsigned int absx = x.data_ & 0x7FFF, absy = y.data_ & 0x7FFF, sign = x.data_ & 0x8000; if(absx >= 0x7C00 || absy >= 0x7C00) return half(detail::binary, (absx>0x7C00 || absy>0x7C00) ? detail::signal(x.data_, y.data_) : (absx==0x7C00) ? detail::invalid() : x.data_); if(!absy) return half(detail::binary, detail::invalid()); if(!absx) return x; if(absx == absy) return half(detail::binary, sign); return half(detail::binary, sign|detail::mod(absx, absy)); } /// Remainder of division. /// **See also:** Documentation for [std::remainder](https://en.cppreference.com/w/cpp/numeric/math/remainder). /// \param x first operand /// \param y second operand /// \return remainder of floating-point division. /// \exception FE_INVALID if \a x is infinite or \a y is 0 or if \a x or \a y is signaling NaN inline half remainder(half x, half y) { unsigned int absx = x.data_ & 0x7FFF, absy = y.data_ & 0x7FFF, sign = x.data_ & 0x8000; if(absx >= 0x7C00 || absy >= 0x7C00) return half(detail::binary, (absx>0x7C00 || absy>0x7C00) ? detail::signal(x.data_, y.data_) : (absx==0x7C00) ? detail::invalid() : x.data_); if(!absy) return half(detail::binary, detail::invalid()); if(absx == absy) return half(detail::binary, sign); return half(detail::binary, sign^detail::mod(absx, absy)); } /// Remainder of division. /// **See also:** Documentation for [std::remquo](https://en.cppreference.com/w/cpp/numeric/math/remquo). /// \param x first operand /// \param y second operand /// \param quo address to store some bits of quotient at /// \return remainder of floating-point division. /// \exception FE_INVALID if \a x is infinite or \a y is 0 or if \a x or \a y is signaling NaN inline half remquo(half x, half y, int *quo) { unsigned int absx = x.data_ & 0x7FFF, absy = y.data_ & 0x7FFF, value = x.data_ & 0x8000; if(absx >= 0x7C00 || absy >= 0x7C00) return half(detail::binary, (absx>0x7C00 || absy>0x7C00) ? detail::signal(x.data_, y.data_) : (absx==0x7C00) ? detail::invalid() : (*quo = 0, x.data_)); if(!absy) return half(detail::binary, detail::invalid()); bool qsign = ((value^y.data_)&0x8000) != 0; int q = 1; if(absx != absy) value ^= detail::mod(absx, absy, &q); return *quo = qsign ? -q : q, half(detail::binary, value); } /// Fused multiply add. /// This function is exact to rounding for all rounding modes. /// /// **See also:** Documentation for [std::fma](https://en.cppreference.com/w/cpp/numeric/math/fma). /// \param x first operand /// \param y second operand /// \param z third operand /// \return ( \a x * \a y ) + \a z rounded as one operation. /// \exception FE_INVALID according to operator*() and operator+() unless any argument is a quiet NaN and no argument is a signaling NaN /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding the final addition inline half fma(half x, half y, half z) { #ifdef HALF_ARITHMETIC_TYPE detail::internal_t fx = detail::half2float(x.data_), fy = detail::half2float(y.data_), fz = detail::half2float(z.data_); #if FP_FAST_FMA return half(detail::binary, detail::float2half(std::fma(fx, fy, fz))); #else return half(detail::binary, detail::float2half(fx*fy+fz)); #endif #else int absx = x.data_ & 0x7FFF, absy = y.data_ & 0x7FFF, absz = z.data_ & 0x7FFF, exp = -15; unsigned int sign = (x.data_^y.data_) & 0x8000; bool sub = ((sign^z.data_)&0x8000) != 0; if(absx >= 0x7C00 || absy >= 0x7C00 || absz >= 0x7C00) return (absx>0x7C00 || absy>0x7C00 || absz>0x7C00) ? half(detail::binary, detail::signal(x.data_, y.data_, z.data_)) : (absx==0x7C00) ? half(detail::binary, (!absy || (sub && absz==0x7C00)) ? detail::invalid() : (sign|0x7C00)) : (absy==0x7C00) ? half(detail::binary, (!absx || (sub && absz==0x7C00)) ? detail::invalid() : (sign|0x7C00)) : z; if(!absx || !absy) return absz ? z : half(detail::binary, (half::round_style==std::round_toward_neg_infinity) ? (z.data_|sign) : (z.data_&sign)); for(; absx<0x400; absx<<=1,--exp) ; for(; absy<0x400; absy<<=1,--exp) ; detail::uint32 m = static_cast((absx&0x3FF)|0x400) * static_cast((absy&0x3FF)|0x400); int i = m >> 21; exp += (absx>>10) + (absy>>10) + i; m <<= 3 - i; if(absz) { int expz = 0; for(; absz<0x400; absz<<=1,--expz) ; expz += absz >> 10; detail::uint32 mz = static_cast((absz&0x3FF)|0x400) << 13; if(expz > exp || (expz == exp && mz > m)) { std::swap(m, mz); std::swap(exp, expz); if(sub) sign = z.data_ & 0x8000; } int d = exp - expz; mz = (d<23) ? ((mz>>d)|((mz&((static_cast(1)<(half::round_style==std::round_toward_neg_infinity)<<15); for(; m<0x800000; m<<=1,--exp) ; } else { m += mz; i = m >> 24; m = (m>>i) | (m&i); exp += i; } } if(exp > 30) return half(detail::binary, detail::overflow(sign)); else if(exp < -10) return half(detail::binary, detail::underflow(sign)); return half(detail::binary, detail::fixed2half(m, exp-1, sign)); #endif } /// Maximum of half expressions. /// **See also:** Documentation for [std::fmax](https://en.cppreference.com/w/cpp/numeric/math/fmax). /// \param x first operand /// \param y second operand /// \return maximum of operands, ignoring quiet NaNs /// \exception FE_INVALID if \a x or \a y is signaling NaN inline constexpr_NOERR half fmax(half x, half y) { return half(detail::binary, (!isnan(y) && (isnan(x) || (x.data_^(0x8000|(0x8000-(x.data_>>15)))) < (y.data_^(0x8000|(0x8000-(y.data_>>15)))))) ? detail::select(y.data_, x.data_) : detail::select(x.data_, y.data_)); } /// Minimum of half expressions. /// **See also:** Documentation for [std::fmin](https://en.cppreference.com/w/cpp/numeric/math/fmin). /// \param x first operand /// \param y second operand /// \return minimum of operands, ignoring quiet NaNs /// \exception FE_INVALID if \a x or \a y is signaling NaN inline constexpr_NOERR half fmin(half x, half y) { return half(detail::binary, (!isnan(y) && (isnan(x) || (x.data_^(0x8000|(0x8000-(x.data_>>15)))) > (y.data_^(0x8000|(0x8000-(y.data_>>15)))))) ? detail::select(y.data_, x.data_) : detail::select(x.data_, y.data_)); } /// Positive difference. /// This function is exact to rounding for all rounding modes. /// /// **See also:** Documentation for [std::fdim](https://en.cppreference.com/w/cpp/numeric/math/fdim). /// \param x first operand /// \param y second operand /// \return \a x - \a y or 0 if difference negative /// \exception FE_... according to operator-(half,half) inline half fdim(half x, half y) { if(isnan(x) || isnan(y)) return half(detail::binary, detail::signal(x.data_, y.data_)); return (x.data_^(0x8000|(0x8000-(x.data_>>15)))) <= (y.data_^(0x8000|(0x8000-(y.data_>>15)))) ? half(detail::binary, 0) : (x-y); } /// Get NaN value. /// **See also:** Documentation for [std::nan](https://en.cppreference.com/w/cpp/numeric/math/nan). /// \param arg string code /// \return quiet NaN inline half nanh(const char *arg) { unsigned int value = 0x7FFF; while(*arg) value ^= static_cast(*arg++) & 0xFF; return half(detail::binary, value); } /// \} /// \anchor exponential /// \name Exponential functions /// \{ /// Exponential function. /// This function is exact to rounding for all rounding modes. /// /// **See also:** Documentation for [std::exp](https://en.cppreference.com/w/cpp/numeric/math/exp). /// \param arg function argument /// \return e raised to \a arg /// \exception FE_INVALID for signaling NaN /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding inline half exp(half arg) { #ifdef HALF_ARITHMETIC_TYPE return half(detail::binary, detail::float2half(std::exp(detail::half2float(arg.data_)))); #else int abs = arg.data_ & 0x7FFF; if(!abs) return half(detail::binary, 0x3C00); if(abs >= 0x7C00) return half(detail::binary, (abs==0x7C00) ? (0x7C00&((arg.data_>>15)-1U)) : detail::signal(arg.data_)); if(abs >= 0x4C80) return half(detail::binary, (arg.data_&0x8000) ? detail::underflow() : detail::overflow()); detail::uint32 m = detail::multiply64(static_cast((abs&0x3FF)+((abs>0x3FF)<<10))<<21, 0xB8AA3B29); int e = (abs>>10) + (abs<=0x3FF), exp; if(e < 14) { exp = 0; m >>= 14 - e; } else { exp = m >> (45-e); m = (m<<(e-14)) & 0x7FFFFFFF; } return half(detail::binary, detail::exp2_post(detail::exp2(m, 26), exp, (arg.data_&0x8000)!=0)); #endif } /// Binary exponential. /// This function is exact to rounding for all rounding modes. /// /// **See also:** Documentation for [std::exp2](https://en.cppreference.com/w/cpp/numeric/math/exp2). /// \param arg function argument /// \return 2 raised to \a arg /// \exception FE_INVALID for signaling NaN /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding inline half exp2(half arg) { #if defined(HALF_ARITHMETIC_TYPE) return half(detail::binary, detail::float2half(std::exp2(detail::half2float(arg.data_)))); #else int abs = arg.data_ & 0x7FFF; if(!abs) return half(detail::binary, 0x3C00); if(abs >= 0x7C00) return half(detail::binary, (abs==0x7C00) ? (0x7C00&((arg.data_>>15)-1U)) : detail::signal(arg.data_)); if(abs >= 0x4E40) return half(detail::binary, (arg.data_&0x8000) ? detail::underflow() : detail::overflow()); int e = (abs>>10) + (abs<=0x3FF), exp = (abs&0x3FF) + ((abs>0x3FF)<<10); detail::uint32 m = detail::exp2((static_cast(exp)<<(6+e))&0x7FFFFFFF, 28); exp >>= 25 - e; if(m == 0x80000000) { if(arg.data_&0x8000) exp = -exp; else if(exp > 15) return half(detail::binary, detail::overflow()); return half(detail::binary, detail::fixed2half(m, exp+14)); } return half(detail::binary, detail::exp2_post(m, exp, (arg.data_&0x8000)!=0)); #endif } /// Exponential minus one. /// This function may be 1 ULP off the correctly rounded exact result in <0.05% of inputs for `std::round_to_nearest` /// and in <1% of inputs for any other rounding mode. /// /// **See also:** Documentation for [std::expm1](https://en.cppreference.com/w/cpp/numeric/math/expm1). /// \param arg function argument /// \return e raised to \a arg and subtracted by 1 /// \exception FE_INVALID for signaling NaN /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding inline half expm1(half arg) { #if defined(HALF_ARITHMETIC_TYPE) return half(detail::binary, detail::float2half(std::expm1(detail::half2float(arg.data_)))); #else unsigned int abs = arg.data_ & 0x7FFF, sign = arg.data_ & 0x8000; if(!abs) return arg; if(abs >= 0x7C00) return half(detail::binary, (abs==0x7C00) ? (0x7C00+(sign>>1)) : detail::signal(arg.data_)); if(abs >= 0x4A00) return half(detail::binary, (arg.data_&0x8000) ? detail::rounded(0xBBFF, 1, 1) : detail::overflow()); detail::uint32 m = detail::multiply64(static_cast((abs&0x3FF)+((abs>0x3FF)<<10))<<21, 0xB8AA3B29); int e = (abs>>10) + (abs<=0x3FF), exp; if(e < 14) { exp = 0; m >>= 14 - e; } else { exp = m >> (45-e); m = (m<<(e-14)) & 0x7FFFFFFF; } m = detail::exp2(m); if(sign) { int s = 0; if(m > 0x80000000) { ++exp; m = detail::divide64(0x80000000, m, s); } m = 0x80000000 - ((m>>exp)|((m&((static_cast(1)<>exp) : 1; for(exp+=14; m<0x80000000 && exp; m<<=1,--exp) ; if(exp > 29) return half(detail::binary, detail::overflow()); return half(detail::binary, detail::rounded(sign+(exp<<10)+(m>>21), (m>>20)&1, (m&0xFFFFF)!=0)); #endif } /// Natural logarithm. /// This function is exact to rounding for all rounding modes. /// /// **See also:** Documentation for [std::log](https://en.cppreference.com/w/cpp/numeric/math/log). /// \param arg function argument /// \return logarithm of \a arg to base e /// \exception FE_INVALID for signaling NaN or negative argument /// \exception FE_DIVBYZERO for 0 /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding inline half log(half arg) { #ifdef HALF_ARITHMETIC_TYPE return half(detail::binary, detail::float2half(std::log(detail::half2float(arg.data_)))); #else int abs = arg.data_ & 0x7FFF, exp = -15; if(!abs) return half(detail::binary, detail::pole(0x8000)); if(arg.data_ & 0x8000) return half(detail::binary, (arg.data_<=0xFC00) ? detail::invalid() : detail::signal(arg.data_)); if(abs >= 0x7C00) return (abs==0x7C00) ? arg : half(detail::binary, detail::signal(arg.data_)); for(; abs<0x400; abs<<=1,--exp) ; exp += abs >> 10; return half(detail::binary, detail::log2_post( detail::log2(static_cast((abs&0x3FF)|0x400)<<20, 27)+8, exp, 17)); #endif } /// Common logarithm. /// This function is exact to rounding for all rounding modes. /// /// **See also:** Documentation for [std::log10](https://en.cppreference.com/w/cpp/numeric/math/log10). /// \param arg function argument /// \return logarithm of \a arg to base 10 /// \exception FE_INVALID for signaling NaN or negative argument /// \exception FE_DIVBYZERO for 0 /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding inline half log10(half arg) { #ifdef HALF_ARITHMETIC_TYPE return half(detail::binary, detail::float2half(std::log10(detail::half2float(arg.data_)))); #else int abs = arg.data_ & 0x7FFF, exp = -15; if(!abs) return half(detail::binary, detail::pole(0x8000)); if(arg.data_ & 0x8000) return half(detail::binary, (arg.data_<=0xFC00) ? detail::invalid() : detail::signal(arg.data_)); if(abs >= 0x7C00) return (abs==0x7C00) ? arg : half(detail::binary, detail::signal(arg.data_)); switch(abs) { case 0x4900: return half(detail::binary, 0x3C00); case 0x5640: return half(detail::binary, 0x4000); case 0x63D0: return half(detail::binary, 0x4200); case 0x70E2: return half(detail::binary, 0x4400); } for(; abs<0x400; abs<<=1,--exp) ; exp += abs >> 10; return half(detail::binary, detail::log2_post( detail::log2(static_cast((abs&0x3FF)|0x400)<<20, 27)+8, exp, 16)); #endif } /// Binary logarithm. /// This function is exact to rounding for all rounding modes. /// /// **See also:** Documentation for [std::log2](https://en.cppreference.com/w/cpp/numeric/math/log2). /// \param arg function argument /// \return logarithm of \a arg to base 2 /// \exception FE_INVALID for signaling NaN or negative argument /// \exception FE_DIVBYZERO for 0 /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding inline half log2(half arg) { #if defined(HALF_ARITHMETIC_TYPE) return half(detail::binary, detail::float2half(std::log2(detail::half2float(arg.data_)))); #else int abs = arg.data_ & 0x7FFF, exp = -15, s = 0; if(!abs) return half(detail::binary, detail::pole(0x8000)); if(arg.data_ & 0x8000) return half(detail::binary, (arg.data_<=0xFC00) ? detail::invalid() : detail::signal(arg.data_)); if(abs >= 0x7C00) return (abs==0x7C00) ? arg : half(detail::binary, detail::signal(arg.data_)); if(abs == 0x3C00) return half(detail::binary, 0); for(; abs<0x400; abs<<=1,--exp) ; exp += (abs>>10); if(!(abs&0x3FF)) { unsigned int value = static_cast(exp<0) << 15, m = std::abs(exp) << 6; for(exp=18; m<0x400; m<<=1,--exp) ; return half(detail::binary, value+(exp<<10)+m); } detail::uint32 ilog = exp, sign = detail::sign_mask(ilog), m = (((ilog<<27)+(detail::log2(static_cast((abs&0x3FF)|0x400)<<20, 28)>>4))^sign) - sign; if(!m) return half(detail::binary, 0); for(exp=14; m<0x8000000 && exp; m<<=1,--exp) ; for(; m>0xFFFFFFF; m>>=1,++exp) s |= m & 1; return half(detail::binary, detail::fixed2half(m, exp, sign&0x8000, s)); #endif } /// Natural logarithm plus one. /// This function may be 1 ULP off the correctly rounded exact result in <0.05% of inputs for `std::round_to_nearest` /// and in ~1% of inputs for any other rounding mode. /// /// **See also:** Documentation for [std::log1p](https://en.cppreference.com/w/cpp/numeric/math/log1p). /// \param arg function argument /// \return logarithm of \a arg plus 1 to base e /// \exception FE_INVALID for signaling NaN or argument <-1 /// \exception FE_DIVBYZERO for -1 /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding inline half log1p(half arg) { #if defined(HALF_ARITHMETIC_TYPE) return half(detail::binary, detail::float2half(std::log1p(detail::half2float(arg.data_)))); #else if(arg.data_ >= 0xBC00) return half(detail::binary, (arg.data_==0xBC00) ? detail::pole(0x8000) : (arg.data_<=0xFC00) ? detail::invalid() : detail::signal(arg.data_)); int abs = arg.data_ & 0x7FFF, exp = -15; if(!abs || abs >= 0x7C00) return (abs>0x7C00) ? half(detail::binary, detail::signal(arg.data_)) : arg; for(; abs<0x400; abs<<=1,--exp) ; exp += abs >> 10; detail::uint32 m = static_cast((abs&0x3FF)|0x400) << 20; if(arg.data_ & 0x8000) { m = 0x40000000 - (m>>-exp); for(exp=0; m<0x40000000; m<<=1,--exp) ; } else { if(exp < 0) { m = 0x40000000 + (m>>-exp); exp = 0; } else { m += 0x40000000 >> exp; int i = m >> 31; m >>= i; exp += i; } } return half(detail::binary, detail::log2_post(detail::log2(m), exp, 17)); #endif } /// \} /// \anchor power /// \name Power functions /// \{ /// Square root. /// This function is exact to rounding for all rounding modes. /// /// **See also:** Documentation for [std::sqrt](https://en.cppreference.com/w/cpp/numeric/math/sqrt). /// \param arg function argument /// \return square root of \a arg /// \exception FE_INVALID for signaling NaN and negative arguments /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding inline half sqrt(half arg) { #ifdef HALF_ARITHMETIC_TYPE return half(detail::binary, detail::float2half(std::sqrt(detail::half2float(arg.data_)))); #else int abs = arg.data_ & 0x7FFF, exp = 15; if(!abs || arg.data_ >= 0x7C00) return half(detail::binary, (abs>0x7C00) ? detail::signal(arg.data_) : (arg.data_>0x8000) ? detail::invalid() : arg.data_); for(; abs<0x400; abs<<=1,--exp) ; detail::uint32 r = static_cast((abs&0x3FF)|0x400) << 10, m = detail::sqrt<20>(r, exp+=abs>>10); return half(detail::binary, detail::rounded((exp<<10)+(m&0x3FF), r>m, r!=0)); #endif } /// Cubic root. /// This function is exact to rounding for all rounding modes. /// /// **See also:** Documentation for [std::cbrt](https://en.cppreference.com/w/cpp/numeric/math/cbrt). /// \param arg function argument /// \return cubic root of \a arg /// \exception FE_INVALID for signaling NaN /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding inline half cbrt(half arg) { #if defined(HALF_ARITHMETIC_TYPE) return half(detail::binary, detail::float2half(std::cbrt(detail::half2float(arg.data_)))); #else int abs = arg.data_ & 0x7FFF, exp = -15; if(!abs || abs == 0x3C00 || abs >= 0x7C00) return (abs>0x7C00) ? half(detail::binary, detail::signal(arg.data_)) : arg; for(; abs<0x400; abs<<=1, --exp); detail::uint32 ilog = exp + (abs>>10), sign = detail::sign_mask(ilog), f, m = (((ilog<<27)+(detail::log2(static_cast((abs&0x3FF)|0x400)<<20, 24)>>4))^sign) - sign; for(exp=2; m<0x80000000; m<<=1,--exp) ; m = detail::multiply64(m, 0xAAAAAAAB); int i = m >> 31, s; exp += i; m <<= 1 - i; if(exp < 0) { f = m >> -exp; exp = 0; } else { f = (m<> (31-exp); } m = detail::exp2(f, (half::round_style==std::round_to_nearest) ? 29 : 26); if(sign) { if(m > 0x80000000) { m = detail::divide64(0x80000000, m, s); ++exp; } exp = -exp; } return half(detail::binary, (half::round_style==std::round_to_nearest) ? detail::fixed2half(m, exp+14, arg.data_&0x8000) : detail::fixed2half((m+0x80)>>8, exp+14, arg.data_&0x8000)); #endif } /// Hypotenuse function. /// This function is exact to rounding for all rounding modes. /// /// **See also:** Documentation for [std::hypot](https://en.cppreference.com/w/cpp/numeric/math/hypot). /// \param x first argument /// \param y second argument /// \return square root of sum of squares without internal over- or underflows /// \exception FE_INVALID if \a x or \a y is signaling NaN /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding of the final square root inline half hypot(half x, half y) { #ifdef HALF_ARITHMETIC_TYPE detail::internal_t fx = detail::half2float(x.data_), fy = detail::half2float(y.data_); return half(detail::binary, detail::float2half(std::hypot(fx, fy))); #else int absx = x.data_ & 0x7FFF, absy = y.data_ & 0x7FFF, expx = 0, expy = 0; if(absx >= 0x7C00 || absy >= 0x7C00) return half(detail::binary, (absx==0x7C00) ? detail::select(0x7C00, y.data_) : (absy==0x7C00) ? detail::select(0x7C00, x.data_) : detail::signal(x.data_, y.data_)); if(!absx) return half(detail::binary, absy ? detail::check_underflow(absy) : 0); if(!absy) return half(detail::binary, detail::check_underflow(absx)); if(absy > absx) std::swap(absx, absy); for(; absx<0x400; absx<<=1,--expx) ; for(; absy<0x400; absy<<=1,--expy) ; detail::uint32 mx = (absx&0x3FF) | 0x400, my = (absy&0x3FF) | 0x400; mx *= mx; my *= my; int ix = mx >> 21, iy = my >> 21; expx = 2*(expx+(absx>>10)) - 15 + ix; expy = 2*(expy+(absy>>10)) - 15 + iy; mx <<= 10 - ix; my <<= 10 - iy; int d = expx - expy; my = (d<30) ? ((my>>d)|((my&((static_cast(1)<(mx+my, expx)); #endif } /// Hypotenuse function. /// This function is exact to rounding for all rounding modes. /// /// **See also:** Documentation for [std::hypot](https://en.cppreference.com/w/cpp/numeric/math/hypot). /// \param x first argument /// \param y second argument /// \param z third argument /// \return square root of sum of squares without internal over- or underflows /// \exception FE_INVALID if \a x, \a y or \a z is signaling NaN /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding of the final square root inline half hypot(half x, half y, half z) { #ifdef HALF_ARITHMETIC_TYPE detail::internal_t fx = detail::half2float(x.data_), fy = detail::half2float(y.data_), fz = detail::half2float(z.data_); return half(detail::binary, detail::float2half(std::sqrt(fx*fx+fy*fy+fz*fz))); #else int absx = x.data_ & 0x7FFF, absy = y.data_ & 0x7FFF, absz = z.data_ & 0x7FFF, expx = 0, expy = 0, expz = 0; if(!absx) return hypot(y, z); if(!absy) return hypot(x, z); if(!absz) return hypot(x, y); if(absx >= 0x7C00 || absy >= 0x7C00 || absz >= 0x7C00) return half(detail::binary, (absx==0x7C00) ? detail::select(0x7C00, detail::select(y.data_, z.data_)) : (absy==0x7C00) ? detail::select(0x7C00, detail::select(x.data_, z.data_)) : (absz==0x7C00) ? detail::select(0x7C00, detail::select(x.data_, y.data_)) : detail::signal(x.data_, y.data_, z.data_)); if(absz > absy) std::swap(absy, absz); if(absy > absx) std::swap(absx, absy); if(absz > absy) std::swap(absy, absz); for(; absx<0x400; absx<<=1,--expx) ; for(; absy<0x400; absy<<=1,--expy) ; for(; absz<0x400; absz<<=1,--expz) ; detail::uint32 mx = (absx&0x3FF) | 0x400, my = (absy&0x3FF) | 0x400, mz = (absz&0x3FF) | 0x400; mx *= mx; my *= my; mz *= mz; int ix = mx >> 21, iy = my >> 21, iz = mz >> 21; expx = 2*(expx+(absx>>10)) - 15 + ix; expy = 2*(expy+(absy>>10)) - 15 + iy; expz = 2*(expz+(absz>>10)) - 15 + iz; mx <<= 10 - ix; my <<= 10 - iy; mz <<= 10 - iz; int d = expy - expz; mz = (d<30) ? ((mz>>d)|((mz&((static_cast(1)<>1) | (my&1); if(++expy > expx) { std::swap(mx, my); std::swap(expx, expy); } } d = expx - expy; my = (d<30) ? ((my>>d)|((my&((static_cast(1)<(mx+my, expx)); #endif } /// Power function. /// This function may be 1 ULP off the correctly rounded exact result for any rounding mode in ~0.00025% of inputs. /// /// **See also:** Documentation for [std::pow](https://en.cppreference.com/w/cpp/numeric/math/pow). /// \param x base /// \param y exponent /// \return \a x raised to \a y /// \exception FE_INVALID if \a x or \a y is signaling NaN or if \a x is finite an negative and \a y is finite and not integral /// \exception FE_DIVBYZERO if \a x is 0 and \a y is negative /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding inline half pow(half x, half y) { #ifdef HALF_ARITHMETIC_TYPE return half(detail::binary, detail::float2half(std::pow(detail::half2float(x.data_), detail::half2float(y.data_)))); #else int absx = x.data_ & 0x7FFF, absy = y.data_ & 0x7FFF, exp = -15; if(!absy || x.data_ == 0x3C00) return half(detail::binary, detail::select(0x3C00, (x.data_==0x3C00) ? y.data_ : x.data_)); bool is_int = absy >= 0x6400 || (absy>=0x3C00 && !(absy&((1<<(25-(absy>>10)))-1))); unsigned int sign = x.data_ & (static_cast((absy<0x6800)&&is_int&&((absy>>(25-(absy>>10)))&1))<<15); if(absx >= 0x7C00 || absy >= 0x7C00) return half(detail::binary, (absx>0x7C00 || absy>0x7C00) ? detail::signal(x.data_, y.data_) : (absy==0x7C00) ? ((absx==0x3C00) ? 0x3C00 : (!absx && y.data_==0xFC00) ? detail::pole() : (0x7C00&-((y.data_>>15)^(absx>0x3C00)))) : (sign|(0x7C00&((y.data_>>15)-1U)))); if(!absx) return half(detail::binary, (y.data_&0x8000) ? detail::pole(sign) : sign); if((x.data_&0x8000) && !is_int) return half(detail::binary, detail::invalid()); if(x.data_ == 0xBC00) return half(detail::binary, sign|0x3C00); if(y.data_ == 0x3800) return sqrt(x); if(y.data_ == 0x3C00) return half(detail::binary, detail::check_underflow(x.data_)); if(y.data_ == 0x4000) return x * x; for(; absx<0x400; absx<<=1,--exp) ; detail::uint32 ilog = exp + (absx>>10), msign = detail::sign_mask(ilog), f, m = (((ilog<<27)+((detail::log2(static_cast((absx&0x3FF)|0x400)<<20)+8)>>4))^msign) - msign; for(exp=-11; m<0x80000000; m<<=1,--exp) ; for(; absy<0x400; absy<<=1,--exp) ; m = detail::multiply64(m, static_cast((absy&0x3FF)|0x400)<<21); int i = m >> 31; exp += (absy>>10) + i; m <<= 1 - i; if(exp < 0) { f = m >> -exp; exp = 0; } else { f = (m<> (31-exp); } return half(detail::binary, detail::exp2_post(detail::exp2(f), exp, ((msign&1)^(y.data_>>15))!=0, sign)); #endif } /// \} /// \anchor trigonometric /// \name Trigonometric functions /// \{ /// Compute sine and cosine simultaneously. /// This returns the same results as sin() and cos() but is faster than calling each function individually. /// /// This function is exact to rounding for all rounding modes. /// \param arg function argument /// \param sin variable to take sine of \a arg /// \param cos variable to take cosine of \a arg /// \exception FE_INVALID for signaling NaN or infinity /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding inline void sincos(half arg, half *sin, half *cos) { #ifdef HALF_ARITHMETIC_TYPE detail::internal_t f = detail::half2float(arg.data_); *sin = half(detail::binary, detail::float2half(std::sin(f))); *cos = half(detail::binary, detail::float2half(std::cos(f))); #else int abs = arg.data_ & 0x7FFF, sign = arg.data_ >> 15, k; if(abs >= 0x7C00) *sin = *cos = half(detail::binary, (abs==0x7C00) ? detail::invalid() : detail::signal(arg.data_)); else if(!abs) { *sin = arg; *cos = half(detail::binary, 0x3C00); } else if(abs < 0x2500) { *sin = half(detail::binary, detail::rounded(arg.data_-1, 1, 1)); *cos = half(detail::binary, detail::rounded(0x3BFF, 1, 1)); } else { if(half::round_style != std::round_to_nearest) { switch(abs) { case 0x48B7: *sin = half(detail::binary, detail::rounded((~arg.data_&0x8000)|0x1D07, 1, 1)); *cos = half(detail::binary, detail::rounded(0xBBFF, 1, 1)); return; case 0x598C: *sin = half(detail::binary, detail::rounded((arg.data_&0x8000)|0x3BFF, 1, 1)); *cos = half(detail::binary, detail::rounded(0x80FC, 1, 1)); return; case 0x6A64: *sin = half(detail::binary, detail::rounded((~arg.data_&0x8000)|0x3BFE, 1, 1)); *cos = half(detail::binary, detail::rounded(0x27FF, 1, 1)); return; case 0x6D8C: *sin = half(detail::binary, detail::rounded((arg.data_&0x8000)|0x0FE6, 1, 1)); *cos = half(detail::binary, detail::rounded(0x3BFF, 1, 1)); return; } } std::pair sc = detail::sincos(detail::angle_arg(abs, k), 28); switch(k & 3) { case 1: sc = std::make_pair(sc.second, -sc.first); break; case 2: sc = std::make_pair(-sc.first, -sc.second); break; case 3: sc = std::make_pair(-sc.second, sc.first); break; } *sin = half(detail::binary, detail::fixed2half((sc.first^-static_cast(sign))+sign)); *cos = half(detail::binary, detail::fixed2half(sc.second)); } #endif } /// Sine function. /// This function is exact to rounding for all rounding modes. /// /// **See also:** Documentation for [std::sin](https://en.cppreference.com/w/cpp/numeric/math/sin). /// \param arg function argument /// \return sine value of \a arg /// \exception FE_INVALID for signaling NaN or infinity /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding inline half sin(half arg) { #ifdef HALF_ARITHMETIC_TYPE return half(detail::binary, detail::float2half(std::sin(detail::half2float(arg.data_)))); #else int abs = arg.data_ & 0x7FFF, k; if(!abs) return arg; if(abs >= 0x7C00) return half(detail::binary, (abs==0x7C00) ? detail::invalid() : detail::signal(arg.data_)); if(abs < 0x2900) return half(detail::binary, detail::rounded(arg.data_-1, 1, 1)); if(half::round_style != std::round_to_nearest) switch(abs) { case 0x48B7: return half(detail::binary, detail::rounded((~arg.data_&0x8000)|0x1D07, 1, 1)); case 0x6A64: return half(detail::binary, detail::rounded((~arg.data_&0x8000)|0x3BFE, 1, 1)); case 0x6D8C: return half(detail::binary, detail::rounded((arg.data_&0x8000)|0x0FE6, 1, 1)); } std::pair sc = detail::sincos(detail::angle_arg(abs, k), 28); detail::uint32 sign = -static_cast(((k>>1)&1)^(arg.data_>>15)); return half(detail::binary, detail::fixed2half((((k&1) ? sc.second : sc.first)^sign) - sign)); #endif } /// Cosine function. /// This function is exact to rounding for all rounding modes. /// /// **See also:** Documentation for [std::cos](https://en.cppreference.com/w/cpp/numeric/math/cos). /// \param arg function argument /// \return cosine value of \a arg /// \exception FE_INVALID for signaling NaN or infinity /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding inline half cos(half arg) { #ifdef HALF_ARITHMETIC_TYPE return half(detail::binary, detail::float2half(std::cos(detail::half2float(arg.data_)))); #else int abs = arg.data_ & 0x7FFF, k; if(!abs) return half(detail::binary, 0x3C00); if(abs >= 0x7C00) return half(detail::binary, (abs==0x7C00) ? detail::invalid() : detail::signal(arg.data_)); if(abs < 0x2500) return half(detail::binary, detail::rounded(0x3BFF, 1, 1)); if(half::round_style != std::round_to_nearest && abs == 0x598C) return half(detail::binary, detail::rounded(0x80FC, 1, 1)); std::pair sc = detail::sincos(detail::angle_arg(abs, k), 28); detail::uint32 sign = -static_cast(((k>>1)^k)&1); return half(detail::binary, detail::fixed2half((((k&1) ? sc.first : sc.second)^sign) - sign)); #endif } /// Tangent function. /// This function is exact to rounding for all rounding modes. /// /// **See also:** Documentation for [std::tan](https://en.cppreference.com/w/cpp/numeric/math/tan). /// \param arg function argument /// \return tangent value of \a arg /// \exception FE_INVALID for signaling NaN or infinity /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding inline half tan(half arg) { #ifdef HALF_ARITHMETIC_TYPE return half(detail::binary, detail::float2half(std::tan(detail::half2float(arg.data_)))); #else int abs = arg.data_ & 0x7FFF, exp = 13, k; if(!abs) return arg; if(abs >= 0x7C00) return half(detail::binary, (abs==0x7C00) ? detail::invalid() : detail::signal(arg.data_)); if(abs < 0x2700) return half(detail::binary, detail::rounded(arg.data_, 0, 1)); if(half::round_style != std::round_to_nearest) switch(abs) { case 0x658C: return half(detail::binary, detail::rounded((arg.data_&0x8000)|0x07E6, 1, 1)); case 0x7330: return half(detail::binary, detail::rounded((~arg.data_&0x8000)|0x4B62, 1, 1)); } std::pair sc = detail::sincos(detail::angle_arg(abs, k), 30); if(k & 1) sc = std::make_pair(-sc.second, sc.first); detail::uint32 signy = detail::sign_mask(sc.first), signx = detail::sign_mask(sc.second); detail::uint32 my = (sc.first^signy) - signy, mx = (sc.second^signx) - signx; for(; my<0x80000000; my<<=1,--exp) ; for(; mx<0x80000000; mx<<=1,++exp) ; return half(detail::binary, detail::tangent_post(my, mx, exp, (signy^signx^arg.data_)&0x8000)); #endif } /// Arc sine. /// This function is exact to rounding for all rounding modes. /// /// **See also:** Documentation for [std::asin](https://en.cppreference.com/w/cpp/numeric/math/asin). /// \param arg function argument /// \return arc sine value of \a arg /// \exception FE_INVALID for signaling NaN or if abs(\a arg) > 1 /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding inline half asin(half arg) { #ifdef HALF_ARITHMETIC_TYPE return half(detail::binary, detail::float2half(std::asin(detail::half2float(arg.data_)))); #else unsigned int abs = arg.data_ & 0x7FFF, sign = arg.data_ & 0x8000; if(!abs) return arg; if(abs >= 0x3C00) return half(detail::binary, (abs>0x7C00) ? detail::signal(arg.data_) : (abs>0x3C00) ? detail::invalid() : detail::rounded(sign|0x3E48, 0, 1)); if(abs < 0x2900) return half(detail::binary, detail::rounded(arg.data_, 0, 1)); if(half::round_style != std::round_to_nearest && (abs == 0x2B44 || abs == 0x2DC3)) return half(detail::binary, detail::rounded(arg.data_+1, 1, 1)); std::pair sc = detail::atan2_args(abs); detail::uint32 m = detail::atan2(sc.first, sc.second, (half::round_style==std::round_to_nearest) ? 27 : 26); return half(detail::binary, detail::fixed2half(m, 14, sign)); #endif } /// Arc cosine function. /// This function is exact to rounding for all rounding modes. /// /// **See also:** Documentation for [std::acos](https://en.cppreference.com/w/cpp/numeric/math/acos). /// \param arg function argument /// \return arc cosine value of \a arg /// \exception FE_INVALID for signaling NaN or if abs(\a arg) > 1 /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding inline half acos(half arg) { #ifdef HALF_ARITHMETIC_TYPE return half(detail::binary, detail::float2half(std::acos(detail::half2float(arg.data_)))); #else unsigned int abs = arg.data_ & 0x7FFF, sign = arg.data_ >> 15; if(!abs) return half(detail::binary, detail::rounded(0x3E48, 0, 1)); if(abs >= 0x3C00) return half(detail::binary, (abs>0x7C00) ? detail::signal(arg.data_) : (abs>0x3C00) ? detail::invalid() : sign ? detail::rounded(0x4248, 0, 1) : 0); std::pair cs = detail::atan2_args(abs); detail::uint32 m = detail::atan2(cs.second, cs.first, 28); return half(detail::binary, detail::fixed2half(sign ? (0xC90FDAA2-m) : m, 15, 0, sign)); #endif } /// Arc tangent function. /// This function is exact to rounding for all rounding modes. /// /// **See also:** Documentation for [std::atan](https://en.cppreference.com/w/cpp/numeric/math/atan). /// \param arg function argument /// \return arc tangent value of \a arg /// \exception FE_INVALID for signaling NaN /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding inline half atan(half arg) { #ifdef HALF_ARITHMETIC_TYPE return half(detail::binary, detail::float2half(std::atan(detail::half2float(arg.data_)))); #else unsigned int abs = arg.data_ & 0x7FFF, sign = arg.data_ & 0x8000; if(!abs) return arg; if(abs >= 0x7C00) return half(detail::binary, (abs==0x7C00) ? detail::rounded(sign|0x3E48, 0, 1) : detail::signal(arg.data_)); if(abs <= 0x2700) return half(detail::binary, detail::rounded(arg.data_-1, 1, 1)); int exp = (abs>>10) + (abs<=0x3FF); detail::uint32 my = (abs&0x3FF) | ((abs>0x3FF)<<10); detail::uint32 m = (exp>15) ? detail::atan2(my<<19, 0x20000000>>(exp-15), (half::round_style==std::round_to_nearest) ? 26 : 24) : detail::atan2(my<<(exp+4), 0x20000000, (half::round_style==std::round_to_nearest) ? 30 : 28); return half(detail::binary, detail::fixed2half(m, 14, sign)); #endif } /// Arc tangent function. /// This function may be 1 ULP off the correctly rounded exact result in ~0.005% of inputs for `std::round_to_nearest`, /// in ~0.1% of inputs for `std::round_toward_zero` and in ~0.02% of inputs for any other rounding mode. /// /// **See also:** Documentation for [std::atan2](https://en.cppreference.com/w/cpp/numeric/math/atan2). /// \param y numerator /// \param x denominator /// \return arc tangent value /// \exception FE_INVALID if \a x or \a y is signaling NaN /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding inline half atan2(half y, half x) { #ifdef HALF_ARITHMETIC_TYPE return half(detail::binary, detail::float2half(std::atan2(detail::half2float(y.data_), detail::half2float(x.data_)))); #else unsigned int absx = x.data_ & 0x7FFF, absy = y.data_ & 0x7FFF, signx = x.data_ >> 15, signy = y.data_ & 0x8000; if(absx >= 0x7C00 || absy >= 0x7C00) { if(absx > 0x7C00 || absy > 0x7C00) return half(detail::binary, detail::signal(x.data_, y.data_)); if(absy == 0x7C00) return half(detail::binary, (absx<0x7C00) ? detail::rounded(signy|0x3E48, 0, 1) : signx ? detail::rounded(signy|0x40B6, 0, 1) : detail::rounded(signy|0x3A48, 0, 1)); return (x.data_==0x7C00) ? half(detail::binary, signy) : half(detail::binary, detail::rounded(signy|0x4248, 0, 1)); } if(!absy) return signx ? half(detail::binary, detail::rounded(signy|0x4248, 0, 1)) : y; if(!absx) return half(detail::binary, detail::rounded(signy|0x3E48, 0, 1)); int d = (absy>>10) + (absy<=0x3FF) - (absx>>10) - (absx<=0x3FF); if(d > (signx ? 18 : 12)) return half(detail::binary, detail::rounded(signy|0x3E48, 0, 1)); if(signx && d < -11) return half(detail::binary, detail::rounded(signy|0x4248, 0, 1)); if(!signx && d < ((half::round_style==std::round_toward_zero) ? -15 : -9)) { for(; absy<0x400; absy<<=1,--d) ; detail::uint32 mx = ((absx<<1)&0x7FF) | 0x800, my = ((absy<<1)&0x7FF) | 0x800; int i = my < mx; d -= i; if(d < -25) return half(detail::binary, detail::underflow(signy)); my <<= 11 + i; return half(detail::binary, detail::fixed2half(my/mx, d+14, signy, my%mx!=0)); } detail::uint32 m = detail::atan2( ((absy&0x3FF)|((absy>0x3FF)<<10))<<(19+((d<0) ? d : (d>0) ? 0 : -1)), ((absx&0x3FF)|((absx>0x3FF)<<10))<<(19-((d>0) ? d : (d<0) ? 0 : 1))); return half(detail::binary, detail::fixed2half(signx ? (0xC90FDAA2-m) : m, 15, signy, signx)); #endif } /// \} /// \anchor hyperbolic /// \name Hyperbolic functions /// \{ /// Hyperbolic sine. /// This function is exact to rounding for all rounding modes. /// /// **See also:** Documentation for [std::sinh](https://en.cppreference.com/w/cpp/numeric/math/sinh). /// \param arg function argument /// \return hyperbolic sine value of \a arg /// \exception FE_INVALID for signaling NaN /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding inline half sinh(half arg) { #ifdef HALF_ARITHMETIC_TYPE return half(detail::binary, detail::float2half(std::sinh(detail::half2float(arg.data_)))); #else int abs = arg.data_ & 0x7FFF, exp; if(!abs || abs >= 0x7C00) return (abs>0x7C00) ? half(detail::binary, detail::signal(arg.data_)) : arg; if(abs <= 0x2900) return half(detail::binary, detail::rounded(arg.data_, 0, 1)); std::pair mm = detail::hyperbolic_args(abs, exp, (half::round_style==std::round_to_nearest) ? 29 : 27); detail::uint32 m = mm.first - mm.second; for(exp+=13; m<0x80000000 && exp; m<<=1,--exp) ; unsigned int sign = arg.data_ & 0x8000; if(exp > 29) return half(detail::binary, detail::overflow(sign)); return half(detail::binary, detail::fixed2half(m, exp, sign)); #endif } /// Hyperbolic cosine. /// This function is exact to rounding for all rounding modes. /// /// **See also:** Documentation for [std::cosh](https://en.cppreference.com/w/cpp/numeric/math/cosh). /// \param arg function argument /// \return hyperbolic cosine value of \a arg /// \exception FE_INVALID for signaling NaN /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding inline half cosh(half arg) { #ifdef HALF_ARITHMETIC_TYPE return half(detail::binary, detail::float2half(std::cosh(detail::half2float(arg.data_)))); #else int abs = arg.data_ & 0x7FFF, exp; if(!abs) return half(detail::binary, 0x3C00); if(abs >= 0x7C00) return half(detail::binary, (abs>0x7C00) ? detail::signal(arg.data_) : 0x7C00); std::pair mm = detail::hyperbolic_args(abs, exp, (half::round_style==std::round_to_nearest) ? 23 : 26); detail::uint32 m = mm.first + mm.second, i = (~m&0xFFFFFFFF) >> 31; m = (m>>i) | (m&i) | 0x80000000; if((exp+=13+i) > 29) return half(detail::binary, detail::overflow()); return half(detail::binary, detail::fixed2half(m, exp)); #endif } /// Hyperbolic tangent. /// This function is exact to rounding for all rounding modes. /// /// **See also:** Documentation for [std::tanh](https://en.cppreference.com/w/cpp/numeric/math/tanh). /// \param arg function argument /// \return hyperbolic tangent value of \a arg /// \exception FE_INVALID for signaling NaN /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding inline half tanh(half arg) { #ifdef HALF_ARITHMETIC_TYPE return half(detail::binary, detail::float2half(std::tanh(detail::half2float(arg.data_)))); #else int abs = arg.data_ & 0x7FFF, exp; if(!abs) return arg; if(abs >= 0x7C00) return half(detail::binary, (abs>0x7C00) ? detail::signal(arg.data_) : (arg.data_-0x4000)); if(abs >= 0x4500) return half(detail::binary, detail::rounded((arg.data_&0x8000)|0x3BFF, 1, 1)); if(abs < 0x2700) return half(detail::binary, detail::rounded(arg.data_-1, 1, 1)); if(half::round_style != std::round_to_nearest && abs == 0x2D3F) return half(detail::binary, detail::rounded(arg.data_-3, 0, 1)); std::pair mm = detail::hyperbolic_args(abs, exp, 27); detail::uint32 my = mm.first - mm.second - (half::round_style!=std::round_to_nearest), mx = mm.first + mm.second, i = (~mx&0xFFFFFFFF) >> 31; for(exp=13; my<0x80000000; my<<=1,--exp) ; mx = (mx>>i) | 0x80000000; return half(detail::binary, detail::tangent_post(my, mx, exp-i, arg.data_&0x8000)); #endif } /// Hyperbolic area sine. /// This function is exact to rounding for all rounding modes. /// /// **See also:** Documentation for [std::asinh](https://en.cppreference.com/w/cpp/numeric/math/asinh). /// \param arg function argument /// \return area sine value of \a arg /// \exception FE_INVALID for signaling NaN /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding inline half asinh(half arg) { #if defined(HALF_ARITHMETIC_TYPE) return half(detail::binary, detail::float2half(std::asinh(detail::half2float(arg.data_)))); #else int abs = arg.data_ & 0x7FFF; if(!abs || abs >= 0x7C00) return (abs>0x7C00) ? half(detail::binary, detail::signal(arg.data_)) : arg; if(abs <= 0x2900) return half(detail::binary, detail::rounded(arg.data_-1, 1, 1)); if(half::round_style != std::round_to_nearest) switch(abs) { case 0x32D4: return half(detail::binary, detail::rounded(arg.data_-13, 1, 1)); case 0x3B5B: return half(detail::binary, detail::rounded(arg.data_-197, 1, 1)); } return half(detail::binary, detail::area(arg.data_)); #endif } /// Hyperbolic area cosine. /// This function is exact to rounding for all rounding modes. /// /// **See also:** Documentation for [std::acosh](https://en.cppreference.com/w/cpp/numeric/math/acosh). /// \param arg function argument /// \return area cosine value of \a arg /// \exception FE_INVALID for signaling NaN or arguments <1 /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding inline half acosh(half arg) { #if defined(HALF_ARITHMETIC_TYPE) return half(detail::binary, detail::float2half(std::acosh(detail::half2float(arg.data_)))); #else int abs = arg.data_ & 0x7FFF; if((arg.data_&0x8000) || abs < 0x3C00) return half(detail::binary, (abs<=0x7C00) ? detail::invalid() : detail::signal(arg.data_)); if(abs == 0x3C00) return half(detail::binary, 0); if(arg.data_ >= 0x7C00) return (abs>0x7C00) ? half(detail::binary, detail::signal(arg.data_)) : arg; return half(detail::binary, detail::area(arg.data_)); #endif } /// Hyperbolic area tangent. /// This function is exact to rounding for all rounding modes. /// /// **See also:** Documentation for [std::atanh](https://en.cppreference.com/w/cpp/numeric/math/atanh). /// \param arg function argument /// \return area tangent value of \a arg /// \exception FE_INVALID for signaling NaN or if abs(\a arg) > 1 /// \exception FE_DIVBYZERO for +/-1 /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding inline half atanh(half arg) { #if defined(HALF_ARITHMETIC_TYPE) return half(detail::binary, detail::float2half(std::atanh(detail::half2float(arg.data_)))); #else int abs = arg.data_ & 0x7FFF, exp = 0; if(!abs) return arg; if(abs >= 0x3C00) return half(detail::binary, (abs==0x3C00) ? detail::pole(arg.data_&0x8000) : (abs<=0x7C00) ? detail::invalid() : detail::signal(arg.data_)); if(abs < 0x2700) return half(detail::binary, detail::rounded(arg.data_, 0, 1)); detail::uint32 m = static_cast((abs&0x3FF)|((abs>0x3FF)<<10)) << ((abs>>10)+(abs<=0x3FF)+6), my = 0x80000000 + m, mx = 0x80000000 - m; for(; mx<0x80000000; mx<<=1,++exp) ; int i = my >= mx, s; return half(detail::binary, detail::log2_post(detail::log2( (detail::divide64(my>>i, mx, s)+1)>>1, 27)+0x10, exp+i-1, 16, arg.data_&0x8000)); #endif } /// \} /// \anchor special /// \name Error and gamma functions /// \{ /// Error function. /// This function may be 1 ULP off the correctly rounded exact result for any rounding mode in <0.5% of inputs. /// /// **See also:** Documentation for [std::erf](https://en.cppreference.com/w/cpp/numeric/math/erf). /// \param arg function argument /// \return error function value of \a arg /// \exception FE_INVALID for signaling NaN /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding inline half erf(half arg) { #if defined(HALF_ARITHMETIC_TYPE) return half(detail::binary, detail::float2half(std::erf(detail::half2float(arg.data_)))); #else unsigned int abs = arg.data_ & 0x7FFF; if(!abs || abs >= 0x7C00) return (abs>=0x7C00) ? half(detail::binary, (abs==0x7C00) ? (arg.data_-0x4000) : detail::signal(arg.data_)) : arg; if(abs >= 0x4200) return half(detail::binary, detail::rounded((arg.data_&0x8000)|0x3BFF, 1, 1)); return half(detail::binary, detail::erf(arg.data_)); #endif } /// Complementary error function. /// This function may be 1 ULP off the correctly rounded exact result for any rounding mode in <0.5% of inputs. /// /// **See also:** Documentation for [std::erfc](https://en.cppreference.com/w/cpp/numeric/math/erfc). /// \param arg function argument /// \return 1 minus error function value of \a arg /// \exception FE_INVALID for signaling NaN /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding inline half erfc(half arg) { #if defined(HALF_ARITHMETIC_TYPE) return half(detail::binary, detail::float2half(std::erfc(detail::half2float(arg.data_)))); #else unsigned int abs = arg.data_ & 0x7FFF, sign = arg.data_ & 0x8000; if(abs >= 0x7C00) return (abs>=0x7C00) ? half(detail::binary, (abs==0x7C00) ? (sign>>1) : detail::signal(arg.data_)) : arg; if(!abs) return half(detail::binary, 0x3C00); if(abs >= 0x4400) return half(detail::binary, detail::rounded((sign>>1)-(sign>>15), sign>>15, 1)); return half(detail::binary, detail::erf(arg.data_)); #endif } /// Natural logarithm of gamma function. /// This function may be 1 ULP off the correctly rounded exact result for any rounding mode in ~0.025% of inputs. /// /// **See also:** Documentation for [std::lgamma](https://en.cppreference.com/w/cpp/numeric/math/lgamma). /// \param arg function argument /// \return natural logarith of gamma function for \a arg /// \exception FE_INVALID for signaling NaN /// \exception FE_DIVBYZERO for 0 or negative integer arguments /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding inline half lgamma(half arg) { #if defined(HALF_ARITHMETIC_TYPE) return half(detail::binary, detail::float2half(std::lgamma(detail::half2float(arg.data_)))); #else int abs = arg.data_ & 0x7FFF; if(abs >= 0x7C00) return half(detail::binary, (abs==0x7C00) ? 0x7C00 : detail::signal(arg.data_)); if(!abs || arg.data_ >= 0xE400 || (arg.data_ >= 0xBC00 && !(abs&((1<<(25-(abs>>10)))-1)))) return half(detail::binary, detail::pole()); if(arg.data_ == 0x3C00 || arg.data_ == 0x4000) return half(detail::binary, 0); return half(detail::binary, detail::gamma(arg.data_)); #endif } /// Gamma function. /// This function may be 1 ULP off the correctly rounded exact result for any rounding mode in <0.25% of inputs. /// /// **See also:** Documentation for [std::tgamma](https://en.cppreference.com/w/cpp/numeric/math/tgamma). /// \param arg function argument /// \return gamma function value of \a arg /// \exception FE_INVALID for signaling NaN, negative infinity or negative integer arguments /// \exception FE_DIVBYZERO for 0 /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding inline half tgamma(half arg) { #if defined(HALF_ARITHMETIC_TYPE) return half(detail::binary, detail::float2half(std::tgamma(detail::half2float(arg.data_)))); #else unsigned int abs = arg.data_ & 0x7FFF; if(!abs) return half(detail::binary, detail::pole(arg.data_)); if(abs >= 0x7C00) return (arg.data_==0x7C00) ? arg : half(detail::binary, detail::signal(arg.data_)); if(arg.data_ >= 0xE400 || (arg.data_ >= 0xBC00 && !(abs&((1<<(25-(abs>>10)))-1)))) return half(detail::binary, detail::invalid()); if(arg.data_ >= 0xCA80) return half(detail::binary, detail::underflow((1-((abs>>(25-(abs>>10)))&1))<<15)); if(arg.data_ <= 0x100 || (arg.data_ >= 0x4900 && arg.data_ < 0x8000)) return half(detail::binary, detail::overflow()); if(arg.data_ == 0x3C00) return arg; return half(detail::binary, detail::gamma(arg.data_)); #endif } /// \} /// \anchor rounding /// \name Rounding /// \{ /// Nearest integer not less than half value. /// **See also:** Documentation for [std::ceil](https://en.cppreference.com/w/cpp/numeric/math/ceil). /// \param arg half to round /// \return nearest integer not less than \a arg /// \exception FE_INVALID for signaling NaN /// \exception FE_INEXACT if value had to be rounded inline half ceil(half arg) { return half(detail::binary, detail::integral(arg.data_)); } /// Nearest integer not greater than half value. /// **See also:** Documentation for [std::floor](https://en.cppreference.com/w/cpp/numeric/math/floor). /// \param arg half to round /// \return nearest integer not greater than \a arg /// \exception FE_INVALID for signaling NaN /// \exception FE_INEXACT if value had to be rounded inline half floor(half arg) { return half(detail::binary, detail::integral(arg.data_)); } /// Nearest integer not greater in magnitude than half value. /// **See also:** Documentation for [std::trunc](https://en.cppreference.com/w/cpp/numeric/math/trunc). /// \param arg half to round /// \return nearest integer not greater in magnitude than \a arg /// \exception FE_INVALID for signaling NaN /// \exception FE_INEXACT if value had to be rounded inline half trunc(half arg) { return half(detail::binary, detail::integral(arg.data_)); } /// Nearest integer. /// **See also:** Documentation for [std::round](https://en.cppreference.com/w/cpp/numeric/math/round). /// \param arg half to round /// \return nearest integer, rounded away from zero in half-way cases /// \exception FE_INVALID for signaling NaN /// \exception FE_INEXACT if value had to be rounded inline half round(half arg) { return half(detail::binary, detail::integral(arg.data_)); } /// Nearest integer. /// **See also:** Documentation for [std::lround](https://en.cppreference.com/w/cpp/numeric/math/round). /// \param arg half to round /// \return nearest integer, rounded away from zero in half-way cases /// \exception FE_INVALID if value is not representable as `long` inline long lround(half arg) { return detail::half2int(arg.data_); } /// Nearest integer using half's internal rounding mode. /// **See also:** Documentation for [std::rint](https://en.cppreference.com/w/cpp/numeric/math/rint). /// \param arg half expression to round /// \return nearest integer using default rounding mode /// \exception FE_INVALID for signaling NaN /// \exception FE_INEXACT if value had to be rounded inline half rint(half arg) { return half(detail::binary, detail::integral(arg.data_)); } /// Nearest integer using half's internal rounding mode. /// **See also:** Documentation for [std::lrint](https://en.cppreference.com/w/cpp/numeric/math/rint). /// \param arg half expression to round /// \return nearest integer using default rounding mode /// \exception FE_INVALID if value is not representable as `long` /// \exception FE_INEXACT if value had to be rounded inline long lrint(half arg) { return detail::half2int(arg.data_); } /// Nearest integer using half's internal rounding mode. /// **See also:** Documentation for [std::nearbyint](https://en.cppreference.com/w/cpp/numeric/math/nearbyint). /// \param arg half expression to round /// \return nearest integer using default rounding mode /// \exception FE_INVALID for signaling NaN inline half nearbyint(half arg) { return half(detail::binary, detail::integral(arg.data_)); } /// Nearest integer. /// **See also:** Documentation for [std::llround](https://en.cppreference.com/w/cpp/numeric/math/round). /// \param arg half to round /// \return nearest integer, rounded away from zero in half-way cases /// \exception FE_INVALID if value is not representable as `long long` inline long long llround(half arg) { return detail::half2int(arg.data_); } /// Nearest integer using half's internal rounding mode. /// **See also:** Documentation for [std::llrint](https://en.cppreference.com/w/cpp/numeric/math/rint). /// \param arg half expression to round /// \return nearest integer using default rounding mode /// \exception FE_INVALID if value is not representable as `long long` /// \exception FE_INEXACT if value had to be rounded inline long long llrint(half arg) { return detail::half2int(arg.data_); } /// \} /// \anchor float /// \name Floating point manipulation /// \{ /// Decompress floating-point number. /// **See also:** Documentation for [std::frexp](https://en.cppreference.com/w/cpp/numeric/math/frexp). /// \param arg number to decompress /// \param exp address to store exponent at /// \return significant in range [0.5, 1) /// \exception FE_INVALID for signaling NaN inline half frexp(half arg, int *exp) { *exp = 0; unsigned int abs = arg.data_ & 0x7FFF; if(abs >= 0x7C00 || !abs) return (abs>0x7C00) ? half(detail::binary, detail::signal(arg.data_)) : arg; for(; abs<0x400; abs<<=1,--*exp) ; *exp += (abs>>10) - 14; return half(detail::binary, (arg.data_&0x8000)|0x3800|(abs&0x3FF)); } /// Multiply by power of two. /// This function is exact to rounding for all rounding modes. /// /// **See also:** Documentation for [std::scalbln](https://en.cppreference.com/w/cpp/numeric/math/scalbn). /// \param arg number to modify /// \param exp power of two to multiply with /// \return \a arg multplied by 2 raised to \a exp /// \exception FE_INVALID for signaling NaN /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding inline half scalbln(half arg, long exp) { unsigned int abs = arg.data_ & 0x7FFF, sign = arg.data_ & 0x8000; if(abs >= 0x7C00 || !abs) return (abs>0x7C00) ? half(detail::binary, detail::signal(arg.data_)) : arg; for(; abs<0x400; abs<<=1,--exp) ; exp += abs >> 10; if(exp > 30) return half(detail::binary, detail::overflow(sign)); else if(exp < -10) return half(detail::binary, detail::underflow(sign)); else if(exp > 0) return half(detail::binary, sign|(exp<<10)|(abs&0x3FF)); unsigned int m = (abs&0x3FF) | 0x400; return half(detail::binary, detail::rounded(sign|(m>>(1-exp)), (m>>-exp)&1, (m&((1<<-exp)-1))!=0)); } /// Multiply by power of two. /// This function is exact to rounding for all rounding modes. /// /// **See also:** Documentation for [std::scalbn](https://en.cppreference.com/w/cpp/numeric/math/scalbn). /// \param arg number to modify /// \param exp power of two to multiply with /// \return \a arg multplied by 2 raised to \a exp /// \exception FE_INVALID for signaling NaN /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding inline half scalbn(half arg, int exp) { return scalbln(arg, exp); } /// Multiply by power of two. /// This function is exact to rounding for all rounding modes. /// /// **See also:** Documentation for [std::ldexp](https://en.cppreference.com/w/cpp/numeric/math/ldexp). /// \param arg number to modify /// \param exp power of two to multiply with /// \return \a arg multplied by 2 raised to \a exp /// \exception FE_INVALID for signaling NaN /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding inline half ldexp(half arg, int exp) { return scalbln(arg, exp); } /// Extract integer and fractional parts. /// **See also:** Documentation for [std::modf](https://en.cppreference.com/w/cpp/numeric/math/modf). /// \param arg number to decompress /// \param iptr address to store integer part at /// \return fractional part /// \exception FE_INVALID for signaling NaN inline half modf(half arg, half *iptr) { unsigned int abs = arg.data_ & 0x7FFF; if(abs > 0x7C00) { arg = half(detail::binary, detail::signal(arg.data_)); return *iptr = arg, arg; } if(abs >= 0x6400) return *iptr = arg, half(detail::binary, arg.data_&0x8000); if(abs < 0x3C00) return iptr->data_ = arg.data_ & 0x8000, arg; unsigned int exp = abs >> 10, mask = (1<<(25-exp)) - 1, m = arg.data_ & mask; iptr->data_ = arg.data_ & ~mask; if(!m) return half(detail::binary, arg.data_&0x8000); for(; m<0x400; m<<=1,--exp) ; return half(detail::binary, (arg.data_&0x8000)|(exp<<10)|(m&0x3FF)); } /// Extract exponent. /// **See also:** Documentation for [std::ilogb](https://en.cppreference.com/w/cpp/numeric/math/ilogb). /// \param arg number to query /// \return floating-point exponent /// \retval FP_ILOGB0 for zero /// \retval FP_ILOGBNAN for NaN /// \retval INT_MAX for infinity /// \exception FE_INVALID for 0 or infinite values inline int ilogb(half arg) { int abs = arg.data_ & 0x7FFF, exp; if(!abs || abs >= 0x7C00) { detail::raise(FE_INVALID); return !abs ? FP_ILOGB0 : (abs==0x7C00) ? INT_MAX : FP_ILOGBNAN; } for(exp=(abs>>10)-15; abs<0x200; abs<<=1,--exp) ; return exp; } /// Extract exponent. /// **See also:** Documentation for [std::logb](https://en.cppreference.com/w/cpp/numeric/math/logb). /// \param arg number to query /// \return floating-point exponent /// \exception FE_INVALID for signaling NaN /// \exception FE_DIVBYZERO for 0 inline half logb(half arg) { int abs = arg.data_ & 0x7FFF, exp; if(!abs) return half(detail::binary, detail::pole(0x8000)); if(abs >= 0x7C00) return half(detail::binary, (abs==0x7C00) ? 0x7C00 : detail::signal(arg.data_)); for(exp=(abs>>10)-15; abs<0x200; abs<<=1,--exp) ; unsigned int value = static_cast(exp<0) << 15; if(exp) { unsigned int m = std::abs(exp) << 6; for(exp=18; m<0x400; m<<=1,--exp) ; value |= (exp<<10) + m; } return half(detail::binary, value); } /// Next representable value. /// **See also:** Documentation for [std::nextafter](https://en.cppreference.com/w/cpp/numeric/math/nextafter). /// \param from value to compute next representable value for /// \param to direction towards which to compute next value /// \return next representable value after \a from in direction towards \a to /// \exception FE_INVALID for signaling NaN /// \exception FE_OVERFLOW for infinite result from finite argument /// \exception FE_UNDERFLOW for subnormal result inline half nextafter(half from, half to) { int fabs = from.data_ & 0x7FFF, tabs = to.data_ & 0x7FFF; if(fabs > 0x7C00 || tabs > 0x7C00) return half(detail::binary, detail::signal(from.data_, to.data_)); if(from.data_ == to.data_ || !(fabs|tabs)) return to; if(!fabs) { detail::raise(FE_UNDERFLOW, !HALF_ERRHANDLING_UNDERFLOW_TO_INEXACT); return half(detail::binary, (to.data_&0x8000)+1); } unsigned int out = from.data_ + (((from.data_>>15)^static_cast( (from.data_^(0x8000|(0x8000-(from.data_>>15))))<(to.data_^(0x8000|(0x8000-(to.data_>>15))))))<<1) - 1; detail::raise(FE_OVERFLOW, fabs<0x7C00 && (out&0x7C00)==0x7C00); detail::raise(FE_UNDERFLOW, !HALF_ERRHANDLING_UNDERFLOW_TO_INEXACT && (out&0x7C00)<0x400); return half(detail::binary, out); } /// Next representable value. /// **See also:** Documentation for [std::nexttoward](https://en.cppreference.com/w/cpp/numeric/math/nexttoward). /// \param from value to compute next representable value for /// \param to direction towards which to compute next value /// \return next representable value after \a from in direction towards \a to /// \exception FE_INVALID for signaling NaN /// \exception FE_OVERFLOW for infinite result from finite argument /// \exception FE_UNDERFLOW for subnormal result inline half nexttoward(half from, long double to) { int fabs = from.data_ & 0x7FFF; if(fabs > 0x7C00) return half(detail::binary, detail::signal(from.data_)); long double lfrom = static_cast(from); if(detail::builtin_isnan(to) || lfrom == to) return half(static_cast(to)); if(!fabs) { detail::raise(FE_UNDERFLOW, !HALF_ERRHANDLING_UNDERFLOW_TO_INEXACT); return half(detail::binary, (static_cast(detail::builtin_signbit(to))<<15)+1); } unsigned int out = from.data_ + (((from.data_>>15)^static_cast(lfrom 0x7C00; } /// Check if normal number. /// **See also:** Documentation for [std::isnormal](https://en.cppreference.com/w/cpp/numeric/math/isnormal). /// \param arg number to check /// \retval true if normal number /// \retval false if either subnormal, zero, infinity or NaN inline constexpr bool isnormal(half arg) { return ((arg.data_&0x7C00)!=0) & ((arg.data_&0x7C00)!=0x7C00); } /// Check sign. /// **See also:** Documentation for [std::signbit](https://en.cppreference.com/w/cpp/numeric/math/signbit). /// \param arg number to check /// \retval true for negative number /// \retval false for positive number inline constexpr bool signbit(half arg) { return (arg.data_&0x8000) != 0; } /// \} /// \anchor compfunc /// \name Comparison /// \{ /// Quiet comparison for greater than. /// **See also:** Documentation for [std::isgreater](https://en.cppreference.com/w/cpp/numeric/math/isgreater). /// \param x first operand /// \param y second operand /// \retval true if \a x greater than \a y /// \retval false else inline constexpr bool isgreater(half x, half y) { return ((x.data_^(0x8000|(0x8000-(x.data_>>15))))+(x.data_>>15)) > ((y.data_^(0x8000|(0x8000-(y.data_>>15))))+(y.data_>>15)) && !isnan(x) && !isnan(y); } /// Quiet comparison for greater equal. /// **See also:** Documentation for [std::isgreaterequal](https://en.cppreference.com/w/cpp/numeric/math/isgreaterequal). /// \param x first operand /// \param y second operand /// \retval true if \a x greater equal \a y /// \retval false else inline constexpr bool isgreaterequal(half x, half y) { return ((x.data_^(0x8000|(0x8000-(x.data_>>15))))+(x.data_>>15)) >= ((y.data_^(0x8000|(0x8000-(y.data_>>15))))+(y.data_>>15)) && !isnan(x) && !isnan(y); } /// Quiet comparison for less than. /// **See also:** Documentation for [std::isless](https://en.cppreference.com/w/cpp/numeric/math/isless). /// \param x first operand /// \param y second operand /// \retval true if \a x less than \a y /// \retval false else inline constexpr bool isless(half x, half y) { return ((x.data_^(0x8000|(0x8000-(x.data_>>15))))+(x.data_>>15)) < ((y.data_^(0x8000|(0x8000-(y.data_>>15))))+(y.data_>>15)) && !isnan(x) && !isnan(y); } /// Quiet comparison for less equal. /// **See also:** Documentation for [std::islessequal](https://en.cppreference.com/w/cpp/numeric/math/islessequal). /// \param x first operand /// \param y second operand /// \retval true if \a x less equal \a y /// \retval false else inline constexpr bool islessequal(half x, half y) { return ((x.data_^(0x8000|(0x8000-(x.data_>>15))))+(x.data_>>15)) <= ((y.data_^(0x8000|(0x8000-(y.data_>>15))))+(y.data_>>15)) && !isnan(x) && !isnan(y); } /// Quiet comarison for less or greater. /// **See also:** Documentation for [std::islessgreater](https://en.cppreference.com/w/cpp/numeric/math/islessgreater). /// \param x first operand /// \param y second operand /// \retval true if either less or greater /// \retval false else inline constexpr bool islessgreater(half x, half y) { return x.data_!=y.data_ && ((x.data_|y.data_)&0x7FFF) && !isnan(x) && !isnan(y); } /// Quiet check if unordered. /// **See also:** Documentation for [std::isunordered](https://en.cppreference.com/w/cpp/numeric/math/isunordered). /// \param x first operand /// \param y second operand /// \retval true if unordered (one or two NaN operands) /// \retval false else inline constexpr bool isunordered(half x, half y) { return isnan(x) || isnan(y); } /// \} /// \anchor casting /// \name Casting /// \{ /// Cast to or from half-precision floating-point number. /// This casts between [half](\ref half_float::half) and any built-in arithmetic type. The values are converted /// directly using the default rounding mode, without any roundtrip over `float` that a `static_cast` would otherwise do. /// /// Using this cast with neither of the two types being a [half](\ref half_float::half) or with any of the two types /// not being a built-in arithmetic type (apart from [half](\ref half_float::half), of course) results in a compiler /// error and casting between [half](\ref half_float::half)s returns the argument unmodified. /// \tparam T destination type (half or built-in arithmetic type) /// \tparam U source type (half or built-in arithmetic type) /// \param arg value to cast /// \return \a arg converted to destination type /// \exception FE_INVALID if \a T is integer type and result is not representable as \a T /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding template T half_cast(U arg) { return detail::half_caster::cast(arg); } /// Cast to or from half-precision floating-point number. /// This casts between [half](\ref half_float::half) and any built-in arithmetic type. The values are converted /// directly using the specified rounding mode, without any roundtrip over `float` that a `static_cast` would otherwise do. /// /// Using this cast with neither of the two types being a [half](\ref half_float::half) or with any of the two types /// not being a built-in arithmetic type (apart from [half](\ref half_float::half), of course) results in a compiler /// error and casting between [half](\ref half_float::half)s returns the argument unmodified. /// \tparam T destination type (half or built-in arithmetic type) /// \tparam R rounding mode to use. /// \tparam U source type (half or built-in arithmetic type) /// \param arg value to cast /// \return \a arg converted to destination type /// \exception FE_INVALID if \a T is integer type and result is not representable as \a T /// \exception FE_OVERFLOW, ...UNDERFLOW, ...INEXACT according to rounding template T half_cast(U arg) { return detail::half_caster::cast(arg); } /// \} /// \} /// \anchor errors /// \name Error handling /// \{ /// Clear exception flags. /// This function works even if [automatic exception flag handling](\ref HALF_ERRHANDLING_FLAGS) is disabled, /// but in that case manual flag management is the only way to raise flags. /// /// **See also:** Documentation for [std::feclearexcept](https://en.cppreference.com/w/cpp/numeric/fenv/feclearexcept). /// \param excepts OR of exceptions to clear /// \retval 0 all selected flags cleared successfully inline int feclearexcept(int excepts) { detail::errflags() &= ~excepts; return 0; } /// Test exception flags. /// This function works even if [automatic exception flag handling](\ref HALF_ERRHANDLING_FLAGS) is disabled, /// but in that case manual flag management is the only way to raise flags. /// /// **See also:** Documentation for [std::fetestexcept](https://en.cppreference.com/w/cpp/numeric/fenv/fetestexcept). /// \param excepts OR of exceptions to test /// \return OR of selected exceptions if raised inline int fetestexcept(int excepts) { return detail::errflags() & excepts; } /// Raise exception flags. /// This raises the specified floating point exceptions and also invokes any additional automatic exception handling as /// configured with the [HALF_ERRHANDLIG_...](\ref HALF_ERRHANDLING_ERRNO) preprocessor symbols. /// This function works even if [automatic exception flag handling](\ref HALF_ERRHANDLING_FLAGS) is disabled, /// but in that case manual flag management is the only way to raise flags. /// /// **See also:** Documentation for [std::feraiseexcept](https://en.cppreference.com/w/cpp/numeric/fenv/feraiseexcept). /// \param excepts OR of exceptions to raise /// \retval 0 all selected exceptions raised successfully inline int feraiseexcept(int excepts) { detail::errflags() |= excepts; detail::raise(excepts); return 0; } /// Save exception flags. /// This function works even if [automatic exception flag handling](\ref HALF_ERRHANDLING_FLAGS) is disabled, /// but in that case manual flag management is the only way to raise flags. /// /// **See also:** Documentation for [std::fegetexceptflag](https://en.cppreference.com/w/cpp/numeric/fenv/feexceptflag). /// \param flagp adress to store flag state at /// \param excepts OR of flags to save /// \retval 0 for success inline int fegetexceptflag(int *flagp, int excepts) { *flagp = detail::errflags() & excepts; return 0; } /// Restore exception flags. /// This only copies the specified exception state (including unset flags) without incurring any additional exception handling. /// This function works even if [automatic exception flag handling](\ref HALF_ERRHANDLING_FLAGS) is disabled, /// but in that case manual flag management is the only way to raise flags. /// /// **See also:** Documentation for [std::fesetexceptflag](https://en.cppreference.com/w/cpp/numeric/fenv/feexceptflag). /// \param flagp adress to take flag state from /// \param excepts OR of flags to restore /// \retval 0 for success inline int fesetexceptflag(const int *flagp, int excepts) { detail::errflags() = (detail::errflags()|(*flagp&excepts)) & (*flagp|~excepts); return 0; } /// Throw C++ exceptions based on set exception flags. /// This function manually throws a corresponding C++ exception if one of the specified flags is set, /// no matter if automatic throwing (via [HALF_ERRHANDLING_THROW_...](\ref HALF_ERRHANDLING_THROW_INVALID)) is enabled or not. /// This function works even if [automatic exception flag handling](\ref HALF_ERRHANDLING_FLAGS) is disabled, /// but in that case manual flag management is the only way to raise flags. /// \param excepts OR of exceptions to test /// \param msg error message to use for exception description /// \throw std::domain_error if `FE_INVALID` or `FE_DIVBYZERO` is selected and set /// \throw std::overflow_error if `FE_OVERFLOW` is selected and set /// \throw std::underflow_error if `FE_UNDERFLOW` is selected and set /// \throw std::range_error if `FE_INEXACT` is selected and set inline void fethrowexcept(int excepts, const char *msg = "") { excepts &= detail::errflags(); if(excepts & (FE_INVALID|FE_DIVBYZERO)) throw std::domain_error(msg); if(excepts & FE_OVERFLOW) throw std::overflow_error(msg); if(excepts & FE_UNDERFLOW) throw std::underflow_error(msg); if(excepts & FE_INEXACT) throw std::range_error(msg); } /// \} } #undef HALF_UNUSED_NOERR #undef constexpr_NOERR #undef HALF_TWOS_COMPLEMENT_INT #ifdef HALF_POP_WARNINGS #pragma warning(pop) #undef HALF_POP_WARNINGS #endifxtl-0.7.2/include/xtl/xhash.hpp000066400000000000000000000145661400411521700164140ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * * Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XTL_HASH_HPP #define XTL_HASH_HPP #include #include #include #include namespace xtl { std::size_t hash_bytes(const void* buffer, std::size_t length, std::size_t seed); uint32_t murmur2_x86(const void* buffer, std::size_t length, uint32_t seed); uint64_t murmur2_x64(const void* buffer, std::size_t length, uint64_t seed); /****************************** * hash_bytes implementation * ******************************/ namespace detail { // Dummy hash implementation for unusual sizeof(std::size_t) template std::size_t murmur_hash(const void* buffer, std::size_t length, std::size_t seed) { std::size_t hash = seed; const char* data = static_cast(buffer); for (; length != 0; --length) { hash = (hash * 131) + static_cast(*data++); } return hash; } // Murmur hash is an algorithm written by Austin Appleby. See https://github.com/aappleby/smhasher/blob/master/src/MurmurHash2.cpp inline uint32_t murmur2_x86_impl(const void* buffer, std::size_t length, uint32_t seed) { const uint32_t m = 0x5bd1e995; uint32_t len = static_cast(length); // Initialize the hash to a 'random' value uint32_t h = seed ^ len; // Mix 4 bytes at a time into the hash const unsigned char * data = (const unsigned char *)buffer; while(len >= 4) { uint32_t k = *(uint32_t*)data; k *= m; k ^= k >> 24; k *= m; h *= m; h ^= k; data += 4; len -= 4; } // Handle the last few bytes of the input array switch(len) { case 3: h ^= static_cast(data[2] << 16); case 2: h ^= static_cast(data[1] << 8); case 1: h ^= static_cast(data[0]); h *= m; }; // Do a few final mixes of the hash to ensure the last few // // bytes are well-incorporated. h ^= h >> 13; h *= m; h ^= h >> 15; return h; } template <> inline std::size_t murmur_hash<4>(const void* buffer, std::size_t length, std::size_t seed) { return std::size_t(murmur2_x86_impl(buffer, length, static_cast(seed))); } inline std::size_t load_bytes(const char* p, int n) { std::size_t result = 0; --n; do { result = (result << 8) + static_cast(p[n]); } while (--n >= 0); return result; } #if INTPTR_MAX == INT64_MAX // 64-bits hash for 64-bits platform template <> inline std::size_t murmur_hash<8>(const void* buffer, std::size_t length, std::size_t seed) { constexpr std::size_t m = (static_cast(0xc6a4a793UL) << 32UL) + static_cast(0x5bd1e995UL); constexpr int r = 47; const char* data = static_cast(buffer); const char* end = data + (length & std::size_t(~0x7)); std::size_t hash = seed ^ (length * m); while (data != end) { std::size_t k; std::memcpy(&k, data, sizeof(k)); k *= m; k ^= k >> r; k *= m; hash ^= k; hash *= m; data += 8; } if ((length & 0x7) != 0) { std::size_t k = load_bytes(end, length & 0x7); hash ^= k; hash *= m; } hash ^= hash >> r; hash *= m; hash ^= hash >> r; return hash; } #elif INTPTR_MAX == INT32_MAX //64-bits hash for 32-bits platform inline void mmix(uint32_t& h, uint32_t& k, uint32_t m, int r) { k *= m; k ^= k >> r; k *= m; h *= m; h ^= k; } template <> inline std::size_t murmur_hash<8>(const void* buffer, std::size_t length, std::size_t seed) { const uint32_t m = 0x5bd1e995; const int r = 24; uint32_t l = length; const auto* data = reinterpret_cast(buffer); uint32_t h = seed; while (length >= 4) { uint32_t k = *(uint32_t*)data; mmix(h, k, m, r); data += 4; length -= 4; } uint32_t t = 0; switch (length) { case 3: t ^= data[2] << 16; case 2: t ^= data[1] << 8; case 1: t ^= data[0]; }; mmix(h, t, m, r); mmix(h, l, m, r); h ^= h >> 13; h *= m; h ^= h >> 15; return h; } #else #error Unknown pointer size or missing size macros! #endif } inline std::size_t hash_bytes(const void* buffer, std::size_t length, std::size_t seed) { return detail::murmur_hash(buffer, length, seed); } inline uint32_t murmur2_x86(const void* buffer, std::size_t length, uint32_t seed) { return detail::murmur2_x86_impl(buffer, length, seed); } inline uint64_t murmur2_x64(const void* buffer, std::size_t length, uint64_t seed) { return detail::murmur_hash<8>(buffer, length, seed); } } #endif xtl-0.7.2/include/xtl/xhierarchy_generator.hpp000066400000000000000000000045321400411521700215050ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * * Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XTL_HIERARCHY_GENERATOR_HPP #define XTL_HIERARCHY_GENERATOR_HPP #include "xmeta_utils.hpp" namespace xtl { /********************************* * scattered hierarchy generator * *********************************/ template class U> class xscatter_hierarchy_generator; template