diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..6b96ea34 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +out/pdf/sycl-1.2.1.pdf filter=lfs diff=lfs merge=lfs -text diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..a11610bd --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1 @@ +A reminder that this issue tracker is managed by the Khronos Group. Interactions here should follow the Khronos Code of Conduct (https://www.khronos.org/developers/code-of-conduct), which prohibits aggressive or derogatory language. Please keep the discussion friendly and civil. diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt new file mode 100644 index 00000000..9c993d47 --- /dev/null +++ b/COPYRIGHT.txt @@ -0,0 +1,35 @@ +Copyright (c) 2011-2021 The Khronos Group, Inc. + +This specification is protected by copyright laws and contains material proprietary +to Khronos. Except as described by these terms, it or any components +may not be reproduced, republished, distributed, transmitted, displayed, broadcast +or otherwise exploited in any manner without the express prior written permission +of Khronos. + +Khronos grants a conditional copyright license to use and reproduce the +unmodified Specification for any purpose, without fee or royalty, EXCEPT no licenses +to any patent, trademark or other intellectual property rights are granted under these +terms. Parties desiring to implement the specification and make use of Khronos trademarks +in relation to that implementation, and receive reciprocal patent license protection under +the Khronos IP Policy must become Adopters and confirm the implementation as conformant under +the process defined by Khronos for this specification; see https://www.khronos.org/adopters. + +Khronos makes no, and expressly disclaims any, representations or warranties, +express or implied, regarding this specification, including, without limitation: +merchantability, fitness for a particular purpose, non-infringement of any +intellectual property, correctness, accuracy, completeness, timeliness, and +reliability. Under no circumstances will Khronos, or any of its Promoters, +Contributors or Members, or their respective partners, officers, directors, +employees, agents or representatives be liable for any damages, whether direct, +indirect, special or consequential damages for lost revenues, lost profits, or +otherwise, arising from or in connection with these materials. + +Vulkan is a registered trademark and Khronos, OpenXR, SPIR, SPIR-V, SYCL, WebGL, +WebCL, OpenVX, OpenVG, EGL, COLLADA, glTF, NNEF, OpenKODE, OpenKCAM, StreamInput, +OpenWF, OpenSL ES, OpenMAX, OpenMAX AL, OpenMAX IL, OpenMAX DL, OpenML and DevU are +trademarks of The Khronos Group, Inc. ASTC is a trademark of ARM Holdings PLC, +OpenCL is a trademark of Apple Inc. and OpenGL and OpenML are registered trademarks +and the OpenGL ES and OpenGL SC logos are trademarks of Hewlett Packard Enterprise +all used under license by Khronos. All other product names, trademarks, +and/or company names are used solely for identification and belong to their +respective owners. diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 00000000..54cbc384 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,29 @@ +Copyright (c) 2011-2021 The Khronos Group, Inc. + +The files in, and generated output documents from this SYCL-Docs project are +under a mix of copyright and license statements. Refer to the individual files +for specific information. As a general guideline: + +- the AsciiDoctor sources for the SYCL Specifications and other documention + such are the SYCL code samples + are under the Creative Commons Attribution 4.0 International (CC BY 4.0) + license. Details of the license are at: + https://creativecommons.org/licenses/by/4.0/ + +- the source files for building the specification, such as Makefiles + and some scripts, the SYCL headers and the SYCL code samples are + under the Apache 2.0 license. Details of the license are at: + https://www.apache.org/licenses/LICENSE-2.0.html + +Unless required by applicable law or agreed to in writing, material distributed +under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +CONDITIONS OF ANY KIND, either express or implied. If all or a portion of this +material is re-used, notice substantially similar to the following must be included: + + This SYCL specification includes material developed at The Khronos Group + (http://www.khronos.org/). Khronos supplied such material on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, under + the terms of the Creative Commons Attribution 4.0 International (CC BY 4.0) + License (the "License"), available at https://creativecommons.org/licenses/by/4.0/. + All use of such material is governed by the term of the License. Khronos bears + no responsibility whatsoever for additions or modifications to its material. diff --git a/README.md b/README.md new file mode 100644 index 00000000..069b1b63 --- /dev/null +++ b/README.md @@ -0,0 +1,161 @@ +![SYCL Logo](adoc/logos/SYCL_RGB_June16-inkscape-1500.png) + +[//]: # "to update to newer CI when going public ![Build Status](https://api.travis-ci.com/KhronosGroup/SYCL-Docs.svg?branch=master)"" +[//]: # "to update to newer CI when going public [![SPEC master](https://img.shields.io/badge/SPEC-master-red.svg?logo=adobe-acrobat-reader)](https://khronosgroup.github.io/SYCL-Docs/sycl/sycl.pdf)" +[![SPEC master](https://img.shields.io/badge/SPEC-master-red.svg?logo=adobe-acrobat-reader)](https://gitlab.khronos.org/sycl/Specification/-/jobs) +[![SPEC 2020-1](https://img.shields.io/badge/SPEC-2020--1-orange.svg?logo=adobe-acrobat-reader)](https://www.khronos.org/registry/SYCL/specs/sycl-2020-provisional.pdf) +[![Join the Slack group](https://img.shields.io/badge/chat-on%20slack-blue.svg?logo=slack)](https://khr.io/slack) + +# SYCL Open Source Specification + +This repository contains the source and tool chain used to generate +the formal SYCL specifications found on [https://www.khronos.org/sycl/](https://www.khronos.org/sycl/). + +## Reading the latest version of the SYCL specification + +The GitLab CI pipeline builds the specification. This is accessible +from this page, under the green check symbol, on the top right of the +page or more generally from the rocket symbol on the left side. + +Then on the pipeline page, select the *Jobs* tab and click on the +*download* icon on the bottom right. + + +## Building the SYCL specification + +### Using GitLab CI + +The simplest way to build the specification is not to actually build +it, but to rely on the Khronos continuous integration process which +builds automatically a branch when it is changed on +https://gitlab.khronos.org/sycl/Specification + +Look at CI/CD-Jobs (the rocket-ship icon on the left menu bar or +https://gitlab.khronos.org/sycl/Specification/-/jobs), click on the +`Download` icon for the latest CI job in the branch of interest or +click on `Passed` to dive into more details. Once unzipping the +compilation artifacts, look inside `adoc/out` directory to find the +HTML and PDF version. + +Note that to read the HTML specification correctly with all the +mathematical symbols, you need also to have the `katex` directory +along the `html` one. This might not be the case if your downloading +framework lazily unzips just what you read. + +You can use this CI infrastructure while developing: you can git-push +or git-force-push your branch on the server and go to CI/CD-Jobs to +look at the compiled version. + +All this works because of the existing `.gitlab-ci.yml` recipe. + +### Using pre-configured AsciiDoctor-capable Docker image + +Compiling the specification requires some specific AsciiDoctor related +packages. + +To simplify the setup, Khronos provides a pre-configured Docker Linux +Ubuntu image you can use on a Docker executor to compile the +specification on various OS able to run Docker. + +Assuming you are on Debian/Ubuntu Linux, the first time you need to +install Docker with for example: +```bash +sudo apt update +sudo apt install docker.io +``` + +The base image used to build the specifications can be downloaded or +updated to the latest version via +```bash +docker pull khronosgroup/docker-images:vulkan-docs-base +``` +Or you can manually generate the image using the script provided in +`https://github.com/KhronosGroup/DockerContainers`. + + +To compile the specification you can rely on the `Makefile` inside the +`adoc` directory, for example with: +```bash +cd adoc +make clean docker-html docker-pdf +``` + +There are a few variables defined in the `Makefile` you can set to +change the behavior, such as to display verbosely the compilation +process: +```bash +make QUIET= clean docker-html docker-pdf +``` + +If you need to launch explicitly Docker without using `make` on the +host, look at the `adoc/Makefile` and imitate on your system how +Docker is launched. + +Since the Docker image is old, there is a new path using a script to +upgrade the files inside the Docker image to be used as: +```bash +make DOCKER_COMMAND="make QUIET= --directory=/sycl/adoc clean html pdf" dock +``` + +### Using native computer + +If you are using a Debian/Ubuntu Linux distribution, you can look at +how the previous process works and how the Docker image is done at +https://github.com/KhronosGroup/DockerContainers and specifically +https://github.com/KhronosGroup/DockerContainers/blob/master/Dockerfile.vulkan-docs-base +which gives an idea of the packages to install and +https://github.com/KhronosGroup/DockerContainers/blob/master/entrypoint.vulkan.sh + +*TODO*: find the minimal recipe. +```bash +sudo apt update +sudo apt install bison \ + build-essential \ + cmake \ + flex \ + fonts-lyx \ + g++ \ + ghostscript \ + git \ + libcairo2-dev \ + libffi-dev \ + libgdk-pixbuf2.0-dev \ + libpango1.0-dev \ + libreadline-dev \ + libxml2-dev \ + nodejs \ + node-escape-string-regexp \ + node-he \ + node-lunr \ + poppler-utils \ + python3 \ + ruby-dev + +sudo apt clean + +sudo gem install asciidoctor \ + asciidoctor-diagram \ + asciidoctor-mathematical \ + asciidoctor-pdf \ + coderay \ + json-schema \ + i18n \ + pygments.rb \ + rouge \ + text-hyphen +``` + +Then use for example: +```bash +make QUIET= clean html pdf +``` + +There is also some discussion back-ground in +https://gitlab.khronos.org/sycl/Specification/-/merge_requests/484#note_270338 + + +### Windows recipe + +*TODO*: Investigate the Docker route +https://docs.docker.com/docker-for-windows/install/ , WSL2, CygWin, +VCPKG... diff --git a/adoc/.gitignore b/adoc/.gitignore new file mode 100644 index 00000000..b05eeef3 --- /dev/null +++ b/adoc/.gitignore @@ -0,0 +1 @@ +.asciidoctor diff --git a/adoc/Makefile b/adoc/Makefile new file mode 100644 index 00000000..260a3fd4 --- /dev/null +++ b/adoc/Makefile @@ -0,0 +1,312 @@ +# Copyright (c) 2011-2021 The Khronos Group, Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +# SYCL Specification makefile + +# If a recipe fails, delete its target file. Without this cleanup, the leftover +# file from the failed recipe can falsely satisfy dependencies on subsequent +# runs of `make`. +.DELETE_ON_ERROR: + +# IMAGEOPTS is normally set to generate inline SVG images, but can be +# overridden to an empty string, since the inline option doesn't work +# well with our HTML diffs. +# This select opts as explained in "Taming SVGs" of +# https://asciidoctor.org/docs/user-manual/#taming-svgs +# Do not use inline because it breaks the text of the figures in the +# HTML output. +IMAGEOPTS = + +# The default 'all' target builds the following sub-targets: +# html - HTML single-page API specification +# pdf - PDF single-page API specification + +# Jon: don't build PDF yet - some weird errors (related to code: macro?) +all: html + +# +QUIET ?= @ +PYTHON ?= python3 +ASCIIDOC ?= asciidoctor +# Using such variables allows running local version with: +# BUNDLE_GEMFILE=.../asciidoctor-pdf/Gemfile make QUIET= ASCIIDOCPDF="bundle exec asciidoctor-pdf" pdf +ASCIIDOCPDF ?= asciidoctor-pdf +RUBY = ruby +NODEJS = node +PATCH = patch +RM = rm -f +RMRF = rm -rf +MKDIR = mkdir -p +CP = cp +ECHO = echo +GS_EXISTS = $(shell command -v gs 2> /dev/null) + +# Path to Python scripts used in generation +SCRIPTS = scripts + +# Compute the absolute directory name from the location of this Makefile +# so that we can compile from anywhere even if we use make -f +# : +SYCL_DIR := $(abspath $(dir $(firstword $(MAKEFILE_LIST)))/..) + +# Target directories for output files +# HTMLDIR - 'html' target +# PDFDIR - 'pdf' target +OUTDIR = $(GENERATED)/out +HTMLDIR = $(OUTDIR)/html +PDFDIR = $(OUTDIR)/pdf + +# PDF Equations are written to SVGs, this dictates the location to +# store those files (temporary) +PDFMATHDIR = $(OUTDIR)/equations_temp + +# Set VERBOSE to -v to --verbose to see what asciidoc is doing. +VERBOSE = --verbose + +# Some AsciiDoctor attributes (such as OPENCL_VERSION, +# SYCL_LANGUAGE_VERSION, SYCL_NAME, SYCL_VERSION & SYCL_REVISION) are +# based on this external configuration file: +include $(SYCL_DIR)/sycl_version.txt + +# In particular, SYCL_LANGUAGE_VERSION is derived from other values +SYCL_LANGUAGE_VERSION=$(shell printf "%04d%02d" $(SYCLLANGVERSION) \ + $(SYCLREVISION)) +SYCL_NAME=$(SYCLNAME) +SYCL_VERSION=$(SYCLVERSION) +SYCL_REVISION=$(SYCLREVISION) +# Name the generated spec from the revision +SPEC_BASE_NAME=$(shell echo $(SYCL_NAME)-$(SYCL_VERSION) \ + | tr [:upper:] [:lower:]) + +# asciidoc build attributes to set (defaults are usually OK) +# NOTEOPTS sets options controlling which NOTEs are generated +# ATTRIBOPTS sets the API revision and enables KaTeX generation +# VERSIONATTRIBS sets attributes for enabled API versions +# EXTRAATTRIBS sets additional attributes, if passed to make +# ADOCMISCOPTS miscellaneous options controlling error behavior, etc. +# ADOCEXTS asciidoctor extensions to load +# ADOCOPTS options for asciidoc->HTML5 output + +# Uncomment to get TODO notes +NOTEOPTS = --attribute showtodos + +# Spell out ISO 8601 format as not all date commands support --rfc-3339 +SPECDATE = $(shell echo `date -u "+%Y-%m-%d %TZ"`) + +# Generate Asciidoc attributes for spec remark +# Could use `git log -1 --format="%cd"` to get branch commit date +# This used to be a dependency in the spec html/pdf targets, +# but that's likely to lead to merge conflicts. Just regenerate +# when pushing a new spec for review to the sandbox. +# The dependency on HEAD is per the suggestion in +# http://neugierig.org/software/blog/2014/11/binary-revisions.html +# Get back something clearer from the old LaTeX-based specification by +# name the exact annotated tag. If not, list a path to the closest tag. +SPECREMARK = from git $(shell \ + echo `git describe --exact-match 2> /dev/null \ + || ( git describe 2> /dev/null; echo "on branch:" ; \ + git symbolic-ref --short HEAD 2> /dev/null \ + || echo Git branch not available )`) \ + commit: $(shell echo `git log -1 --format="%H" 2> /dev/null \ + || echo Git commit not available`) + +# Some of the attributes used in building all spec documents: +# chapters - absolute path to chapter sources +# appendices - absolute path to appendix sources +# images - absolute path to images +# code_dir - absolute path of the directory with code samples +# header_dir - absolute path of the directory with header samples +# generated - absolute path to generated sources +# refprefix - controls which generated extension metafiles are +# included at build time. Must be empty for specification, +# 'refprefix.' for refpages (see ADOCREFOPTS below). +ATTRIBOPTS = --attribute revdate="$(SPECDATE)" \ + --attribute revremark="$(SPECREMARK)" \ + --attribute OPENCL_VERSION="$(OPENCLVERSION)" \ + --attribute SYCL_LANGUAGE_VERSION="$(SYCLLANGVERSION)" \ + --attribute SYCL_NAME="$(SYCLNAME)" \ + --attribute SYCL_VERSION="$(SYCLVERSION)" \ + --attribute SYCL_REVISION="$(SYCLREVISION)" \ + --attribute stem=latexmath \ + --attribute imageopts="$(IMAGEOPTS)" \ + --attribute config=$(CURDIR)/config \ + --attribute images=$(IMAGEPATH) \ + --attribute code_dir=$(CODE_DIR) \ + --attribute header_dir=$(HEADER_DIR) \ + --attribute generated=$(GENERATED) \ + --attribute refprefix \ + $(VERSIONATTRIBS) +ADOCMISCOPTS = --require asciidoctor-diagram --failure-level ERROR +ADOCEXTS = --require $(CURDIR)/config/spec-macros.rb \ + --require $(CURDIR)/config/rouge_sycl.rb +ADOCOPTS = --doctype book $(ADOCMISCOPTS) $(ATTRIBOPTS) \ + $(NOTEOPTS) $(VERBOSE) $(ADOCEXTS) + +ADOCHTMLEXTS = --require $(CURDIR)/config/katex_replace.rb \ + --require $(CURDIR)/config/loadable_html.rb + +# ADOCHTMLOPTS relies on the relative runtime path from the output HTML +# file to the katex scripts being set with KATEXDIR. This is overridden +# by some targets. +# ADOCHTMLOPTS also relies on the absolute build-time path to the +# 'stylesdir' containing our custom CSS. +KATEXDIR = katex +ADOCHTMLOPTS = $(ADOCHTMLEXTS) --attribute katexpath=$(KATEXDIR) \ + --attribute stylesheet=khronos.css --attribute stylesdir=$(CURDIR)/config \ + --attribute sectanchors +ADOCPDFEXTS = --require asciidoctor-pdf --require asciidoctor-mathematical \ + --require $(CURDIR)/config/asciidoctor-mathematical-ext.rb +ADOCPDFOPTS = $(ADOCPDFEXTS) --attribute mathematical-format=svg \ + --attribute imagesoutdir=$(PDFMATHDIR) \ + --attribute pdf-stylesdir=$(CURDIR)/config/themes \ + --attribute pdf-theme=pdf \ + --attribute hyphens=en_us + +.PHONY: directories + +# Images used by the spec. These are included in generated HTML now. +IMAGEPATH = $(CURDIR)/images +SVGFILES = $(wildcard $(IMAGEPATH)/*.svg) + +# Code samples +CODE_DIR = $(CURDIR)/code + +# Header samples +HEADER_DIR = $(CURDIR)/headers + +# Top-level spec source file +SPECSRC = syclbase.adoc +# Static files making up sections of the API spec. +SPECFILES = $(wildcard *.adoc) $(wildcard chapters/*.adoc) + +# Shorthand for where different types of generated files go. +# All can be relocated by overriding GENERATED in the make invocation. +GENERATED = $(CURDIR) +# All non-format-specific dependencies +COMMONDOCS = $(SPECFILES) $(GENDEPENDS) + +# Install katex in $(OUTDIR)/katex for reference by all HTML targets +# README.md is a proxy for all the katex files that need to be installed +katexinst: KATEXDIR = katex +katexinst: $(OUTDIR)/$(KATEXDIR)/README.md + +$(OUTDIR)/$(KATEXDIR)/README.md: katex/README.md + $(QUIET)$(MKDIR) $(OUTDIR) + $(QUIET)$(RMRF) $(OUTDIR)/$(KATEXDIR) + $(QUIET)$(CP) --archive katex $(OUTDIR) + +# Script to add href to anchors +GENANCHORLINKS = $(SCRIPTS)/genanchorlinks.py + +# Spec targets +# There is some complexity to try and avoid short virtual targets like 'html' +# causing specs to *always* be regenerated. +ROSWELL = ros +ROSWELLOPTS ?= dynamic-space-size=4000 +CHUNKER = $(HOME)/common-lisp/asciidoctor-chunker/roswell/asciidoctor-chunker.ros +CHUNKINDEX = $(CURDIR)/config/chunkindex +# Only the $(ROSWELL) step is required unless the search index is to be +# generated and incorporated into the chunked spec. +# +# Dropped $(QUIET) for now +# Should set NODE_PATH=/usr/local/lib/node_modules or wherever, outside Makefile +# Copying chunked.js into target avoids a warning from the chunker +chunked: $(HTMLDIR)/$(SPEC_BASE_NAME).html $(SPECSRC) $(COMMONDOCS) + $(QUIET)$(PATCH) $(HTMLDIR)/$(SPEC_BASE_NAME).html \ + -o $(HTMLDIR)/prechunked.html $(CHUNKINDEX)/custom.patch + $(QUIET)$(CP) $(CHUNKINDEX)/chunked.css $(CHUNKINDEX)/chunked.js \ + $(CHUNKINDEX)/lunr.js $(HTMLDIR) + $(QUIET)$(ROSWELL) $(ROSWELLOPTS) $(CHUNKER) \ + $(HTMLDIR)/prechunked.html -o $(HTMLDIR) + $(QUIET)$(RM) $(HTMLDIR)/prechunked.html + $(QUIET)$(RUBY) $(CHUNKINDEX)/generate-index.rb $(HTMLDIR)/chap*html | \ + $(NODEJS) $(CHUNKINDEX)/build-index.js > $(HTMLDIR)/search.index.js + +html: $(HTMLDIR)/$(SPEC_BASE_NAME).html $(SPECSRC) $(COMMONDOCS) + +%.html: KATEXDIR = ../katex +%.html: $(SPECSRC) $(COMMONDOCS) katexinst + $(QUIET)$(ASCIIDOC) --backend html5 $(ADOCOPTS) $(ADOCHTMLOPTS) \ + --out-file $@ $(SPECSRC) + $(QUIET)$(PYTHON) $(GENANCHORLINKS) $@ $@ + $(QUIET)$(NODEJS) translate_math.js $@ + +diff_html: $(HTMLDIR)/diff.html $(SPECSRC) $(COMMONDOCS) + +$(HTMLDIR)/diff.html: KATEXDIR = ../katex +$(HTMLDIR)/diff.html: $(SPECSRC) $(COMMONDOCS) katexinst + $(QUIET)$(ASCIIDOC) --backend html5 $(ADOCOPTS) $(ADOCHTMLOPTS) \ + --attribute diff_extensions="$(DIFFEXTENSIONS)" \ + --require $(CURDIR)/config/extension-highlighter.rb --trace \ + --out-file $@ $(SPECSRC) + $(QUIET)$(NODEJS) translate_math.js $@ + +pdf: $(PDFDIR)/$(SPEC_BASE_NAME).pdf $(SPECSRC) $(COMMONDOCS) + +%.pdf: $(SPECSRC) $(COMMONDOCS) + $(QUIET)$(MKDIR) $(PDFDIR) + $(QUIET)$(MKDIR) $(PDFMATHDIR) + $(QUIET)$(ASCIIDOCPDF) --trace $(ADOCOPTS) $(ADOCPDFOPTS) \ + --out-file $@ $(SPECSRC) +ifndef GS_EXISTS + $(QUIET) echo "Warning: Ghostscript not installed, skipping pdf optimization" +else + $(QUIET)$(CURDIR)/config/optimize-pdf $@ + $(QUIET)rm $@ + $(QUIET)mv $*-optimized.pdf $@ +endif + $(QUIET)rm -rf $(PDFMATHDIR) + +# Reflow text in spec sources +REFLOW = $(SCRIPTS)/reflow.py +REFLOWOPTS = -overwrite + +reflow: + $(QUIET) echo "Warning: please verify the spec outputs build without changes!" + $(PYTHON) $(REFLOW) $(REFLOWOPTS) $(SPECSRC) $(SPECFILES) + +# Clean generated and output files + +clean: clean_html clean_pdf + +clean_html: + $(QUIET)$(RMRF) $(HTMLDIR) $(OUTDIR)/katex + +clean_pdf: + $(QUIET)$(RMRF) $(PDFDIR) + +# Expose docker-TARGET to forward a TARGET inside a Docker container. +# For example: +# make docker-clean docker-html docker-pdf +# Also useful to have a shell inside docker: +# make docker-bash +docker-%: + # Run with current user and group id the published AsciiDoctor + # capable Khronos docker image with current SYCL specification + # directory mounted in /sycl + # Re-set MAKEFLAGS to pass variables to the inner make since + # variables are dropped by docker. + sudo docker run --user `id --user`:`id --group` \ + --interactive --tty --rm \ + --volume $(SYCL_DIR):/sycl khronosgroup/docker-images:vulkan-docs-base \ + $(MAKE) MAKEFLAGS="$(MAKEFLAGS)" --directory=/sycl/adoc $* + +dock: + # First update the Docker image to latest Gem with rouge and run + # $DOCKER_COMMAND with current user and group id the published + # AsciiDoctor capable Khronos docker image with current SYCL + # specification directory mounted in /sycl + sudo docker run \ + --interactive --tty --rm \ + -e USER_ID=`id --user` -e GROUP_ID=`id --group` \ + --volume $(SYCL_DIR):/sycl khronosgroup/docker-images:vulkan-docs-base \ + /sycl/adoc/scripts/install-rouge.sh \ + $(DOCKER_COMMAND) + +# Use a default rule to just execute by the shell the given rule. +# For example "make bash" will run bash, "make env" will display the +# environment to debug the configuration, etc. +# Mainly to be used in docker context. +.DEFAULT: + $@ diff --git a/adoc/chapters/acknowledgements.adoc b/adoc/chapters/acknowledgements.adoc new file mode 100644 index 00000000..83b04d69 --- /dev/null +++ b/adoc/chapters/acknowledgements.adoc @@ -0,0 +1,80 @@ +[[acknowledgements]] += Acknowledgements + +*Editors* + + * Maria Rovatsou, Codeplay + * Lee Howes, Qualcomm + * Ronan Keryell, Xilinx (current) + +*Contributors* + + * Eric Berdahl, Adobe + * Shivani Gupta, Adobe + * David Neto, Altera + * Brian Sumner, AMD + * Thomas Applencourt, Argonne National Laboratory + * Hal Finkel, Argonne National Laboratory + * Kevin Harms, Argonne National Laboratory + * Nevin Liber, Argonne National Laboratory + * Anastasia Stulova, ARM + * Balázs Keszthelyi, Broadcom + * Alexandra Crabb, Caster Communications + * Stuart Adams, Codeplay + * Gordon Brown, Codeplay + * Morris Hafner, Codeplay + * Alexander Johnston, Codeplay + * Marios Katsigiannis, Codeplay + * Paul Keir, Codeplay + * Steffen Larsen, Codeplay + * Victor Lomüller, Codeplay + * Tomas Matheson, Codeplay + * Duncan McBain, Codeplay + * Ralph Potter, Codeplay + * Ruyman Reyes, Codeplay + * Andrew Richards, Codeplay + * Maria Rovatsou, Codeplay + * Panagiotis Stratis, Codeplay + * Michael Wong, Codeplay + * Peter Žužek, Codeplay + * Matt Newport, EA + * Ruslan Arutyunyan, Intel + * Alexey Bader, Intel + * James Brodman, Intel + * Ilya Burylov, Intel + * Jessica Davies, Intel + * Felipe de Azevedo Piovezan, Intel + * Allen Hux, Intel + * Michael Kinsner, Intel + * Greg Lueck, Intel + * John Pennycook, Intel + * Roland Schulz, Intel + * Sergey Semenov, Intel + * Jason Sewall, Intel + * James O'Riordon, Khronos + * Jon Leech, Luna Princeps LLC + * Kathleen Mattson, Miller & Mattson, LLC + * Dave Miller, Miller & Mattson, LLC + * Neil Trevett, NVIDIA + * Lee Howes, Qualcomm + * Chu-Cheow Lim, Qualcomm + * Jack Liu, Qualcomm + * Ruihao Zhang, Qualcomm + * Dave Airlie, Red Hat + * Aksel Alpay, Self + * Dániel Berényi, Self + * Máté Nagy-Egri, Stream HPC + * Tom Deakin, University of Bristol + * Philip Salzmann, University of Innsbruck + * Peter Thoman, University of Innsbruck + * Biagio Cosenza, University of Salerno + * Paul Preney, University of Windsor + * Andrew Gozillon, Xilinx + * Gauthier Harnisch, Xilinx + * Ronan Keryell, Xilinx + * Lin-Ya Yu, Xilinx + +// Jon: in other specs we credit Khronos staff who have helped. +// Ronan: indeed! Just reading this while actually adding the... Khronos +// staff! ;-) +// Could do that here. diff --git a/adoc/chapters/architecture.adoc b/adoc/chapters/architecture.adoc new file mode 100644 index 00000000..500efaa0 --- /dev/null +++ b/adoc/chapters/architecture.adoc @@ -0,0 +1,1862 @@ +// %%%%%%%%%%%%%%%%%%%%%%%%%%%% begin architecture %%%%%%%%%%%%%%%%%%%%%%%%%%%% + +[[architecture]] += SYCL architecture + +This chapter describes the structure of a SYCL application, and how the +SYCL generic programming model lays out on top of a number of <>s. + + +== Overview + +SYCL is an open industry standard for programming a heterogeneous system. The +design of SYCL allows standard {cpp} source code to be written such that it can +run on either an heterogeneous device or on the <>. + +The terminology used for SYCL inherits historically from OpenCL with some +SYCL-specific additions. However SYCL is a generic {cpp} programming model +that can be laid out on top of other heterogeneous APIs apart from OpenCL. +SYCL implementations can provide <>s for various heterogeneous APIs, +implementing the SYCL general specification on top of them. We refer to this +heterogeneous API as the <>. The SYCL general specification +defines the behavior that all SYCL implementations must expose to SYCL users +for a SYCL application to behave as expected. + +A function object that can execute on a <> exposed by a <> +is called a <>. + +To ensure maximum interoperability with different <>s, software +developers can access the <> alongside the SYCL general API +whenever they include the <> interoperability headers. +However, interoperability is a <>-specific feature. +An application that uses interoperability does not conform to the +SYCL general application model, since it is not portable across backends. + +// Note below I leave the reference to OpenCL intentionally + +The target users of SYCL are {cpp} programmers who want all the performance and +portability features of a standard like OpenCL, but with the flexibility to use +higher-level {cpp} abstractions across the host/device code boundary. +Developers can use most of the abstraction features of {cpp}, such as +templates, classes and operator overloading. + +However, some {cpp} language features are not permitted inside +kernels, due to the limitations imposed by the capabilities of the underlying +heterogeneous platforms. +These features include virtual functions, virtual inheritance, +throwing/catching exceptions, and run-time type-information. These features are +available outside kernels as normal. Within these constraints, developers can +use abstractions defined by SYCL, or they can develop their own on top. These +capabilities make SYCL ideal for library developers, middleware providers and +application developers who want to separate low-level highly-tuned algorithms +or data structures that work on heterogeneous systems from higher-level software +development. Software developers can produce templated algorithms that are easily +usable by developers in other fields. + + +[[sec:anatomy]] +== Anatomy of a SYCL application + +Below is an example of a typical <> which schedules a job to run +in parallel on any heterogeneous device available. + +// An AsciiDoctor "feature", the language is specified as the second +// parameter of this attribute, even if we do not want it. So add a +// empty language with ",," so the highlighter can go on using the +// language specified in ":source-highlighter:" +[source,,linenums] +---- +include::{code_dir}/anatomy.cpp[lines=4..-1] +---- + +At line 1, we [code]#{hash}include# the SYCL header files, which +provide all of the SYCL features that will be used. + +A SYCL application runs on a <>. +The application is structured in three scopes which specify the different sections; +<>, <> and <>. +The <> specifies a single kernel function that will +be, or has been, compiled by a <> and executed on a +<>. In this example <> is defined by lines +26 to 29. The <> specifies a unit of work which is +comprised of a <> and <>. In this +example <> is defined by lines 21 to 30. The +<> specifies all other code outside of a +<>. +These three scopes are used to control the application flow and the +construction and lifetimes of the various objects used within SYCL, as +explained in <>. + +A <> is the scoped block of code that will be +compiled using a device compiler. This code may be defined by the +body of a lambda function or by the [code]#operator()# function of +a function object. Each instance of the +<> will be executed as a single, though not +necessarily entirely independent, flow of execution and has to adhere +to restrictions on what operations may be allowed to enable device +compilers to safely compile it to a range of underlying devices. + +The [code]#parallel_for# member function can be templated with a class. +This class is used to manually name the +kernel when desired, such as to avoid a compiler-generated name when debugging +a kernel defined through a lambda, to provide a known name with which to apply +build options to a kernel, or to ensure compatibility with multiple +compiler-pass implementations. + +The [code]#parallel_for# member function creates an instance of a <>, +which is the entity that will be enqueued within a +command group. In the case of [code]#parallel_for# the +<> will be executed over the given range from 0 to 1023. +The different member functions to +execute kernels can be found in <>. + +A <> is the syntactic scope wrapped by the construction +of a <> as seen on line 21. The +<> may invoke only a single +<>, and it takes a parameter of type command group +[code]#handler#, which is constructed by the runtime. + +All the requirements for a kernel to execute are +defined in this <>, as described in +<>. In this case the constructor used +for [code]#myQueue# on line 15 is the default constructor, which allows +the queue to select the best underlying device to execute on, leaving the +decision up to the runtime. + +In SYCL, data that is required within a <> must +be contained within a <>, <>, or <> allocation, as described in +<>. We +construct a buffer on line 18. Access to the <> is controlled via +an <> which is constructed on line 23. +The <> is used to +keep track of access to the data and the <> is used to request +access to the data on a queue, as well as to track the dependencies between +<>. In this example the <> is used to +write to the data buffer on line 28. + + +[[sec:normativerefs]] +== Normative references + +// Jon: are any of the OpenCL specifications normative? They are also +// referred to from the SYCL spec, and some of the definitions appear to be +// required. + +The documents in the following list are referred to within this SYCL +specification, and their content is a requirement for this document. + + . *{cpp17}:* <>, referred to in this + specification as the {cpp} core language. The SYCL specification refers to + language in the following {cpp} defect reports and assumes a compiler that + implements them: <>. + . *{cpp20}:* <>, referred to in this specification as the next {cpp} specification. + +[[sec:nonnormativerefs]] +== Non-normative notes and examples + +Unless stated otherwise, text within this SYCL specification is normative and defines +the required behavior of a SYCL implementation. Non-normative / informational notes +are included within this specification using a "`note`" callout, of the form: + +[NOTE] +==== +Information within a note callout, such as this text, is for informational purposes +and does not impose requirements on or specify behavior of a SYCL implementation. +==== + +Source code examples within the specification are provided to aid with understanding, +and are non-normative. + +In case of any conflict between a non-normative note or source example, and normative +text within the specification, the normative text must be taken to be correct. + +[[sec:platformmodel]] +== The SYCL platform model + +The SYCL platform model is based on the OpenCL platform model. +The model consists of a host connected to one or more heterogeneous devices, +called <>. + +A SYCL <> is constructed, either directly by the user or implicitly +when creating a <>, to hold all the runtime information required by +the SYCL runtime and the <> to operate on a device, or group of devices. +When a group of devices can be grouped together on the same context, they have +some visibility of each other's memory objects. The SYCL runtime can assume that memory +is visible across all devices in the same <>. +Not all devices exposed from the same <> can be grouped together +in the same <>. + +A SYCL application executes on the host as a standard {cpp} program. +<> are exposed through different <> to the SYCL application. +The SYCL application submits <> to <>. +Each <> enables execution on a given device. + +The <> then extracts operations from the +<>, e.g. an explicit copy operation or a +<>. When the operation is a +<>, the <> uses a +<>-specific mechanism to extract the device binary from the SYCL +application and pass it to the heterogeneous API for execution on the +<>. + +A SYCL <> is divided into one or more compute units (CUs) which are each divided +into one or more processing elements (PEs). Computations on a device occur +within the processing elements. +How computation is mapped to PEs is <> and <> specific. +Two devices exposed via two different backends can map computations differently to the +same device. + +When a SYCL application contains <> objects, the SYCL +implementation must provide an offline compilation mechanism that enables the +integration of the device binaries into the SYCL application. +The output of the offline compiler can be an intermediate representation, such as +SPIR-V, that will be finalized during execution or a final device ISA. + +A device may expose special purpose functionality as a _built-in_ function. +The SYCL API exposes functions to query and dispatch said _built-in_ functions. +Some <> and <> may not support programmable kernels, and only support +_built-in_ functions. +// TODO: Conformance of these custom-devices? + + +== The SYCL backend model + +SYCL is a generic programming model for the {cpp} language that can target multiple +heterogeneous APIs, such as OpenCL. + +SYCL implementations enable these target APIs by implementing <>. +For a SYCL implementation to be conformant on said <>, it must execute +the SYCL generic programming model on the backend. All SYCL implementations must +provide at least one backend. + +The present document covers the SYCL generic interface available to +all <>. How the SYCL generic interface maps to a particular +<> is defined either by a separate <> specification +document, provided by the Khronos SYCL group, or by the SYCL +implementation documentation. Whenever there is a <> +specification document, this takes precedence over SYCL implementation +documentation. + +When a SYCL user builds their SYCL application, she decides which of the +<> will be used to build the SYCL application. This is called the set +of _active backends_. Implementations must ensure that the active +backends selected by the user can be used simultaneously by the SYCL +implementation at runtime. If two backends are available at compile time but +will produce an invalid SYCL application at runtime, the SYCL implementation +must emit a compilation error. + +A SYCL application built with a number of active backends does not necessarily +guarantee that said backends can be executed at runtime. +The subset of active backends available at runtime is called +_available backends_. +A backend is said to be _available_ if the host platform where the +SYCL application is executed exposes support for the heterogeneous API +required for the <>. + +It is implementation dependent whether certain backends require third-party +libraries to be available in the system. Failure to have all dependencies +required for all active backends at runtime will cause the SYCL application to +not run. + +Once the application is running, users can query what SYCL platforms are available. +SYCL implementations will expose the devices provided by each backend grouped +into platforms. A backend must expose at least one platform. + +Under the <> model, SYCL objects can contain one or multiple references +to a certain <> native type. +Not all SYCL objects will map directly to a <> native type. +The mapping of SYCL objects to <> native types is defined by the +<> specification document when available, or by the SYCL implementation +otherwise. + +To guarantee that multiple <> objects can interoperate with +each other, SYCL memory objects are not bound to a particular <>. +SYCL memory objects can be accessed from any device exposed by an +_available_ backend. +SYCL Implementations can potentially map SYCL memory objects to +multiple native types in different <>. + +Since SYCL memory objects are independent of any particular <>, +SYCL <> can request access to memory objects allocated +by any <>, and execute it on the backend associated with the <>. +This requires the SYCL implementation to be able to transfer memory objects +across <>. + +USM allocations are subject to the limitations +described in <>. + +When a SYCL application runs on any number of <> without relying on +any <>-specific behavior or interoperability, it is said to be a +SYCL general application, and it is expected to run in any SYCL-conformant +implementation that supports the required features for the application. + + +=== Platform mixed version support + +The SYCL generic programming model exposes a number of <>, each of +them exposing a number of <>. Each <> is bound +to a certain <>. SYCL <> associated with said <> +are associated with that <>. + +Although the APIs in the SYCL generic programming model are defined according +to this specification and their version is indicated by the macro +[code]#SYCL_LANGUAGE_VERSION#, this does not apply to APIs exposed by the +<>. Each <> provides its own document that defines its APIs, +and that document tells how to query for the device and platform versions. + + +== SYCL execution model + +As described in <>, a <> is comprised +of three scopes: <>, <>, and +<>. Code in the <> and +<> runs on the host and is governed by the +_SYCL application execution model_. Code in the kernel scope runs on a +device and is governed by the _SYCL kernel execution model_. + +[NOTE] +==== +A SYCL device does not necessarily correspond to a physical accelerator. +A SYCL implementation may choose to expose some or all of the host's +resources as a SYCL device; such an implementation would execute +code in <> on the host, but that code would still be governed by +the _SYCL kernel execution model_. +==== + + +[[sec:executionmodel]] +=== SYCL application execution model + +The SYCL application defines the execution order of the kernels by grouping +each kernel with its requirements into a <>. +<> are submitted +for execution via a <> object, which defines the device where the kernel +will run. This specification sometimes refers to this as "`submitting the +kernel to a device`". The same <> object can be submitted to +different queues. When a <> is submitted to a SYCL <>, +the requirements of the kernel execution are captured. The implementation can +start executing a kernel as soon as its requirements have been satisfied. + +==== <> resources managed by the SYCL application + +The SYCL runtime integrated with the SYCL application will manage +the resources required by the <> +to manage the heterogeneous devices it is providing access to. +This includes, but is not limited to, resource handlers, memory pools, +dispatch queues and other temporary handler objects. + +The SYCL programming interface represents the lifetime of the resources +managed by the SYCL application using RAII rules. +Construction of a SYCL object will typically entail the creation of multiple +<> objects, which will be properly released on destruction of said +SYCL object. +The overall rules for construction and destruction are detailed in +<>. +Those <> with a <> document will detail how the resource +management from SYCL objects map down to the <> objects. + +In SYCL, the minimum required object for submitting work to devices is +the <>, which contains references to a <>, <> +and a <> internally. + +The resources managed by SYCL are: + +// Note enumerate below was meant originally to showcase SYCL features +// for each OpenCL resource, this is now re-worded to cover for a +// general case of what resources are managed. +// Also, references to the SYCL API are removed to make text independent +// from changes in the programming + + . <>: all features of <>s are implemented by + platforms. A platform can be viewed as a given vendor's runtime and the + devices accessible through it. Some devices will only be accessible to + one vendor's runtime and hence multiple platforms may be present. SYCL + manages the different platforms for the user which are accessible through a + [code]#sycl::platform# object. + . <>: any <> resource that is acquired by the user is + attached to a context. A context contains a collection of devices that + the host can use and manages memory objects that can be shared between + the devices. Devices belonging to the same <> must be able to + access each other's global memory using some implementation-specific + mechanism. A given context can only wrap devices owned by a single + platform. A context is exposed to the user with a + [code]#sycl::context# object. + . <>: platforms provide one or more devices for executing SYCL + kernels. In SYCL, a device is accessible through a + [code]#sycl::device# object. + . <>: the SYCL functions that run on SYCL devices are defined + as {cpp} function objects (a named function object type or a lambda + function). A kernel can be introspected through a + [code]#sycl::kernel# object. ++ +-- +Note that some <> may expose non-programmable functionality as +pre-defined kernels. +-- + . <>: Kernels are stored internally in the SYCL + application as device images, and these device images can be grouped into a + [code]#sycl::kernel_bundle# object. These objects provide a way for the + application to control the online compilation of kernels for devices. + . <>: SYCL kernels execute in command queues. The user must + create a [code]#sycl::queue# object, + which references an associated context, platform and + device. The context, platform and device may be chosen automatically, or + specified by the user. + SYCL queues execute <> on a particular device of a + particular context, but can have dependencies from any device on any + available <>. + +The SYCL implementation guarantees the correct initialization and +destruction of any resource handled by the underlying <>, except +for those the user has obtained manually via the SYCL interoperability API. + +==== SYCL command groups and execution order + +By default, SYCL queues execute kernel functions in an out-of-order fashion +based on dependency information. +Developers only need to specify what data is required to execute a particular +kernel. The SYCL runtime will guarantee that kernels are executed in an order +that guarantees correctness. +By specifying access modes and types of memory, a directed acyclic dependency +graph (DAG) of kernels is built at runtime. This is achieved via the usage of +<> objects. A SYCL <> object defines a set +of requisites (_R_) and a kernel function (_k_). A <> is +_submitted_ to a queue when using the +[code]#sycl::queue::submit# member function. + +A *requisite* (_r~i~_) is a requirement that must be fulfilled for +a kernel-function (_k_) to be executed on a particular device. +For example, a requirement may be that certain data is available on a +device, or that another command group has finished execution. +An implementation may evaluate the requirements of a command group at any +point after it has been submitted. +The _processing of a command group_ is the process by which a SYCL +runtime evaluates all the requirements in a given _R_. +The SYCL runtime will execute _k_ only when all _r~i~_ are satisfied (i.e., +when all requirements are satisfied). +To simplify the notation, in the specification we refer to the set of +requirements of a command group named _foo_ as +_CG~foo~ = r~1~, {ldots}, r~n~_. + +The _evaluation of a requisite_ ({SYCLeval}(_r~i~_)) returns the status of +the requisite, which can be _True_ or _False_. +A _satisfied_ requisite implies the requirement is met. +{SYCLeval}(_r~i~_) never alters the requisite, only observes the current status. +The implementation may not block to check the requisite, and the same check +can be performed multiple times. + +An *action* (_a~i~_) is a collection of implementation-defined +operations that must be performed in order to satisfy a requisite. +The set of actions for a given <> _A_ is permitted +to be empty if no operation is required to satisfy the requirement. +The notation _a~i~_ represents the action required to satisfy _r~i~_. +Actions of different requisites can be satisfied in any order with +respect to +each other without side effects (i.e., given two requirements _r~j~_ and _r~k~_, +_(r~j~, r~k~)_ {equiv} _(r~k~, r~j~)_). The intersection of two +actions is not necessarily empty. +*Actions* can include (but are not limited to): memory copy operations, +mapping operations, host side synchronization, or implementation-specific +behavior. + +Finally, _Performing an action_ ({SYCLperform}(_a~i~_)) executes the +action operations required to satisfy the requisite _r~j~_. Note that, after +{SYCLperform}(_a~i~_), the evaluation {SYCLeval}(_r~j~_) will return _True_ +until the kernel is executed. After the kernel execution, it is not defined +whether a different <> with the same requirements needs to +perform the action again, where actions of different requisites inside the +same <> object can be satisfied in any order with +respect to each +other without side effects: Given two requirements _r~j~_ and _r~k~_, +{SYCLperform}(_a~j~_) followed by {SYCLperform}(_a~k~_) is equivalent to +{SYCLperform}(_a~k~_) followed by {SYCLperform}(_a~j~_). + +The requirements of different <> submitted to the same +or different queues are evaluated in the relative order of submission. +<> objects whose intersection of requirement sets is +not empty are said to depend on each other. +They are executed in order of submission to the queue. +If <> are submitted to different queues or by multiple +threads, the order of execution is determined by the SYCL runtime. +Note that independent <> objects can be submitted +simultaneously without affecting dependencies. + +<> illustrates the execution order of three +<> objects (_CG~a~,CG~b~,CG~c~_) with certain requirements +submitted to the same queue. +Both _CG~a~_ and _CG~b~_ only have one requirement, _r~1~_ and _r~2~_ respectively. +_CG~c~_ requires both _r~1~_ and _r~2~_. +This enables the SYCL runtime to potentially execute _CG~a~_ and _CG~b~_ +simultaneously, whereas _CG~c~_ cannot be executed until both _CG~a~_ and _CG~b~_ +have been completed. +The SYCL runtime evaluates the *requisites* and performs the +*actions* required (if any) for the _CG~a~_ and _CG~b~_. +When evaluating the *requisites* of _CG~c~_, they will be satisfied +once the _CG~a~_ and _CG~b~_ have finished. + +// Formerly in three_cg_one_queue.tex + +// Jon: source code markup doesn't work with embedded asciidoctor markup +// Image is not centered + +[[fig:three-cg-one-queue]] +.Execution order of three command groups submitted to the same queue +[width="100%",options="header",cols="50%,50%"] +|==== +| *SYCL Application Enqueue Order* | *SYCL Kernel Execution Order* +a| +//[source,,subs="quotes"] works only with HTML but hurts the PDF output +[listing,subs="quotes"] +---- +sycl::queue syclQueue; +syclQueue.submit(_CG~a~(r~1~)_); +syclQueue.submit(_CG~b~(r~2~)_); +syclQueue.submit(_CG~c~(r~1~,r~2~)_); +---- + a| +image::{images}/three-cg-one-queue.svg[align="center",opts="{imageopts}"] +|==== + +<> uses three separate SYCL queue objects +to submit the same <> objects as before. +Regardless of using three different queues, the execution order +of the different <> objects is the same. +When different threads enqueue to different queues, the execution order +of the command group will be the order in which the submit member functions are executed. +In this case, since the different <> objects execute on +different devices, the *actions* required to satisfy the +*requirements* may be different (e.g, the SYCL runtime may +need to copy data to a different device in a separate context). + + +// Formerly in three_cg_three_queue.tex + +// Jon: source code markup doesn't work with embedded asciidoctor markup +// Image is not centered + +[[fig:three-cg-three-queue]] +.Execution order of three command groups submitted to the different queues +[width="100%",options="header",cols="50%,50%"] +|==== +| *SYCL Application Enqueue Order* | *SYCL Kernel Execution Order* +a| +//[source,,subs="quotes"] works only with HTML but hurts the PDF output +[listing,subs="quotes"] +---- +sycl::queue syclQueue1; +sycl::queue syclQueue2; +sycl::queue syclQueue3; +syclQueue1.submit(_CG~a~(r~1~)_); +syclQueue2.submit(_CG~b~(r~2~)_); +syclQueue3.submit(_CG~c~(r~1~,r~2~)_); +---- + a| +image::{images}/three-cg-three-queue.svg[align="center",opts="{imageopts}"] +|==== + +==== Controlling execution order with events + +Submitting an action for execution returns an [code]#event# object. Programmers +may use these events to explicitly synchronize programs. Host code can wait for an +event to complete, which will block execution on the host until the action represented +by the event has completed. The [code]#event# class is described in greater detail +in <>. + +Events may also be used to explicitly order the execution of kernels. Host code may +wait for the completion of specific event, which blocks execution on the host until +that event's action has completed. Events may also define requisites between +<>. Using events in this manner informs the runtime +that one or more <> must complete before another +<> may begin executing. See <> for +greater detail. + +=== SYCL kernel execution model + +When a kernel is submitted for execution, an index space is defined. +An instance of the kernel body executes for each point in this index space. +This kernel instance is called a <> and is identified by its +point in the index space, which provides a <> for the work-item. Each +work-item executes the same code but the specific execution pathway through the +code and the data operated upon can vary by using the work-item global id to +specialize the computation. + +==== Basic kernels + +SYCL allows a simple execution model in which a kernel is invoked over an +_N_-dimensional index space defined by [code]#range#, where _N_ is one, two +or three. Each work-item in such a kernel executes independently. + +Each work-item is identified by a value of type [code]#item#. The type +[code]#item# encapsulates a work-item identifier of type [code]#id# and +a [code]#range# representing the number of work-items executing the kernel. + +==== ND-range kernels + +Work-items can be organized into <>, providing a more +coarse-grained decomposition of the index space. Each work-group is assigned a +unique <> with the same dimensionality as the index space used for +the work-items. Work-items are each assigned a <>, unique within the +work-group, so that a single work-item can be uniquely identified by its global +id or by a combination of its local id and work-group id. The work-items in a +given work-group execute concurrently on the processing elements of a single +compute unit. + +When work-groups are used in SYCL, the index space is called an <>. +An ND-range is an +_N_-dimensional index space, where _N_ is one, two or three. In +SYCL, the ND-range is represented via the [code]#nd_range# class. An +[code]#nd_range# is made up of a global range and a local range, each +represented via values of type [code]#range#. +Additionally, there can be a global offset, represented via a value of type [code]#id#; this is deprecated in SYCL 2020. The types +[code]#range# and [code]#id# are each _N_-element +arrays of integers. The iteration space defined via an [code]#nd_range# +is an _N_-dimensional index space starting at the ND-range's global +offset whose size is its global range, split into work-groups of the +size of its local range. + +Each work-item in the ND-range is identified by a value of type +[code]#nd_item#. The type [code]#nd_item# encapsulates a +global id, local id and work-group id, all of type [code]#id# +(the iteration space offset also of type [code]#id#, but this is deprecated in SYCL 2020), as well as +global and local ranges and synchronization operations necessary to +make work-groups useful. Work-groups are assigned ids using a similar +approach to that used for work-item global ids. Work-items are +assigned to a work-group and given a local id with components in the +range from zero to the size of the work-group in that dimension minus +one. Hence, the combination of a work-group id and the local id +within a work-group uniquely defines a work-item. + +==== Backend-specific kernels + +SYCL allows a <> to expose fixed functionality as +non-programmable built-in kernels. The availability and behavior of these +built-in kernels are <>-specific, and are not required to follow the +SYCL execution and memory models. Furthermore the interface exposed utilize +these built-in kernels is also <>-specific. +See the relevant backend specification for details. + +[[sec:memory.model]] +== Memory model + +Since SYCL is a single-source programming model, the memory model affects both +the application and the device kernel parts of a program. +On the SYCL application, the SYCL runtime will make sure data is available +for execution of the kernels. +On the SYCL device kernel, the <> rules describing how the memory +behaves on a specific device are mapped to SYCL {cpp} constructs. Thus it is +possible to program kernels efficiently in pure {cpp}. + + +[[sub.section.memmodel.app]] +=== SYCL application memory model + +The application running on the host uses SYCL <> objects using instances of +the [code]#sycl::buffer# class or <> allocation functions +to allocate memory in the global address +space, or can allocate specialized image memory using the +[code]#sycl::unsampled_image# and [code]#sycl::sampled_image# classes. + +In the SYCL application, memory objects are bound to all devices in which +they are used, regardless of the SYCL context where they reside. +SYCL memory objects (namely, <> and <> objects) +can encapsulate multiple underlying <> memory objects together with +multiple host memory allocations to enable the same object to be shared +between devices in different contexts, platforms or backends. <> +allocations uniquely identify a memory allocation and are bound to a SYCL context. +They are only valid on the backend used by the context. + +The order of execution of <> objects ensures a sequentially +consistent access to the memory from the different devices to the memory +objects. Accessing a USM allocation does not alter the order of execution. +Users must explicitly inform the SYCL runtime of any requirements necessary +for a legal execution. + +To access a memory object, the user must create an <> object +which parameterizes the type of access to the memory object that a kernel or +the host requires. The <> object defines a requirement to access +a memory object, and this requirement is defined by construction of an +accessor, regardless of whether there are any uses in a kernel or by the +host. An accessor object specifies whether the +access is via global memory, constant memory or image samplers and their +associated access functions. The <> also specifies whether the +access is read-only (RO), write-only (WO) or read-write (RW). An optional +[code]#no_init# property can be added to an accessor to tell the system to +discard any previous contents of the data the accessor refers to, so there +are two additional requirement types: no-init-write-only (NWO) and +no-init-read-write (NRW). For simplicity, when a *requisite* represents an +accessor object in a certain access mode, we represent it as +MemoryObject~AccessMode~. For example, an accessor that +accesses memory object *buf1* in *RW* mode is represented as +_buf1~RW~_. A <> object that uses such an accessor is +represented as _CG(buf1~RW~)_. The *action* required to satisfy a +requisite and the location of the latest copy of a memory object will vary +depending on the implementation. + +<> illustrates an example where +<> objects are enqueued to two separate SYCL queues +executing in devices in different contexts. The *requisites* for the +<> execution are the same, but the *actions* to +satisfy them are different. For example, if the data is on the host before +execution, _A(b1~RW~)_ and _A(b2~RW~)_ can potentially be implemented as +copy operations from the host memory to [code]#context1# or +[code]#context2# respectively. After _CG~a~_ and _CG~b~_ are executed, +_A'(b1~RW~)_ will likely be an empty operation, since the result of the +kernel can stay on the device. On the other hand, the results of _CG~b~_ are +now on a different context than _CG~c~_ is executing, therefore _A'(b2~RW~)_ +will need to copy data across two separate contexts using an +implementation specific mechanism. + +// TODO : The example below mentions OpenCL but I think is illustrative of a +// potential implementation and behavior so I am inclined to leave it there + +// Formerly in device_to_device.tex + +// Jon: source code markup doesn't work with embedded asciidoctor markup +// Image is not centered + +[[fig:devicetodevice]] +.Actions performed when three command groups are submitted to two distinct queues +[width="100%",options="header",cols="50%,50%"] +|==== +| *SYCL Application Enqueue Order* | *SYCL Kernel Execution Order* +a| +//[source,,subs="quotes"] works only with HTML but hurts the PDF output +[listing,subs="quotes"] +---- +sycl::queue q1(context1); +sycl::queue q2(context2); +q1.submit(__CG~a~(b1~RW~)__); +q2.submit(_CG~b~(b2~RW~)_); +q1.submit(_CG~c~(b1~RW~,b2~RW~)_); +---- + a| +image::{images}/device_to_device1.svg[align="center",opts="{imageopts}"] +2+a| *Possible implementation by a SYCL Runtime* + +2+a| +image::{images}/device_to_device2.svg[align="center",opts="{imageopts}"] +|==== + +// Jon: The full caption for the above "figure"/table follows - this is hard +// to do in asciidoctor + +<> shows actions performed when three command groups are +submitted to two distinct queues, and potential implementation in an OpenCL +<> by a SYCL runtime. Note that in this example, each SYCL buffer +(_b2,b2_) is implemented as separate [code]#cl_mem# objects per +context} + +Note that the order of the definition of the accessors within the +<> is irrelevant to the requirements they define. +All accessors always apply to the entire <> object where +they are defined. + +When multiple <> in the same <> define different +requisites to the same memory object these requisites must be resolved. + +Firstly, any requisites with different access modes but the same access target +are resolved into a single requisite with the union of the different access +modes according to <>. The atomic access mode acts +as if it was read-write (RW) when determining the combined requirement. The +rules in <> are commutative and associative. + +[[table.access.mode.union]] +.Combined requirement from two different accessor access modes within the same <>. The rules are commutative and associative +[width="100%",options="header",cols="44%,33%,33%"] +|==== +| *One access mode* | *Other access mode* | *Combined requirement* +| read (RO) | write (WO) | read-write (RW) +| read (RO) | read-write (RW) | read-write (RW) +| write (WO) | read-write (RW) | read-write (RW) +| no-init-write (NWO) | no-init-read-write (NRW) | no-init-read-write (NRW) +| no-init-write (NWO) | write (WO) | write (WO) +| no-init-write (NWO) | read (RO) | read-write (RW) +| no-init-write (NWO) | read-write (RW) | read-write (RW) +| no-init-read-write (NRW) | write (WO) | read-write (RW) +| no-init-read-write (NRW) | read (RO) | read-write (RW) +| no-init-read-write (NRW) | read-write (RW) | read-write (RW) +|==== + +The result of this should be that there should not be any requisites with the +same access target. + +Secondly, the remaining requisites must adhere to the following rule. Only +one of the requisites may have write access (_W_ or _RW_), otherwise the +<> must throw an exception. All requisites create a +requirement for the data they represent to be made available in the specified +access target, however only the requisite with write access determines the side +effects of the <>, i.e. only the data which that requisite +represents will be updated. + +For example: + + * _CG(b1^G^~RW~, b1^H^~R~)_ is permitted. + * _CG(b1^G^~RW~, b1^H^~RW~)_ is *not* permitted. + * _CG(b1^G^~W~, b1^C^~RW~)_ is *not* permitted. + +Where _G_ and _C_ correspond to a [code]#target::device# and +[code]#target::constant_buffer# accessor and _H_ corresponds to a host +accessor. + +A buffer created from a range of an existing buffer is called +a [keyword]#sub-buffer#. +A buffer may be overlaid with any number of sub-buffers. +Accessors can be created to operate on these [keyword]#sub-buffers#. +Refer to <> for details on [keyword]#sub-buffer# +creation and restrictions. +A requirement to access a sub-buffer is represented by specifying its +range, e.g. _CG(b1~RW,[0,5)~)_ represents the requirement of accessing +the range _[0,5)_ buffer _b1_ in read write mode. + +If two accessors are constructed to +access the same buffer, but both are to non-overlapping sub-buffers of the +buffer, then the two accessors are said to not [keyword]#overlap#, otherwise the +accessors do overlap. Overlapping is the test that is used to determine the +scheduling order of command groups. +Command-groups with non-overlapping requirements may execute concurrently. + +// Formerly in overlap.tex +// Uses same definitions for cga, cgb, and cgc in code and picture, +// but they're marked up in different languages, so no sharing is possible. + +// Jon: source code markup doesn't work with embedded asciidoctor markup +// Image is not centered + +[[fig:overlap]] +.Requirements on overlapping vs non-overlapping [keyword]#sub-buffer# +[width="100%",options="header",cols="50%,50%"] +|==== +| *SYCL Application Enqueue Order* | *SYCL Kernel Execution Order* +a| +//[source,,subs="quotes"] works only with HTML but hurts the PDF output +[listing,subs="quotes"] +---- +sycl::queue q1(context1); +q1.submit(_CG~a~(b1~{RW,[0,10)}~)_); +q1.submit(_CG~b~(b1~{RW,[10,20)~)_); +q1.submit(_CG~c~(b1~RW,[5,15)~)_); +---- + a| +image::{images}/overlap.svg[align="center",opts="{imageopts}"] +|==== + +It is permissible for command groups that only read data to not copy that data +back to the host or other devices after reading and for the runtime to maintain +multiple read-only copies of the data on multiple devices. + +A special case of requirement is the one defined by a *host accessor*. +Host accessors are represented with +_H(MemoryObject~accessMode~)_, e.g, +_H(b1~RW~)_ represents a host accessor to _b1_ in read-write mode. +Host accessors are a special type of accessor constructed from a memory +object outside a command group, and require that the data associated with +the given memory object is available on the host in the given pointer. +This causes the runtime to block on construction of this object until the +requirement has been satisfied. +*Host accessor* objects are effectively barriers on all accesses to +a certain memory object. +<> shows an example of multiple command groups +enqueued to the same queue. Once the host accessor _H(b1~RW~)_ is reached, +the execution cannot proceed until _CG~a~_ is finished. +However, _CG~b~_ does not have any requirements on _b1_, therefore, it can +execute concurrently with the barrier. +Finally, _CG~c~_ will be enqueued after _H(b1~RW~)_ is finished, +but still has to wait for _CG~b~_ to conclude for all its requirements to +be satisfied. +See <> for details on synchronization rules. + +// Formerly in host_acc.tex +// Uses same definitions for cga, cgb, cgc, and hostA in code and picture, +// but they're marked up in different languages, so no sharing is possible. + +// Jon: source code markup doesn't work with embedded asciidoctor markup +// Image is not centered + +[[fig:host-acc]] +.Execution of command groups when using host accessors +[width="100%",options="header",cols="50%,50%"] +|==== +| *SYCL Application Enqueue Order* | *SYCL Kernel Execution Order* +a| +//[source,,subs="quotes"] works only with HTML but hurts the PDF output +[listing,subs="quotes"] +---- +sycl::queue q1; +q1.submit(_CG~a~(b1~RW~)_); +q1.submit(_CG~b~(b2~RW~)_); + +_H(b1~RW~)_; + +q1.submit(_CG~c~(b1~RW~, b2~RW~)_); +---- + a| +image::{images}/host-acc.svg[align="center",opts="{imageopts}"] +|==== + + +=== SYCL device memory model + +The memory model for SYCL devices is based on the OpenCL 1.2 memory model. +Work-items executing in a kernel have access to three distinct address spaces +(memory regions) and a virtual address space overlapping some concrete address spaces: + + * <> is accessible to all work-items in all work-groups. + Work-items can read from or write to any element of a global memory + object. Reads and writes to global memory may be cached depending on the + capabilities of the device. Global memory is persistent across kernel + invocations, however there is no guarantee that two concurrently + executing kernels can simultaneously write to the same memory object and + expect correct results. + * <> is accessible to all work-items in a single + work-group. Attempting to access local memory in one work-group from + another work group results in undefined behavior. This memory region can be + used to allocate variables that are shared by all work-items in a + work-group. Work-group-level visibility allows local memory to be + implemented as dedicated regions of the device memory where this is + appropriate. + * <> is a region of memory private to a work-item. + Attempting to access private memory in one work-item from another work-item + results in undefined behavior. + * <> is a virtual address space which overlaps the + global, local and private address spaces. + +==== Access to memory + +Accessors in the device kernels provide access to the memory objects, +acting as pointers to the corresponding address space. + +Pointers can be passed directly as kernel arguments if an implementation +supports <>. See <> for information on when it is legal +to dereference pointers passed from the host inside kernels. + +To allocate local memory within a kernel, the user can either pass +a [code]#sycl::local_accessor# object as a argument to an ND-range +kernel (that has a user-defined work-group size), or +can define a variable in work-group scope inside +[code]#sycl::parallel_for_work_group#. + +Any variable defined inside a [code]#sycl::parallel_for# scope or +[code]#sycl::parallel_for_work_item# scope will be allocated in private +memory. Any variable defined inside a [code]#sycl::parallel_for_work_group# +scope will be allocated in local memory. + +Users can create accessors that reference sub-buffers as well as entire buffers. + + +Within kernels, the underlying {cpp} pointer types can be obtained from an +accessor. The pointer types will contain a compile-time deduced address space. +So, for example, if a {cpp} pointer is obtained from an accessor to global memory, +the {cpp} pointer type will have a global address space attribute attached to it. +The address space attribute will be compile-time propagated to other pointer +values when one pointer is initialized to another pointer value using a defined +algorithm. + +When developers need to explicitly state the address space of a pointer value, +one of the explicit pointer classes can be used. There is a different explicit +pointer class for each address space: [code]#sycl::raw_local_ptr#, +[code]#sycl::raw_global_ptr#, [code]#sycl::raw_private_ptr#, + [code]#sycl::raw_generic_ptr#, +[code]#sycl::decorated_local_ptr#, +[code]#sycl::decorated_global_ptr#, [code]#sycl::decorated_private_ptr#, + or [code]#sycl::decorated_generic_ptr#. + +The classes with the [code]#decorated# prefix expose pointers that use an +implementation-defined address space decoration, while the classes with the +[code]#raw# prefix do not. Buffer accessors with an access target +[code]#target::device# or [code]#target::constant_buffer# and local accessors +can be converted into explicit pointer classes ([code]#multi_ptr)#. Explicit +pointer class values cannot be passed as arguments to kernels or stored in +global memory. + +For templates that need to adapt to different address spaces, a +[code]#sycl::multi_ptr# class is defined which is templated +via a compile-time constant enumerator value to specify the address space. + +[[sec:memoryconsistency]] +=== SYCL memory consistency model + +The SYCL memory consistency model is based upon the memory consistency +model of the {cpp} core language. Where SYCL offers extensions to classes and +functions that may affect memory consistency, the default behavior when these +extensions are not used always matches the behavior of standard {cpp}. + +A SYCL implementation must guarantee that the same memory consistency model is +used across host and device code. Every <> must support the +memory model defined by the minimum version of {cpp} described in +<>; SYCL implementations supporting +additional versions of {cpp} must also support the corresponding memory models. + +Within a work-item, operations are ordered according to the _sequenced before_ +relation defined by the {cpp} core language. + +Ensuring memory consistency across different work-items requires careful usage +of <> operations, <> operations and atomic +operations. The ordering of operations across different work-items is +determined by the _happens before_ relation defined by the {cpp} core language, +with a single relation governing all address spaces (memory regions). + +On any SYCL device, local and global memory may be made consistent +across work-items in a single <> through use of a <> +operation. On SYCL devices supporting acquire-release or sequentially +consistent memory orderings, all memory visible to a set of work-items may be +made consistent across the work-items in that set through the use of +<> and atomic operations. + +Memory consistency between the host and SYCL device(s), or different SYCL +devices in the same context, can be guaranteed through synchronization in +the host application as defined in <>. On SYCL devices +supporting concurrent atomic accesses to USM allocations and acquire-release or sequentially +consistent memory orderings, cross-device memory consistency can be +enforced through the use of <> and atomic operations. + +==== Memory ordering + +[source,,linenums] +---- +include::{header_dir}/memoryOrder.h[lines=4..-1] +---- + +The memory synchronization order of a given atomic operation is controlled by a +[code]#sycl::memory_order# parameter, which can take one of the following +values: + + * [code]#sycl::memory_order::relaxed#; + * [code]#sycl::memory_order::acquire#; + * [code]#sycl::memory_order::release#; + * [code]#sycl::memory_order::acq_rel#; + * [code]#sycl::memory_order::seq_cst#. + +The meanings of these values are identical to those defined in the {cpp} core +language. + +The complete set of memory orders is not guaranteed to be supported by every +device, nor across all combinations of devices within a context. The memory +orders supported by a specific device and context can be queried using +functionalities of the [code]#sycl::device# and [code]#sycl::context# classes, +respectively. + +[NOTE] +==== +SYCL implementations are not required to support a memory order equivalent +to [code]#std::memory_order::consume#, and using this ordering within a SYCL +device kernel results in undefined behavior. Developers are encouraged to use +[code]#sycl::memory_order::acquire# instead. +==== + +==== Memory scope + +[source,,linenums] +---- +include::{header_dir}/memoryScope.h[lines=4..-1] +---- + +The set of <> and devices to which the memory ordering +constraints of a given atomic operation apply is controlled by a +[code]#sycl::memory_scope# parameter, which can take one of the following +values: + + * [code]#sycl::memory_scope::work_item# The ordering constraint applies + only to the calling work-item; + * [code]#sycl::memory_scope::sub_group# The ordering constraint applies + only to work-items in the same <> as the calling work-item; + * [code]#sycl::memory_scope::work_group# The ordering constraint applies + only to work-items in the same <> as the calling + work-item; + * [code]#sycl::memory_scope::device# The ordering constraint applies only + to work-items executing on the same device as the calling work-item; + * [code]#sycl::memory_scope::system# The ordering constraint applies to any + work-item or host thread in the system that is currently permitted to + access the memory allocation containing the referenced object, as + defined by the capabilities of <> and <>. + +The broadest scope that can be applied to an atomic operation corresponds to +the set of work-items which can access the associated memory location. For +example, the broadest scope that can be applied to atomic operations in +work-group local memory is [code]#sycl::memory_scope::work_group#. If a +broader scope is supplied, the behavior is as-if the narrowest scope containing +all work-items which can access the associated memory location was supplied. + +[NOTE] +==== +The addition of memory scopes to the {cpp} memory model modifies the +definition of some concepts from the {cpp} core language. For example: +data races, the synchronizes-with relationship and sequential +consistency must be defined in a way that accounts for atomic +operations with differing (but compatible) scopes, in a manner +similar to the <>. Efforts to +formalize the memory model of SYCL are ongoing, and a formal memory model +will be included in a future version of the SYCL specification. +==== + +==== Atomic operations + +Atomic operations can be performed on memory in buffers and USM. The +[code]#sycl::atomic_ref# class must be used to provide safe atomic access +to the buffer or USM allocation from device code. + +==== Forward progress + +Memory consistency guarantees are independent of any forward progress +guarantees. A SYCL implementation must execute work-items concurrently +and must ensure that the work-items in a group obey the semantics of +<>, but are not required to provide any +additional forward progress guarantees. + +Synchronizing work-items via memory operations is unsafe in general, but is +supported if and only if the following conditions are true: + + * acquire-release or sequentially consistent memory ordering is supported + at the scope containing the set of work-items being synchronized; + + * the work-items being synchronized are guaranteed to make forward progress + with respect to one another. + +The ability of work-items to make forward progress with respect to work-items +in other work-groups is implementation-defined. + +// Later, this label will move onto a new subsection - see below +[[sec:progmodel.cpp]] +== The SYCL programming model + +A SYCL program is written in standard {cpp}. Host code and device code is +written in the same {cpp} source file, enabling instantiation of templated +kernels from host code and also enabling kernel source code to be shared +between host and device. +The device kernels are encapsulated {cpp} callable types (a function object +with [code]#operator()# or a lambda function), which have +been designated to be compiled as SYCL kernels. + +SYCL programs target heterogeneous systems. The kernels may be compiled and +optimized for multiple different processor architectures with very different +binary representations. + + +// TODO: Add \subsection{SYCL {cpp} language requirements} before merging +// Don't do until then to avoid changing section numbers +// [[sec:progmodel.cpp]] + +[[sec:progmodel.minimumcppversion]] +=== Minimum version of {cpp} + +The {cpp} features used in SYCL are based on a specific version of {cpp}. +Implementations of SYCL must support this minimum {cpp} version, which defines the +{cpp} constructs that can consequently be used by SYCL feature definitions +(for example, lambdas). + +The minimum {cpp} version of this SYCL specification is determined by the normative {cpp} +core language defined in <>. All implementations +of this specification must support at least this core language, and features within this +specification are defined using features of the core language. Note that not all +core language constructs are supported within <> or code +invoked by a <>, as detailed by +<>. + +Implementations may support newer {cpp} versions than the minimum required by SYCL. +Code written using newer features than the SYCL requirement, though, may +not be portable to other implementations that don't support the same {cpp} version. + + +[[sec:progmodel.futurecppversion]] +=== Alignment with future versions of {cpp} + +Some features of SYCL are aligned with the next {cpp} specification, as defined +in <>. + +The following features are pre-adopted by SYCL 2020 and made available in the +[code]#sycl::# namespace: [code]#std::span#, +[code]#std::bit_cast#. The implementations of pre-adopted features are +compliant with the next {cpp} specification, and are expected to forward directly +to standard {cpp} features in a future version of SYCL. + +The following features of SYCL 2020 use syntax based on the next {cpp} +specification: [code]#sycl::atomic_ref#. These features behave as +described in the next {cpp} specification, barring modifications to ensure +compatibility with other SYCL 2020 features and heterogeneous +programming. Any such modifications are documented in the corresponding +sections of this specification. + +=== Basic data parallel kernels + +Data-parallel <>s that execute as +multiple <>s and where no local synchronization is required are enqueued +with the [code]#sycl::parallel_for# function parameterized by a +[code]#sycl::range# parameter. These kernels will execute the kernel +function body once for each work-item in the specified <>. + +Functionality tied to <> of work-items, including +<> and <>, must not be used +within these kernels. + +Variables with <> semantics can be added to basic data parallel +kernels using the features described in <>. + +=== Work-group data parallel kernels + +Data parallel <>s can also execute in a mode where the set of +<>s is divided into <>s of user-defined dimensions. +The user specifies the global <> and local work-group size as +parameters to the [code]#sycl::parallel_for# function with a +[code]#sycl::nd_range# parameter. In this mode of execution, +kernels execute over the <> in work-groups of the specified +size. It is possible to share data among work-items within the same +work-group in <> or <> and to synchronize between +work-items in the same work-group by calling the +[code]#group_barrier# function. All work-groups in a given +[code]#parallel_for# will be the same size, and the global size +defined in the nd-range must be a multiple of the work-group size in +each dimension. + +Work-groups may be further subdivided into <>s. +The size and number of sub-groups is implementation-defined and may differ for +each kernel, and different devices may make different guarantees with respect +to how sub-groups within a work-group are scheduled. The maximum number of +work-items in any sub-group in a kernel is based on a combination of the kernel +and its dispatch dimensions. The size of any sub-group in the dispatch is +between 1 and this maximum sub-group size, and the size of an individual +sub-group is invariant for the duration of a kernel's execution. Similarly +to work-groups, the work-items within the same sub-group can be synchronized +by calling the [code]#group_barrier# function. + +To maximize portability across devices, developers should not assume that +work-items within a sub-group execute in any particular order, that work-groups +are subdivided into sub-groups in a specific way, nor that two sub-groups +within a work-group will make independent forward progress with respect to one +another. + +Variables with <> semantics can be added to work-group data +parallel kernels using the features described in <>. + + +=== Hierarchical data parallel kernels + +[NOTE] +==== +Based on developer and implementation feedback, the hierarchical +data parallel kernel feature described next is undergoing +improvements to better align with the frameworks and patterns +prevalent in modern programming. As this is a key part of the SYCL +API and we expect to make changes to it, we temporarily recommend +that new codes refrain from using this feature until the new API +is finished in a near-future version of the SYCL specification, +when full use of the updated feature will be recommended for use +in new code. Existing codes using this feature will of course be +supported by conformant implementations of this specification. +==== + +The SYCL compiler provides a way of specifying data parallel kernels +that execute within work-groups via a different syntax which +highlights the hierarchical nature of the parallelism. This mode is +purely a compiler feature and does not change the execution model of +the kernel. Instead of calling [code]#sycl::parallel_for# the +user calls [code]#sycl::parallel_for_work_group# with a +[code]#sycl::range# value representing the number of +work-groups to launch and optionally a second +[code]#sycl::range# representing the size of each work-group +for performance tuning. All code within the +[code]#parallel_for_work_group# scope effectively executes once +per work-group. Within the [code]#parallel_for_work_group# scope, +it is possible to call [code]#parallel_for_work_item# which +creates a new scope in which all work-items within the current +work-group execute. This enables a programmer to write code that looks +like there is an inner work-item loop inside an outer work-group loop, +which closely matches the effect of the execution model. All variables +declared inside the [code]#parallel_for_work_group# scope are +allocated in work-group local memory, whereas all variables declared +inside the [code]#parallel_for_work_item# scope are declared in +private memory. All [code]#parallel_for_work_item# calls within a +given [code]#parallel_for_work_group# execution must have the +same dimensions. + + +=== Kernels that are not launched over parallel instances + +Simple kernels for which only a single instance of the kernel function will be +executed are enqueued with the [code]#sycl::single_task# function. The +kernel enqueued takes no "`work-item id`" parameter and will only execute once. +The behavior is logically equivalent to executing a kernel on a single compute +unit with a single work-group comprising only one work-item. Such kernels may be +enqueued on multiple queues and devices and as a result may be executed in +task-parallel fashion. + + +[[sec:pre-defined-kernels]] +=== Pre-defined kernels + +Some <> may expose pre-defined functionality to users as kernels. +These kernels are not programmable, hence they are not bound by the SYCL +{cpp} programming model restrictions, and how they are written is +implementation-defined. + + +[[sec:synchronization]] +=== Synchronization + +Synchronization of processing elements executing inside a device is handled +by the SYCL device kernel following the SYCL kernel execution model. +The synchronization of the different SYCL device kernels executing with +the host memory is handled by the SYCL application via the SYCL runtime. + +==== Synchronization in the SYCL application + +Synchronization points between host and device(s) are exposed through +the following operations: + + * _Buffer destruction_: The destructors for + [code]#sycl::buffer#, [code]#sycl::unsampled_image# and + [code]#sycl::sampled_image# objects wait for all submitted work on + those objects to complete and to copy the data back to host memory + before returning. These destructors only wait if the object was + constructed with attached host memory and if data needs to be copied + back to the host. ++ +-- +More complex forms of synchronization on buffer destruction +can be specified by the user by constructing buffers with other kinds of +references to memory, such as [code]#shared_ptr# and [code]#unique_ptr#. +-- + * _Host Accessors_: The constructor for a host accessor waits for all + kernels that modify the same buffer (or image) in any queues to complete + and then copies data back to host memory before the constructor returns. + Any command groups with requirements to the same memory object cannot + execute until the host accessor is destroyed as shown on <>. + * _Command group enqueue_: The <> internally ensures + that any command groups added to queues have the correct event + dependencies added to those queues to ensure correct operation. Adding + command groups to queues never blocks. Instead any required + synchronization is added to the queue and events of type + [code]#sycl::event# are returned by the queue's submit function + that contain event information related to the specific command group. + * _Queue operations_: The user can manually use queue operations, + such as [code]#sycl::queue::wait()# to block execution of the calling thread until all + the command groups submitted to the queue have finished execution. Note + that this will also affect the dependencies of those command groups in + other queues. + * _SYCL event objects_: SYCL provides [code]#sycl::event# + objects which can be used for synchronization. If synchronization is + required across SYCL contexts from different <>, then the + <> ensures that extra host-based synchronization is + added to enable the SYCL event objects to operate between contexts + correctly. + +Note that the destructors of other SYCL objects +([code]#sycl::queue#, [code]#sycl::context#,{ldots}) do +not block. Only a [code]#sycl::buffer#, [code]#sycl::sampled_image# or +[code]#sycl::unsampled_image# destructor might block. The rationale is +that an object without any side effect on the host does not need to +block on destruction as it would impact the performance. So it is up +to the programmer to use a member function to wait for completion in some +cases if this does not fit the goal. +See <> for more information +on object life time. + +==== Synchronization in SYCL kernels + +In SYCL, synchronization can be either global or local within a +group of work-items. Synchronization between work-items in a single +group is achieved using a <>. + +All the work-items of a group must execute the barrier before any are +allowed to continue execution beyond the barrier. Note that the +group barrier must be encountered by all work-items of a +group executing the kernel or by none at all. In SYCL, +<> and <> functionality is +exposed via the [code]#group_barrier# function. + +Synchronization between work-items in different work-groups via atomic +operations is possible only on SYCL devices with certain capabilities, +as described in <>. + +=== Error handling + +In SYCL, there are two types of errors: synchronous errors that can be +detected immediately when an API call is made, and <> +that can only be detected later after an API call has returned. +Synchronous errors, such as failure to construct an +object, are reported immediately by the runtime throwing an +exception. <>, such as an error occurring during +execution of a kernel on a device, are reported via an asynchronous +error-handler mechanism. + +<> are not reported immediately as they occur. The +asynchronous error handler for a context or queue is called with a +[code]#sycl::exception_list# object, which contains a list of +asynchronously-generated exception objects, on the conditions described by +<> and <>. + +Asynchronous errors may be generated regardless of whether the user has +specified any asynchronous error handler(s), as described in +<>. + +Some <> can report errors that are specific to the platform +they are targeting, or that are more concrete than the errors provided +by the SYCL API. +Any error reported by a <> must derive from the base +[code]#sycl::exception#. +When a user wishes to capture specifically an error thrown by a <>, +she must include the <>-specific headers for said <>. + +=== Fallback mechanism + +A <> can be submitted either to a single queue +to be executed on, or to a secondary queue. If a +<> fails to be enqueued to the primary queue, then +the system will attempt to enqueue it to the secondary queue, if given as a +parameter to the submit function. If the <> fails to be +queued to both of these queues, then a synchronous SYCL exception will be thrown. + +It is possible that a command group may be successfully enqueued, +but then asynchronously fail to run, for some reason. In this case, it may be +possible for the runtime system to execute the <> +on the secondary queue, instead of the primary queue. The situations where a SYCL +runtime may be able to achieve this asynchronous fall-back is implementation-defined. + +=== Scheduling of kernels and data movement + +A <> takes a reference to a command group +[code]#handler# as a parameter and anything within that scope is +immediately executed and takes the handler object as a parameter. The +intention is that a user will perform calls to SYCL functions, member functions, +destructors and constructors inside that scope. These calls will be non-blocking +on the host, but enqueue operations to the queue that the command group is submitted +to. All user functions within the command group scope will be called on the host +as the <> is executed, but any device kernels it +invokes will be added to the SYCL <>. All kernels added to the <> +will be executed out-of-order from each other, according to their data dependencies. + + +[[sec:managing-object-lifetimes]] +=== Managing object lifetimes + +A SYCL application does not initialize any <> features until a +[code]#sycl::context# object is created. A user does not need to +explicitly create a [code]#sycl::context# object, but they do need to +explicitly create a [code]#sycl::queue# object, for which a +[code]#sycl::context# object will be implicitly created if not provided +by the user. + +All <> objects encapsulated in SYCL objects are reference-counted and will +be destroyed once all references have been released. This means that a user needs +only create a SYCL <> (which will automatically create an SYCL context) for +the lifetime of their application to initialize and release any <> objects +safely. + +There is no global state specified to be required in SYCL implementations. This +means, for example, that if the user creates two queues without explicitly +constructing a common context, then a SYCL implementation does not have to +create a shared context for the two queues. Implementations are free to share or +cache state globally for performance, but it is not required. + +Memory objects can be constructed with or without attached host memory. If no +host memory is attached at the point of construction, then destruction of that +memory object is non-blocking. The user may use {cpp} standard pointer classes +for sharing the host data with the user application and for defining blocking, +or non-blocking behavior of the buffers and images. +If host memory is attached by using a raw pointer, then the default behavior is +followed, which is that the destructor will block until any command groups +operating on the memory object have completed, then, if the contents of the +memory object is modified on a device those contents are copied back to host and +only then does the destructor return. + +In the case where host memory is shared +between the user application and the <> with a +[code]#std::shared_ptr#, then the reference counter +of the [code]#std::shared_ptr# determines whether the buffer needs to copy +data back on destruction, and in that case the blocking or non-blocking behavior +depends on the user application. + +Instead of a [code]#std::shared_ptr#, a [code]#std::unique_ptr# may be +provided, which uses move semantics for initializing and using the +associated host memory. In this case, the behavior of the buffer in +relation to the user application will be non-blocking on destruction. + +As said in <>, the only blocking +operations in SYCL (apart from explicit wait operations) are: + + * host accessor constructor, which waits for any kernels enqueued before + its creation that write to the corresponding object to finish and be + copied back to host memory before it starts processing. The host + accessor does not necessarily copy back to the same host memory as + initially given by the user; + * memory object destruction, in the case where copies back to host memory + have to be done or when the host memory is used as a backing-store. + + +=== Device discovery and selection + +A user specifies which queue to submit a +<> and each <> is +targeted to run on a specific <> (and <>). A user +can specify the actual device on queue creation, or they can specify a +<> which causes the <> to choose a +device based on the user's provided preferences. Specifying a +<> causes the <> to perform device +discovery. No device discovery is performed until a SYCL +<> is passed to a queue constructor. Device +topology may be cached by the <>, but this is not +required. + +Device discovery will return all <> from all <> exposed +by all the supported <>. + +=== Interfacing with the SYCL backend API + +There are two styles of developing a SYCL application: + +. writing a pure SYCL generic application; +. writing a SYCL application that relies on some <> specific behavior. + +When users follow 1., there is no assumption about what <> will be used during +compilation or execution of the SYCL application. Therefore, the <> +is not assumed to be available to the developer. +Only standard {cpp} types and interfaces are assumed to be available, +as described in <>. +Users only need to include the [code]## header to write a +SYCL generic application. + +On the other hand, when users follow 2., they must know what <>s +they are using. In this case, any header required for the normal +programmability of the <> is assumed to be available to the user. +In addition to the [code]## header, users must also +include the <>-specific header as defined in +<>. The <>-specific header +provides the interoperability interface for the SYCL API to interact with +<>. + +The interoperability API is defined in <>. + +== Memory objects + +SYCL memory objects represent data that is handled by the <> and +can represent allocations in one or multiple <> at any time. +Memory objects, both buffers and images, may have one or more underlying +<> to ensure that <> objects +can use data in any device. A SYCL implementation may have multiple +<> for the same device. +The <> is responsible for ensuring the different copies are up-to-date +whenever necessary, using whatever mechanism is available in the system +to update the copies of the underlying <>. + +[NOTE] +.Implementation note +==== +A valid mechanism for this update is to transfer the data from one +<> into the system memory using the <>-specific +mechanism available, and then transfer it to a different device +using the mechanism exposed by the new <>. +==== + +Memory objects in SYCL fall into one of two categories: <> objects +and <> objects. A buffer object stores a one-, two- or +three-dimensional collection of elements that are stored linearly directly back +to back in the same way C or {cpp} stores arrays. An image object is used to store +a one-, two- or three-dimensional texture, frame-buffer or image data that may be +stored in an optimized and device-specific format in memory and must be accessed +through specialized operations. + +Elements of a buffer object can be a scalar data type (such as an +[code]#int# or [code]#float#), vector data type, or a user-defined +structure. In SYCL, a <> object is a templated type +([code]#sycl::buffer#), parameterized by the element type and number of +dimensions. An <> object is stored in one of a limited number of +formats. The elements of an image object are selected from a list of +predefined image formats which are provided by an underlying <> +implementation. Images are encapsulated in the +[code]#sycl::unsampled_image# or [code]#sycl::sampled_image# +types, which are templated by the number of dimensions in the image. The +minimum number of elements in a memory object is one. + +The fundamental differences between a buffer and an image object are: + + * elements in a buffer are stored in an array of 1, 2 or 3 dimensions and + can be accessed using an accessor by a kernel executing on a device. The + accessors for kernels provide a member function to get {cpp} pointer types, or the + [code]#sycl::global_ptr# class; + * elements of an image are stored in a format that is opaque to the user + and cannot be directly accessed using a pointer. SYCL provides image + accessors and samplers to allow a kernel to read from or write to an + image; + * for a buffer object the data is accessed within a kernel in the same + format as it is stored in memory, but in the case of an image object the + data is not necessarily accessed within a kernel in the same format as + it is stored in memory; + * image elements are always a 4-component vector (each component can be a + float or signed/unsigned integer) in a kernel. Accessors that read an + image convert image elements from their storage format into a 4-component + vector. ++ +-- +Similarly, the SYCL accessor member functions provided to write to an +image convert the image element from a 4-component vector to +the appropriate image format specified such as four 8-bit +elements, for example. +-- + +Users may want fine-grained control of the synchronization, memory management +and storage semantics of SYCL image or buffer objects. For example, a user may +wish to specify the host memory for a memory object to use, but may not want the +memory object to block on destruction. + +Depending on the control and the use cases of the SYCL applications, +well established {cpp} classes and patterns can be used for reference counting and +sharing data between user applications and the <>. For control over +memory allocation on the host and mapping between host and device memory, +pre-defined or user-defined {cpp} [code]#std::allocator# classes are +used. For better control of synchronization between a SYCL and a non SYCL +application that share data, [code]#std::shared_ptr# and +[code]#std::mutex# classes are used. + + +== Multi-dimensional objects and linearization + +SYCL defines a number of multi-dimensional objects such as buffers and +accessors. The iteration space of work-items in a kernel may also be +multi-dimensional. The size of each dimension is defined by a [code]#range# +object of one, two or three dimensions, and an element in the multi-dimensional +space can be identified using an [code]#id# object with the same number of +dimensions as the corresponding [code]#range#. + +[[sec:multi-dim-linearization]] +=== Linearization + +Some multi-dimensional objects can be viewed in a linear form. When this +happens, the right-most term in the object's range varies fastest in the +linearization. + +A three-dimensional element [code]#id{id0, id1, id2}# within a +three-dimensional object of range [code]#range{r0, r1, r2}# has a linear +position defined by: +[latexmath] +++++ +id2 + (id1 \cdot r2) + (id0 \cdot r1 \cdot r2) +++++ + +A two-dimensional element [code]#id{id0, id1}# within a two-dimensional +[code]#range{r0, r1}# follows a similar equation: +[latexmath] +++++ +id1 + (id0 \cdot r1) +++++ + +A one-dimensional element [code]#id{id0}# within a one-dimensional range +[code]#range{r0}# is equivalent to its linear form. + + +[[sec:multi-dim-subscript]] +=== Multi-dimensional subscript operators + +Some multi-dimensional objects can be indexed using the subscript operator +where consecutive subscript operators correspond to each dimension. The +right-most operator varies fastest, as with standard {cpp} arrays. Formally, a +three-dimensional subscript access [code]#a[id0][id1][id2]# references the element +at [code]#id{id0, id1, id2}#. A two-dimensional subscript access +[code]#a[id0][id1]# references the element at [code]#id{id0, id1}#. A +one-dimensional subscript access [code]#a[id0]# references the element at +[code]#id{id0}#. + + +== Implementation options + +The SYCL language is designed to allow several different possible +implementations. The contents of this section are non-normative, so +implementations need not follow the guidelines listed here. However, this +section is intended to help readers understand the possible strategies that can +be used to implement SYCL. + +=== Single source multiple compiler passes + +With this technique, known as <>, there are separate host and device +compilers. Each SYCL source file is compiled two times: once by the host +compiler and once by the device compiler. An implementation could support more +than one device compiler, in which case each SYCL source file is compiled +more than two times. The host compiler in this technique could be an +off-the-shelf compiler with no special knowledge of SYCL, but the device +compiler must be SYCL aware. The device compiler parses the source file to +identify each <> and any <> it calls. SYCL is designed so that this analysis can be +done statically. The device compiler then generates code only for the +<> and the <>. + +Typically, the device compilers generate header files which interface between +the host compiler and the <>. Therefore, the device compiler +runs first, and then the host compiler consumes these header files when +generating the host code. + +The device compilers in this technique generate one or more <> for the <>, which +can be read by the <>. Each <> could either +contain native ISA for a device or it could contain an intermediate language +such as SPIR-V. In the later case, the <> must translate the +intermediate language into native device ISA when the <> +is submitted to a device. + +Since this technique has separate host and device compilers, there needs to be +some way to associate a <> (which is compiled by the +device compiler) with the code that invokes it (which is compiled by the host +compiler). Implementations conformant to the reduced feature set +(<>) can do this by using the {cpp} type of the +<>. This type is specified via the <> +template parameter if the <> is a lambda function, or it +is obtained from the class type if the <> is an object. +Implementations conformant to the full feature set (<>) +do not require a <> at the invocation site, so they must implement +some other way to make the association. + + +=== Single source single compiler pass + +With this technique, the vendor implements a custom compiler that reads each +SYCL source file only once, and that compiler generates the host code as well +as the <> for the <>. As in the <> case, each <> could +either contain native device ISA or an intermediate language. + +=== Library-only implementation + +It is also possible to implement SYCL purely as a library, using an +off-the-shelf host compiler with no special support for SYCL. In such an +implementation, each <> may run on the host system. + + +== Language restrictions in kernels + +The SYCL <> are executed on SYCL devices and all of the +functions called from a SYCL kernel are going to be compiled for the device +by a SYCL <>. Due to restrictions of the heterogeneous +devices where the SYCL kernel will execute, there are certain restrictions +on the base {cpp} language features that can be used inside kernel code. For +details on language restrictions please refer +to <>. + +SYCL kernels use arguments that are captured by value in the +<> or are passed from the host to the device using +<>. Sharing data structures between host and device code +imposes certain restrictions, such as using only objects that are +<>, and in general, no pointers +initialized for the host can be used on the device. SYCL memory objects, +such as [code]#sycl::buffer#, [code]#sycl::unsampled_image#, and +[code]#sycl::sampled_image#, cannot be passed to a kernel. Instead, a kernel +must interact with these objects through <>. +No hierarchical structures of +these memory object classes are supported and any other data containers need to be +converted to the SYCL data management classes using the SYCL interface. For +more details on the rules for kernel parameter passing, please refer +to <>. + +Pointers to <> allocations +may be passed to a kernel either directly as arguments or indirectly +inside of other objects. Pointers to <> allocations that are +passed as kernel arguments are treated as being in the global +address space. + +[[sec::device.copyable]] +=== Device copyable + +The SYCL implementation may need to copy data between the host and a device +or between two devices. For example, this may occur when a <> +has a requirement for the contents of a buffer or when the application passes +certain arguments to a <> (as described in +<>). Such data must have a type that is +<> as defined below. + +Any type that is trivially copyable (as defined by the {cpp} core language) is +implicitly device copyable. In addition, the following types from the {cpp} +core language are implicitly device copyable: + + * [code]#std::array#; + * [code]#std::array# if [code]#T# is device copyable; + * [code]#std::optional# if [code]#T# is device copyable; + * [code]#std::pair# if [code]#T1# and [code]#T2# are device copyable; + * [code]#std::tuple<>#; + * [code]#+std::tuple+# if all the types in the parameter pack + [code]#Types# are device copyable; + * [code]#std::variant<>#; + * [code]#+std::variant+# if all the types in the parameter pack + [code]#Types# are device copyable; + * [code]#std::basic_string_view#; + * [code]#std::span# (the [code]#std::span# type has + been introduced in {cpp}20). + +[NOTE] +==== +The types [code]#std::basic_string_view# and +[code]#std::span# are both view types, which reference +underlying data that is not contained within their type. Although these view +types are device copyable, the implementation copies just the view and not +the contained data when doing an inter-device copy. In order to reference the +contained data after such a copy, the application must allocate the contained +data in unified shared memory (USM) that is accessible on both the host and +device (or on both devices in the case of a device-to-device copy). +==== + +In addition, the implementation may allow the application to explicitly declare +certain class types as device copyable. If the implementation has this support, +it must predefine the preprocessor macro [code]#SYCL_DEVICE_COPYABLE# to +[code]#1#, and it must not predefine this preprocessor macro if it does not +have this support. When the implementation has this support, a class type +[code]#T# is device copyable if all of the following statements are true: + + * The application defines the trait [code]#is_device_copyable_v# to + [code]#true#; + * Type [code]#T# has at least one eligible copy constructor, move + constructor, copy assignment operator, or move assignment operator; + * Each eligible copy constructor, move constructor, copy assignment operator, + and move assignment operator is [code]#public#; + * When doing an inter-device transfer of an object of type [code]#T#, the + effect of each eligible copy constructor, move constructor, copy assignment + operator, and move assignment operator is the same as a bitwise copy of the + object; + * Type [code]#T# has a [code]#public# non-deleted destructor; + * The destructor has no effect when executed on the device. + +When the application explicitly declares a class type to be device copyable, +arrays of that type and cv-qualified versions of that type are also device +copyable. + +[NOTE] +==== +It is unspecified whether the implementation actually calls the copy +constructor, move constructor, copy assignment operator, or move assignment +operator of a class declared as [code]#is_device_copyable_v# when doing an +inter-device copy. Since these operations must all be the same as a bitwise +copy, the implementation may simply copy the memory where the object resides. +Likewise, it is unspecified whether the implementation actually calls the +destructor for such a class on the device since the destructor must have no +effect on the device. +==== + +=== SYCL linker + +In SYCL, only offline linking is supported for SYCL programs and libraries, +however the mechanism is optional. +In the case of linking {cpp} functions to a SYCL application, +where the definitions are not available in the +same translation unit of the compiler, then the macro [code]#SYCL_EXTERNAL# +has to be provided. + + +=== Functions and data types available in kernels + +Inside kernels, the functions and data types available are restricted by the +underlying capabilities of <> devices. + + +== Endianness support + +SYCL does not mandate any particular byte order, but the byte order of the +host always matches the byte order of the devices. This allows data to be +copied between the host and the devices without any byte swapping. + +== Example SYCL application + +Below is a more complex example application, combining some of the features +described above. + +[source,,linenums] +---- +include::{code_dir}/largesample.cpp[lines=4..-1] +---- + + +// %%%%%%%%%%%%%%%%%%%%%%%%%%%% end architecture %%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/adoc/chapters/copyright-spec.adoc b/adoc/chapters/copyright-spec.adoc new file mode 100644 index 00000000..fa373956 --- /dev/null +++ b/adoc/chapters/copyright-spec.adoc @@ -0,0 +1,80 @@ +Copyright 2011-2021 The Khronos Group, Inc. + +This Specification is protected by copyright laws and contains material +proprietary to Khronos. Except as described by these terms, it or any +components may not be reproduced, republished, distributed, transmitted, +displayed, broadcast or otherwise exploited in any manner without the +express prior written permission of Khronos. +Khronos grants a conditional copyright license to use and reproduce the +unmodified Specification for any purpose, without fee or royalty, EXCEPT no +licenses to any patent, trademark or other intellectual property rights are +granted under these terms. + +Khronos makes no, and expressly disclaims any, representations or +warranties, express or implied, regarding this Specification, including, +without limitation: merchantability, fitness for a particular purpose, +non-infringement of any intellectual property, correctness, accuracy, +completeness, timeliness, and reliability. +Under no circumstances will Khronos, or any of its Promoters, Contributors +or Members, or their respective partners, officers, directors, employees, +agents or representatives be liable for any damages, whether direct, +indirect, special or consequential damages for lost revenues, lost profits, +or otherwise, arising from or in connection with these materials. + +This Specification has been created under the Khronos Intellectual Property +Rights Policy, which is Attachment A of the Khronos Group Membership +Agreement available at https://www.khronos.org/files/member_agreement.pdf, and which +defines the terms 'Scope', 'Compliant Portion', and 'Necessary Patent Claims'. +Parties desiring to implement the Specification and make use of Khronos trademarks +in relation to that implementation, and receive reciprocal patent license protection +under the Khronos Intellectual Property Rights Policy must become Adopters and +confirm the implementation as conformant under the process defined by Khronos for +this Specification; see https://www.khronos.org/adopters. + +Some parts of this Specification are purely informative and so are EXCLUDED from +the Scope of this Specification. +// Jon: how much do we want to say about Informative spec sections? No +// convention in use at present. Could also add a "technical terminology" +// section and link from the following paragraph. +// The <> section of the +// <> defines how these parts of the Specification are identified. + +Where this Specification uses technical +terminology, defined in the <> or otherwise, that refer to +enabling technologies that are not expressly set forth in this +Specification, those enabling technologies are EXCLUDED from the Scope of +this Specification. +For clarity, enabling technologies not disclosed with particularity in this +Specification (e.g. semiconductor manufacturing technology, hardware +architecture, processor architecture or microarchitecture, memory +architecture, compiler technology, object oriented technology, basic +operating system technology, compression technology, algorithms, and so on) +are NOT to be considered expressly set forth; only those application program +interfaces and data structures disclosed with particularity are included in +the Scope of this Specification. + +For purposes of the Khronos Intellectual Property Rights Policy as it relates +to the definition of Necessary Patent Claims, all recommended or optional +features, behaviors and functionality set forth in this Specification, if +implemented, are considered to be included as Compliant Portions. + +Where this Specification includes +normative references to external documents, only the specifically +identified sections of those external documents are INCLUDED in the Scope of +this Specification. If not created by Khronos, those external documents may +contain contributions from non-members of Khronos not covered by the Khronos +Intellectual Property Rights Policy. + +ifndef::ratified_core_spec[] +This document contains extensions which are not ratified by Khronos, and as +such is not a ratified Specification, though it contains text from (and is a +superset of) the ratified SYCL Specification. The ratified version of the +SYCL Specification can be found at +https://www.khronos.org/registry/SYCL . +endif::ratified_core_spec[] + +Khronos and Vulkan are registered trademarks, and SPIR-V is a trademark of +The Khronos Group Inc. OpenCL is a trademark of Apple Inc. and OpenGL is a +registered trademarks of Hewlett Packard Enterprise, all used under license +by Khronos. All other product names, trademarks, and/or company names are +used solely for identification and belong to their respective owners. diff --git a/adoc/chapters/device_compiler.adoc b/adoc/chapters/device_compiler.adoc new file mode 100644 index 00000000..e7047d81 --- /dev/null +++ b/adoc/chapters/device_compiler.adoc @@ -0,0 +1,827 @@ +// %%%%%%%%%%%%%%%%%%%%%%%%%%%% begin compiler_abi %%%%%%%%%%%%%%%%%%%%%%%%%%%% + +[[chapter.device.compiler]] += SYCL Device Compiler + +This section specifies the requirements of the SYCL device compiler. +Most features described in this section relate to underlying <> +capabilities of target devices and limiting the requirements of device +code to ensure portability. + + +== Offline compilation of SYCL source files + +There are two alternatives for a SYCL <>: a +[keyword]#single-source device compiler# and a device compiler that supports +the technique of <>. + +A SYCL device compiler takes in a {cpp} source file, extracts only the SYCL +kernels and outputs the device code in a form that can be enqueued from host +code by the associated <>. How the <> +invokes the kernels is implementation-defined, but a typical approach is for +a device compiler to produce a header file with the compiled kernel +contained within it. By providing a command-line option to the host +compiler, it would cause the implementation's SYCL header files to +[code]#{hash}include# the generated header file. The SYCL specification has +been written to allow this as an implementation approach in order to allow +<>. However, any of the mechanisms needed from the SYCL compiler, +the <> and build system are implementation-defined, as they +can vary depending on the platform and approach. + +A SYCL single-source device compiler takes in a {cpp} source file and compiles +both host and device code at the same time. This specification specifies how +a SYCL single-source device compiler sees and outputs device code for kernels, +but does not specify the host compilation. + + +[[sec:naming.kernels]] +== Naming of kernels + +SYCL kernels are extracted from {cpp} source files and stored in an +implementation-defined format. In the case of the shared-source compilation model, the kernels +have to be uniquely identified by both host and device compiler. This is +required in order for the host runtime to be able to load the kernel by using +a backend-specific host runtime interface. + +From this requirement the following rules apply for naming the kernels: + + * The kernel name is a [keyword]#{cpp} typename#. + * The kernel name must be forward declarable at namespace scope + (including global namespace scope) and may not be forward declared other + than at namespace scope. If it isn't forward declared + but is specified as a template argument in a kernel invoking interface, + as described in <>, then it may not conflict + with a name in any enclosing namespace scope. + +[NOTE] +==== +The requirement that a kernel name be forward declarable makes some types +for kernel names illegal, such as anything declared in the [code]#std# +namespace (adding a declaration to namespace [code]#std# leads to undefined +behavior). +==== + + * If the kernel is defined as a named function object type, the name can + be the typename of the function object as long as it is either declared + at namespace scope, or does not conflict with any name in an enclosing + namespace scope. + * If the kernel is defined as a lambda, a typename can optionally be + provided to the kernel invoking interface as described + in <>, so that the developer can control the + kernel name for purposes such as debugging or referring to the kernel + when applying build options. + * If a kernel function relies on template parameters, then those template + parameters must be contained by the kernel name. If such a kernel name + is specified as a template argument in a kernel invoking interface, then + the template parameters on which the kernel depends must be forward + declarable at namespace scope. + +In both single-source and shared-source implementations, a device compiler should +detect the kernel invocations (e.g. [code]#parallel_for)# +in the source code and compile the enclosed kernels, storing them with their +associated type name. + +The format of the kernel and the compilation techniques are details of an +implementation and not specified. The interface between the compiler and the +runtime for extracting and executing SYCL kernels on the device is a detail of +an implementation and not specified. + + +== Compilation of functions + +The SYCL device compiler parses an entire {cpp} source file supplied by the +user, including any header files referenced via [code]#{hash}include# +directives. From this source file, the SYCL device compiler must compile +kernels for the device, as well as any functions that the kernels call. + +The device compiler identifies kernels by looking for calls to +<> such as [code]#parallel_for#. One of +the parameters is a function object which is known as a +<>, and this function must always return +[code]#void#. Any function called by the <> is +also compiled for the device, and these functions together with the +<> are known as <>. The device +compiler searches recursively for any functions called from a +<>, and these functions are also compiled for the device and +known as <>. + +To illustrate, the following source code shows three functions and a kernel +invoke with comments explaining which functions need to be compiled for the +device. + +[source,,linenums] +---- +void f(handler& cgh) { + // Function "f" is not compiled for device + + cgh.single_task([=] { + // This code is compiled for device + g(); // This line forces "g" to be compiled for device + }); +} + +void g() { + // Called from kernel, so "g" is compiled for device +} + +void h() { + // Not called from a device function, so not compiled for device +} +---- + +In order for the SYCL device compiler to correctly compile <>, all +functions in the source file, whether <> or not, must be +syntactically correct functions according to this specification. A syntactically +correct function adheres to at least the minimum required {cpp} version +defined in <>. + + +[[sec:language.restrictions.kernels]] +== Language restrictions for device functions + +<> must abide by certain restrictions. The full set of +{cpp} features are not available to these functions. Following is a list of +these restrictions: + + * Pointers and objects containing pointers may be shared. However, when a pointer is + passed between SYCL devices or between the host and a SYCL device, + dereferencing that pointer on the device produces undefined behavior unless + the device supports <> and the pointer is an address within a + <> memory region (see <>). + * Memory storage allocation is not allowed in kernels. All memory allocation + for the device is done on the host using accessor classes or using + <> as explained in <>. + Consequently, the default allocation [code]#operator new# overloads + that allocate storage are disallowed in a SYCL kernel. The placement + [code]#new# operator and any user-defined overloads that do not + allocate storage are permitted. + * Kernel functions must always have a [code]#void# return type. A + kernel lambda trailing-return-type that is not [code]#void# is + therefore illegal, as is a return statement (that would return from the + kernel function) with an expression that does not convert to + [code]#void#. + * The odr-use of polymorphic classes and classes with virtual + inheritance is allowed. However, no virtual member functions are allowed + to be called in a <>. + * No function pointers or references are allowed to be called in a + <>. + * RTTI is disabled inside <>. + * No variadic functions are allowed to be called in a + <>. + * Exception-handling cannot be used inside a + <>. + [code]#noexcept# is allowed. + * Recursion is not allowed in a <>. + * Variables with thread storage duration ([code]#thread_local# + storage class specifier) are not allowed to be odr-used in a + <>. + * Variables with static storage duration that are odr-used inside a + <>, must be [code]#const# + or [code]#constexpr# and zero-initialized or constant-initialized. + +[NOTE] +==== +Amongst other things, this restriction makes it illegal for a +<> to access a global variable that isn't [code]#const# +or [code]#constexpr#. +==== + + * The rules for kernels apply to both the kernel function objects + themselves and all functions, operators, member functions, constructors + and destructors called by the kernel. This means that kernels can only + use library functions that have been adapted to work with SYCL. + Implementations are not required to support any library routines in + kernels beyond those explicitly mentioned as usable in kernels in this + spec. Developers should refer to the SYCL built-in functions + in <> to find functions that are specified to be usable + in kernels. + * Interacting with a special <> class (e.g. SYCL + [code]#accessor# or [code]#stream)# that is stored within a {cpp} union + is undefined behavior. + + +[[subsec:scalartypes]] +== Built-in scalar data types + +In a SYCL device compiler, the device definition of all standard {cpp} +fundamental types from <> must match the +host definition of those types, in both size and alignment. A device +compiler may have this preconfigured so that it can match them based on the +definitions of those types on the platform, or there may be a necessity for +a device compiler command-line option to ensure the types are the same. + +The standard {cpp} fixed width types, e.g. [code]#int8_t#, +[code]#int16_t#, [code]#int32_t#,[code]#int64_t#, +should have the same size as defined by the {cpp} standard for host and +device. + +ifdef::showtodos[] +[NOTE] +.Note +==== +To ensure that pointer types and [code]#size_t# use the same amount of +storage on host and device when inside structures, SYCL also requires that +device compilers use the host sizes for pointers or [code]#size_t#. Devices +may be using a smaller size internally for pointers and [code]#size_t#, +but this should not impact the programming model for users. In the case where +devices use larger pointer size internally than the host, then +[code]#size_t# will match the <> size. For structures shared +between host and device it is recommended to use fixed width types for pointers. +Scalar data types for a SYCL device compiler are described in +<>. +==== +endif::showtodos[] + + + +[[table.types.fundamental]] +.Fundamental data types supported by SYCL +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Fundamental data type @ Description +a@ +[source] +---- +bool +---- + a@ A conditional data type which can be either true or false. The value + true expands to the integer constant 1 and the value false expands to the + integer constant 0. + +a@ +[source] +---- +char +---- + a@ A signed or unsigned 8-bit integer, as defined by the {cpp} core language + +a@ +[source] +---- +signed char +---- + a@ A signed 8-bit integer, as defined by the {cpp} core language + +a@ +[source] +---- +unsigned char +---- + a@ An unsigned 8-bit integer, as defined by the {cpp} core language + +a@ +[source] +---- +short int +---- + a@ A signed integer of at least 16-bits, as defined by the {cpp} core language + +a@ +[source] +---- +unsigned short int +---- + a@ An unsigned integer of at least 16-bits, as defined by the {cpp} core language + +a@ +[source] +---- +int +---- + a@ A signed integer of at least 16-bits, as defined by the {cpp} core language + +a@ +[source] +---- +unsigned int +---- + a@ An unsigned integer of at least 16-bits, as defined by the {cpp} core language + +a@ +[source] +---- +long int +---- + a@ A signed integer of at least 32-bits, as defined by the {cpp} core language + +a@ +[source] +---- +unsigned long int +---- + a@ An unsigned integer of at least 32-bits, as defined by the {cpp} core language + +a@ +[source] +---- +long long int +---- + a@ An integer of at least 64-bits, as defined by the {cpp} core language + +a@ +[source] +---- +unsigned long long int +---- + a@ An unsigned integer of at least 64-bits, as defined by the {cpp} core language + +a@ +[source] +---- +float +---- + a@ A 32-bit floating-point. The float data type must conform to the IEEE 754 + single precision storage format. + +a@ +[source] +---- +double +---- + a@ A 64-bit floating-point. The double data type must conform to the IEEE 754 + double precision storage format. This type is only supported on devices + that have [code]#aspect::fp64#. + +|==== + + + +== Preprocessor directives and macros + +The standard {cpp} preprocessing directives and macros are supported. +The following preprocessor macros must be defined by all conformant +implementations: + + * [code]#SYCL_LANGUAGE_VERSION# substitutes an integer reflecting + the version number and revision of the SYCL language being supported + by the implementation. The version of SYCL defined in this document + will have [code]#SYCL_LANGUAGE_VERSION# substitute the integer + [code]#{SYCL_LANGUAGE_VERSION}#, composed with the general SYCL version + followed by 2 digits representing the revision number; + * [code]#SYCL_DEVICE_COPYABLE# is defined to 1 if the implementation + supports explicitly specified <> types as described in + <>. Otherwise, the implementation's definition of + device copyable falls back to {cpp} trivially copyable and + [code]#sycl::is_device_copyable# is ignored; + * [code]#+__SYCL_DEVICE_ONLY__+# is defined to 1 if the source file is + being compiled with a SYCL device compiler which does not produce host + binary; + * [code]#+__SYCL_SINGLE_SOURCE__+# is defined to 1 if the source file + is being compiled with a SYCL single-source compiler which produces host + as well as device binary; + * [code]#SYCL_FEATURE_SET_FULL# is defined to 1 if the SYCL implementation + supports the full feature set and is not defined otherwise. For more details + see <>; + * [code]#SYCL_FEATURE_SET_REDUCED# is defined to 1 if the SYCL implementation + supports the reduced feature set and not the full feature set, otherwise it + is not defined. For more details see <>; + * [code]#SYCL_EXTERNAL# is an optional macro which enables external + linkage of SYCL functions and member functions to be included in a SYCL kernel. + The macro is only defined if the implementation supports external linkage. + For more details see <> + +In addition, for each <> supported, the preprocessor macros described +in <> must be defined by all conformant implementations. + + +[[sec:optional-kernel-features]] +== Optional kernel features + +A number of kernel features defined by this SYCL specification are optional; +they may be supported on some devices but not on other devices. As described +in <>, an application can test whether a device supports +these features by testing whether the device has an associated aspect. The +following aspects are those that correspond to optional kernel features: + + * [code]#fp16# + * [code]#fp64# + * [code]#atomic64# + +In order to guarantee source code portability of SYCL applications that use +optional kernel features, all SYCL implementations must be able to compile +device code that uses these optional features regardless of whether the +implementation supports the features on any of its devices. + +Of course, applications that make use of optional kernel features should ensure +that a kernel using such a feature is submitted only to a device that supports +the feature. If the application submits a <> using a secondary +queue, then any kernel submitted from the <> should use only +features that are supported by both the primary queue's device and the +secondary queue's device. If an application fails to do this, the +implementation must throw a synchronous exception with the +[code]#errc::kernel_not_supported# error code from the +<> (e.g. [code]#parallel_for()#). + +It is legal for a SYCL application to define several kernels in the same +translation unit even if they use different optional features, as shown in the +following example: + +[source,,linenums] +---- +include::{code_dir}/twoOptionalFeatures.cpp[lines=4..-1] +---- + +An implementation may not raise a compile time diagnostic or a run time +exception merely due to speculative compilation of a kernel for a device when +the application does not actually submit the kernel to that device. To +illustrate using the example above, assume that device [code]#dev1# does not +have [code]#aspect::atomic64# and device [code]#dev2# doe not have +[code]#aspect::fp16#. An implementation cannot raise a diagnostic due to +compilation of [code]#KernelA# for device [code]#dev2# or for compilation of +[code]#KernelB# for device [code]#dev1# because the application does not submit +these kernels to those devices. + +[NOTE] +==== +It is expected that this requirement will have an impact on the way an +implementation bundles kernels into device images. For example, naively +bundling [code]#KernelA# and [code]#KernelB# into the same device image could +run afoul of this requirement if the implementation compiles the entire device +image when [code]#KernelA# is submitted to device [code]#dev1#. +==== + + +[[sec:device.attributes]] +== Attributes for device code + +{cpp} attributes may be used to decorate kernels and device functions in order +to influence the code generated by the device compiler. These attributes are +all defined in the [code]#+[[sycl::]]+# namespace, with the exception of the +deprecated attributes described in <>. + +Each attribute-token defined in this section may be applied at most once for +any particular kernel or device function. Applications that decorate a kernel +or device function with the same attribute-token more than once are ill formed +and the compiler must issue a diagnostic. If a kernel or device function is +decorated with one of these attributes, the decoration must exist on the first +declaration of the kernel or device function in the translation unit. Programs +which fail to do this are ill formed and the compiler must issue a diagnostic. +If a function is declared with an attribute in one translation unit and the +same function is declared without the same attribute in another translation +unit, the program is ill formed and no diagnostic is required. Applying these +attributes to any language construct other than those specified in this section +has implementation-defined effect. + +If any of these attributes is applied to a device function that is also +compiled for the host, it has no effect when the function is compiled for the +host. + + +=== Kernel attributes + +The attributes in <> are applied to the function-type +of kernel function declarations. The example below demonstrates this syntax +using the [code]#[[sycl::reqd_work_group_size(16)]]# attribute. + +[source,,linenums] +---- +include::{code_dir}/attributes.cpp[lines=4..-1] +---- + +[[table.kernel.attributes]] +.Attributes for kernel functions +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ SYCL attribute @ Description +a@ +[source] +---- +reqd_work_group_size(dim0) +reqd_work_group_size(dim0, dim1) +reqd_work_group_size(dim0, dim1, dim2) +---- + a@ Indicates that the kernel must be launched with the specified work-group size. + The order of the arguments matches the constructor of the [code]#group# + class. Each argument to the attribute must be an integral constant expression. The + dimensionality of the attribute variant used must match the dimensionality of + the work-group used to invoke the kernel. + +SYCL device compilers should give a compilation error if the required +work-group size is unsupported. If the kernel is submitted for execution using +an incompatible work-group size, the SYCL runtime must throw an +[code]#exception# with the [code]#errc::nd_range# error code. + +a@ +[source] +---- +work_group_size_hint(dim0) +work_group_size_hint(dim0, dim1) +work_group_size_hint(dim0, dim1, dim2) +---- + a@ Hint to the compiler on the work-group size most likely to be used when + launching the kernel at runtime. Each argument must be an integral constant + expression, and the number of dimensional values defined provide additional + information to the compiler on the dimensionality most likely to be used when + launching the kernel at runtime. The effect of this attribute, if any, is + implementation-defined. + +a@ +[source] +---- +vec_type_hint() +---- + a@ Hint to the compiler on the vector computational width of of the kernel. The + argument must be one of the vector types defined in <>. + The effect of this attribute, if any, is implementation-defined. + +This attribute is deprecated (available for use, but will likely be removed in +a future version of the specification and is not recommended for use in new code). + +a@ +[source] +---- +reqd_sub_group_size(dim) +---- + a@ Indicates that the kernel must be compiled and executed with the specified + sub-group size. The argument to the attribute must be an integral constant + expression. + +SYCL device compilers should give a compilation error if the required sub-group +size is unsupported by the device or incompatible with any language feature used +by the kernel. The set of valid sub-group sizes for a kernel can be queried as +described in <> and +<>. + +a@ +[source] +---- +sycl::requires(has(aspect, ...)) +---- + a@ This attribute may be used to decorate either the declaration of a kernel + function that is defined in the current translation unit or to decorate + the declaration of a non-kernel device function. The following + description applies when the attribute decorates a kernel function. + +The parameter list to the [code]#sycl::requires()# attribute may either be +empty or it may be a single [code]#has()# clause. The parameter list to the +[code]#has()# clause consists of zero or more [code]#constexpr# integral +expressions, where each integer is interpreted as one of the enumerated values +in the [code]#sycl::aspect# enumeration type. Specifying an empty parameter +list to [code]#sycl::requires()# is equivalent to specifying a [code]#has()# +clause with an empty parameter list. + +Specifying this attribute on a kernel has two effects. First, it causes the +<> to throw a synchronous exception with the +[code]#errc::kernel_not_supported# error code if the kernel is submitted to a +device that does not have one of the listed aspects. (This includes the device +associated with the secondary queue if the kernel is submitted from a +<> that has a secondary queue.) Second, it causes the compiler +to issue a diagnostic if the kernel (or any of the functions it calls) uses an +optional feature that is associated with an aspect that is not listed in the +attribute. + +The value of each parameter to the [code]#has()# clause must be equal to one of +the values in the [code]#sycl::aspect# enumeration type (including any extended +values the implementation may provide). If it does not, the program is ill +formed and the compiler must issue a diagnostic. + +See <> for an example of this attribute. + +|==== + +.Example of the [code]#sycl::requires()# attribute +[[listing:requires]] +[source,,linenums] +---- +include::{code_dir}/requires.cpp[lines=4..-1] +---- + + +=== Device function attributes + +The attributes in <> are applied to the declaration +of a non-kernel device function. + +[[table.device.attributes]] +.Attributes for non-kernel device functions +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ SYCL attribute @ Description +a@ +[source] +---- +sycl::requires(has(aspect, ...)) +---- + a@ This attribute may be used to decorate either the declaration of a kernel + function that is defined in the current translation unit or to decorate + the declaration of a non-kernel device function. The following + description applies when the attribute decorates a non-kernel device + function declaration. + +The syntax of this attribute's parameter list is the same as the syntax for +the form of [code]#sycl::requires()# that is specified on a kernel function +(see <>). + +This attribute is required when a non-kernel device function that uses optional +device features is called in one translation unit and defined in another +translation unit via the [code]#SYCL_EXTERNAL# macro. + +When this attribute appears in a translation unit that calls the decorated +device function, it is an assertion that the device function uses optional +features that correspond to the aspects listed in the attribute. The program +is ill formed if the called device function uses optional features that do not +correspond to any of the aspects listed in the attribute, or if the function +uses optional features and the attribute is not specified. No diagnostic is +required in this case. + +When this attribute appears in a translation unit that defines the decorated +device function, it causes the compiler to issue a diagnostic if the device +function (or any of the functions it calls) uses an optional feature that is +associated with an aspect that is not listed in the attribute. + +|==== + + +[[subsec::attributes.deprecated]] +=== Deprecated kernel attribute syntax + +The SYCL 1.2.1 specification (superseded by this version) defined two mechanisms +for kernel attributes to be specified, which are deprecated in this version of +SYCL. The old syntaxes are supported but will be removed in a future version, and +are therefore not recommended for use. Specifically, the following two +attribute syntaxes defined by the SYCL 1.2.1 specification are deprecated: + + . The attribute syntax defined by the OpenCL C specification within device + code like [code]#+__attribute__((attrib))+#. + . The {cpp} attribute specifier syntax in the [code]#+[[cl::]]+# namespace + applied to device functions (not the function-type of a kernel + function), including automatic propagation of the attribute to any + caller of such device functions. + + +== Address-space deduction + +{cpp} has no type-level support to represent address spaces. As a consequence, +the SYCL generic programming model does not directly affect the {cpp} type of +unannotated pointers and references. + +Source level guarantees about address spaces in the SYCL generic +programming model can only be achieved using pointer classes (instances of +[code]#multi_ptr#), which are regular classes that represent pointers +to data stored in the corresponding address spaces. + +In SYCL, the address space of pointer and references are derived from: + + * Accessors that give access to shared data. They can be bound to a memory + object in a command group and passed into a kernel. Accessors are used + in scheduling of kernels to define ordering. Accessors to buffers have a + compile-time address space based on their access mode. + * Explicit pointer classes (e.g. [code]#global_ptr#) holds a pointer + which is known to be addressing the address space represented by the + [code]#access::address_space#. This allows the compiler to + determine whether the pointer references global, local, constant or + private memory and generate code accordingly. + * Raw {cpp} pointer and reference types (e.g. [code]#int*#) are allowed + within SYCL kernels. They can be constructed from the address of local + variables, explicit pointer classes, or accessors. + + +[[subsec:addrspaceAssignment]] +=== Address space assignment + +In order to understand where data lives, the device compiler is +expected to assign address spaces while lowering types for the +underlying target based on the context. Depending on the <> +and mode, address space deducing rules differ slightly. + +If the target of the SYCL backend can represent the generic address space, +then the "common address space deduction rules" in +<> and the "generic as default address space rules" +in <> apply. If the target of the SYCL backend +cannot represent the generic address space, then the "common address space +deduction rules" in <> and the "inferred address +space rules" in <> apply. + +[NOTE] +==== +SYCL address space does not affect the type, address space shall be +understood as memory segment in which data is allocated. For +instance, if [code]#int i;# is allocated to the global address +space, then [code]#decltype(&i)# shall evaluate to +[code]#int*#. +==== + + +[[subsec:commonAddressSpace]] +=== Common address space deduction rules + +The variable declarations get assigned to an address space depending on their +scope and storage class: + + * Namespace scope + ** If the type is [code]#const#, the address space the declaration is assigned to + is implementation-defined. If the target of the SYCL backend can represent the + generic address space, then the assigned address space must be compatible with + the generic address space. + +[NOTE] +==== +Namespace scope non-[code]#const# declarations cannot be used within a kernel, +as restricted in <>. This means that +non-[code]#const# global variables cannot be accessed by any device kernel or +code called by the device kernel. +==== + + * Block scope and function parameter scope + ** Declarations with static storage duration are treated the same way as variables + in namespace scope + ** Otherwise the declaration is assigned to the local address space if + declared in a hierarchical context + ** Otherwise the declaration is assigned to the private address space + * Class scope + ** Static data members are treated the same way as for variable in + namespace scope + +The result of a prvalue-to-xvalue conversion is assigned to the local +address space if it happens in a hierarchical context or to the private +address space otherwise. + + +[[subsec:genericAddressSpace]] +=== Generic as default address space + +For SYCL backends that can represent the generic address space +(see <>), unannotated pointers and +references are considered to be pointing to the generic address space. + + +[[subsec:inferredAddressSpace]] +=== Inferred address space + +[NOTE] +.Note for this version +==== +The address space deduction feature described next is inherited from +the SYCL 1.2.1 specifications. This section will be changed in a future version +to better align with addition of generic address space and generic +as default address space. +==== + +For SYCL backends that cannot represent the generic address space +(see <>), inside kernels the SYCL device +compiler will need to auto-deduce the memory region +of unannotated pointer and reference types during the lowering of types +from {cpp} to the underlying representation. + +If a kernel function or device function contains a pointer or reference type, +then the address space deduction must be attempted using the following rules: + + * If an explicit pointer class is converted into a {cpp} pointer value, then + the {cpp} pointer value will point to same address space as the one + represented by the explicit pointer class. + * If a variable is declared as a pointer type, but initialized in its + declaration to a pointer value with an already-deduced address space, + then that variable will have the same address space as its initializer. + * If a function parameter is declared as a pointer type, and the argument + is a pointer value with a deduced address space, then the function will + be compiled as if the parameter had the same address space as its + argument. It is legal for a function to be called in different places + with different address spaces for its arguments: in this case the + function is said to be "`duplicated`" and compiled multiple times. Each + duplicated instance of the function must compile legally in order to + have defined behavior. + * If a function return type is declared as a pointer type and return + statements use address space deduced expressions, then the function will + be compiled as if the return type had the same address space. To compile + legally, all return expressions must deduce to the same address space. + * The rules for pointer types also apply to reference types. i.e. a + reference variable takes its address space from its initializer. A + function with a reference parameter takes its address space from its + argument. + * If no other rule above can be applied to a declaration of a pointer, + then it is assumed to be in the private address space. + +It is illegal to assign a pointer value addressing one address space to a pointer +variable addressing a different address space. + + +== SYCL offline linking + +// Jon: Section empty, but subsection has content? Odd choice. + + +[[subsec:syclexternal]] +=== SYCL functions and member functions linkage + +The default behavior in SYCL applications is that all the definitions and +declarations of the functions and member functions are available to the SYCL compiler, +in the same translation unit. When this is not the case, all the symbols that +need to be exported to a SYCL library or from a {cpp} library to a SYCL +application need to be defined using the macro: [code]#SYCL_EXTERNAL#. + +The [code]#SYCL_EXTERNAL# macro will only be defined if the implementation +supports offline linking. The macro is implementation-defined, but the following +restrictions apply: + + * [code]#SYCL_EXTERNAL# can only be used on functions; + * if the SYCL backend does not support the generic address space then the + function cannot use raw pointers as parameter or return types. Explicit + pointer classes must be used instead; + * externally defined functions cannot call a + [code]#sycl::parallel_for_work_item# member function; + * externally defined functions cannot be called from a + [code]#sycl::parallel_for_work_group# scope. + +The SYCL linkage mechanism is optional and implementation-defined. + +// %%%%%%%%%%%%%%%%%%%%%%%%%%%% end compiler_abi %%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/adoc/chapters/extensions.adoc b/adoc/chapters/extensions.adoc new file mode 100644 index 00000000..91b49ab0 --- /dev/null +++ b/adoc/chapters/extensions.adoc @@ -0,0 +1,204 @@ +// %%%%%%%%%%%%%%%%%%%%%%%%%%%% begin extensions %%%%%%%%%%%%%%%%%%%%%%%%%%%% + +[[chapter.extensions]] += SYCL Extensions + +This chapter describes the mechanism by which the <> can be +extended. Some parts of this chapter are requirements that all implementations +must follow if they extend the <>, while other parts of the chapter +are merely guidelines. Unless a requirement is specifically stated as +normative, all content in this chapter is a non-normative guideline. + +An extension can be either of two flavors: an extension ratified by the Khronos +SYCL group or a vendor supplied extension. In both cases, an extension is an +optional feature set which an implementation need not implement in order to be +conformant with the <>. + +Vendors may choose to define extensions in order to expose custom features or +to gather feedback on an API that is not yet ready for inclusion in the +<>. Once a vendor extension has stabilized, the vendor is +encouraged to promote it to a future version of the <> or to a +ratified Khronos extension. Thus, vendor extensions can be viewed as a +pipeline of features for consideration in future SYCL versions. + +The Khronos SYCL group may define extensions for features that are not yet +ready for the <> but are implemented by more than one vendor. +These extensions also may be considered for inclusion in a future version of +the <>. + +This chapter does not describe any particular extension to SYCL. Rather, it +describes the _mechanism_ for defining an extension. Each extension is defined +by its own separate document. If an extension is ratified by the Khronos SYCL +group, that group will release a document describing the extension. If a +vendor defines an extension, the vendor is responsible for releasing its +documentation. + + +== Definition of an extension + +An extension can take many possible forms. Some examples include: + + * adding new types or free functions to the SYCL runtime; + * modifying existing SYCL classes, structs, or enumeration types by + adding new members, member functions, or enumerated values; + * adding new overloads for existing free functions or member functions; + * defining new specializations for existing SYCL templates; + * adding new {cpp} attributes; + * adding new predefined macros; + * adding new keywords to the language; + * adding a new backend. + +An extension may also broaden the definition of existing functions defined in +the <> by defining semantics for cases that are left unspecified by +the <>. + + +== Requirements for an extension + +This section is normative. All vendors which provide an extension must abide +by the requirements described here. + +An extension may not change the definition of existing functions defined by the +<> in a way that changes their specified behavior. Also, an +extension may not remove any feature defined by the <>. + +The vendor must choose at least one [code]## which uniquely +identifies the vendor's SYCL implementation. The Khronos SYCL group does not +provide any registry of the strings, so each vendor is responsible for choosing +its own. One way to choose a unique string is to use the vendor's company name +or a marketing name that is associated with the vendor's implementation. +Ultimately, it is each vendor's responsibility to choose a string that is +unique. The strings "khr" and "KHR" are reserved for the Khronos SYCL group +for its own extensions, so vendors may not use these as a +[code]##. + +The implementation must predefine at least one macro of the form +[code]#SYCL_IMPLEMENTATION_# which allows applications to test +whether they are being compiled with that vendor's implementation. For +example, the Acme vendor could predefine a macro whose name is +[code]#SYCL_IMPLEMENTATION_ACME#. + + +== Guidelines for portable extensions + +Vendors who want to ensure that their extension does not collide with other +vendors' extensions or with future versions of the <> should follow +the additional rules specified in this section. However, this is not a +requirement for conformance. + +=== Extension namespace + +If an extension adds new types or free functions, it should avoid adding these +directly in the [code]#sycl::# namespace since future versions of the +<> may also add new identifiers in this namespace. The namespace +[code]#sycl::ext::# is reserved for use by extensions. For +example, the Acme vendor could define extended types and free functions in the +namespace [code]#sycl::ext::acme#, and this would guarantee that they will not +collide with definitions in other vendors' extensions or with future versions +of the <>. + +=== Names for extensions to existing classes or enumerations + +An extension may add new members or member functions to existing SYCL classes +or new values to existing SYCL enumeration types. To ensure these extensions +do not collide, vendors are encouraged to name them with the prefix +[code]#ext__#. For example, the Acme vendor could add a new +member function to the [code]#sycl::device# class named +[code]#device::ext_acme_fancy()# or a new value to the [code]#sycl::aspect# +enumeration named [code]#aspect::ext_acme_fancier#. + +In some cases, an extension does not have the freedom to choose a specific +function name. For example, this could happen if the extension adds a new +constructor overload for an existing SYCL class. In cases like this, the +extension should ensure that one of the function parameters has a type that is +defined in the extension's namespace. For example, the Acme vendor could add +a new constructor for [code]#sycl::context# with the signature +[code]#context(ext::acme::frobber &)#. + +A similar situation can occur if an existing SYCL template is specialized with +an extended enumerated value. +Obviously, the extension cannot rename the template in this case. Instead, +it is sufficient that the template is specialized with an extended enumerated +value, and this guarantees that the extended specialization will not collide. + +[NOTE] +==== +Vendors are encouraged to use the [code]#ext__# prefix form when +possible for additions to existing SYCL classes because this form makes the +extension's vendor name apparent. People reading application code will +immediately know that a member function is an extension, and they will +immediately know which vendor's documentation to consult. +==== + +=== Feature test macros + +Vendors are encouraged to group a related set of extensions together into a +"feature" and to predefine a feature-test macro when the implementation +supports the extensions in that feature. The feature-test macro should have +the following form to ensure it is unique: +[code]#SYCL_EXT__#. For example, the Acme vendor +might define a feature-test macro named [code]#SYCL_EXT_ACME_FANCYFEATURE#. +This allows applications to protect code using the extension with +[code]##ifdef#, so that the code is skipped when compiled with an +implementation that doesn't support the feature. + +Since the interface to an extension might change from one release to another, +vendors are also encouraged to predefine the macro's value to the version of +the extension. Vendors should use a numerical value that monotonically +increases for each revision of the extension API. + +Of course, an extension may also predefine other macros. In order to ensure +that these macro names do not collide with other extensions or future versions +of the <>, the name should start with the prefix +[code]#SYCL_EXT_# or [code]#SYCL_IMPLEMENTATION_#. + +=== Attribute namespace + +An extension may define new {cpp} attributes. The attribute namespace +[code]#sycl::# is reserved for the <>, so vendors should choose a +different namespace for any attributes they add. + +=== Include file paths + +An extension may define new [code]##include# files under the [code]#"sycl"# +path. The path prefix [code]#"sycl/ext/"# is reserved for this +purpose. For example, the Acme vendor could add a header file +[code]#"sycl/ext/acme/fancy.h"# and be guaranteed that it would not conflict +with other extensions or with future versions of the <>. + +=== Optional kernel features + +An extension may also add new optional kernel features -- features which are +supported on some devices but not on others. Vendors are encouraged to follow +the same mechanism outlined in <>. Therefore, +an extended optional kernel feature should have a matching extension to the +[code]#sycl::aspect# enumerated type. + +=== Adding a backend + +An extension may also add a new backend. If it does, the naming of the +backend APIs follows the normal guidelines for extensions and also follows +the naming pattern for backends that are defined in the <>. To +illustrate: + +* The extension should add a new value to the [code]#sycl::backend# enumeration + type using a naming scheme like [code]#ext__#. For + example, if the Acme vendor adds a backend named "foo", it would add an + enumerated value named [code]#sycl::backend::ext_acme_foo#. + +* The extension should define the backend's interop API in a namespace named + [code]#sycl::ext::::#. For our hypothetical Acme + example, this would be a namespace named [code]#sycl::ext::acme::foo#. + +* If the backend interop API is available through a separate header file, that + header should be named + [code]#"sycl/ext//backend/.hpp"#. For our + hypothetical Acme example this would be + [code]#"sycl/ext/acme/backend/foo.hpp"#. + +* The extension should predefine a macro for the backend when it is "active". + The name of this macro should be + [code]#SYCL_EXT__BACKEND_#. For our hypothetical + Acme example this would be [code]#SYCL_EXT_ACME_BACKEND_FOO#. + +// %%%%%%%%%%%%%%%%%%%%%%%%%%%% end extensions %%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/adoc/chapters/feature_sets.adoc b/adoc/chapters/feature_sets.adoc new file mode 100644 index 00000000..94acb198 --- /dev/null +++ b/adoc/chapters/feature_sets.adoc @@ -0,0 +1,74 @@ +// %%%%%%%%%%%%%%%%%%%%%%%%%%%% begin feature_sets %%%%%%%%%%%%%%%%%%%%%%%%%%%% + +[appendix] +[[cha:feature-sets]] += Feature sets + +As of SYCL 2020 there are now two distinct feature sets which a SYCL +implementation can conform to, in order to better fit the requirements of +different domains, such as embedded, mobile, and safety critical, which may have +limitations because of the toolchains used. + +A SYCL implementation can choose to conform to either the full feature set or +the reduced feature set. + + +[[sec:feature-sets.full]] +== Full feature set + +The full feature set includes all features specified in the <> with +no exceptions. + + +[[sec:feature-sets.reduced]] +== Reduced feature set + +The reduced feature set makes certain features optional or restricted to +specific forms. The following list defines all the differences between the +reduced feature set and the full feature set. + + . *Un-named SYCL kernel functions:* <> + which are defined using a lambda expression and therefore have no standard + name are required to be provided a name via the kernel name template parameter + of kernel invocation functions such as [code]#parallel_for#. This overrides + the <> rules for <> naming as specified in + <>. + + . *Address space mode:* The <> mode used in the reduced feature set is not required to be + <>, regardless of SYCL + backend in use. + Instead the <> mode + may always be used. + + . *Declarations:* In addition to the requirements specified in + <>, the reduced feature set does not require + support for odr-use inside <> of variables + declared [code]#const# or [code]#constexpr# with static storage duration. + + +[[sec:feature-sets.compatibility]] +== Compatibility + +In order to avoid introducing any kind of divergence the reduced and full +feature sets are defined such that the full feature set is a subsumption of +the reduced feature set. This means that any applications which are +developed for the reduced feature set will be compatible with both a SYCL +reduced implementation and a SYCL full implementation. + + +[[sec:feature-sets.conformance]] +== Conformance + +One of the reasons for having this be defined in the specification is that +hardware vendors which wish to support SYCL on their platform(s) want to be able +to demonstrate their support for it by passing conformance. However, if passing +conformance means adopting features which they do not believe to be necessary at +an additional development effort then this may deter them. + +Each feature set has its own route for passing conformance allowing adopters of +SYCL to specify the feature set they wish to test conformance against. The +conformance test suite would then alter or disable the tests within the test +suite according to how the feature sets are differentiated above. + +// %%%%%%%%%%%%%%%%%%%%%%%%%%%% end feature_sets %%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/adoc/chapters/glossary.adoc b/adoc/chapters/glossary.adoc new file mode 100644 index 00000000..0df2cd3d --- /dev/null +++ b/adoc/chapters/glossary.adoc @@ -0,0 +1,560 @@ +// %%%%%%%%%%%%%%%%%%%%%%%%%%%% begin glossary %%%%%%%%%%%%%%%%%%%%%%%%%%%% + +// TODO 2019/06/10 +// Look at the remaining [keyword] spans in the document and add the +// lacking entries here + +// The purpose of this glossary is to define the key concepts involved in +// specifying SYCL. This section includes definitions of terminology used +// throughout the specification document. + +[glossary] +[[glossary]] += Glossary + +[glossary] +[[accessor]]accessor:: + An accessor is a class which allows a <> to access data managed + by a <> or <> class or allows a <> + to access local memory on a <>. Accessors are also used to express + the dependencies among the different <>. + For the full description please refer to <> + +[[application-scope]]application scope:: + The application scope starts with the construction first + <> class object and finishes with the destruction of the + last one. Application refers to the {cpp} <> and not + the <>. + +[[aspect]]aspect:: + A characteristic of a <> which determines whether it supports + some optional feature. Aspects are always boolean, so a <> + either has or does not have an aspect. + +[[async-error]]asynchronous error:: + A SYCL asynchronous error is an error occurring after the host API call + invoking the error causing action has returned, such that the error + cannot be thrown as a typical {cpp} exception from a host API call. Such + errors are typically generated from device kernel invocations which are + executed when SYCL task graph dependencies are satisfied, which occur + asynchronously from host code execution. For the full description and + associated asynchronous error handling mechanisms, please refer to + <>. + +[[async-handler]]async_handler:: + An asynchronous error handler object is a function class instance + providing necessary code for handling all the asynchronous errors + triggered from the execution of command groups on a queue, within a + context or an associated event. For the full description please refer to + <>. + +[[barrier]]barrier:: + A barrier is either a <>, or a kernel execution + <> depending on whether it is a synchronization point on + the command queue or on a group of work-items in a kernel execution. + +[[blocking-accessor]]blocking accessor:: + A blocking accessor is an <> which provides immediate access + and continues to provide access until it is destroyed. For the full + description please refer to <> + +[[buffer]]buffer:: ++ +-- +The buffer class manages data for the SYCL {cpp} host application and the +SYCL device kernels. The buffer class may acquire ownership of some host +pointers passed to its constructors according to the constructor kind. + +The buffer class, together with the accessor class, is responsible for +tracking memory transfers and guaranteeing data consistency among the +different kernels. The <> manages the memory allocations +on both the host and the <> within the lifetime of the buffer +object. For the full description please refer to <>. +-- + +[[bundle-state]]bundle state:: + A SYCL bundle state represents the state of a <> and + therefore its capabilities in the SYCL programming API. Possible states + are <>, <> or <>. + +[[command]]command:: + A request to execute work that is submitted to a <> such as the + invocation of a <>, the invocation of a + <> or an asynchronous copy. + +[[command-group]]command group:: + In SYCL, the operations required to process data on a <> are + represented using a <>. Each + <> is given a unique <> + object to perform all the necessary work required to correctly process + data on a <> using a kernel. In this way, the group of + commands for transferring and processing data is enqueued as a command + group on a <> for execution. A command group is submitted + atomically to a SYCL queue. + +[[command-group-function-object]]command group function object:: + A type which is callable with [code]#operator()# that takes a + reference to a <>, that defines a <> which + can be submitted by a <>. The function object can be a named + type, lambda function or [code]#std::function#. + +[[handler]]command group handler:: + The command group handler class provides the interface for the commands + that can be executed inside the <>. It is + provided as a scoped object to all of the data access requests within + the command group scope. For the full description please refer to + <>. + +[[command-group-scope]]command group scope:: + The command group scope is the function scope defined by the + <>. The command group <> + object lifetime is restricted to the command group scope. For more + details see <>. + +[[queue-barrier]]command queue barrier:: + The SYCL API provides two variants for functions that force + synchronization on a SYCL command queue. The + [code]#sycl::queue::wait()# and + [code]#sycl::queue::wait_and_throw()# functions force the SYCL + command queue to wait for the execution of the + <> before it is able to continue + executing. + +[[constant-memory]]constant memory:: + A region of memory that remains constant during the execution of + a kernel. The <> allocates and initializes memory + objects placed into constant memory. + +[[context]]context:: + A <> represents the runtime data structures and state + required by a <> API to interact with a group of <> + associated with a <>. The context is defined as the + [code]#sycl::context# class, for further details please see + <>. + +[[control-flow]]control flow:: + When all <> in a <> are executing the same + sequence of statements, they are said to be executing under _converged_ + control flow. Control flow _diverges_ when different work-items in a + group execute a different sequence of statements, typically as a result + of evaluating conditions differently (e.g. in selection statements or + loops). + +[[core-spec]]core SYCL specification:: + The text of the SYCL language specification (this document), excluding + the text of any backend specifications and excluding the text for any + extensions. + +[[device]]device:: + A SYCL device is an abstraction of a piece of hardware that can execute + <>. + +[[device-compiler]]device compiler:: + A SYCL device compiler is a compiler that produces <> + binaries from a valid <>. For the full description + please refer to <>. + +[[device-copyable]]device copyable:: + Data that is shared between the host and the devices must generally + have a type that abides by the restrictions listed in + <> for a device copyable type. + +[[device-function]]device function:: + A device function is any function in a <> + that can be run on a <>. This includes + <> and, recursively, functions + they call. + +[[device-image]]device image:: + A device image is a representation of one or more <> in an + implementation-defined format. A device image could be a compiled version + of the kernels in an intermediate language representation which needs to be + translated at runtime into a form that can be invoked on a <>, it + could be a compiled version of the kernels in a native code format that is + ready to be invoked without further translation, or it could be a source + code representation which needs to be compiled before it can be invoked. + Other representations are possible too. + +[[device-image-selection-function]]device image selection function:: + A callable object which takes the begin and end iterators of a + <> pointing to a sequence of <> and returns an + iterator to a chosen <>. + +[[device-selector]]device selector:: + A way to select a device used in various places. This is a callable + object taking a <> reference and returning an integer rank. + One of the device with the highest positive value is selected. See + <> for more details. + +[[event]]event:: + A SYCL object that represents the status of an operation that is being + executed by the SYCL runtime. + +[[executable]]executable:: + A state which a <> can be in, representing + <> as an executable. + +[[generic-memory]]generic memory:: + Generic memory is a virtual memory region which can represent + <>, <> and <> region. + +[[global-id]]global id:: + As in OpenCL, a global ID is used to uniquely identify a <> + and is derived from the number of global <> specified + when executing a kernel. A global ID is a one, two or three-dimensional + value that starts at 0 per dimension. + +[[global-memory]]global memory:: + Global memory is a memory region accessible to all <> + executing on a <>. + +[[group]]group:: + A group of work-items within the index space of a SYCL kernel execution, + such as a <> or <>. + +[[group-barrier]]group barrier:: + A synchronization function within a group of <>. All the + <> of a group must execute the barrier construct before any + <> continues execution beyond the barrier. Additionally all work-items + in the group execute a release <> prior to synchronizing at the + barrier, all work-items in the group execute an acquire <> after + synchronizing at the barrier, and there is an implicit synchronization between + these acquire and release fences as if through an atomic operation on an + atomic object internal to the barrier implementation. + +[[h-item]]h-item:: + A unique identifier representing a single <> within the + index space of a SYCL kernel hierarchical execution. Can be one, two or + three dimensional. In the SYCL interface a <> is represented + by the [code]#h_item# class (see <>). + +[[host]]host:: + Host is the system that executes the {cpp} application including the SYCL + API. + +[[host-pointer]]host pointer:: + A pointer to memory on the host. Cannot be accessed directly from a + <>. + +[[host-task]]host task:: + A <> which invokes a native {cpp} callable, scheduled + conforming to SYCL dependency rules. + +[[host-task-command]]host task command:: + A type of command that can be used inside a <> in order + to schedule a native {cpp} function. + +[[id]]id:: + It is a unique identifier of an item in an index space. It can be one, + two or three dimensional index space, since the SYCL kernel execution + model is an <>. It is one of the index space classes. For + the full description please refer to <>. + +[[image]]image:: + Images in SYCL, like buffers, are abstractions of multidimensional + structured arrays. Image can refer to [code]#unsampled_image# and + [code]#sampled_image#. For the full description please refer to + <>. + +[[implementation-defined]]implementation-defined:: + Behavior that is explicitly allowed to vary between conforming + implementations of SYCL. A SYCL implementer is required to document the + implementation-defined behavior. + +[[index-space-classes]]index space classes:: + Like in OpenCL, the kernel execution model defines an + <> index space. + The <> class that defines an <> is the + [code]#sycl::nd_range#, which takes as input the sizes of global + and local work-items, represented using the [code]#sycl::range# + class. The kernel library classes for indexing in the defined + <> are the following classes: ++ + * [code]#sycl::id# : The basic index class representing an <>; + * [code]#sycl::item# : The <> index class that contains the + <> and <>; + * [code]#sycl::nd_item# : The <> index class that contains the + <>, <> and the <>; + * [code]#sycl::group# : The <> class that contains the + <> and the member functions on a <>. + +[[input]]input:: + A state which a <> can be in, representing + <> as a source or intermediate representation + +[[item]]item:: + An item id is an interface used to retrieve the <>, + <> and <>. For further details see + <>. + +[[kernel]]kernel:: + A kernel represents a <> that has been compiled for a + device, including all of the <> it calls. + A kernel is implicitly created when a <> is submitted + to a device via a <>. However, a kernel can + also be created manually by pre-compiling a <> (see + <>). + +[[kernel-bundle]]kernel bundle:: + A kernel bundle is a collection of <> that are + associated with the same <> and with a set of <>. + Kernel bundles have one of three states: <>, <> or + <>. Kernel bundles in the executable state are ready to be + invoked on a device, whereas bundles in the other states need to be + translated into the executable state before they can be invoked. + +[[kernel-handler]]kernel handler:: + A representation of a <> being invoked that is + available to the <>. + +// May conflict with host_task MR + +[[kernel-invocation-command]]kernel invocation command:: + A type of command that can be used inside a <> in order + to schedule a <>, includes + [code]#single_task#, all variants of [code]#parallel_for# and + [code]#parallel_for_workgroup#. + +[[kernel-name]]kernel name:: + A kernel name is a class type that is used to assign a name to the + kernel function, used to link the host system with the kernel object + output by the device compiler. For details on naming kernels please see + <>. + +[[kernel-scope]]kernel scope:: + The function scope of the [code]#operator()# on a + <>. Note that any function or member function called from + the kernel is also compiled in kernel scope. The kernel scope allows {cpp} + language extensions as well as restrictions to reflect the capabilities + of devices. The extensions and restrictions are defined in the + SYCL device compiler specification. + +[[local-id]]local id:: + A unique identifier of a <> among other work-items of a + <>. + +[[local-memory]]local memory:: + Local memory is a memory region associated with a <> and + accessible only by <> in that <>. + +[[native-backend-object]]native backend object:: + An opaque object defined by a specific backend that represents a + high-level SYCL object on said backend. There is no guarantee of having + native backend objects for all SYCL types. + +[[native-specialization-constant]]native-specialization constant:: + A <> in a device image whose value can be used by + an online compiler as an immediate value during the compilation. + + +[[nd-item]]nd-item:: + A unique identifier representing a single <> and + <> within the index space of a SYCL kernel execution. Can + be one, two or three dimensional. In the SYCL interface a <> + is represented by the [code]#nd_item# class (see + <>). + +[[nd-range]]nd-range:: + A representation of the index space of a SYCL kernel execution, the + distribution of <> within into <>. + Contains a <> specifying the number of global + <>, a <> specifying the number of local + <> and a <> specifying the global offset. Can be + one, two or three dimensional. The minimum size of each <> + within the <> is 1 per dimension. In the SYCL interface an + <> is represented by the [code]#nd_range# class (see + <>). + +[[mem-fence]]mem-fence:: + A memory fence provides control over re-ordering of memory load + and store operations when coupled with an atomic operation that + synchronizes two fences with each other (or when the fences are part of + a <> in which case there is implicit synchronization + as if an atomic operation has synchronized the fences). The + [code]#sycl::atomic_fence# function acts as a fence across all + work-items and devices specified by a [code]#memory_scope# + argument. + +[[object]]object:: + A state which a <> can be in, representing + <> as a non-executable object. + +[[platform]]platform:: + A collection of <> managed by a single + <>. + +[[private-memory]]private memory:: + A region of memory private to a <>. Variables defined in one + work-item's private memory are not visible to another work-item. + The [code]#sycl::private_memory# class provides + access to the work-item's private memory for the hierarchical API as it + is described at <>. + +[[queue]]queue:: + A SYCL command queue is an object that holds command groups to be + executed on a SYCL <>. SYCL provides a heterogeneous platform + integration using device queue, which is the minimum requirement for a + SYCL application to run on a SYCL <>. For the full description + please refer to <>. + +[[range]]range:: + A representation of a number of <> or <> + within the index space of a SYCL kernel execution. Can be one, two or + three dimensional. In the SYCL interface a <> is + represented by the [code]#group# class (see <>). + +[[ranged-accessor]]ranged accessor:: + A ranged accessor is a host or buffer <> that was constructed + with a non-zero offset into the data buffer or with an access range smaller + than the range of the data buffer, or both. Please refer to + <> for more info. + +[[reduction]]reduction:: + An operation that produces a single value by combining multiple values + in an unspecified order using a binary operator. If the operator is + non-associative or non-commutative, the behavior of a reduction may be + non-deterministic. + +[[rule-of-five]]rule of five:: + For a given class, if at least one of the copy constructor, move + constructor, copy assignment operator, move assignment operator or + destructor is explicitly declared, all of them should be explicitly + declared. + +[[rule-of-zero]]rule of zero:: + For a given class, if the copy constructor, move constructor, copy + assignment operator, move assignment operator and destructor would all + be inlined, public and defaulted, none of them should be explicitly + declared. + +[[smcp]]SMCP:: + The single-source multiple compiler-passes (SMCP) technique allows a + single source file to be parsed by multiple compilers for building + native programs per compilation target. For example, a standard {cpp} CPU + compiler for targeting <> will parse the <> to + create the {cpp} <> which offloads parts of the + computation to other <>. A SYCL device compiler will parse + the same source file and target only SYCL kernels. + +[[specialization-constant]]specialization constant:: + A constant variable where the value is not known until compilation of + the <>. + +[[specialization-id]]specialization id:: + An identifier which represents a reference to a + <> both in the <> for setting + the value prior to the compilation of a <> and in a + <> for retrieving the value during invocation. + +[[string-kernel-name]]string kernel name:: + The name of a <> in string form, this can be the + name of a kernel function created via interop or a string form of a + <>. + +[[sub-group]]sub-group:: + The SYCL sub-group ([code]#sycl::sub_group# class) is a + representation of a collection of related work-items within a + <> that execute concurrently, and which may make + independent forward progress with respect to other sub-groups in the + same <>. For further details for the + [code]#sycl::sub_group# class see <>. + +[[sub-group-barrier]]sub-group barrier:: + A <> for all <> in a <>. + +[[sub-group-mem-fence]]sub-group mem-fence:: + A <> for all <> in a <>. + +[[sycl-application]]SYCL application:: + A SYCL application is a {cpp} application which uses the SYCL programming + model in order to execute <> on <>. + +[[backend]]SYCL backend:: + An implementation of the SYCL programming model using an heterogeneous + programming API. A SYCL backend exposes one or multiple SYCL + <>. For example, the OpenCL backend, via the ICD loader, + can expose multiple OpenCL <>. + +[[backend-api]]SYCL backend API:: + The exposed API for writing SYCL code against a given <>. + +[[sycl-library]]SYCL {cpp} template library:: + The template library is a set of {cpp} templated classes which provide the + programming interface to the SYCL developer. + +[[sycl-file]]SYCL file:: + A SYCL {cpp} source file that contains SYCL API calls. + +[[sycl-kernel-function]]SYCL kernel function:: + A type which is callable with [code]#operator()# that takes a + <>, <>, <> or <> which can be passed to + kernel enqueue member functions of the <>. A + <> defines an entry point to a <>. The + function object can be a named <> type or lambda + function. + +[[sycl-runtime]]SYCL runtime:: + A SYCL runtime is an implementation of the SYCL API specification. The + SYCL runtime manages the different <>, + <>, <> as well as memory + handling of data between host and <> <> + to enable semantically correct execution of SYCL programs. + +[[type-kernel-name]]type kernel name:: + The name of a <> in type form, this can be either + a <> provided to a <> or the + type of a function object use as a <>. + +[[usm]]USM:: ++ +-- +Unified Shared Memory (USM) provides a pointer-based alternative to the +<> programming model. USM enables: + + * easier integration into existing code bases by representing allocations + as pointers rather than buffers, with full support for pointer + arithmetic into allocations; + * fine-grain control over ownership and accessibility of allocations, to + optimally choose between performance and programmer convenience; + * a simpler programming model, by automatically migrating some allocations + between SYCL <> and the <>. + +See <> +-- + +[[work-group]]work-group:: + The SYCL work-group ([code]#sycl::group# class) is a representation + of a collection of related <> that execute on a single + compute unit. The <> in the group execute the same + kernel-instance and <>. + For further details for the [code]#sycl::group# + class see <>. + +[[work-group-barrier]]work-group barrier:: + A <> for all <> in a <>. + +[[work-group-mem-fence]]work-group mem-fence:: + A <> for all <> in a <>. + +[[work-group-id]]work-group id:: + As in OpenCL, SYCL kernels execute in <>. The group ID + is the ID of the <> that a <> is executing + within. A group ID is an one, two or three dimensional value that starts + at 0 per dimension. + +[[work-group-range]]work-group range:: + A group range is the size of the <> for every dimension. + +[[work-item]]work-item:: + The SYCL work-item is a representation of a <> among a + collection of parallel executions of a kernel invoked on a <> + by a <>. A <> is executed by one or more processing + elements as part of a <> executing on a compute unit. A + <> is distinguished from other <> by its + <> or the combination of its <> and its + <> within a <>. + +:work-items: <> + + +// %%%%%%%%%%%%%%%%%%%%%%%%%%%% end glossary %%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/adoc/chapters/host_backend.adoc b/adoc/chapters/host_backend.adoc new file mode 100644 index 00000000..1c514546 --- /dev/null +++ b/adoc/chapters/host_backend.adoc @@ -0,0 +1,95 @@ +// This appendix is not built into the spec!! +// +// The host backend is no longer required for SYCL conformance, but an +// implementation can still provide some sort of host backend if it wants to. +// We'd like to have a common definition of "host backend" for consistency +// between implementations that provide it, however, we are not yet in +// agreement about the details of this backend. For example, should the +// backend be a faithful emulation of a typical GPU accelerator? Or, should +// it be an optimized backend tailored to run on the host CPU? If we choose +// the later, the host backend could allow kernels to call arbitrary C++ code. +// If we choose the former, we would not allow this. There are likely other +// ramifications of this decision too. +// +// At present, the text below does not reflect an agreed upon definition, but +// it could be a good starting point for future discussions about the "host +// backend". + +// %%%%%%%%%%%%%%%%%%%%%%%%%%%% begin host_backend %%%%%%%%%%%%%%%%%%%%%%%%%%%% + +[appendix] +[[chapter:host-backend]] += Host backend specification + +This chapter describes how SYCL is mapped on the <>. +The <> exposes the host where the SYCL application is executing +as a platform to dispatch SYCL kernels. +The <> exposes at least one <>. + + +== Mapping of the SYCL programming model on the host + +// From Glossary, reworded to match backend + +The SYCL host device implements all functionality required to execute the +SYCL kernels directly on the host, without relying on a third party API. +It has full SYCL capabilities and reports them through the SYCL information retrieval +interface. At least one SYCL host device must be exposed in the SYCL host +backend in all SYCL implementations, and it must always be available. +Any {cpp} application debugger, if available on the system, +can be used for debugging SYCL kernels executing on a SYCL host device. + +// From Architecture, Section 3.3 +When a SYCL implementation executes kernels on the host device, +it is free to use whatever parallel execution facilities available on the +host, as long as it executes within the semantics of the kernel execution model +defined by the SYCL kernel execution model. + +Kernel math library functions on the host must conform to OpenCL math precision +requirements. The SYCL host device needs to be queried for the capabilities it +provides. This ensures consistency when executing any SYCL general application. + +The <> must report as supporting images and therefore support +the minimum image formats. + +The range of image formats supported by the host device is implementation-defined, +but must match the minimum requirements of the OpenCL specification. + +SYCL implementors can provide extensions on the host-device to match any other +backend-specific extension. This allows developers to rely on the host device +to execute their programs when said backend is not available. + + +=== SYCL memory model on the host + +All SYCL device memories are available on devices from the host backend. + +[[table.host.memory]] +.Mapping of SYCL memory regions into host memory regions +[width="40%",options="header",cols="50%,50%"] +|==== +| SYCL | Host +| Global | System memory +| Constant | System memory +| Local | System memory +| Private | Stack +|==== + + +== Interoperability with the host application + +The host backend must ensure all functionality of the SYCL generic programming +model is always available to developers. +However, since there is no heterogeneous API behind the host backend (it +directly targets the host platform), there are no native types for SYCL +objects to map to in the SYCL application. + +Inside SYCL kernels, the host backend must ensure interoperability with +existing host code, so that existing host libraries can be used inside +SYCL kernels executing on the host. +In particular, when retrieving a raw pointer from a multi pointer object, +the pointer returned must be usable by any library accessible by the +SYCL application. + + +// %%%%%%%%%%%%%%%%%%%%%%%%%%%% end host_backend %%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/adoc/chapters/information_descriptors.adoc b/adoc/chapters/information_descriptors.adoc new file mode 100644 index 00000000..8da6dff5 --- /dev/null +++ b/adoc/chapters/information_descriptors.adoc @@ -0,0 +1,80 @@ +// %%%%%%%%%%%%%%%%%%%%%%%%%%%% begin descriptors %%%%%%%%%%%%%%%%%%%%%%%%%%%% + +[appendix] +[[sec:information-descriptors]] += Information descriptors + +The purpose of this chapter is to include all the headers of the +memory object descriptors, which are described in detail in +<>, for platform, +context, device, and queue. + + +[[appendix.platform.descriptors]] +== Platform information descriptors + +The following interface includes all the information descriptors for the +[code]#platform# class as described in <>. +[source,,linenums] +---- +include::{header_dir}/platformInfo.h[lines=4..-1] +---- + + +[[appendix.context.descriptors]] +== Context information descriptors + +The following interface includes all the information descriptors for the +[code]#context# class as described in <>. +[source,,linenums] +---- +include::{header_dir}/contextInfo.h[lines=4..-1] +---- + + +[[appendix.device.descriptors]] +== Device information descriptors + +The following interface includes all the information descriptors for the +[code]#device# class as described in <>. +[source,,linenums] +---- +include::{header_dir}/deviceInfo.h[lines=4..-1] +---- + + +[[appendix.queue.descriptors]] +== Queue information descriptors + +The following interface includes all the information descriptors for the +[code]#queue# class as described in <>. +[source,,linenums] +---- +include::{header_dir}/queueInfo.h[lines=4..-1] +---- + + +[[appendix.kernel.descriptors]] +== Kernel information descriptors + +The following interface includes all the information descriptors +that apply to kernels as described in <>. +[source,,linenums] +---- +include::{header_dir}/kernelInfo.h[lines=4..-1] +---- + + +[[appendix.event.descriptors]] +== Event information descriptors + +The following interface includes all the information descriptors +for the [code]#event# class as described in <> +and <>. +[source,,linenums] +---- +include::{header_dir}/eventInfo.h[lines=4..-1] +---- + + +// %%%%%%%%%%%%%%%%%%%%%%%%%%%% end descriptors %%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/adoc/chapters/introduction.adoc b/adoc/chapters/introduction.adoc new file mode 100644 index 00000000..35a36d41 --- /dev/null +++ b/adoc/chapters/introduction.adoc @@ -0,0 +1,147 @@ +// %%%%%%%%%%%%%%%%%%%%%%%%%%%% begin introduction %%%%%%%%%%%%%%%%%%%%%%%%%%%% + +[[introduction]] += Introduction + +SYCL (pronounced "`sickle`") is a royalty-free, cross-platform +abstraction {cpp} programming model for heterogeneous computing. SYCL +builds on the underlying concepts, portability and efficiency of +parallel API or standards like OpenCL while adding much of the ease of +use and flexibility of single-source {cpp}. + +Developers using SYCL are able to write standard modern {cpp} code, with +many of the techniques they are accustomed to, such as inheritance and +templates. At the same time, developers have access to the full range +of capabilities of the underlying implementation (such as OpenCL) both +through the features of the SYCL libraries and, where necessary, +through interoperation with code written directly using the underneath +implementation, via their APIs. + +To reduce programming effort and increase the flexibility with which +developers can write code, SYCL extends the concepts found in +standards like OpenCL model in a few ways beyond the general use of {cpp} +features: + + * execution of parallel kernels on a heterogeneous device is made + simultaneously convenient and flexible. Common parallel patterns are + prioritized with simple syntax, which through a series {cpp} types allow + the programmer to express additional requirements, such as synchronization, + if needed; + * when using buffers and accessors, data access in SYCL is separated from + data storage. By relying on the {cpp}-style resource acquisition is + initialization (RAII) idiom to capture data dependencies between device + code blocks, the runtime library can track data movement and provide + correct behavior without the complexity of manually managing event + dependencies between kernel instances and without the programmer having to + explicitly move data. This approach enables the data-parallel task-graphs + that might be already part of the execution model to be built up easily + and safely by SYCL programmers; + * Unified Shared Memory (<>) provides a mechanism for explicit data + allocation and movement. This approach enables the use of pointer-based + algorithms and data structures on heterogeneous devices, and allows for + increased re-use of code across host and device; + * the hierarchical parallelism syntax offers a way of expressing + data parallelism similar to the OpenCL device or OpenMP target + device execution model in an easy-to-understand modern {cpp} form. It + more cleanly layers parallel loops and synchronization points to + avoid fragmentation of code and to more efficiently map to CPU-style + architectures. + +SYCL retains the execution model, runtime feature set and device +capabilities inspired by the OpenCL standard. This standard imposes +some limitations on the full range of {cpp} features that SYCL is able +to support. This ensures portability of device code across as wide a +range of devices as possible. As a result, while the code can be +written in standard {cpp} syntax with interoperability with standard {cpp} +programs, the entire set of {cpp} features is not available in SYCL +device code. In particular, SYCL device code, as defined by this +specification, does not support virtual function calls, function +pointers in general, exceptions, runtime type information or the full +set of {cpp} libraries that may depend on these features or on features +of a particular host compiler. Nevertheless, these basic restrictions +can be relieved by some specific Khronos or vendor extensions. + +SYCL implements an <> design which offers the power of source +integration while allowing toolchains to remain flexible. The <> +design supports embedding of code intended to be compiled for a device, +for example a GPU, inline with host code. This embedding of code offers three +primary benefits: + +Simplicity:: + For novice programmers using frameworks like OpenCL, the separation of + host and device source code in OpenCL can become complicated to deal + with, particularly when similar kernel code is used for multiple + different operations on different data types. A single compiler flow and + integrated tool chain combined with libraries that perform a lot of + simple tasks simplifies initial OpenCL programs to a minimum complexity. + This reduces the learning curve for programmers new to heterogeneous programming and allows + them to concentrate on parallelization techniques rather than syntax. +Reuse:: + {cpp}'s type system allows for complex interactions between different code + units and supports efficient abstract interface design and reuse of + library code. For example, a [keyword]#transform# or [keyword]#map# + operation applied to an array of data may allow specialization on both + the operation applied to each element of the array and on the type of + the data. The <> design of SYCL enables this interaction to + bridge the host code/device code boundary such that the device code to + be specialized on both of these factors directly from the host code. +Efficiency:: + Tight integration with the type system and reuse of library code enables + a compiler to perform inlining of code and to produce efficient + specialized device code based on decisions made in the host code without + having to generate kernel source strings dynamically. + +The use of {cpp} features such as generic programming, templated code, +functional programming and inheritance on top of existing +heterogeneous execution model opens a wide scope for innovation in +software design for heterogeneous systems. Clean integration of device +and host code within a single {cpp} type system enables the development +of modern, templated generic and adaptable libraries that build +simple, yet efficient, interfaces to offer more developers access to +heterogeneous computing capabilities and devices. SYCL is intended to +serve as a foundation for innovation in programming models for +heterogeneous systems, that builds on open and widely implemented +standard foundation like OpenCL or Vulkan. + +SYCL is designed to be as close to standard {cpp} as possible. In +practice, this means that as long as no dependence is created on +SYCL's integration with the underlying implementation, a +standard {cpp} compiler can compile SYCL programs and they will run +correctly on a host CPU. Any use of specialized low-level features can +be masked using the C preprocessor in the same way that +compiler-specific intrinsics may be hidden to ensure portability +between different host compilers. + +SYCL is designed to allow a compilation flow where the source file is passed +through multiple different compilers, including a standard {cpp} host compiler of +the developer's choice, and where the resulting application combines the results +of these compilation passes. This is distinct from a single-source flow that +might use language extensions that preclude the use of a standard host compiler. +The SYCL standard does not preclude the use of a single compiler flow, but is +designed to not require it. SYCL can also be implemented purely as a library, +in which case no special compiler support is required at all. + +The advantages of this design are two-fold. First, it offers better integration +with existing tool chains. An application that already builds using a chosen +compiler can continue to do so when SYCL code is added. Using the SYCL tools on +a source file within a project will both compile for a device and let +the same source file be compiled using the same host compiler that the rest of +the project is compiled with. Linking and library relationships are unaffected. +This design simplifies porting of pre-existing applications to SYCL. Second, the +design allows the optimal compiler to be chosen for each device where different +vendors may provide optimized tool-chains. + +To summarize, SYCL enables computational kernels to be written inside +{cpp} source files as normal {cpp} code, leading to the concept of +"`single-source`" programming. This means that software developers can +develop and use generic algorithms and data structures using standard +{cpp} template techniques, while still supporting multi-platform, +multi-device heterogeneous execution. Access to the low level APIs of +an underlying implementation (such as OpenCL) is also supported. +The specification has been designed to enable implementation +across as wide a variety of platforms as possible as well as ease of +integration with other platform-specific technologies, thereby letting +both users and implementers build on top of SYCL as an open platform +for system-wide heterogeneous processing innovation. + +// %%%%%%%%%%%%%%%%%%%%%%%%%%%% end introduction %%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/adoc/chapters/opencl_backend.adoc b/adoc/chapters/opencl_backend.adoc new file mode 100644 index 00000000..1c96ad7f --- /dev/null +++ b/adoc/chapters/opencl_backend.adoc @@ -0,0 +1,1180 @@ +// %%%%%%%%%%%%%%%%%%%%%%%%%%%% begin opencl_backend %%%%%%%%%%%%%%%%%%%%%%%%%%%% + +[appendix] +[[chapter:opencl-backend]] += OpenCL backend specification + +This chapter describes how the SYCL general programming model is mapped on top +of OpenCL, and how the SYCL generic interoperability interface must be +implemented by vendors providing SYCL for OpenCL implementations to ensure SYCL +applications written for the OpenCL backend are interoperable. + + +[[sec:opencl:native-interop-application]] +== SYCL application interoperability native backend objects + +For each <> class which supports <> interoperability, +specializations of [code]#backend_traits::input_type# +and [code]#backend_traits::return_type# must be defined as the +type of <> interoperability <> +associated with [code]#SyclType# for the <>. + +The types of the native backend objects for <> +interoperability are described in <>. + +[[sec:opencl:native-interop-kernel]] +== Kernel function interoperability native backend objects + +For each <> class which supports kernel function interoperability, +a specialization of [code]#backend_traits::return_type# must be defined as the type of kernel +function interoperability <> associated with [code]#SyclType# +for the <>. + +The types of the native backend objects for kernel function interoperability are +described in <>. + +[[table.opencl.kernelfunctioninterop.nativeobjects]] +.Types of native backend objects kernel function interoperability +[width="100%",options="header",cols="60%,40%"] +|==== +| [code]#SyclType# | [code]#backend_return_t# +| [code]#accessor# | [code]#__global T*# +| [code]#accessor# | [code]#__constant T*# +| [code]#accessor# | [code]#__local T*# +| [code]#local_accessor# | [code]#__local T*# +| [code]#sampled_image_accessor# | [code]#sampler_1dimage_pair_t# +| [code]#sampled_image_accessor# | [code]#sampler_2dimage_pair_t# +| [code]#sampled_image_accessor# | [code]#sampler_3dimage_pair_t# +| [code]#unsampled_image_accessor# | [code]#image1d_t# +| [code]#unsampled_image_accessor# | [code]#image2d_t# +| [code]#unsampled_image_accessor# | [code]#image3d_t# +| [code]#stream# | [code]#__global cl_char*# +| [code]#device_event# | [code]#event_t# +|==== + +The [code]#sampler_1dimage_pair_t#, [code]#sampler_1dimage_pair_t# and +[code]#sampler_1dimage_pair_t# types must be implemented as described below. + +[source,,linenums] +---- +include::{header_dir}/openclBackend/samplerImagePair.h[lines=4..-1] +---- + +[[sec:opencl:native-interop-destruction]] +== Destruction of interop constructed objects with reference semantics + +On destruction of the last copy of an instance of a SYCL class which is +specified to have reference semantics as described in +<> that was constructed using one of the <> +interoperability [code]#make_*# functions specified in +<> additional lifetime related operations may +be performed which are required for the underlying <>. + +The additional behavior performed by the OpenCL <> for each SYCL class +is described in <>. + +[[table.opencl.interop.destructors]] +.Destructor behavior of interop constructed objects with reference semantics +[width="100%",options="header",cols="30%,70%"] +|==== +| SYCL object | Destructor behavior +| accessor | No additional behavior is performed. +| buffer | [code]#clReleaseMemObject# will be called on the native [code]#cl_mem# object provided during construction. +| context | [code]#clReleaseContext# will be called on the native [code]#cl_context# object provided during construction. +| device | [code]#clReleaseDevice# will be called on the native [code]#cl_device# object provided during construction. +| event | [code]#clReleaseEvent# will be called on the native [code]#cl_event# object provided during construction. +| kernel | [code]#clReleaseKernel# will be called on the native [code]#cl_kernel# objects provided during construction. +| kernel_bundle | [code]#clReleaseProgram# will be called on the native [code]#cl_program# objects provided during construction. +| platform | No additional behavior is performed. +| queue | [code]#clReleaseCommandQueue# will be called on the native [code]#cl_command_queue# object provided during construction. +| sampled_image | [code]#clReleaseMemObject# will be called on the native [code]#cl_mem# object provided during construction. +| unsampled_image | [code]#clReleaseMemObject# will be called on the native [code]#cl_mem# object provided during construction. +|==== + +// From 3.8 SYCL for OpenCL Framework +== SYCL for OpenCL framework + +The SYCL framework allows applications to +use a host and one or more OpenCL devices as a single heterogeneous parallel +computer system. The framework contains the following components: + + * <>: The template library provides a set of {cpp} templates + and classes which provide the programming model to the user. It enables + the creation of runtime classes such as SYCL queues, buffers and images, + as well as access to some underlying OpenCL runtime object, such as + contexts, platforms, devices and program objects. + * <>: The <> interfaces with the + underlying OpenCL implementations and handles scheduling of commands in + queues, moving of data between host and devices, manages contexts, + programs, kernel compilation and memory management. + * [keyword]#OpenCL Implementation(s)#: The SYCL system assumes the + existence of one or more OpenCL implementations available on the host + machine. + * SYCL <>: The SYCL <> compile + SYCL {cpp} kernels into a format which can be executed on an OpenCL device + at runtime. There may be more than one SYCL device compiler in a SYCL + implementation. The format of the compiled SYCL kernels is not defined. + A SYCL device compiler may, or may not, also compile the host parts of + the program. + +The OpenCL backend is enabled using the [code]#sycl::backend::opencl# +value of [code]#enum class backend#. That means that when the OpenCL +backend is active, the value of +[code]#sycl::is_backend_active::value# will be +[code]#true#. + + +== Mapping of SYCL programming model on top of OpenCL + +The SYCL programming model was originally designed as a high-level model +for the OpenCL API, hence the mapping of SYCL on the OpenCL API is +mostly straightforward. + +When the OpenCL backend is active on a SYCL application, all visible +OpenCL platforms are exported as SYCL platforms. + +// From Architecture, Section 3.3 +When a SYCL implementation executes kernels on an OpenCL +device, it achieves this by enqueuing OpenCL *commands* to +execute computations on the processing elements within a device. The +processing elements within an OpenCL compute unit may execute a single +stream of instructions as ALUs within a SIMD unit (which execute in +lockstep with a single stream of instructions), as independent SPMD +units (where each PE maintains its own program counter) or as some +combination of the two. + + +// From Architecture, Section 3.3.1 (Platform mixed version support) +=== Platform mixed version support + +The SYCL system presents the user with a set of devices, grouped into some +number of platforms. +The device version is an indication of the device's +capabilities, as represented by the device information returned by the +[code]#sycl::device::get_info()# member function. Examples of attributes +associated with the device version are resource limits and information +about functionality beyond the requirements in the <>. +The version returned corresponds to the highest version of the OpenCL +specification for which the device is conformant, but is not higher than +the version of the device's platform which bounds the overall capabilities +of the runtime operating the device. + + +=== OpenCL memory model + +The memory model for SYCL devices running on OpenCL platforms follows the +memory model of the OpenCL version they conform to. + +In addition to <> , <> and <> memory, +the OpenCL backend permits the use of <> space in SYCL: + + * <> is a region of memory that remains constant + during the execution of a kernel. A pointer to the generic address space cannot + represent an address to this memory region. + +Work-items executing in a kernel have access to four distinct memory regions, +with the mapping between SYCL and OpenCL described in <>. + +[[table.opencl.memory]] +.Mapping of SYCL memory regions into OpenCL memory regions +[width="40%",options="header",cols="50%,50%"] +|==== +| SYCL | OpenCL +| Global | Global memory +| Constant | Constant memory +| Local | Local memory +| Private | Private memory +|==== + +=== OpenCL interface for buffer command accessors + +The enumerator [code]#target::constant_buffer# is deprecated, but will remain a +part of the OpenCL backend as an extension. This enables SYCL kernel functions +to access the contents of a buffer through the OpenCL device’s constant memory. + +// From 3.4.1.1 OpenCL resources managed by SYCL Application +=== OpenCL resources managed by SYCL application + +In OpenCL, a developer must create a <> to be able to execute +commands on a device. Creating a context involves choosing a <> +and a list of <>. In SYCL, contexts, platforms and devices all +exist, but the user can choose whether to specify them or have the SYCL +implementation create them automatically. The minimum required object for +submitting work to devices in SYCL is the <>, which contains +references to a platform, device and context internally. + +The resources managed by SYCL are: + + . <>: all features of OpenCL are implemented by platforms. A + platform can be viewed as a given hardware vendor's runtime and the + devices accessible through it. Some devices will only be accessible to + one vendor's runtime and hence multiple platforms may be present. SYCL + manages the different platforms for the user. In SYCL, a platform + resource is accessible through a [code]#sycl::platform# object. + . <>: any OpenCL resource that is acquired by the user is + attached to a context. A context contains a collection of devices that + the host can use and manages memory objects that can be shared between + the devices. Data movement between devices within a context may be + efficient and hidden by the underlying OpenCL runtime while data + movement between contexts may involve the host. A given context can only + wrap devices owned by a single platform. In SYCL, a context resource is + accessible through a [code]#sycl::context# object. + . <>: platforms provide one or more devices for executing + kernels. In SYCL, a device is accessible through a + [code]#sycl::device# object. + . <>: OpenCL objects that store implementation + data for the SYCL kernels. These objects are only required for advanced use + in SYCL and are encapsulated in the [code]#sycl::kernel_bundle# class. + . <>: SYCL kernels execute in command queues. The user must + create a queue, which references an associated context, platform and + device. The context, platform and device may be chosen automatically, or + specified by the user. In SYCL, command queues are accessible through + [code]#sycl::queue# objects. + +// Removed from OpenCL Spec document +// In OpenCL, queues can operate using in-order execution or out-of-order +// execution. In SYCL, the implementation must provide out-of-order +// execution ordering when possible, regardless of whether the underlying +// OpenCL queue is in-order or out-of-order. + + +[[sec:opencl:interfacing-with-opencl]] +== Interoperability with the OpenCL API + +// Original sections from 1.2.1 +// From Architecture, 3.1; +// +// To ensure maximum backward-compatibility, a software developer can produce +// a program that mixes standard OpenCL C kernels and OpenCL API code with +// SYCL code and expect fully compatible interoperability. + +The OpenCL backend for SYCL ensures maximum compatibility between SYCL +and OpenCL kernels and API. This includes supporting devices with +different capabilities and support for different versions of the +OpenCL C language, in addition to supporting SYCL kernels written in {cpp}. + +// Original from 3.6.11, Interfacing with OpenCL +// https://cvs.khronos.org/bugzilla/show_bug.cgi?id=10426 + +<> classes which encapsulate an OpenCL opaque type such as +SYCL [code]#context# or SYCL [code]#queue# must provide an +interoperability constructor taking an instance of the OpenCL opaque type. +These constructors must retain that instance to increase the reference count +of the OpenCL resource. + +The destructor for the <> classes which encapsulate an +OpenCL opaque type must release that instance to decrease the reference +count of the OpenCL resource. + +Note that an instance of a <> class which encapsulates an +OpenCL opaque type can encapsulate any number of instances of the OpenCL +type, unless it was constructed via the interoperability constructor, in +which case it can encapsulate only a single instance of the OpenCL type. + +The lifetime of a <> class that encapsulates an OpenCL +opaque type and the instance of that opaque type retrieved via the +[code]#get_native()# free function are not tied in either direction given +correct usage of OpenCL reference counting. For example if a user were to +retrieve a [code]#cl_command_queue# instance from a SYCL +[code]#queue# instance and then immediately destroy the SYCL +[code]#queue# instance, the [code]#cl_command_queue# instance is +still valid. Or if a user were to construct a SYCL [code]#queue# +instance from a [code]#cl_command_queue# instance and then immediately +release the [code]#cl_command_queue# instance, the SYCL +[code]#queue# instance is still valid. + +Note that a <> class that encapsulates an OpenCL opaque type +is not responsible for any incorrect use of OpenCL reference counting +outside of the <>. For example if a user were to retrieve a +[code]#cl_command_queue# instance from a SYCL [code]#queue# +instance and then release the [code]#cl_command_queue# instance more +than once without any prior retain then the SYCL [code]#queue# instance +that the [code]#cl_command_queue# instance was retrieved from is now +undefined. + +Note that an instance of the SYCL [code]#buffer# or SYCL +[code]#image# class templates constructed via the interoperability +constructor is free to copy from the [code]#cl_mem# into another memory +allocation within the <> to achieve normal SYCL semantics, +for as long as the SYCL [code]#buffer# or SYCL [code]#image# +instance is alive. + +<> relates SYCL objects +to their OpenCL native type in the SYCL application. + +[[table.opencl.interop]] +.List of native types per SYCL object in the OpenCL backend +[width="100%",options="header",separator="@",cols="15%,15%,15%,55%"] +|==== +@ [code]#SyclType# + @ [code]#backend_input_t# + @ [code]#backend_return_t# + @ Description +a@ +[source] +---- +device +---- + a@ [code]#cl_device_id# + a@ [code]#cl_device_id# + a@ A SYCL device object encapsulates an OpenCL device object. +a@ +[source] +---- +context +---- + a@ [code]#cl_context# + a@ [code]#cl_context# + a@ A SYCL context object encapsulates an OpenCL context object. +a@ +[source] +---- +kernel +---- + a@ [code]#cl_kernel# + a@ [code]#cl_kernel# + a@ A SYCL kernel object encapsulates an OpenCL kernel object. +a@ +[source] +---- +template +kernel_bundle +---- + a@ [code]#cl_program# + a@ [code]#std::vector# + a@ A SYCL kernel bundle can encapsulate one or more OpenCL program objects. + It can also encapsulate one or more OpenCL kernel objects + which can be retrieved using the appropriate [code]#kernel# object. +a@ +[source] +---- +event +---- + a@ [code]#std::vector# + a@ [code]#std::vector# + a@ // Original from 3.6.5.1 Synchronization in the SYCL application + +A SYCL event can encapsulate one or multiple OpenCL events, +representing a number of dependencies in the same or different contexts, +that must be satisfied for the SYCL event to be complete. +a@ +[source] +---- +buffer +---- + a@ [code]#cl_mem# + a@ [code]#std::vector# + a@ SYCL buffers containing OpenCL memory objects + can handle multiple [code]#cl_mem# objects in the same or different context. + The interoperability interface will return a list of active buffers in the SYCL runtime. +a@ +[source] +---- +sampled_image +---- + a@ [code]#cl_mem# + a@ [code]#std::vector# + a@ SYCL sampled images containing OpenCL image objects + can handle multiple underlying [code]#cl_mem# objects + at the same time in the same or different OpenCL contexts. + The interoperability interface will return a list of active images in the SYCL runtime. +a@ +[source] +---- +unsampled_image +---- + a@ [code]#cl_mem# + a@ [code]#std::vector# + a@ SYCL unsampled images containing OpenCL image objects + can handle multiple underlying [code]#cl_mem# objects + at the same time in the same or different OpenCL contexts. + The interoperability interface will return a list of active images in the SYCL runtime. +|==== + +Inside the SYCL kernel, the SYCL API offers interoperability with OpenCL device types. +<> describes the mapping of kernel types. + +[[table.opencl.kerneltypes]] +.List of native types per SYCL object on kernel code +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ SYCL kernel native types in OpenCL @ Description +a@ +[source] +---- +multi_ptr::get_decorated() +---- + a@ Returns a pointer in the OpenCL address space + corresponding to the type of multi pointer object +|==== + +// \section{SYCL Programming interface} +// From 3.6 SYCL programming model (eliminated) +// SYCL programs are explicitly parallel and expose the full heterogeneous +// parallelism of the underlying machine model of OpenCL. This includes exposing +// the data-parallelism, multiple execution devices and multiple memory storage +// spaces of OpenCL. However, SYCL adds on top of OpenCL a higher level of +// abstraction allowing developers to hide much of the complexity from the source +// code, when a developer so chooses. + + +// From 3.7 memory object +When a buffer or image is allocated on more than +one OpenCL device, if these devices are on separate contexts then multiple +[code]#cl_mem# objects may be allocated for the memory object, depending on +whether the object has actively been used on these devices yet or not. + + +// From 3.10 Language restrictions in kernels + +Some types in SYCL vary according to pointer size or vary on the host +according to the host ABI, such as [code]#size_t# or [code]#long#. In order +for the SYCL device compiler to ensure that the sizes of +these types match the sizes on the host and to enable data of these types +to be shared between host and device, the OpenCL interoperability types +are defined, [code]#sycl::cl_int# and [code]#sycl::cl_size_t#. + +The OpenCL C function qualifier [code]#+__kernel+# and the access +qualifiers: [code]#+__read_only+#, [code]#+__write_only+# and [code]#+__read_write+# +are not exposed in SYCL via keywords, but are instead encapsulated in +SYCL's parameter passing system inside accessors. Users wishing to +achieve the OpenCL equivalent of these qualifiers in SYCL should +instead use SYCL accessors with equivalent semantics. + +// From 3.10.1 SYCL Linker +Any OpenCL C function included in a pre-built OpenCL library can be +defined as an [code]#extern "C"# function and the OpenCL program +has to be linked against any SYCL program that contains kernels using +the external function. In this case, the data types used have to comply with +the interoperability aliases defined in <>. + + +== Programming interface + +The following section describes the OpenCL-specific API. +All free functions are available in the [code]#sycl::opencl# namespace. + +=== Construct SYCL objects from OpenCL ones + +[width="100%",options="header",separator="@",cols="40%,60%"] +|==== +@ OpenCL interoperability function @ Description +a@ +[source] +---- +context make_context( + const cl_context &clContext, + const async_handler &asyncHandler = {}) +---- + a@ Constructs a SYCL [code]#context# instance from an OpenCL [code]#cl_context# in accordance with the requirements described in <>. +a@ +[source] +---- +sycl::event make_event(const cl_event &clEvent, + const sycl::context &syclContext) +---- + a@ Constructs a SYCL [code]#event# instance from an OpenCL [code]#cl_event# in accordance with the requirements described in <>. +a@ +[source] +---- +sycl::device make_device( + const cl_device_id &clDeviceId) +---- + a@ Constructs a SYCL [code]#device# instance from an OpenCL [code]#cl_device_id# in accordance with the requirements described in <>. +a@ +[source] +---- +sycl::platform make_platform( + const cl_platform_id &clPlatformId) +---- + a@ Constructs a SYCL [code]#platform# instance from an OpenCL [code]#cl_platform_id# in accordance with the requirements described in <>. +a@ +[source] +---- +sycl::queue make_queue( + const cl_command_queue &clQueue, + const sycl::context &syclContext, + const sycl::async_handler &asyncHandler = {}) +---- + a@ Constructs a SYCL [code]#queue# instance with an optional + [code]#async_handler# from an OpenCL [code]#cl_command_queue# + in accordance with the requirements described + in <>. +a@ +[source] +---- +template >> +sycl::buffer make_buffer( + const cl_mem &clMemObject, + const sycl::context &syclContext, + sycl::event availableEvent) +---- + a@ Available only when: [code]#dimensions == 1#. + +Constructs a SYCL [code]#buffer# instance from an OpenCL [code]#cl_mem# in accordance with the requirements described in <>. +The instance of the SYCL [code]#buffer# class template being constructed must wait for the SYCL [code]#event# parameter, [code]#availableEvent# to signal that the [code]#cl_mem# instance is ready to be used. +The SYCL [code]#context# parameter [code]#syclContext# is the context associated with the memory object. + +a@ +[source] +---- +template >> +sycl::buffer make_buffer( + const cl_mem &clMemObject, + const sycl::context &syclContext) +---- + a@ Available only when: [code]#dimensions == 1#. + +Constructs a SYCL [code]#buffer# instance from an OpenCL [code]#cl_mem# in accordance with the requirements described in <>. + +a@ +[source] +---- +template +sycl::sampled_image make_sampled_image( + const cl_mem &clMemObject, + const context &syclContext, + event availableEvent) +---- + a@ Constructs a SYCL [code]#sampled_image# instance from an OpenCL [code]#cl_mem# in accordance with the requirements described in <>. + The instance of the SYCL [code]#image# class template being constructed must wait for the SYCL [code]#event# parameter, [code]#availableEvent# to signal that the [code]#cl_mem# instance is ready to be used. + The SYCL [code]#context# parameter [code]#syclContext# is the context associated with the memory object. + +a@ +[source] +---- +template +sycl::sampled_image make_sampled_image( + const cl_mem &clMemObject, + const context &syclContext) +---- + a@ Constructs a SYCL [code]#sampled_image# instance from an OpenCL [code]#cl_mem# in accordance with the requirements described in <>. + The SYCL [code]#context# parameter [code]#syclContext# is the context associated with the memory object. + +a@ +[source] +---- +template +sycl::unsampled_image make_unsampled_image( + const cl_mem &clMemObject, + const sycl::context &syclContext, + sycl::image_sampler syclImageSampler, + event availableEvent) +---- + a@ Constructs a SYCL [code]#unsampled_image# instance from an OpenCL [code]#cl_mem# in accordance with the requirements described in <>. + The instance of the SYCL [code]#image# class template being constructed must wait for the SYCL [code]#event# parameter, [code]#availableEvent# to signal that the [code]#cl_mem# instance is ready to be used. + The SYCL [code]#context# parameter [code]#syclContext# is the context associated with the memory object. + +a@ +[source] +---- +template +sycl::unsampled_image make_unsampled_image( + const cl_mem &clMemObject, + const sycl::context &syclContext, + sycl::image_sampler syclImageSampler) +---- + a@ Constructs a SYCL [code]#unsampled_image# instance from an OpenCL [code]#cl_mem# in accordance with the requirements described in <>. +a@ +[source] +---- +kernel make_kernel(const cl_kernel &clKernel, + const context &syclContext); +---- + a@ Constructs a SYCL [code]#kernel# instance from an OpenCL kernel object. +a@ +[source] +---- +template +kernel_bundle make_kernel_bundle( + const cl_program &clProgram, + const context& syclContext) +---- + a@ Constructs a SYCL [code]#kernel_bundle# instance from an OpenCL + [code]#cl_program# for the devices in [code]#syclContext# + in accordance with the requirements described in <>. + The SYCL [code]#context# must represent the same underlying OpenCL + context associated with the OpenCL program object. + +The [code]#state# specifies the expected [code]#kernel_bundle# state. + The mapping between the [code]#kernel_bundle# state + and OpenCL program state ([code]#CL_PROGRAM_BINARY_TYPE#) is as follows: + + * [code]#bundle_state::input# - [code]#CL_PROGRAM_BINARY_TYPE_NONE# + * [code]#bundle_state::object# - + [code]#CL_PROGRAM_BINARY_TYPE_COMPILED_OBJECT# or + [code]#CL_PROGRAM_BINARY_TYPE_INTERMEDIATE# or + [code]#CL_PROGRAM_BINARY_TYPE_LIBRARY#. + * [code]#bundle_state::executable# - [code]#CL_PROGRAM_BINARY_TYPE_EXECUTABLE# + +If the internal state of the OpenCL program doesn't match [code]#state#, + the kernel bundle will be compiled and linked as necessary. + If the OpenCL program is already an executable binary, + but the specified [code]#state# is not [code]#bundle_state::executable#, + an [code]#exception# with the [code]#errc::invalid# error code is thrown. + If the specified [code]#state# is [code]#bundle_state::input#, + but the OpenCL program already has a binary associated with it, + an [code]#exception# with the [code]#errc::invalid# error code is thrown. + +Throws an [code]#exception# with the [code]#errc::invalid# error code + if any error is produced by the <>. +|==== + + +=== Extension query + +Platforms and devices with an OpenCL backend may support extensions. +For convenience, the extensions supported by a platform or device can be queried +through the following functions provided in the [code]#sycl::opencl# namespace. + +[width="100%",options="header",separator="@",cols="35%,65%"] +|==== +@ Extension query @ Description +a@ +[source] +---- +bool has_extension( + const sycl::platform &syclPlatform, + const std::string &extension) +---- + a@ Returns true if the OpenCL platform associated with [code]#syclPlatform# + supports the extension identified by [code]#extension#, otherwise it returns + false. If [code]#syclPlatform.get_backend() != sycl::backend::opencl# an + [code]#exception# with the [code]#errc::backend_mismatch# error code is + thrown. +a@ +[source] +---- +bool has_extension( + const sycl::device &syclDevice, + const std::string &extension) +---- + a@ Returns true if the OpenCL device associated with [code]#syclDevice# + supports the extension identified by [code]#extension#, otherwise it returns + false. If [code]#syclDevice.get_backend() != sycl::backend::opencl# an + [code]#exception# with the [code]#errc::backend_mismatch# error code is + thrown. +|==== + +=== Reference counting + +All OpenCL objects are reference counted. The SYCL general programming model +doesn't require that native objects are reference counted. However, for +convenience, the following function is provided in the +[code]#sycl::opencl# namespace. + +[width="100%",options="header",separator="@",cols="35%,65%"] +|==== +@ Reference counting @ Description +a@ +[source] +---- +template + cl_uint get_reference_count(openCLT obj) +---- + a@ Returns the reference count of the given object +|==== + + +=== Errors and limitations + +If there is an OpenCL error associated with an exception triggered, then the +OpenCL error code can be obtained by the free function [code]#cl_int sycl::opencl::get_error_code(sycl::exception&)#. In the case where there is +no OpenCL error associated with the exception triggered, the OpenCL error +code will be [code]#CL_SUCCESS#. + + +// TODO: Errors and limitations +// The only exception to +// this rule is when a buffer is constructed from a [code]#cl_mem# +// object to interoperate with OpenCL. Use of an interoperability +// buffer on a queue mapping to a context other than that in which the +// [code]#cl_mem# was created is an error. + +// Since data management and storage is handled by the <>, the +// [code]#event# class is used for providing the appropriate interface for +// OpenCL/SYCL interoperability. In the case where SYCL objects contain +// OpenCL memory objects created outside of the SYCL mechanism, then events +// can be used to provide the <> with the initial events that it has +// to synchronize against. However, the events mechanism does not provide +// full interoperability with OpenCL during SYCL code execution. +// Interoperability is achieved by using the synchronization rules with the +// [code]#buffer# and [code]#image# classes. + + +[[sec:opencl:interop-kernel-bundle]] +=== Interoperability with kernel bundles + +In <> any kernel function that is enqueued over an nd-range +is represented by a [code]#cl_kernel# and must be compiled and linked via a +[code]#cl_program# using [code]#clBuildProgram#, +[code]#clCompileProgram# and [code]#clLinkProgram#. + +For OpenCL <> this detail is abstracted away by <> and +a [code]#kernel_bundle# object containing all <> +is retrieved by calling the free function [code]#get_kernel_bundle#. + +The OpenCL <> specification provides additional free functions +which provide convenience functions for constructing kernel bundles +from OpenCL specific objects. + +[source,,linenums] +---- +include::{header_dir}/openclBackend/createBundle.h[lines=4..-1] +---- + +[source,,linenums] +---- +template +kernel_bundle create_bundle(const context &ctxt, + const std::vector &devs, + const std::vector &clPrograms) +---- + . _Preconditions:_ The <> specified by [code]#ctxt# + must be associated with the OpenCL <>. + All devices in [code]#devs# must be associated with [code]#ctxt#. + All OpenCL programs in [code]#clPrograms# must be associated with [code]#ctxt#. ++ +-- +_Effects:_ Constructs a <> in the specified [code]#bundle_state# +from the provided list of OpenCL programs and associated with the +<> specified by [code]#syclContext# by invoking the necessary OpenCL APIs. +Follows the same rules as calling [code]#make_kernel_bundle# on a single OpenCL program, +except that the rules apply to all OpenCL programs in [code]#clPrograms#. +Multiple programs will be linked together into a single one +if required by the requested [code]#State#. +The constructed [code]#kernel_bundle# will retain all provided OpenCL programs +and will also release them on destruction. + +_Throws:_ An [code]#exception# with the [code]#errc::build# error code if any error is produced +by invoking the OpenCL APIs. +-- + +[source,,linenums] +---- +kernel_bundle +create_bundle(const context &ctxt, const std::vector &devs, + const std::vector &clKernels) +---- + . _Preconditions:_ The <> specified by [code]#ctxt# + must be associated with the OpenCL <>. + All devices in [code]#devs# must be associated with [code]#ctxt#. + All OpenCL kernels in [code]#clKernels# must be associated with [code]#ctxt#. ++ +-- +_Effects:_ Constructs an executable <> +from the provided list of OpenCL kernels and associated with the +<> specified by [code]#syclContext# by invoking the necessary OpenCL APIs. +[code]#cl_kernel# objects might be associated with different [code]#cl_program# objects, +the kernel bundle will encapsulate all of them. + +_Throws:_ An [code]#exception# with the [code]#errc::build# error code if any error is produced +by invoking the OpenCL APIs. +-- + + +=== Interoperability with kernels + +A [code]#kernel_bundle# object contains one or multiple OpenCL programs +and one or multiple OpenCL kernels. +Calling [code]#kernel_bundle::get_kernel# returns a [code]#kernel# object + which can be invoked by any of +<> such as [code]#parallel_for# which take +a [code]#kernel# but not <>. + +Calling [code]#make_kernel# must trigger a call to [code]#clRetainKernel# +and the resulting [code]#kernel# object must call +[code]#clReleaseKernel# on destruction. + +It is also possible to construct a <> from previously created OpenCL +[code]#cl_kernel# objects by calling the free function [code]#create_bundle# +as described in <>. + +The kernel arguments for the OpenCL C kernel kernel can either be set prior to +creating the [code]#kernel# object or by calling [code]#set_arg# or [code]#set_args# +member functions of the [code]#handler# class. + +If kernel arguments are set prior to creating the [code]#kernel# object the +<> is not responsible for managing the data of these arguments. + + +[[sec:opencl:kernel-conventions-sycl]] +=== OpenCL kernel conventions and SYCL + +OpenCL and SYCL use opposite conventions for the unit stride dimension. SYCL +aligns with {cpp} conventions, which is important to understand from a +performance perspective when porting code to SYCL. The unit stride +dimension, at least for data, is implicit in the linearization equations in +SYCL (<>) and OpenCL. SYCL aligns with +{cpp} array subscript ordering [code]#arr[a][b][c]#, in that range +constructor dimension ordering used to launch a kernel (e.g. +[code]#range<3> R{a,b,c}#) and range and ID queries within a kernel, +are ordered in the same way as the {cpp} multi-dimensional subscript operators +(unit stride on the right). + +When specifying a [code]#range# as the global or local size +in a [code]#parallel_for# that invokes an OpenCL interop kernel (through +[code]#cl_kernel# interop), +the highest dimension of the range in SYCL will map to the +lowest dimension within the OpenCL kernel. That statement applies to both +an underlying enqueue operation such as [code]#clEnqueueNDRangeKernel# +in OpenCL, and also ID and size queries within the OpenCL kernel. +For example, a 3D global range specified in SYCL as: + +[source] +---- +range<3> R{r0,r1,r2}; +---- + +maps to an [code]#clEnqueueNDRangeKernel# [code]#global_work_size# argument +of: + +[source] +---- +size_t cl_interop_range[3] = {r2,r1,r0}; +---- + +Likewise, a 2D global range specified in SYCL as: + +[source] +---- +range<2> R{r0,r1}; +---- + +maps to an [code]#clEnqueueNDRangeKernel# [code]#global_work_size# argument +of: + +[source] +---- +size_t cl_interop_range[2] = {r1,r0}; +---- + +The mapping of highest dimension in SYCL to lowest dimension in OpenCL applies to all +operations where a multi-dimensional construct must be mapped, such as when mapping SYCL +explicit memory operations to OpenCL APIs like [code]#clEnqueueCopyBufferRect#. + +Work-item and work-group ID and range queries have the same reversed +convention for unit stride dimension between SYCL and OpenCL. For example, +with three, two, or one dimensional SYCL global ranges, OpenCL and SYCL +kernel code queries relate to the range as shown in +<>. The "SYCL kernel query" column +applies for SYCL-defined kernels, and the "OpenCL kernel query" column +applies for kernels defined through OpenCL interop. + +// Jon: Need to code-format most of these cells and use gray backgrounds on +// column-spanning sub-titles. + +[[table.syclOpenCL.mapping]] +.Example range mapping from SYCL enqueued three dimensional global [code]#range# to OpenCL and SYCL queries +[width="100%",options="header",cols="60%,20%,20%"] +|==== +| SYCL kernel query | OpenCL kernel query | Returned Value + +3+|With enqueued 3D SYCL global [code]#range# of [code]#range<3> R{r0,r1,r2}# +| nd_item::get_global_range(0) / item::get_range(0) + | get_global_size(2) + | [code]#r0# +| nd_item::get_global_range(1) / item::get_range(1) + | get_global_size(1) + | [code]#r1# +| nd_item::get_global_range(2) / item::get_range(2) + | get_global_size(0) + | [code]#r2# +| nd_item::get_global_id(0) / item::get_id(0) + | get_global_id(2) + | Value in range 0..([code]#r0-1)}# +| nd_item::get_global_id(1) / item::get_id(1) + | get_global_id(1) + | Value in range 0..([code]#r1-1)}# +| nd_item::get_global_id(2) / item::get_id(2) + | get_global_id(0) + | Value in range 0..([code]#r2-1)}# + +3+|With enqueued 2D SYCL global [code]#range# of [code]#range<2> R{r0,r1}# +| nd_item::get_global_range(0) / item::get_range(0) + | get_global_size(1) + | [code]#r0# +| nd_item::get_global_range(1) / item::get_range(1) + | get_global_size(0) + | [code]#r1# +| nd_item::get_global_id(0) / item::get_id(0) + | get_global_id(1) + | Value in range 0..([code]#r0-1)}# +| nd_item::get_global_id(1) / item::get_id(1) + | get_global_id(0) + | Value in range 0..([code]#r1-1)}# + +3+|With enqueued 1D SYCL global [code]#range# of [code]#range<1> R{r0}# +| nd_item::get_global_range(0) / item::get_range(0) + | get_global_size(0) + | [code]#r0# +| nd_item::get_global_id(0) / item::get_id(0) + | get_global_id(0) + | Value in range 0..([code]#r0-1)}# + +|==== + + +=== Data types + +The OpenCL C language standard <> defines its own built-in +scalar data types, and these have additional requirements in terms of size and +signedness on top of what is guaranteed by ISO {cpp}. For the purpose of +interoperability and portability, SYCL defines a set of aliases to {cpp} types +within the [code]#sycl::opencl# namespace using the [code]#cl_# +prefix. These aliases are described in <> + + +[[table.types.aliases]] +.Scalar data type aliases supported by SYCL OpenCL backend +[width="100%",options="header",separator="@",cols="25%,75%"] +|==== +@ Scalar data type alias @ Description +a@ +[source] +---- +cl_bool +---- + a@ Alias to a conditional data type which can be either true or false. The value + true expands to the integer constant 1 and the value false expands to the + integer constant 0. + +a@ +[source] +---- +cl_char +---- + a@ Alias to a signed 8-bit integer, as defined by the {cpp} core language. + +a@ +[source] +---- +cl_uchar +---- + a@ Alias to an unsigned 8-bit integer, as defined by the {cpp} core language. + +a@ +[source] +---- +cl_short +---- + a@ Alias to a signed 16-bit integer, as defined by the {cpp} core language. + +a@ +[source] +---- +cl_ushort +---- + a@ Alias to an unsigned 16-bit integer, as defined by the {cpp} core language. + +a@ +[source] +---- +cl_int +---- + a@ Alias to a signed 32-bit integer, as defined by the {cpp} core language. + +a@ +[source] +---- +cl_uint +---- + a@ Alias to an unsigned 32-bit integer, as defined by the {cpp} core language. + +a@ +[source] +---- +cl_long +---- + a@ Alias to a signed 64-bit integer, as defined by the {cpp} core language. + +a@ +[source] +---- +cl_ulong +---- + a@ Alias to an unsigned 64-bit integer, as defined by the {cpp} core language. + +a@ +[source] +---- +cl_float +---- + a@ Alias to a 32-bit floating-point. The float data type must conform to the IEEE + 754 single precision storage format. + +a@ +[source] +---- +cl_double +---- + a@ Alias to a 64-bit floating-point. The double data type must conform to the IEEE + 754 double precision storage format. + +a@ +[source] +---- +cl_half +---- + a@ Alias to a 16-bit floating-point. The half data type must conform to + the IEEE 754-2008 half precision storage format. Kernels using this type + are only supported on devices that have [code]#aspect::fp16#, as described + in <>. + +|==== + + + +== Preprocessor directives and macros + + * [code]#SYCL_BACKEND_OPENCL# substitutes to [code]#1# if the OpenCL <> + is active while building the SYCL application. + + +=== Offline linking with OpenCL C libraries + +SYCL supports linking <> with OpenCL C libraries +during offline compilation or during online compilation by the +<> within a SYCL application. + +Linking with OpenCL C kernel functions offline is an optional feature +and is unspecified. Linking with OpenCL C kernel functions online is +performed by using the SYCL [code]#kernel_bundle# class to compile and +link an OpenCL C source; using the [code]#compile_with_source# or +[code]#build_with_source# member functions. + +OpenCL C functions that are linked with, using either offline or online +compilation, must be declared as [code]#extern "C"# function +declarations. The function parameters of these function declarations must be +defined as the OpenCL C interoperability aliases; [code]#pointer# of +the [code]#multi_ptr# class template, [code]#vector_t# of the +[code]#vec# class template and scalar data type aliases described in +<>. + +// \include{opencl_extensions} +// %%%%%%%%%%%%%%%%%%%%%%%%%%%% begin opencl_extensions %%%%%%%%%%%%%%%%%%%%%%%%%%%% + +== SYCL support of non-core OpenCL features + +In addition to the OpenCL core features, SYCL also provides support for OpenCL +extensions which provide features in OpenCL via khr extensions. + +Some extensions are natively supported within the SYCL interface, however some +can only be used via the OpenCL interoperability interface. The SYCL interface +required for native extensions must be available. However if the respective +extension is not supported by the executing SYCL [code]#device#, the +<> must throw an [code]#exception# with the +[code]#errc::feature_not_supported# or [code]#errc::kernel_not_supported# error +codes. + +The OpenCL backend exposes some khr extensions to SYCL applications through the +[code]#sycl::aspect# enumerated type. Therefore, applications can query +for the existence of these khr extensions by calling the [code]#device::has()# +or [code]#platform::has()# member functions. + +All OpenCL extensions are available through the OpenCL interoperability +interface, but some can also be used through core SYCL APIs. +<> shows which these are. +<> also shows the mapping from each OpenCL +extension name to its associated SYCL device [code]#aspect# when one is +available. + + +[[table.extensionsupport]] +.SYCL support for OpenCL 1.2 extensions +[width="100%",options="header",cols="43%,37%,20%"] +|==== +| SYCL Aspect | OpenCL Extension | Core SYCL API +| [code]#aspect::atomic64# | [code]#cl_khr_int64_base_atomics# | Yes +| [code]#aspect::atomic64# | [code]#cl_khr_int64_extended_atomics# | Yes +| [code]#aspect::fp16# | [code]#cl_khr_fp16# | Yes +| - | [code]#cl_khr_3d_image_writes# | Yes +| - | [code]#cl_khr_gl_sharing# | No +| - | [code]#cl_apple_gl_sharing# | No +| - | [code]#cl_khr_d3d10_sharing# | No +| - | [code]#cl_khr_d3d11_sharing# | No +| - | [code]#cl_khr_dx9_media_sharing# | No +|==== + + + +[[sec:opencl:extension-fp16]] +=== Half precision floating-point + +The half scalar data type: [code]#half# and the half vector data types: +[code]#half1#, [code]#half2#, [code]#half3#, +[code]#half4#, [code]#half8# and [code]#half16# must be +available at compile-time. However a kernel using these types is only +supported on devices that have [code]#aspect::fp16#, as described in +<>. + +The conversion rules for half precision types follow the same rules as in +the OpenCL 1.2 extensions specification <>. + +The math functions for half precision types follow the same rules as in the +OpenCL 1.2 extensions specification <>. The allowed error in ULP(Unit in the Last Place) is +less than 8192, corresponding to <>. + + +=== Writing to 3D image memory objects + +The [code]#unsampled_image_accessor# class +in SYCL supports member functions for writing +3D image memory objects, but this functionality is only allowed on a device +if the extension [code]#cl_khr_3d_image_writes# is +supported on that <>. + +// TODO: Should opencl::aspect::3d_image_writes be promoted to a core SYCL aspect? + + +=== Interoperability with OpenGL + +Interoperability between SYCL and OpenGL is not directly provided by the SYCL interface, +however can be achieved via the SYCL OpenCL interoperability interface. + + +== Correspondence of some OpenCL features to SYCL + +This section describes the correspondence between some OpenCL features and +features in the <> that provide similar functionality. All content +in this section is non-normative. + +=== Work-item functions + +The OpenCL 1.2 specification document <> +defines work-item functions that tell various information about the currently +executing work item in an OpenCL kernel. SYCL provides equivalent +functionality through the item and group classes that are defined in +<>, <> and <>. + +=== Vector data load and store functions + +The functionality from the OpenCL functions as defined in the OpenCL 1.2 +specification document <> is available in SYCL through +the [code]#vec# class in <>. + +=== Synchronization functions + +In SYCL the OpenCL [keyword]#synchronization functions# are available through +the [code]#nd_item# class (<>), as they are applied to +work-items for local or global address spaces. Please +see <>. + +=== [code]#printf# function + +The functionality of the [code]#printf# function is covered by the +[code]#stream# class (<>), which has the +capability to print to standard output all of the SYCL classes and primitives, +and covers the capabilities defined in the OpenCL 1.2 specification +document <>. + +// %%%%%%%%%%%%%%%%%%%%%%%%%%%% end opencl_extensions %%%%%%%%%%%%%%%%%%%%%%%%%%%% + +// %%%%%%%%%%%%%%%%%%%%%%%%%%%% end opencl_backend %%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/adoc/chapters/programming_interface.adoc b/adoc/chapters/programming_interface.adoc new file mode 100644 index 00000000..74bd5427 --- /dev/null +++ b/adoc/chapters/programming_interface.adoc @@ -0,0 +1,21591 @@ +[[chapter:sycl-programming-interface]] += SYCL programming interface + +The SYCL programming interface provides a common abstracted feature set to +one or more <> APIs. This section describes the {cpp} library +interface to the <> which executes across those <>. + +The entirety of the SYCL interface defined in this section is required to be +available for any <>, with the exception of the interoperability +interface, which is described in general terms in this document, not +pertaining to any particular <>. + +SYCL guarantees that all the member functions and special member functions of +the SYCL classes described are thread safe. + + +[[sec:backends]] +== Backends + +The <> that are available to a SYCL implementation can be identified +using the [code]#enum class backend#. + +[source,,linenums] +---- +include::{header_dir}/backends.h[lines=4..-1] +---- + +The [code]#enum class backend# is implementation-defined and must be +populated with a unique identifier for each <> that the SYCL +implementation supports. + +Each named <> enumerated in the [code]#enum class backend# +must be associated with a <> specification. +Many sections of this specification +will refer to the associated <> specification. + + +[[sec:backend-macros]] +=== Backend macros + +As the identifiers defined in [code]#enum class backend# are +implementation-defined, +a SYCL implementation must also define a preprocessor macro for each of +these identifiers. If the <> is defined by the Khronos SYCL group, the +name of the macro has the form [code]#SYCL_BACKEND_#, where +_backend_name_ is the associated identifier from [code]#backend# in +all upper-case. See <> for the name of the macro +if the vendor defines the <> outside of the Khronos SYCL group. + + +[[sec:generic-vs-non-generic]] +== Generic vs non-generic SYCL + +The SYCL programming API is split into two categories; generic SYCL and +non-generic SYCL. Almost everything in the SYCL programming API is considered +generic SYCL. However any usage of the [code]#enum class backend# is +considered non-generic SYCL and should only be used for <> specialized +code paths, as the identifiers defined in [code]#backend# are +implementation-defined. + +In any non-generic SYCL application code where the [code]#backend# enum +class is used, the expression must be guarded with a preprocessor +[code]#{hash}ifdef# guard using the associated preprocessor macro to ensure that +the SYCL application will compile even if the SYCL implementation does not +support that <> being specialized for. + + +[[sec:headers-and-namespaces]] +== Header files and namespaces + +SYCL provides one standard header file: [code]##, which needs to +be included in every translation unit that uses the SYCL programming API. + +All SYCL classes, constants, types and functions defined by this +specification should exist within the [code]#::sycl# namespace. + +For compatibility with SYCL 1.2.1, SYCL provides another standard +header file: [code]##, which can be included in +place of [code]##. In that case, all SYCL classes, constants, +types and functions defined by this specification should exist within the +[code]#::cl::sycl# {cpp} namespace. + +For consistency, the programming API will only refer to the +[code]## header and the [code]#::sycl# namespace, but this +should be considered synonymous with the SYCL 1.2.1 header and namespace. + +Include paths starting with [code]#"sycl/ext/"# and [code]#"sycl/backend/"# are +reserved for extensions to SYCL and for backend interop headers respectively. +Other include paths starting with [code]#"sycl/"# and the [code]#sycl::detail# +namespace are reserved for implementation details. + +When a <> is defined by the Khronos SYCL group, functionality +for that <> is available via the header +[code]#"sycl/backend/.hpp"#, and all <>-specific +functionality is made available in the namespace [code]#sycl::# +where [code]## is the name of the <> as defined in the +<> specification. + +<> defines the allowable header files and +namespaces for any extensions that a vendor may provide, including any +<> that the vendor may define outside of the Khronos SYCL group. + +== Class availability + +In SYCL some <> classes are available to the SYCL application, +some are available within a <> and some are available +on both and can be passed as arguments to a <>. + +Each of the following <> classes: +[code]#buffer#, +[code]#buffer_allocator#, +[code]#context#, +[code]#device#, +[code]#device_image#, +[code]#event#, +[code]#exception#, +[code]#handler#, +[code]#host_accessor#, +[code]#host_sampled_image_accessor#, +[code]#host_unsampled_image_accessor#, +[code]#id#, +[code]#image_allocator#, +[code]#kernel#, +[code]#kernel_id#, +[code]#marray#, +[code]#kernel_bundle#, +[code]#nd_range#, +[code]#platform#, +[code]#queue#, +[code]#range#, +[code]#sampled_image#, +[code]#image_sampler#, +[code]#stream#, +[code]#unsampled_image# and +[code]#vec# +must be available to the host application. + +Each of the following <> classes: +[code]#accessor#, +[code]#atomic_ref#, +[code]#device_event#, +[code]#group#, +[code]#h_item#, +[code]#id#, +[code]#item#, +[code]#local_accessor#, +[code]#marray#, +[code]#multi_ptr#, +[code]#nd_item#, +[code]#range#, +[code]#reducer#, +[code]#sampled_image_accessor#, +[code]#stream#, +[code]#sub_group#, +[code]#unsampled_image_accessor# and +[code]#vec# +must be available within a <>. + +Each of the following <> classes: +[code]#accessor#, +[code]#id#, +[code]#local_accessor#, +[code]#marray#, +[code]#range#, +[code]#reducer#, +[code]#sampled_image_accessor#, +[code]#stream#, +[code]#unsampled_image_accessor# and +[code]#vec# +are permitted as arguments to a <>. + +== Common interface + +When a dimension template parameter is used in SYCL classes, it is +defaulted as 1 in most cases. + + +[[sec:backend-interoperability]] +=== Backend interoperability + +Many of the <> classes may be implemented such that they +encapsulate an object unique to the <> that underpins the +functionality of that class. Where appropriate, these classes may provide an +interface for interoperating between the <> object and the +<> in order to support interoperability within an +application between SYCL and the associated <>. + +There are two forms of interoperability with <> classes: +interoperability on the <> with the <> +and interoperability within a <> with the equivalent +kernel language types of the <>. <> +interoperability and <> interoperability are +provided via different interfaces and may have different +<> types. + +<> interoperability may be provided for +[code]#buffer#, +[code]#context#, +[code]#device#, +[code]#device_image#, +[code]#event#, +[code]#kernel#, +[code]#kernel_bundle#, +[code]#platform#, +[code]#queue#, +[code]#sampled_image#, and +[code]#unsampled_image#. + +<> interoperability may be provided for +[code]#accessor#, +[code]#device_event#, +[code]#local_accessor#, +[code]#sampled_image_accessor#, +[code]#stream# and +[code]#unsampled_image_accessor# +inside <> only and is not available outside of that scope. + +Support for <> interoperability is optional and therefore not required +to be provided by a SYCL implementation. A SYCL application using <> +interoperability is considered to be non-generic SYCL. + +Details on the interoperability for a given <> are available on the +<> specification document for that <>. + +==== Type traits [code]#backend_traits# + +[source,,linenums] +---- +include::{header_dir}/interop/typeTraitsBackendTraits.h[lines=4..-1] +---- + +A series of type traits are provided for <> interoperability, +defined in the [code]#backend_traits# class. + +A specialization of [code]#backend_traits# must be provided for each named +<> enumerated in the enum class [code]#backend#. + + * For each <> class [code]#T# which supports + <> interoperability with the <>, a + specialization of [code]#input_type# must be defined as the type + of <> interoperability <> + associated with [code]#T# for the <>, specified in the + <> specification. + [code]#input_type# is used when constructing SYCL objects + from backend specific native objects. + See the relevant backend specification for details. + * For each <> class [code]#T# which supports + <> interoperability with the <>, a + specialization of [code]#return_type# must be defined as the type + of <> interoperability <> + associated with [code]#T# for the <>, specified in the + <> specification. + [code]#return_type# is used when retrieving + the backend specific native object from a SYCL object. + See the relevant backend specification for details. + * For each <> class [code]#T# which supports kernel + function interoperability with the <>, a specialization of + [code]#return_type# within [code]#backend_traits# must be + defined as the type of the kernel function interoperability + <> associated with [code]#T# for the + <>, specified in the backend specification. + See the relevant backend specification for details. + * A specialization of [code]#errc# must be defined as the + <> error code type. + +The type alias [code]#backend_input_t# is provided +to enable less verbose access to the [code]#input_type# type +within [code]#backend_traits# for a specific SYCL object of type [code]#T#. +The type alias [code]#backend_return_t# is provided +to enable less verbose access to the [code]#return_type# type +within [code]#backend_traits# for a specific SYCL object of type [code]#T#. + +==== Template function [code]#get_native# + +[source,,linenums] +---- +include::{header_dir}/interop/templateFunctionGetNative.h[lines=4..-1] +---- + +For each <> class [code]#T# which supports +<> interoperability, a specialization of +[code]#get_native# must be defined, which takes an instance of +[code]#T# and returns a <> interoperability +<> associated with [code]#syclObject# which +can be used for <> interoperability. The lifetime of the +object returned are backend-defined and specified in the backend +specification. + +For each <> class [code]#T# which supports kernel +function interoperability, a specialization of [code]#get_native# must +be defined, which takes an instance of [code]#T# and returns the kernel +function interoperability <> associated with +[code]#syclObject# which can be used for kernel function +interoperability. The availability and behavior of these template +functions is defined by the <> specification document. + +The [code]#get_native# function +must throw an [code]#exception# with the +[code]#errc::backend_mismatch# error code +if the backend of the SYCL object +doesn't match the target backend. + +[[sec:backend-interoperability-make]] +==== Template functions [code]#make_*# + +[source,,linenums] +---- +include::{header_dir}/interop/templateFunctionMakeX.h[lines=4..-1] +---- + +For each <> class [code]#T# which supports +<> interoperability, a specialization of the appropriate +template function [code]#make_{sycl_class}# where +[code]#{sycl_class}# is the class name of [code]#T#, must be +defined, which takes a <> interoperability +<> and constructs and returns an instance of +[code]#T#. The availability and behavior of these template +functions is defined by the <> specification document. + +Overloads of the [code]#make_{sycl_class}# function +which take a SYCL <> object as an argument +must throw an [code]#exception# with the +[code]#errc::backend_mismatch# error code +if the backend of the provided SYCL context +doesn't match the target backend. + +[[sec:reference-semantics]] +=== Common reference semantics + +Each of the following <> classes: +[code]#accessor#, +[code]#buffer#, +[code]#context#, +[code]#device#, +[code]#device_image#, +[code]#event#, +[code]#host_accessor#, +[code]#host_sampled_image_accessor#, +[code]#host_unsampled_image_accessor#, +[code]#kernel#, +[code]#kernel_id#, +[code]#kernel_bundle#, +[code]#local_accessor#, +[code]#platform#, +[code]#queue#, +[code]#sampled_image#, +[code]#sampled_image_accessor#, +[code]#unsampled_image# and +[code]#unsampled_image_accessor# +must obey the following statements, where [code]#T# is the runtime class type: + + * [code]#T# must be copy constructible and copy assignable on the + host application and within SYCL kernel functions in the case that + [code]#T# is a valid kernel argument. Any instance of + [code]#T# that is constructed as a copy of another instance, via + either the copy constructor or copy assignment operator, must behave + as-if it were the original instance and as-if any action performed on it + were also performed on the original instance and must represent the same + underlying <> as the original instance where + applicable. + * [code]#T# must be destructible on the host application and within + SYCL kernel functions in the case that [code]#T# is a valid kernel + argument. When any instance of [code]#T# is destroyed, including as + a result of the copy assignment operator, any behavior specific to + [code]#T# that is specified as performed on destruction is only + performed if this instance is the last remaining host copy, in + accordance with the above definition of a copy. + * [code]#T# must be move constructible and move assignable on the + host application and within SYCL kernel functions in the case that T is + a valid kernel argument. Any instance of T that is constructed as a move + of another instance, via either the move constructor or move assignment + operator, must replace the original instance rendering said instance + invalid and must represent the same underlying <> as + the original instance where applicable. + * [code]#T# must be equality comparable on the host application. + Equality between two instances of [code]#T# (i.e. [code]#a == b#) must be true if one instance is a copy of the other and non-equality + between two instances of [code]#T# (i.e. [code]#a != b#) must + be true if neither instance is a copy of the other, in accordance with + the above definition of a copy, unless either instance has become + invalidated by a move operation. By extension of the requirements above, + equality on [code]#T# must guarantee to be reflexive (i.e. [code]#a == a#), + symmetric (i.e. [code]#a == b# implies [code]#b == a# and [code]#a != b# + implies [code]#b != a#) and transitive (i.e. [code]#a == b && b == c# + implies [code]#c == a#). + * A specialization of [code]#std::hash# for [code]#T# must exist + on the host application that returns a unique value such that if two + instances of T are equal, in accordance with the above definition, then + their resulting hash values are also equal and subsequently if two hash + values are not equal, then their corresponding instances are also not + equal, in accordance with the above definition. + +Some <> classes will have additional behavior associated +with copy, movement, assignment or destruction semantics. If these are +specified they are in addition to those specified above unless stated +otherwise. + +Each of the runtime classes mentioned above must provide a common +interface of special member functions in order to fulfill the copy, +move, destruction requirements and hidden friend functions in order to +fulfill the equality requirements. + +A hidden friend function is a function first declared via a +[code]#friend# declaration with no additional out of class or namespace +scope declarations. Hidden friend functions are only visible to ADL +(Argument Dependent Lookup) and are hidden from qualified and unqualified +lookup. Hidden friend functions have the benefits of avoiding accidental +implicit conversions and faster compilation. + +These common special member functions and hidden friend functions are +described in <> and +<> respectively. + +[source,,linenums] +---- +include::{header_dir}/common-reference.h[lines=4..-1] +---- + +[[table.specialmembers.common.reference]] +.Common special member functions for reference semantics +[width="100%",options="header",separator="@",cols="1,2"] +|==== +@ Special member function @ Description +a@ +[source] +---- +T(const T &rhs) +---- + a@ Constructs a [code]#T# instance as a copy of the RHS SYCL + [code]#T# in accordance with the requirements set out above. + +a@ +[source] +---- +T(T &&rhs) +---- + a@ Constructs a SYCL [code]#T# instance as a move of the RHS SYCL + [code]#T# in accordance with the requirements set out above. + +a@ +[source] +---- +T &operator=(const T &rhs) +---- + a@ Assigns this SYCL [code]#T# instance with a copy of the RHS SYCL + [code]#T# in accordance with the requirements set out above. + +a@ +[source] +---- +T &operator=(T &&rhs) +---- + a@ Assigns this SYCL [code]#T# instance with a move of the RHS SYCL + [code]#T# in accordance with the requirements set out above. + +a@ +[source] +---- +~T() +---- + a@ Destroys this SYCL [code]#T# instance in accordance with the + requirements set out in <>. On destruction + of the last copy, may perform additional lifetime related operations + required for the underlying <> specified in + the <> specification document, if this SYCL [code]#T# instance + was originally constructed using one of the backend interoperability + [code]#make_*# functions specified in + <>. + See the relevant backend specification for details. + +|==== + +[[table.hiddenfriends.common.reference]] +.Common hidden friend functions for reference semantics +[width="100%",options="header",separator="@"] +|==== +@ Hidden friend function @ Description +a@ +[source] +---- +bool operator==(const T &lhs, const T &rhs) +---- + a@ Returns true if this LHS SYCL [code]#T# is equal to the RHS SYCL + [code]#T# in accordance with the requirements set out above, + otherwise returns false. + +a@ +[source] +---- +bool operator!=(const T &lhs, const T &rhs) +---- + a@ Returns true if this LHS SYCL [code]#T# is not equal to the RHS + SYCL [code]#T# in accordance with the requirements set out above, + otherwise returns false. + +|==== + + +[[sec:byval-semantics]] +=== Common by-value semantics + +Each of the following <> classes: [code]#id#, +[code]#range#, [code]#item#, [code]#nd_item#, +[code]#h_item#, [code]#group#, [code]#sub_group# and +[code]#nd_range# must follow the following statements, where +[code]#T# is the runtime class type: + + * [code]#T# must be default copy constructible and copy assignable on + the host application (in the case where T is available on the host) and + within SYCL kernel functions. + * [code]#T# must be default destructible on the host application (in + the case where T is available on the host) and within SYCL kernel + functions. + * [code]#T# must be default move constructible and default move + assignable on the host application (in the case where T is available on + the host) and within SYCL kernel functions. + * [code]#T# must be equality comparable on the host application (in + the case where T is available on the host) and within SYCL kernel + functions. Equality between two instances of [code]#T# (i.e. + [code]#a == b#) must be true if the value of all members are equal + and non-equality between two instances of [code]#T# (i.e. + [code]#a != b#) must be true if the value of any members are not + equal, unless either instance has become invalidated by a move + operation. By extension of the requirements above, equality on + [code]#T# must guarantee to be reflexive (i.e. [code]#a == a#), + symmetric (i.e. [code]#a == b# implies [code]#b == a# and [code]#a != b# + implies [code]#b != a#) and transitive (i.e. [code]#a == b && b == c# + implies [code]#c == a#). + +Some <> classes will have additional behavior associated +with copy, movement, assignment or destruction semantics. If these are +specified they are in addition to those specified above unless stated +otherwise. + +Each of the runtime classes mentioned above must provide a common +interface of special member functions and member functions in order to +fulfill the copy, move, destruction and equality requirements, +following the <> and the <>. + +These common special member functions and hidden friend functions are +described in <> and +<> respectively. + +[source,,linenums] +---- +include::{header_dir}/common-byval.h[lines=4..-1] +---- + +[[table.specialmembers.common.byval]] +.Common special member functions for by-value semantics +[width="100%",options="header",separator="@",cols="2,1"] +|==== +@ Special member function _(see <> and <>)_ @ Description +a@ +[source] +---- +T(const T &rhs); +---- + a@ Copy constructor. + +a@ +[source] +---- +T(T &&rhs); +---- + a@ Move constructor. + +a@ +[source] +---- +T &operator=(const T &rhs); +---- + a@ Copy assignment operator. + +a@ +[source] +---- +T &operator=(T &&rhs); +---- + a@ Move assignment operator. + +a@ +[source] +---- +~T(); +---- + a@ Destructor. + +|==== + +[[table.hiddenfriends.common.byval]] +.Common hidden friend functions for by-value semantics +[width="100%",options="header",separator="@",cols="1,1"] +|==== +@ Hidden friend function @ Description +a@ +[source] +---- +bool operator==(const T &lhs, const T &rhs) +---- + a@ Returns true if this LHS SYCL [code]#T# is equal to the RHS SYCL [code]#T# in accordance with the requirements set out above, otherwise returns false. + +a@ +[source] +---- +bool operator!=(const T &lhs, const T &rhs) +---- + a@ Returns true if this LHS SYCL [code]#T# is not equal to the RHS SYCL [code]#T# in accordance with the requirements set out above, otherwise returns false. + +|==== + +=== Properties + +Each of the following <> classes: +[code]#accessor#, +[code]#buffer#, +[code]#host_accessor#, +[code]#host_sampled_image_accessor#, +[code]#host_unsampled_image_accessor#, +[code]#context#, +[code]#local_accessor#, +[code]#queue#, +[code]#sampled_image#, +[code]#sampled_image_accessor#, +[code]#stream#, +[code]#unsampled_image#, +[code]#unsampled_image_accessor# and +[code]#usm_allocator# +provide an optional parameter in each of +their constructors to provide a [code]#property_list# which +contains zero or more properties. Each of those properties augments +the semantics of the class with a particular feature. Each of those +classes must also provide [code]#has_property# and +[code]#get_property# member functions for querying for a +particular property. + +The listing below illustrates the usage of various buffer properties, +described in <>. + +The example illustrates how using properties does not affect the type +of the object, thus, does not prevent the usage of SYCL objects in +containers. + +[source,,linenums] +---- +include::{code_dir}/propertyExample.cpp[lines=4..-1] +---- + +Each property is represented by a unique class and an instance of a property +is an instance of that type. Some properties can be default constructed +while others will require an argument on construction. A property may be +applicable to more than one class, however some properties may not be +compatible with each other. See the requirements for the properties of the +SYCL [code]#buffer# class, SYCL [code]#unsampled_image# class and +SYCL [code]#sampled_image# class in <> +and <> respectively. + +Properties can be passed to a <> class +via an instance of [code]#property_list#. +These properties get tied to the <> class instance +and copies of the object will contain the same properties. + +A SYCL implementation or a <> may provide additional properties +other than those defined here, provided they are defined in accordance with +the requirements described in <>. + +==== Properties interface + +Each of the runtime classes mentioned above must provide a common +interface of member functions in order to fulfill the property +interface requirements. + +A synopsis of the common properties interface, the SYCL +[code]#property_list# class and the SYCL property classes is provided +below. The member functions of the common properties interface are listed in +<>. The constructors of the SYCL +[code]#property_list# class are listed in +<>. + +[source,,linenums] +---- +include::{header_dir}/properties.h[lines=4..-1] +---- + + +[[table.traits.properties]] +.Traits for properties +[width="100%",options="header",separator="@"] +|==== +@ Traits @ Description +a@ +[source] +---- +template +struct is_property +---- + a@ An explicit specialization of [code]#is_property# that inherits + from [code]#std::true_type# must be provided for each property, + where [code]#propertyT# is the class defining the property. + This includes both standard properties described in this + specification and any additional non-standard properties defined by + an implementation. All other specializations of + [code]#is_property# must inherit from + [code]#std::false_type#. +a@ +[source,c++] +---- +template +inline constexpr bool is_property_v; +---- + a@ Variable containing value of [code]#is_property#. + +a@ +[source] +---- +template +struct is_property_of +---- + a@ An explicit specialization of [code]#is_property_of# that + inherits from [code]#std::true_type# must be provided for each + property that can be used in constructing a given SYCL class, where + [code]#propertyT# is the class defining the property and + [code]#syclObjectT# is the SYCL class. This includes both + standard properties described in this specification and any + additional non-standard properties defined by an implementation. All + other specializations of [code]#is_property_of# must inherit + from [code]#std::false_type#. +a@ +[source,c++] +---- +template +inline constexpr bool is_property_of_v; +---- + a@ Variable containing value of [code]#is_property_of#. + +|==== + + + +[[table.members.propertyinterface]] +.Common member functions of the SYCL [code]#property# interface +[width="100%",options="header",separator="@",cols="2,3"] +|==== +@ Member function @ Description +a@ +[source] +---- +template +bool has_property() const noexcept +---- + a@ Returns true if [code]#T# was constructed with the property + specified by [code]#propertyT#. Returns false if it was + not. + +a@ +[source] +---- +template +propertyT get_property() const +---- + a@ Returns a copy of the property of type [code]#propertyT# + that [code]#T# was constructed with. Must throw an + [code]#exception# with the [code]#errc::invalid# + error code if [code]#T# was not constructed with the + [code]#propertyT# property. + +|==== + + + +[[table.constructors.propertylist]] +.Constructors of the SYCL [code]#property_list# class +[width="100%",options="header",separator="@",cols="2,3"] +|==== +@ Constructor @ Description +a@ +[source] +---- +template +property_list(propertyTN... props) +---- + a@ Available only when: [code]#is_property::value# + evaluates to [code]#true# where [code]#property# is each + property in [code]#propertyTN#. + +Construct a SYCL [code]#property_list# with zero or more properties. + +|==== + + + +== SYCL runtime classes + + +[[sec:device-selection]] +=== Device selection + +Since a system can have several SYCL-compatible devices attached, it +is useful to have a way to select a specific device or a set of +devices to construct a specific object such as a +[code]#device# (see <>) or a +[code]#queue# (see <>), or +perform some operations on a device subset. + +Device selection is done either by already having a specific instance +of a [code]#device# (see <>) or by +providing a <> which is a ranking function that will give +an integer ranking value to all the devices on the system. + + +[[sec:device-selector]] +==== Device selector + +The actual interface for a <> is a callable +taking a [code]#const device# reference and returning a +value implicitly convertible to an [code]#int#. + +At any point where the <> needs to select a SYCL +[code]#device# using a <>, the system will query +all available SYCL [code]#devices# from all <> in the +system, will call the <> on each device and select the one +which returns the highest score. If the highest value is strictly +negative no device is selected. + +In places where only one device has to be picked and the high score is +obtained by more than one device, then one of the tied devices will be +returned, but which one is not defined and may depend on enumeration +order, for example, outside the control of the SYCL runtime. + +Some predefined <> are provided by the system as +described on <> in a header file with +some definition similar to the following: + + +[[table.device.selectors]] +.Standard device selectors included with all SYCL implementations +[width="100%",options="header",separator="@",cols="50%,50%"] +|==== +@ SYCL device selectors @ Description +a@ +[source] +---- +default_selector_v +---- + a@ Select a SYCL [code]#device# from any supported <> + based on an implementation-defined heuristic. Since all + implementations must support at least one device, this selector + must always return a device. + +[NOTE] +==== +Implementations may choose to return an emulated device (with +[code]#aspect::emulated#) as a fallback if there is no physical device +available on the system. +==== + +a@ +[source] +---- +gpu_selector_v +---- + a@ Select a SYCL [code]#device# from any supported <> + for which the device type is + [code]#info::device_type::gpu#. The SYCL class + constructor using it must throw an [code]#exception# + with the [code]#errc::runtime# error code if no + device matching this requirement can be found. + +a@ +[source] +---- +accelerator_selector_v +---- + a@ Select a SYCL [code]#device# from any supported <> + for which the device type is + [code]#info::device_type::accelerator#. The SYCL + class constructor using it must throw an [code]#exception# + with the [code]#errc::runtime# error code if no device + matching this requirement can be found. + +a@ +[source] +---- +cpu_selector_v +---- + a@ Select a SYCL [code]#device# from any supported <> + for which the device type is + [code]#info::device_type::cpu#. The SYCL class + constructor using it must throw an [code]#exception# + with the [code]#errc::runtime# error code + if no device matching this requirement can be found. + +a@ +[source] +---- +__unspecified_callable__ aspect_selector( + const std::vector &aspectList, + const std::vector &denyList = {}); + +template +__unspecified_callable__ aspect_selector(aspectListTN... aspectList); + +template +__unspecified_callable__ aspect_selector(); +---- +a@ The free function [code]#aspect_selector# has several overloads, +each of which returns a selector object that selects a +SYCL [code]#device# from any supported <> +which contains all the requested aspects, +i.e. for the specific device [code]#dev# +and each aspect [code]#devAspect# from [code]#aspectList# +[code]#dev.has(devAspect)# equals [code]#true#. +If no aspects are passed in, +the generated selector behaves like [code]#default_selector#. + +Required aspects can be passed in as a vector, as function arguments, +or as template parameters, depending on the function overload. +The function overload that takes [code]#aspectList# as a vector +takes another vector argument [code]#denyList# +where the user can specify all the aspects that have to be avoided, +i.e. for the specific device [code]#dev# +and each aspect [code]#devAspect# from [code]#denyList# +[code]#dev.has(devAspect)# equals [code]#false#. + +The SYCL class constructor using the generated selector +must throw an [code]#exception# with the [code]#errc::runtime# error code +if no device matching this requirement can be found. +There are multiple overloads of this function, +please refer to <> for full definitions +and to <> for examples. + +|==== + + +// Interface of the device selector +[[header:device-selector]] +[source,,linenums] +---- +include::{header_dir}/deviceSelector.h[lines=4..-1] +---- + +Typical examples of default and user-provided <> could be: + +[source,,linenums] +---- +sycl::device my_gpu { sycl::gpu_selector_v }; + +sycl::queue my_accelerator { sycl::accelerator_selector_v }; + +int prefer_my_vendor(const sycl::device & d) { + // Return 1 if the vendor name is "MyVendor" or 0 else. + // 0 does not prevent another device to be picked as a second choice + return d.get_info() == "MyVendor"; +} + +// Get the preferred device or another one if not available +sycl::device preferred_device { prefer_my_vendor }; + +// This throws if there is no such device in the system +sycl::queue half_precision_controller { + // Can use a lambda as a device ranking function. + // Returns a negative number to fail in the case there is no such device + [] (auto &d) { return d.has(sycl::aspect::fp16) ? 1 : -1; } +}; + +// To ease porting SYCL 1.2.1 code, there are types whose +// construction leads to the equivalent predefined device selector +sycl::queue my_old_style_gpu { sycl::gpu_selector {} }; +---- + +Examples of using [code]#aspect_selector#: + +[[example:aspect-selector]] +[source,,linenums] +---- +using namespace sycl; // (optional) avoids need for "sycl::" before SYCL names + +// Unrestrained selection, equivalent to default_selector +auto dev0 = device{aspect_selector()}; + +// Pass aspects in a vector +// Only accept CPUs that support half +auto dev1 = device{aspect_selector(std::vector{aspect::cpu, aspect::fp16})}; + +// Pass aspects without a vector +// Only accept GPUs that support half +auto dev2 = device{aspect_selector(aspect::gpu, aspect::fp16)}; + +// Pass aspects as compile-time parameters +// Only accept devices that can be debugged on host and support half +auto dev3 = device{aspect_selector()}; + +// Pass aspects in an allowlist and a denylist +// Only accept devices that support half and double floating point precision, +// but exclude emulated devices and devices of type "custom" +auto dev4 = device{aspect_selector( + std::vector{aspect::fp16, aspect::fp64}, + std::vector{aspect::emulated, aspect::custom} +)}; +---- + +[NOTE] +==== +In SYCL 1.2.1 the predefined device selectors were actually types +that had to be instantiated to be used. Now they are just +instances. To simplify porting code using the old type +instantiations, a backward-compatible API is still provided, such as +[code]#sycl::default_selector#. The new predefined device +selectors have their new names appended with "_v" to avoid +conflicts, thus following the naming style used by traits in the {cpp} +standard library. There is no requirement for the implementation to +have for example [code]#sycl::gpu_selector_v# being an instance +of [code]#sycl::gpu_selector#. +==== + +NOTE: Implementation note: the SYCL API might rely on SFINAE or {cpp20} +concepts to resolve some ambiguity in constructors with default +parameters. + + +[[sec:platform-class]] +=== Platform class + +The SYCL [code]#platform# class encapsulates a single SYCL platform on +which SYCL kernel functions may be executed. A SYCL platform must be +associated with a single <>. + +A SYCL [code]#platform# is also associated with one or more SYCL +[code]#devices# associated with the same <>. + +All member functions of the [code]#platform# class are synchronous and +errors are handled by throwing synchronous SYCL exceptions. + +The execution environment for a SYCL application has a fixed number of +platforms which does not vary as the application executes. The application +can get a list of all these platforms via [code]#platform::get_platforms()#. +The [code]#platform# class also provides constructors, but constructing a new +[code]#platform# instance merely creates a new object that is a copy of one +of the objects returned by [code]#platform::get_platforms()#. + +The SYCL [code]#platform# class provides the common reference semantics +(see <>). + +==== Platform interface + +A synopsis of the SYCL [code]#platform# class is provided below. The +constructors, member functions and static member functions of the SYCL +[code]#platform# class are listed in +<>, <> and +<> respectively. The additional common +special member functions and common member functions are listed in +<> in +<> and +<> respectively. + +// Interface of platform class +[source,,linenums] +---- +include::{header_dir}/platform.h[lines=4..-1] +---- + + +[[table.constructors.platform]] +.Constructors of the SYCL [code]#platform# class +// Jon: Dims{6.7cm}{8.3cm} +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Constructor @ Description +a@ +[source] +---- +platform() +---- + a@ Constructs a SYCL [code]#platform# instance that is a copy of the + [code]#platform# which contains the device returned by + [code]#default_selector_v#. + +a@ +[source] +---- +template + explicit platform(const DeviceSelector &) +---- + a@ Constructs a SYCL [code]#platform# instance that is a copy of the + [code]#platform# which contains the device returned by the + <> parameter. + +|==== + + + +[[table.members.platform]] +.Member functions of the SYCL [code]#platform# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +backend get_backend() const noexcept +---- + a@ Returns a [code]#backend# identifying the <> associated + with this [code]#platform#. + +a@ +[source] +---- +template typename param::return_type get_info() const +---- + a@ Queries this SYCL [code]#platform# for information requested by + the template parameter [code]#param#. + The type alias [code]#param::return_type# must be defined in + accordance with the info parameters in <> to + facilitate returning the type associated with the [code]#param# + parameter. + +a@ +[source] +---- +template typename param::return_type get_backend_info() const +---- + a@ Queries this SYCL [code]#platform# for <>-specific + information requested by the template parameter [code]#param#. + The type alias [code]#param::return_type# must be defined in + accordance with the <> specification. + Must throw an [code]#exception# with the [code]#errc::backend_mismatch# + error code if the <> that corresponds with [code]#param# is different + from the <> that is associated with this [code]#platform#. + +a@ +[source] +---- +bool has(aspect asp) const +---- + a@ Returns true if all of the SYCL [code]#devices# associated with this + SYCL [code]#platform# have the given <>. + +a@ +[source] +---- +bool has_extension(const std::string & extension) const +---- + a@ Deprecated, use [code]#has()# instead. + +Returns true if this SYCL [code]#platform# supports the extension queried by the [code]#extension# parameter. A SYCL [code]#platform# can only support an extension if all associated SYCL [code]#devices# support that extension. + +a@ +[source] +---- +std::vector get_devices( + info::device_type deviceType = + info::device_type::all) const +---- + a@ Returns a [code]#std::vector# containing all SYCL + [code]#devices# associated with this SYCL [code]#platform# + which have the device type encapsulated by [code]#deviceType#. + +|==== + + + +[[table.staticmembers.platform]] +.Static member functions of the SYCL [code]#platform# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Static member function @ Description +a@ +[source] +---- +static std::vector get_platforms() +---- + a@ Returns a [code]#std::vector# containing all SYCL + [code]#platforms# from all <> available in the system. + +|==== + + + +==== Platform information descriptors + +A <> can be queried for information using the [code]#get_info# +member function of the [code]#platform# class, specifying one of the info +parameters in [code]#info::platform#. Every <> +must produce a valid value for each info parameter. The possible values for +each info parameter and any restrictions are defined in the specification +of the <> associated with the <>. All info parameters in +[code]#info::platform# are specified in <> and the +synopsis for [code]#info::platform# is described in +<>. + + +[[table.platform.info]] +.Platform information descriptors +// Jon: Dims{5cm}{2cm}{7cm} +[width="100%",options="header",separator="@",cols="37%,19%,44%"] +|==== +@ Platform descriptors @ Return type @ Description +a@ +[source] +---- +info::platform::version +---- + + @ [.code]#std::string# + a@ Returns the software driver version of the <>. + +a@ +[source] +---- +info::platform::name +---- + + @ [.code]#std::string# + a@ Returns the name of the <>. + +a@ +[source] +---- +info::platform::vendor +---- + + @ [.code]#std::string# + a@ Returns the name of the vendor providing the <>. + +a@ +[source] +---- +info::platform::extensions +---- + + @ [.code]#std::vector# + a@ Deprecated, use [code]#device::get_info()# with + [code]#info::device::aspects# instead. + +Returns the extensions supported by the <>. + +|==== + + + +[[sec:interface.context.class]] +=== Context class + +The <> class represents a SYCL <>. A <> +represents the runtime data structures and state required by a <> +API to interact with a group of devices associated with a platform. + +The SYCL [code]#context# class provides the common reference semantics +(see <>). + + +==== Context interface + +The constructors and member functions of the SYCL [code]#context# class +are listed in <> and +<>, respectively. The additional common special +member functions and common member functions are listed in +<> in +<> and +<>, respectively. + +All member functions of the <> class are synchronous and errors +are handled by throwing synchronous SYCL exceptions. + +All constructors of the SYCL <> class will construct an +instance associated with a particular <>, determined by the +constructor parameters or, in the case of the default constructor, the +SYCL [code]#device# produced by the +[code]#default_selector_v#. + +A SYCL [code]#context# can optionally be constructed with an +[code]#async_handler# parameter. In this case the +[code]#async_handler# is used to report asynchronous SYCL exceptions, +as described in <>. + +Information about a SYCL <> may be queried through the +[code]#get_info()# member function. + +// Interface for class: context +[source,,linenums] +---- +include::{header_dir}/context.h[lines=4..-1] +---- + + +[[table.constructors.context]] +.Constructors of the SYCL [code]#context# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Constructor @ Description +a@ +[source] +---- +explicit context(async_handler asyncHandler = {}) +---- + a@ Constructs a SYCL [code]#context# instance using an instance of + [code]#default_selector_v# to select the associated SYCL + [code]#platform# and [code]#device(s)#. The <> that + are associated with the constructed <> are implementation-defined + but must contain the <> chosen by the device selector. The + constructed SYCL [code]#context# will use the [code]#asyncHandler# + parameter to handle exceptions. + +a@ +[source] +---- +explicit context(const device &dev, + async_handler asyncHandler = {}) +---- + a@ Constructs a SYCL [code]#context# instance using the [code]#dev# parameter as the associated SYCL [code]#device# and the SYCL [code]#platform# associated with the [code]#dev# parameter as the associated SYCL [code]#platform#. The constructed SYCL [code]#context# will use the [code]#asyncHandler# parameter to handle exceptions. + +a@ +[source] +---- +explicit context(const std::vector & deviceList, + async_handler asyncHandler = {}) +---- + a@ Constructs a SYCL [code]#context# instance using the SYCL [code]#device(s)# in the [code]#deviceList# parameter as the associated SYCL [code]#device(s)# and the SYCL [code]#platform# associated with each SYCL [code]#device# in the [code]#deviceList# parameter as the associated SYCL [code]#platform#. This requires that all SYCL [code]#devices# in the [code]#deviceList# parameter have the same associated SYCL [code]#platform#. The constructed SYCL [code]#context# will use the [code]#asyncHandler# parameter to handle exceptions. + +|==== + + + +[[table.members.context]] +.Member functions of the [code]#context# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +backend get_backend() const noexcept +---- + a@ Returns a [code]#backend# identifying the <> associated + with this [code]#context#. + +a@ +[source] +---- +template typename param::return_type get_info() const +---- + a@ Queries this SYCL [code]#context# for information requested by the + template parameter [code]#param#. + The type alias [code]#param::return_type# must be defined in + accordance with the info parameters in <> to + facilitate returning the type associated with the [code]#param# + parameter. + +a@ +[source] +---- +template +typename param::return_type get_backend_info() const +---- + a@ Queries this SYCL [code]#context# for <>-specific information + requested by the template parameter [code]#param#. + The type alias [code]#param::return_type# must be defined in + accordance with the <> specification. + Must throw an [code]#exception# with the [code]#errc::backend_mismatch# + error code if the <> that corresponds with [code]#param# is different + from the <> that is associated with this [code]#context#. + +a@ +[source] +---- +platform get_platform() const +---- + a@ Returns the SYCL [code]#platform# that is associated with this SYCL [code]#context#. The value returned must be equal to that returned by [code]#get_info()#. + +a@ +[source] +---- +std::vector + get_devices() const +---- + a@ Returns a [code]#std::vector# containing all SYCL [code]#devices# that are associated with this SYCL [code]#context#. The value returned must be equal to that returned by [code]#get_info()#. + +|==== + + + +==== Context information descriptors + +A <> can be queried for information using the [code]#get_info# +member function of the [code]#context# class, specifying one of the info +parameters in [code]#info::context#. Every <> +must produce a valid value for each info parameter. The possible values for +each info parameter and any restrictions are defined in the specification of +the <> associated with the <>. All info parameters in +[code]#info::context# are specified in <> and the synopsis +for [code]#info::context# is described in <>. + + +[[table.context.info]] +.Context information descriptors +// Jon: Dims{5cm}{4.4cm}{5cm} +[width="100%",options="header",separator="@",cols="37%,19%,44%"] +|==== +@ Context Descriptors @ Return type @ Description +a@ +[source] +---- +info::context::platform +---- + + @ [.code]#platform# + a@ Returns the <> associated with the <>. + +a@ +[source] +---- +info::context::devices +---- + + @ [.code]#std::vector# + a@ Returns all of the <> associated with the <>. + +a@ +[source] +---- +info::context::atomic_memory_order_capabilities +---- + + @ [.code]#std::vector# + a@ Returns the set of memory orderings supported by atomic operations on all + devices in the context, which is guaranteed to include [code]#relaxed#. + +The memory ordering of the context determines the behavior of atomic operations applied +to any memory that can be concurrently accessed by multiple devices in the context. + +a@ +[source] +---- +info::context::atomic_fence_order_capabilities +---- + + @ [.code]#std::vector# + a@ Returns the set of memory orderings supported by [code]#atomic_fence# + on all devices in the context, which is guaranteed to include + [code]#relaxed#. + +The memory ordering of the context determines the behavior of fence operations applied +to any memory that can be concurrently accessed by multiple devices in the context. + +a@ +[source] +---- +info::context::atomic_memory_scope_capabilities +---- + + @ [.code]#std::vector# + a@ Returns the set of memory scopes supported by atomic operations on all devices in the context, which is guaranteed to include [code]#work_group#. + +a@ +[source] +---- +info::context::atomic_fence_scope_capabilities +---- + + @ [.code]#std::vector# + a@ Returns the set of memory orderings supported by [code]#atomic_fence# on all devices in the context, which is guaranteed to include [code]#work_group#. + +|==== + + + +[[sec:context-properties]] +==== Context properties + +The [code]#property_list# constructor parameters are present for extensibility. + +// \input{device_class} +// %%%%%%%%%%%%%%%%%%%%%%%%%%%% begin device_class %%%%%%%%%%%%%%%%%%%%%%%%%%%% + +[[sec:device-class]] +=== Device class + +The SYCL [code]#device# class encapsulates a single SYCL device on +which <> can be executed. + +All member functions of the [code]#device# class are synchronous and +errors are handled by throwing synchronous SYCL exceptions. + +The execution environment for a SYCL application has a fixed number of +devices which does not vary as the application executes. The application +can get a list of all these devices via [code]#device::get_devices()#. The +[code]#device# class also provides constructors, but constructing a new +[code]#device# instance merely creates a new object that is a copy of one +of the objects returned by [code]#device::get_devices()#. + +A SYCL [code]#device# can be partitioned into multiple SYCL devices, by +calling the [code]#create_sub_devices()# member function template. The +resulting SYCL [code]#devices# are considered sub devices, and it is +valid to partition these sub devices further. The range of support for this +feature is <> and device specific and can be queried for through +[code]#get_info()#. + +The SYCL [code]#device# class provides the common reference semantics +(see <>). + +==== Device interface + +A synopsis of the SYCL [code]#device# class is provided below. The +constructors, member functions and static member functions of the SYCL +[code]#device# class are listed in +<>, <> and +<> respectively. The additional common special +member functions and common member functions are listed in +<> in +<> and +<>, respectively. + +// Interface of the device class +[source,,linenums] +---- +include::{header_dir}/device.h[lines=4..-1] +---- + + +[[table.constructors.device]] +.Constructors of the SYCL [code]#device# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Constructor @ Description +a@ +[source] +---- +device() +---- + a@ Constructs a SYCL [code]#device# instance that is a copy of the device + returned by [code]#default_selector_v#. + +a@ +[source] +---- +template + explicit device(const DeviceSelector &) +---- + a@ Constructs a SYCL [code]#device# instance that is a copy of the device + returned by the <> parameter. + +|==== + + + +[[table.members.device]] +.Member functions of the SYCL [code]#device# class +[width="100%",options="header",separator="@",cols="58%,42%"] +|==== +@ Member function @ Description +a@ +[source] +---- +backend get_backend() const noexcept +---- + a@ Returns a [code]#backend# identifying the <> associated + with this [code]#device#. + +a@ +[source] +---- +platform get_platform() const +---- + a@ Returns the associated SYCL [code]#platform#. + The value returned must be equal to that returned by [code]#get_info()#. + +a@ +[source] +---- +bool is_cpu() const +---- + a@ Returns the same value as [code]#has(aspect::cpu)#. See <>. + +a@ +[source] +---- +bool is_gpu() const +---- + a@ Returns the same value as [code]#has(aspect::gpu)#. See <>. + +a@ +[source] +---- +bool is_accelerator() const +---- + a@ Returns the same value as [code]#has(aspect::accelerator)#. See <>. + +a@ +[source] +---- +template +typename param::return_type get_info() const +---- + a@ Queries this SYCL [code]#device# for information requested by the + template parameter [code]#param#. + The type alias [code]#param::return_type# must be defined in + accordance with the info parameters in <> to + facilitate returning the type associated with the [code]#param# + parameter. + +a@ +[source] +---- +template +typename param::return_type get_backend_info() const +---- + a@ Queries this SYCL [code]#device# for <>-specific information + requested by the template parameter [code]#param#. + The type alias [code]#param::return_type# must be defined in + accordance with the <> specification. + Must throw an [code]#exception# with the [code]#errc::backend_mismatch# + error code if the <> that corresponds with [code]#param# is different + from the <> that is associated with this [code]#device#. + +a@ +[source] +---- +bool has(aspect asp) const +---- + a@ Returns true if this SYCL [code]#device# has the given <>. + SYCL applications can use this member function to determine which + optional features this device supports (if any). + +a@ +[source] +---- +bool has_extension( + const std::string &extension) const +---- + a@ Deprecated, use [code]#has()# instead. + +Returns true if this SYCL [code]#device# supports the extension queried by the [code]#extension# parameter. + +a@ +[source] +---- +template +std::vector create_sub_devices( + size_t count) const +---- + a@ Available only when [code]#prop# is + [code]#info::partition_property::partition_equally#. Returns a + [code]#std::vector# of sub devices partitioned from this SYCL + [code]#device# based on the [code]#count# parameter. The returned vector + contains as many sub devices as can be created such that each sub device + contains [code]#count# compute units. If the device's total number of + compute units (as returned by [code]#info::device::max_compute_units#) is + not evenly divided by [code]#count#, then the remaining compute units are + not included in any of the sub devices. + +If this SYCL [code]#device# does not support +[code]#info::partition_property::partition_equally# an [code]#exception# with +the [code]#errc::feature_not_supported# error code must be thrown. If +[code]#count# exceeds the total number of compute units in the device, an +[code]#exception# with the [code]#errc::invalid# error code must be thrown. + +a@ +[source] +---- +template +std::vector create_sub_devices( + const std::vector &counts) const +---- + a@ Available only when [code]#prop# is + [code]#info::partition_property::partition_by_counts#. Returns a + [code]#std::vector# of sub devices partitioned from this SYCL + [code]#device# based on the [code]#counts# parameter. For each non-zero + value _M_ in the [code]#counts# vector, a sub device with _M_ compute + units is created. + +If the SYCL [code]#device# does not support +[code]#info::partition_property::partition_by_counts# an [code]#exception# with +the [code]#errc::feature_not_supported# error code must be thrown. If the +number of non-zero values in [code]#counts# exceeds the device's maximum +number of sub devices (as returned by +[code]#info::device::partition_max_sub_devices#) or if the total of all the +values in the [code]#counts# vector exceeds the total number of compute units +in the device (as returned by [code]#info::device::max_compute_units#), an +[code]#exception# with the [code]#errc::invalid# error code must be thrown. + +a@ +[source] +---- +template +std::vector create_sub_devices( + info::partition_affinity_domain domain) const +---- +// WARNING: The Asciidoctor PDF renderer seems to be unable to generate a table +// where any single row is taller than a page. This row is already close to +// the page limit. If you add any more text in this cell, check the PDF render +// to see if any of the text is cut off at the bottom of the page. If so, try +// making this column wider so that this row still fits on a page. + + a@ Available only when [code]#prop# is + [code]#info::partition_property::partition_by_affinity_domain#. Returns + a [code]#std::vector# of sub devices partitioned from this SYCL + [code]#device# by affinity domain based on the [code]#domain# parameter, + which must be one of the following values: + +* [code]#info::partition_affinity_domain::numa#: Split the device into + sub devices comprised of compute units that share a NUMA node. + +* [code]#info::partition_affinity_domain::L4_cache#: Split the device into + sub devices comprised of compute units that share a level 4 data cache. + +* [code]#info::partition_affinity_domain::L3_cache#: Split the device into + sub devices comprised of compute units that share a level 3 data cache. + +* [code]#info::partition_affinity_domain::L2_cache#: Split the device into + sub devices comprised of compute units that share a level 2 data cache. + +* [code]#info::partition_affinity_domain::L1_cache#: Split the device into + sub devices comprised of compute units that share a level 1 data cache. + +* [code]#info::partition_affinity_domain::next_partitionable#: Split the device + along the next partitionable affinity domain. The implementation shall find + the first level along which the device or sub device may be further + subdivided in the order [code]#numa#, [code]#L4_cache#, [code]#L3_cache#, + [code]#L2_cache#, [code]#L1_cache#, and partition the device into sub devices + comprised of compute units that share memory subsystems at this level. The + user may determine what happened via + [code]#info::device::partition_type_affinity_domain#. + +If the SYCL [code]#device# does not support +[code]#info::partition_property::partition_by_affinity_domain# or the +SYCL [code]#device# does not support the +[code]#info::partition_affinity_domain# provided, an [code]#exception# +with the [code]#errc::feature_not_supported# error code must be thrown. + +|==== + + + +[[table.staticmembers.device]] +.Static member functions of the SYCL [code]#device# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Static member function @ Description +a@ +[source] +---- +static std::vector get_devices( + info::device_type deviceType = info::device_type::all) +---- + a@ Returns a [code]#std::vector# containing all SYCL + [code]#devices# from all <> available in the + system which have the device type encapsulated by [code]#deviceType#. + +|==== + + + +==== Device information descriptors + +A <> can be queried for information using the [code]#get_info# +member function of the [code]#device# class, specifying one of the info +parameters in [code]#info::device#. Every <> must produce a +valid value for each info parameter. The possible values for each info +parameter and any restriction are defined in the specification of the +<> associated with the <>. All info parameters in +[code]#info::device# are specified in <> and the synopsis +for [code]#info::device# is described in <>. + + +[[table.device.info]] +.Device information descriptors +// Jon: Dims{5cm}{2.5cm}{6.5cm} +[width="100%",options="header",separator="@",cols="37%,19%,44%"] +|==== +@ Device descriptors @ Return type @ Description +a@ +[source] +---- +info::device::device_type +---- + + @ [.code]#info::device_type# + a@ Returns the device type associated with the <>. May not return + [code]#info::device_type::all#. + +a@ +[source] +---- +info::device::vendor_id +---- + + @ [.code]#uint32_t# + a@ Returns a unique vendor device identifier. + +a@ +[source] +---- +info::device::max_compute_units +---- + + @ [.code]#uint32_t# + a@ Returns the number of parallel compute units available to the + <>. The minimum value is 1. + +a@ +[source] +---- +info::device::max_work_item_dimensions +---- + + @ [.code]#uint32_t# + a@ Returns the maximum dimensions that specify the global and local work-item IDs used by the data parallel execution model. + The minimum value is 3 if this SYCL [code]#device# is not of device type [code]#info::device_type::custom#. + +a@ +[source] +---- +info::device::max_work_item_sizes\<1> +---- + + @ [.code]#id<1># + a@ Returns the maximum number of work-items that are permitted of the + work-group of the [code]#nd_range#. The minimum value is latexmath:[(1)] + for [code]#devices# that are not of device type + [code]#info::device_type::custom#. + +a@ +[source] +---- +info::device::max_work_item_sizes\<2> +---- + + @ [.code]#id<2># + a@ Returns the maximum number of work-items that are permitted in both + dimensions of the work-group of the [code]#nd_range#. The minimum value is + latexmath:[(1,1)] for [code]#devices# that are not of device type + [code]#info::device_type::custom#. + +a@ +[source] +---- +info::device::max_work_item_sizes\<3> +---- + + @ [.code]#id<3># + a@ Returns the maximum number of work-items that are permitted in each + dimension of the work-group of the [code]#nd_range#. The minimum value + is latexmath:[(1,1,1)] for [code]#devices# that are not of device type + [code]#info::device_type::custom#. + +a@ +[source] +---- +info::device::max_work_group_size +---- + + @ [.code]#size_t# + a@ Returns the maximum number of work-items that are permitted in a work-group executing a kernel on a single compute unit. + The minimum value is 1. + +a@ +[source] +---- +info::device::max_num_sub_groups +---- + + @ [.code]#uint32_t# + a@ Returns the maximum number of sub-groups in a work-group for any kernel executed on the device. The minimum value is 1. + +a@ +[source] +---- +info::device::sub_group_independent_forward_progress +---- + + @ [.code]#bool# + a@ Returns true if the device supports independent forward progress of sub-groups with respect to other sub-groups in the same work-group. + +a@ +[source] +---- +info::device::sub_group_sizes +---- + + @ [.code]#std::vector# + a@ Returns a [code]#std::vector# of [code]#size_t# containing the set of sub-group sizes supported by the device. + +a@ +[source] +---- +info::device::preferred_vector_width_char +info::device::preferred_vector_width_short +info::device::preferred_vector_width_int +info::device::preferred_vector_width_long +info::device::preferred_vector_width_float +info::device::preferred_vector_width_double +info::device::preferred_vector_width_half +---- + + @ [.code]#uint32_t# + a@ Returns the preferred native vector width size for built-in scalar types that can be put into vectors. The vector width is defined as the number of scalar elements that can be stored in the vector. Must return 0 for [code]#info::device::preferred_vector_width_double# if the [code]#device# does not have [code]#aspect::fp64# and must return 0 for [code]#info::device::preferred_vector_width_half# if the [code]#device# does not have [code]#aspect::fp16#. + +a@ +[source] +---- +info::device::native_vector_width_char +info::device::native_vector_width_short +info::device::native_vector_width_int +info::device::native_vector_width_long +info::device::native_vector_width_float +info::device::native_vector_width_double +info::device::native_vector_width_half +---- + + @ [.code]#uint32_t# + a@ Returns the native ISA vector width. The vector width is defined as the number of scalar elements that can be stored in the vector. Must return 0 for [code]#info::device::preferred_vector_width_double# if the [code]#device# does not have [code]#aspect::fp64# and must return 0 for [code]#info::device::preferred_vector_width_half# if the [code]#device# does not have [code]#aspect::fp16#. + +a@ +[source] +---- +info::device::max_clock_frequency +---- + + @ [.code]#uint32_t# + a@ Returns the maximum configured clock frequency of this SYCL [code]#device# in MHz. + +a@ +[source] +---- +info::device::address_bits +---- + + @ [.code]#uint32_t# + a@ Returns the default compute device address space size specified as an unsigned integer value in bits. Must return either 32 or 64. + +a@ +[source] +---- +info::device::max_mem_alloc_size +---- + + @ [.code]#uint64_t# + a@ Returns the maximum size of memory object allocation in bytes. The minimum value is max (1/4th of [code]#info::device::global_mem_size#,128*1024*1024) if this SYCL [code]#device# is not of device type [code]#info::device_type::custom#. + +a@ +[source] +---- +info::device::image_support +---- + + @ [.code]#bool# + a@ Deprecated. + +Returns the same value as [code]#device::has(aspect::image)#. + +a@ +[source] +---- +info::device::max_read_image_args +---- + + @ [.code]#uint32_t# + a@ Returns the maximum number of simultaneous image objects that can be read from by a kernel. The minimum value is 128 if the SYCL [code]#device# has [code]#aspect::image#. + +a@ +[source] +---- +info::device::max_write_image_args +---- + + @ [.code]#uint32_t# + a@ Returns the maximum number of simultaneous image objects that can be written to by a kernel. The minimum value is 8 if the SYCL [code]#device# has [code]#aspect::image#. + +a@ +[source] +---- +info::device::image2d_max_width +---- + + @ [.code]#size_t# + a@ Returns the maximum width of a 2D image or 1D image in pixels. The minimum value is 8192 if the SYCL [code]#device# has [code]#aspect::image#. + +a@ +[source] +---- +info::device::image2d_max_height +---- + + @ [.code]#size_t# + a@ Returns the maximum height of a 2D image in pixels. The minimum value is 8192 if the SYCL [code]#device# has [code]#aspect::image#. + +a@ +[source] +---- +info::device::image3d_max_width +---- + + @ [.code]#size_t# + a@ Returns the maximum width of a 3D image in pixels. The minimum value is 2048 if the SYCL [code]#device# has [code]#aspect::image#. + +a@ +[source] +---- +info::device::image3d_max_height +---- + + @ [.code]#size_t# + a@ Returns the maximum height of a 3D image in pixels. The minimum value is 2048 if the SYCL [code]#device# has [code]#aspect::image#. + +a@ +[source] +---- +info::device::image3d_max_depth +---- + + @ [.code]#size_t# + a@ Returns the maximum depth of a 3D image in pixels. The minimum value is 2048 if the SYCL [code]#device# has [code]#aspect::image#. + +a@ +[source] +---- +info::device::image_max_buffer_size +---- + + @ [.code]#size_t# + a@ Returns the number of pixels for a 1D image created from a buffer object. The minimum value is 65536 if the SYCL [code]#device# has [code]#aspect::image#. Note that this information is intended for OpenCL interoperability only as this feature is not supported in SYCL. + +a@ +[source] +---- +info::device::max_samplers +---- + + @ [.code]#uint32_t# + a@ Returns the maximum number of samplers that can be used in a kernel. The minimum value is 16 if the SYCL [code]#device# has [code]#aspect::image#. + +a@ +[source] +---- +info::device::max_parameter_size +---- + + @ [.code]#size_t# + a@ Returns the maximum size in bytes of the arguments that can be passed to a kernel. The minimum value is 1024 if this SYCL [code]#device# is not of device type [code]#info::device_type::custom#. For this minimum value, only a maximum of 128 arguments can be passed to a kernel. + +a@ +[source] +---- +info::device::mem_base_addr_align +---- + + @ [.code]#uint32_t# + a@ Returns the minimum value in bits of the largest supported SYCL built-in + data type if this SYCL [code]#device# is not of device type [code]#info::device_type::custom#. + +a@ +[source] +---- +info::device::half_fp_config +---- + + @ [.code]#std::vector# + a@ Returns a [code]#std::vector# of [code]#info::fp_config# + describing the half precision floating-point capability of this SYCL + [code]#device#. The [code]#std::vector# may contain zero or + more of the following values: +-- + * [code]#info::fp_config::denorm:# denorms are supported. + * [code]#info::fp_config::inf_nan:# INF and quiet NaNs are supported. + * [code]#info::fp_config::round_to_nearest:# round to nearest even + rounding mode is supported. + * [code]#info::fp_config::round_to_zero:# round to zero rounding mode + is supported. + * [code]#info::fp_config::round_to_inf:# round to positive and + negative infinity rounding modes are supported. + * [code]#info::fp_config::fma:# IEEE754-2008 fused multiply add is + supported. + * [code]#info::fp_config::correctly_rounded_divide_sqrt:# divide and + sqrt are correctly rounded as defined by the IEEE754 specification. + * [code]#info::fp_config::soft_float:# basic floating-point + operations (such as addition, subtraction, multiplication) are + implemented in software. + +If half precision is supported by this SYCL [code]#device# (i.e. the +[code]#device# has [code]#aspect::fp16# there is no minimum +floating-point capability. If half support is not supported the returned +[code]#std::vector# must be empty. +-- + +a@ +[source] +---- +info::device::single_fp_config +---- + + @ [.code]#std::vector# + a@ Returns a [code]#std::vector# of [code]#info::fp_config# + describing the single precision floating-point capability of this + SYCL [code]#device#. The [code]#std::vector# must + contain one or more of the following values: +-- + * [code]#info::fp_config::denorm:# denorms are supported. + * [code]#info::fp_config::inf_nan:# INF and quiet NaNs are supported. + * [code]#info::fp_config::round_to_nearest:# round to nearest even + rounding mode is supported. + * [code]#info::fp_config::round_to_zero:# round to zero rounding mode + is supported. + * [code]#info::fp_config::round_to_inf:# round to positive and + negative infinity rounding modes are supported. + * [code]#info::fp_config::fma:# IEEE754-2008 fused multiply add is + supported. + * [code]#info::fp_config::correctly_rounded_divide_sqrt:# divide and + sqrt are correctly rounded as defined by the IEEE754 specification. + * [code]#info::fp_config::soft_float:# basic floating-point + operations (such as addition, subtraction, multiplication) are + implemented in software. + +If this SYCL [code]#device# is not of type +[code]#info::device_type::custom# then the minimum floating-point +capability must be: [code]#info::fp_config::round_to_nearest# and +[code]#info::fp_config::inf_nan#. +-- + +a@ +[source] +---- +info::device::double_fp_config +---- + + @ [.code]#std::vector# + a@ Returns a [code]#std::vector# of [code]#info::fp_config# + describing the double precision floating-point capability of this + SYCL [code]#device#. The [code]#std::vector# may contain + zero or more of the following values: +-- + * [code]#info::fp_config::denorm:# denorms are supported. + * [code]#info::fp_config::inf_nan:# INF and NaNs are supported. + * [code]#info::fp_config::round_to_nearest:# round to nearest even + rounding mode is supported. + * [code]#info::fp_config::round_to_zero:# round to zero rounding mode + is supported. + * [code]#info::fp_config::round_to_inf:# round to positive and + negative infinity rounding modes are supported. + * [code]#info::fp_config::fma:# IEEE754-2008 fused multiply-add is + supported. + * [code]#info::fp_config::soft_float:# basic floating-point + operations (such as addition, subtraction, multiplication) are + implemented in software. + +If double precision is supported by this SYCL [code]#device# (i.e. the +[code]#device# has [code]#aspect::fp64# and this SYCL +[code]#device# is not of type [code]#info::device_type::custom# +then the minimum floating-point capability must be: +[code]#info::fp_config::fma#, +[code]#info::fp_config::round_to_nearest#, +[code]#info::fp_config::round_to_zero#, +[code]#info::fp_config::round_to_inf#, +[code]#info::fp_config::inf_nan# and +[code]#info::fp_config::denorm#. If double support is not supported the +returned [code]#std::vector# must be empty. +-- + +a@ +[source] +---- +info::device::global_mem_cache_type +---- + + @ [.code]#info::global_mem_cache_type# + a@ Returns the type of global memory cache supported. + +a@ +[source] +---- +info::device::global_mem_cache_line_size +---- + + @ [.code]#uint32_t# + a@ Returns the size of global memory cache line in bytes. + +a@ +[source] +---- +info::device::global_mem_cache_size +---- + + @ [.code]#uint64_t# + a@ Returns the size of global memory cache in bytes. + +a@ +[source] +---- +info::device::global_mem_size +---- + + @ [.code]#uint64_t# + a@ Returns the size of global device memory in bytes. + +a@ +[source] +---- +info::device::max_constant_buffer_size +---- + + @ [.code]#uint64_t# + a@ Deprecated in SYCL 2020. Returns the maximum size in bytes of a constant buffer allocation. The minimum value is 64 KB if this SYCL [code]#device# is not of type [code]#info::device_type::custom#. + +a@ +[source] +---- +info::device::max_constant_args +---- + + @ [.code]#uint32_t# + a@ Deprecated in SYCL 2020. Returns the maximum number of constant arguments that can be declared in a kernel. The minimum value is 8 if this SYCL [code]#device# is not of type [code]#info::device_type::custom#. + +a@ +[source] +---- +info::device::local_mem_type +---- + + @ [.code]#info::local_mem_type# + a@ Returns the type of local memory supported. This can + be [code]#info::local_mem_type::local# implying dedicated + local memory storage such as SRAM, or [code]#info::local_mem_type::global#. + If this SYCL [code]#device# is of type [code]#info::device_type::custom# this can also be [code]#info::local_mem_type::none#, indicating local memory is not supported. + +a@ +[source] +---- +info::device::local_mem_size +---- + + @ [.code]#uint64_t# + a@ Returns the size of local memory arena in bytes. The minimum value is 32 KB if this SYCL [code]#device# is not of type [code]#info::device_type::custom#. + +a@ +[source] +---- +info::device::error_correction_support +---- + + @ [.code]#bool# + a@ Returns true if the device implements error correction for all accesses to + compute device memory (global and constant). Returns false if the device does + not implement such error correction. + +a@ +[source] +---- +info::device::host_unified_memory +---- + + @ [.code]#bool# + a@ Deprecated, use [code]#device::has()# with one of the [code]#aspect::usm_*# aspects instead. + +Returns true if the device and the host have a unified memory subsystem and +returns false otherwise. + +a@ +[source] +---- +info::device::atomic_memory_order_capabilities +---- + + @ [.code]#std::vector# + a@ Returns the set of memory orderings supported by atomic operations on the device, + which is guaranteed to include [code]#relaxed#. + +a@ +[source] +---- +info::device::atomic_fence_order_capabilities +---- + + @ [.code]#std::vector# + a@ Returns the set of memory orderings supported by [code]#atomic_fence# on the device, + which is guaranteed to include [code]#relaxed#. + +a@ +[source] +---- +info::device::atomic_memory_scope_capabilities +---- + + @ [.code]#std::vector# + a@ Returns the set of memory scopes supported by atomic operations on the device, + which is guaranteed to include [code]#work_group#. + +a@ +[source] +---- +info::device::atomic_fence_scope_capabilities +---- + + @ [.code]#std::vector# + a@ Returns the set of memory scopes supported by [code]#atomic_fence# on the device, + which is guaranteed to include [code]#work_group#. + +a@ +[source] +---- +info::device::profiling_timer_resolution +---- + + @ [.code]#size_t# + a@ Returns the resolution of device timer in nanoseconds. + +a@ +[source] +---- +info::device::is_endian_little +---- + + @ [.code]#bool# + a@ Deprecated. Check the byte order of the host system instead. The host + and device are required to have the same byte order. + +Returns true if this SYCL [code]#device# is a little endian device and returns +false otherwise. + +a@ +[source] +---- +info::device::is_available +---- + + @ [.code]#bool# + a@ Returns true if the SYCL [code]#device# is available and returns false if the device is not + available. + +a@ +[source] +---- +info::device::is_compiler_available +---- + + @ [.code]#bool# + a@ Deprecated. + +Returns the same value as [code]#device::has(aspect::online_compiler)#. + +a@ +[source] +---- +info::device::is_linker_available +---- + + @ [.code]#bool# + a@ Deprecated. + +Returns the same value as [code]#device::has(aspect::online_linker)#. + +a@ +[source] +---- +info::device::execution_capabilities +---- + + @ [.code]#std::vector# + a@ Returns a [code]#std::vector# of the [code]#info::execution_capability# describing the supported execution capabilities. + Note that this information is intended for OpenCL interoperability only as SYCL only supports [code]#info::execution_capability::exec_kernel#. + +a@ +[source] +---- +info::device::queue_profiling +---- + + @ [.code]#bool# + a@ Deprecated. + +Returns the same value as [code]#device::has(aspect::queue_profiling)#. + +a@ +[source] +---- +info::device::built_in_kernel_ids +---- + + @ [.code]#std::vector# + a@ Returns a [code]#std::vector# of identifiers for the built-in kernels + supported by this SYCL [code]#device#. + +a@ +[source] +---- +info::device::built_in_kernels +---- + + @ [.code]#std::vector# + a@ Deprecated. Use [code]#info::device::built_in_kernel_ids# instead. + +Returns a [code]#std::vector# of built-in OpenCL kernels supported by this SYCL +[code]#device#. + +a@ +[source] +---- +info::device::platform +---- + + @ [.code]#platform# + a@ Returns the SYCL [code]#platform# associated with this SYCL [code]#device#. + +a@ +[source] +---- +info::device::name +---- + + @ [.code]#std::string# + a@ Returns the device name of this SYCL [code]#device#. + +a@ +[source] +---- +info::device::vendor +---- + + @ [.code]#std::string# + a@ Returns the vendor of this SYCL [code]#device#. + +a@ +[source] +---- +info::device::driver_version +---- + + @ [.code]#std::string# + a@ Returns a backend-defined driver version as a [code]#std::string#. + If using the OpenCL backend, the returned value represents the + OpenCL software driver version in the form: major_number.minor_number. + +a@ +[source] +---- +info::device::profile +---- + + @ [.code]#std::string# + a@ Deprecated in SYCL 2020. Only supported when using the OpenCL backend + (see <>). + +The value returned can be one of the following strings: +-- + * FULL_PROFILE - if the device supports the OpenCL specification + (functionality defined as part of the core specification and does not + require any extensions to be supported). + * EMBEDDED_PROFILE - if the device supports the OpenCL embedded profile. +-- + +a@ +[source] +---- +info::device::version +---- + + @ [.code]#std::string# + a@ Returns the SYCL version as a [code]#std::string# in the form: + [code]#.#. + +a@ +[source] +---- +info::device::backend_version +---- + + @ [.code]#std::string# + a@ Returns a string describing the version of the <> associated with + the <>. The possible values are specified in the <> + specification of the <> associated with the <>. + +a@ +[source] +---- +info::device::aspects +---- + + @ [.code]#std::vector# + a@ Returns a [code]#std::vector# of <> values supported by this + SYCL [code]#device#. + +a@ +[source] +---- +info::device::extensions +---- + + @ [.code]#std::vector# + a@ Deprecated, use [code]#info::device::aspects# instead. +-- +Returns a [code]#std::vector# of extension names (the extension names +do not contain any spaces) supported by this SYCL [code]#device#. The +extension names returned can be vendor supported extension names and one or +more of the following Khronos approved extension names: + + * [code]#cl_khr_int64_base_atomics# + * [code]#cl_khr_int64_extended_atomics# + * [code]#cl_khr_3d_image_writes# + * [code]#cl_khr_fp16# + * [code]#cl_khr_gl_sharing# + * [code]#cl_khr_gl_event# + * [code]#cl_khr_d3d10_sharing# + * [code]#cl_khr_dx9_media_sharing# + * [code]#cl_khr_d3d11_sharing# + * [code]#cl_khr_depth_images# + * [code]#cl_khr_gl_depth_images# + * [code]#cl_khr_gl_msaa_sharing# + * [code]#cl_khr_image2d_from_buffer# + * [code]#cl_khr_initialize_memory# + * [code]#cl_khr_context_abort# + * [code]#cl_khr_spir# + +If this SYCL [code]#device# is an OpenCL device then following approved +Khronos extension names must be returned by all device that support OpenCL C +1.2: + + * [code]#cl_khr_global_int32_base_atomics# + * [code]#cl_khr_global_int32_extended_atomics# + * [code]#cl_khr_local_int32_base_atomics# + * [code]#cl_khr_local_int32_extended_atomics# + * [code]#cl_khr_byte_addressable_store# + * [code]#cl_khr_fp64# (for backward compatibility if double precision + is supported) + +Please refer to the OpenCL 1.2 Extension Specification for a detailed +description of these extensions. +-- + +a@ +[source] +---- +info::device::printf_buffer_size +---- + + @ [.code]#size_t# + a@ Deprecated in SYCL 2020. + +Returns the maximum size of the internal buffer that holds the output of +[code]#printf# calls from a kernel. The minimum value is 1 MB if +[code]#info::device::profile# returns true for this SYCL [code]#device#. + +a@ +[source] +---- +info::device::preferred_interop_user_sync +---- + + @ [.code]#bool# + a@ Deprecated in SYCL 2020. Only supported when using the OpenCL backend + (see <>). + +Returns true if the preference for this SYCL [code]#device# is for the user to +be responsible for synchronization, when sharing memory objects between OpenCL +and other APIs such as DirectX, false if the device/implementation has a +performant path for performing synchronization of memory object shared between +OpenCL and other APIs such as DirectX. + +a@ +[source] +---- +info::device::parent_device +---- + + @ [.code]#device# + a@ Returns the parent SYCL [code]#device# to which this sub-device is a child if this is a sub-device. + Must throw an [code]#exception# with the [code]#errc::invalid# error code if this SYCL [code]#device# is not a sub device. + +a@ +[source] +---- +info::device::partition_max_sub_devices +---- + + @ [.code]#uint32_t# + a@ Returns the maximum number of sub-devices that can be created when this SYCL [code]#device# is partitioned. The value returned cannot exceed the value returned by [code]#info::device::device_max_compute_units#. + +a@ +[source] +---- +info::device::partition_properties +---- + + @ [.code]#std::vector# + a@ Returns the partition properties supported by this SYCL [code]#device;# a + vector of [code]#info::partition_property#. An element is returned in + this vector only if the device can be partitioned into at least two sub + devices along that partition property. + +a@ +[source] +---- +info::device::partition_affinity_domains +---- + + @ [.code]#std::vector# + a@ Returns a [code]#std::vector# of the partition affinity domains + supported by this SYCL [code]#device# when partitioning with + [code]#info::partition_property::partition_by_affinity_domain#. + An element is returned in this vector only if the device can be + partitioned into at least two sub devices along that affinity domain. + +a@ +[source] +---- +info::device::partition_type_property +---- + + @ [.code]#info::partition_property# + a@ Returns the partition property of this SYCL [code]#device#. If this SYCL [code]#device# is not a sub device then the return value must be [code]#info::partition_property::no_partition#, otherwise it must be one of the following values: +-- + * [code]#info::partition_property::partition_equally# + * [code]#info::partition_property::partition_by_counts# + * [code]#info::partition_property::partition_by_affinity_domain# +-- + +a@ +[source] +---- +info::device::partition_type_affinity_domain +---- + + @ [.code]#info::partition_affinity_domain# + a@ Returns the partition affinity domain of this SYCL [code]#device#. If this SYCL [code]#device# is not a sub device or the sub device was not partitioned with [code]#info::partition_type::partition_by_affinity_domain# then the return value must be [code]#info::partition_affinity_domain::not_applicable#, otherwise it must be one of the following values: +-- + * [code]#info::partition_affinity_domain::numa# + * [code]#info::partition_affinity_domain::L4_cache# + * [code]#info::partition_affinity_domain::L3_cache# + * [code]#info::partition_affinity_domain::L2_cache# + * [code]#info::partition_affinity_domain::L1_cache# +-- + +|==== + + + +[[sec:device-aspects]] +==== Device aspects + +Every SYCL <> has an associated set of <> which +identify characteristics of the [code]#device#. Aspects are defined via +the [code]#enum class aspect# enumeration: + +[source,,linenums] +---- +include::{header_dir}/deviceEnumClassAspect.h[lines=4..-1] +---- + +SYCL applications can query the aspects for a [code]#device# via +[code]#device::has()# in order to determine whether the [code]#device# +supports any optional features. <> lists the aspects that +are defined in the <> and tells which optional features correspond +to each. Backends and extensions may provide additional aspects and additional +optional device features. If so, the <> specification document or the +extension document describes them. + +[[table.device.aspect]] +.Device aspects defined by the <> +[width="100%",options="header",separator="@",cols="50%,50%"] +|==== +@ Aspect @ Description +a@ +[source] +---- +aspect::cpu +---- + a@ A device that runs on a CPU. Devices with this [code]#aspect# have + device type [code]#info::device_type::cpu#. + +a@ +[source] +---- +aspect::gpu +---- + a@ A device that can also be used to accelerate a 3D graphics API. Devices + with this [code]#aspect# have device type + [code]#info::device_type::gpu#. + +a@ +[source] +---- +aspect::accelerator +---- + a@ A dedicated accelerator device, usually using a peripheral interconnect for + communication. Devices with this [code]#aspect# have device type + [code]#info::device_type::accelerator#. + +a@ +[source] +---- +aspect::custom +---- + a@ A dedicated accelerator that can use the SYCL API, but programmable kernels + cannot be dispatched to the device, only fixed functionality is available. + See <>. Devices with this + [code]#aspect# have device type [code]#info::device_type::custom#. + +a@ +[source] +---- +aspect::emulated +---- + a@ Indicates that the device is somehow emulated. A device with this aspect + is not intended for performance, and instead will generally have another + purpose such as emulation or profiling. The precise definition of this + aspect is left open to the SYCL implementation. + +[NOTE] +==== +As an example, a vendor might support both a hardware FPGA device and a +software emulated FPGA, where the emulated FPGA has all the same features +as the hardware one but runs more slowly and can provide additional profiling +or diagnostic information. In such a case, an application's +<> can use [code]#aspect::emulated# to distinguish the two. +==== + +a@ +[source] +---- +aspect::host_debuggable +---- + a@ Indicates that <> running on this device can be debugged + using standard debuggers that are normally available on the host system + where the SYCL implementation resides. The precise definition of this + aspect is left open to the SYCL implementation. + +a@ +[source] +---- +aspect::fp16 +---- + a@ Indicates that kernels submitted to the device may use the + [code]#sycl::half# data type. + +a@ +[source] +---- +aspect::fp64 +---- + a@ Indicates that kernels submitted to the device may use the [code]#double# + data type. + +a@ +[source] +---- +aspect::atomic64 +---- + a@ Indicates that kernels submitted to the device may perform 64-bit atomic + operations. + +a@ +[source] +---- +aspect::image +---- + a@ Indicates that the device supports <>. + +a@ +[source] +---- +aspect::online_compiler +---- + a@ Indicates that the device supports online compilation of device code. + <> that have this aspect support the [code]#build()# + and [code]#compile()# functions defined in <>. + +a@ +[source] +---- +aspect::online_linker +---- + a@ Indicates that the device supports online linking of device code. + <> that have this aspect support the [code]#link()# + functions defined in <>. All + <> that have this aspect also have + [code]#aspect::online_compiler#. + +a@ +[source] +---- +aspect::queue_profiling +---- + a@ Indicates that the device supports queue profiling via [code]#property::queue::enable_profiling#. + +a@ +[source] +---- +aspect::usm_device_allocations +---- + a@ Indicates that the device supports explicit USM allocations as described + in <>. + +a@ +[source] +---- +aspect::usm_host_allocations +---- + a@ Indicates that the device can access USM memory allocated via + [code]#usm::alloc::host#. The device only + supports atomic modification of a host allocation if + [code]#aspect::usm_atomic_host_allocations# is also supported. + (See <>.) + +a@ +[source] +---- +aspect::usm_atomic_host_allocations +---- + a@ Indicates that the device supports USM memory allocated + via [code]#usm::alloc::host#. The host and this device may + concurrently access and atomically modify host allocations. (See <>.) + + +a@ +[source] +---- +aspect::usm_shared_allocations +---- + a@ Indicates that the device supports USM memory allocated via + [code]#usm::alloc::shared# on the same device. Concurrent access + and atomic modification of a shared allocation is only supported + if [code]#aspect::usm_atomic_shared_allocations# is also supported. + (See <>.) + +a@ +[source] +---- +aspect::usm_atomic_shared_allocations +---- + a@ Indicates that the device supports USM memory allocated via + [code]#usm::alloc::shared#. The host and other devices in the same + context that also support this capability may concurrently access + and atomically modify shared allocations. The allocation is free + to migrate between the host and the appropriate devices. (See <>.) + +a@ +[source] +---- +aspect::usm_system_allocations +---- + a@ Indicates that the system allocator may be used instead of SYCL USM + allocation mechanisms for [code]#usm::alloc::shared# allocations on + this device. (See <>.) + +|==== + +The implementation also provides two traits that the application can use to +query aspects at compilation time. The trait [code]#any_device_has# +inherits from [code]#std::true_type# if the compilation environment supports +any device which has the specified aspect, and it inherits from +[code]#std::false_type# if no device has the aspect. The trait +[code]#all_devices_have# inherits from [code]#std::true_type# if all +devices supported by the compilation environment have the specified aspect, +and it inherits from [code]#std::false_type# if any device does not have the +aspect. + +[source,,linenums] +---- +include::{header_dir}/aspectTraits.h[lines=4..-1] +---- + +Applications can use these traits to reduce their code size. The following +example demonstrates one way to use these traits to avoid instantiating a +templated kernel for device features that are not supported by any device. + +[source,,linenums] +---- +include::{code_dir}/aspectTraitExample.cpp[lines=4..-1] +---- + +The kernel function [code]#MyKernel# is templated to use a different +algorithm depending on whether the device has the aspect [code]#aspect::fp16#, +and the call to [code]#dev.has()# chooses the kernel function instantiation +that matches the device's capabilities. However, the use of +[code]#any_device_has_v# and [code]#all_devices_have_v# entirely avoid +useless instantiations of the kernel function. For example, when the +compilation environment does not support any devices with [code]#aspect::fp16#, +[code]#any_device_has_v# is [code]#false#, and the kernel +function is never instantiated with support for the [code]#sycl::half# type. + +[NOTE] +==== +Like any trait, the values of [code]#any_device_has_v# and +[code]#all_devices_have_v# have a uniform value across all parts of a SYCL +application. If an implementation uses <>, all compiler passes define a +particular aspect's specialization of the traits the same way, regardless of +whether that compiler pass' device supports the aspect. Thus, +[code]#any_device_has# and [code]#all_devices_have# cannot be used to determine +whether any particular device supports an aspect. Instead, applications must +use [code]#device::has()# or [code]#platform::has()# for this. +==== + +[NOTE] +==== +An implementation could choose to provide command line options which affect the +set of devices that it supports. If so, those command line options would also +affect these traits. For example, if an implementation provides a command line +option that disables [code]#aspect::accelerator# devices, the trait +[code]#any_device_has_v# would be [code]#false# when that +command line option was specified. +==== + +// %%%%%%%%%%%%%%%%%%%%%%%%%%%% end device_class %%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +[[sec:interface.queue.class]] +=== Queue class + +// \input{queue_class} +// %%%%%%%%%%%%%%%%%%%%%%%%%%%% begin queue_class %%%%%%%%%%%%%%%%%%%%%%%%%%%% + +The SYCL [code]#queue# class encapsulates a single SYCL queue which +schedules kernels on a SYCL device. + +A SYCL [code]#queue# can be used to submit <> to be +executed by the <> using the [code]#submit# member +function. + +All member functions of the [code]#queue# class are synchronous and errors +are handled by throwing synchronous SYCL exceptions. The [code]#submit# +member function schedules <> asynchronously, so any errors +in the submission of a <> are handled by throwing synchronous +SYCL exceptions. Any exceptions from the <> after it has +been submitted are handled by passing <> at specific times to an +<>, as described in <>. + +A SYCL [code]#queue# can wait for all <> that it has +submitted by calling [code]#wait# or [code]#wait_and_throw#. + +The default constructor of the SYCL [code]#queue# class will +construct a queue based on the SYCL [code]#device# returned from +the [code]#default_selector_v# (see <>). +All other constructors construct a queue as determined by the +parameters provided. All constructors will implicitly construct a SYCL +[code]#platform#, [code]#device# and [code]#context# in order to +facilitate the construction of the queue. + +Each constructor takes as the last +parameter an optional SYCL [code]#property_list# to provide properties to +the SYCL [code]#queue#. + +The SYCL [code]#queue# class provides the common reference semantics +(see <>). + + +==== Queue interface + +A synopsis of the SYCL [code]#queue# class is provided below. The +constructors and member functions of the SYCL [code]#queue# class are +listed in <> and <> +respectively. The additional common special member functions and common member +functions are listed in <> in +<> and +<>, respectively. + +Some queue member functions are shortcuts to member functions of the [code]#handler# class. +These are listed in <>. + +// Interface for class: queue +[source,,linenums] +---- +include::{header_dir}/queue.h[lines=4..-1] +---- + + +[[table.constructors.queue]] +.Constructors of the [code]#queue# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Constructor @ Description +a@ +[source] +---- +explicit queue(const property_list &propList = {}) +---- +a@ Constructs a SYCL [code]#queue# instance using the device +constructed from the [code]#default_selector_v#. +Zero or more properties can +be provided to the constructed SYCL [code]#queue# via an instance of +[code]#property_list#. + +a@ +[source] +---- +explicit queue(const async_handler &asyncHandler, + const property_list &propList = {}) +---- +a@ Constructs a SYCL [code]#queue# instance with an +[code]#async_handler# using the device constructed from the +[code]#default_selector_v#. +Zero or more properties can be provided to the +constructed SYCL [code]#queue# via an instance of +[code]#property_list#. + +a@ +[source] +---- +template +explicit queue(const DeviceSelector &deviceSelector, + const property_list &propList = {}) +---- +a@ Constructs a SYCL [code]#queue# instance using the device +returned by the <> provided. Zero or +more properties can be provided to the constructed SYCL +[code]#queue# via an instance of +[code]#property_list#. + +a@ +[source] +---- +template +explicit queue(const DeviceSelector &deviceSelector, + const async_handler &asyncHandler, + const property_list &propList = {}) +---- +a@ Constructs a SYCL [code]#queue# instance with an +[code]#async_handler# using the device returned by the +<> provided. Zero or more properties +can be provided to the constructed SYCL [code]#queue# via +an instance of [code]#property_list#. + +a@ +[source] +---- +explicit queue(const device &syclDevice, + const property_list &propList = {}) +---- +a@ Constructs a SYCL [code]#queue# instance using the [code]#syclDevice# provided. Zero or more properties can be provided to the +constructed SYCL [code]#queue# via an instance of [code]#property_list#. + +a@ +[source] +---- +explicit queue(const device &syclDevice, + const async_handler &asyncHandler, + const property_list &propList = {}) +---- +a@ Constructs a SYCL [code]#queue# instance with an [code]#async_handler# using the [code]#syclDevice# provided. Zero or more +properties can be provided to the constructed SYCL [code]#queue# +via an instance of [code]#property_list#. + +a@ +[source] +---- +template +explicit queue(const context &syclContext, + const DeviceSelector &deviceSelector, + const property_list &propList = {}) +---- +a@ Constructs a SYCL [code]#queue# instance that is associated +with the [code]#syclContext# provided, using the device +returned by the <> provided. Must +throw an [code]#exception# with the +[code]#errc::invalid# error code if +[code]#syclContext# does not encapsulate the SYCL +[code]#device# returned by +[code]#deviceSelector#. Zero or more properties can be +provided to the constructed SYCL [code]#queue# via an +instance of [code]#property_list#. + +a@ +[source] +---- +template +explicit queue(const context &syclContext, + const DeviceSelector &deviceSelector, + const async_handler &asyncHandler, + const property_list &propList = {}) +---- +a@ Constructs a SYCL [code]#queue# instance with an +[code]#async_handler# that is associated with the +[code]#syclContext# provided, using the device returned by +the <> provided. Must throw an +[code]#exception# with the +[code]#errc::invalid# error code if +[code]#syclContext# does not encapsulate the SYCL +[code]#device# returned by +[code]#deviceSelector#. Zero or more properties can be +provided to the constructed SYCL [code]#queue# via an +instance of [code]#property_list#. + +a@ +[source] +---- +explicit queue(const context &syclContext, + const device &syclDevice, + const property_list &propList = {}) +---- +a@ Constructs a SYCL [code]#queue# instance using the [code]#syclDevice# provided, and associated with the +[code]#syclContext# provided. Must throw an +[code]#exception# with the +[code]#errc::invalid# error code if +[code]#syclContext# does not encapsulate the SYCL +[code]#device# [code]#syclDevice#. Zero or more +properties can be provided to the constructed SYCL [code]#queue# +via an instance of [code]#property_list#. + +a@ +[source] +---- +explicit queue(const context &syclContext, + const device &syclDevice, + const async_handler &asyncHandler, + const property_list &propList = {}) +---- +a@ Constructs a SYCL [code]#queue# instance with an [code]#async_handler# using the [code]#syclDevice# provided, and +associated with the [code]#syclContext# provided. Must throw an +[code]#exception# with the +[code]#errc::invalid# error code if +[code]#syclContext# does not encapsulate the SYCL +[code]#device# [code]#syclDevice#. Zero or more +properties can be provided to the constructed SYCL [code]#queue# via +an instance of [code]#property_list#. + +|==== + + + +[[table.members.queue]] +.Member functions for [code]#queue# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +backend get_backend() const noexcept +---- +a@ Returns a [code]#backend# identifying the <> associated +with this [code]#queue#. + +a@ +[source] +---- +context get_context () const +---- +a@ Returns the SYCL queue's context. +Reports errors using SYCL exception classes. +The value returned must be equal to that returned by [code]#get_info()#. + +a@ +[source] +---- +device get_device () const +---- +a@ Returns the SYCL device the queue is associated with. +Reports errors using SYCL exception classes. +The value returned must be equal to that returned by [code]#get_info()#. + +a@ +[source] +---- +bool is_in_order() const +---- +a@ Returns true if the SYCL [code]#queue# was created with the +[code]#in_order# property. +Equivalent to [code]#has_property()#. + +a@ +[source] +---- +void wait() +---- +a@ Performs a blocking wait for the completion of all enqueued tasks +in the queue. Synchronous errors will be reported through SYCL +exceptions. + +a@ +[source] +---- +void wait_and_throw () +---- +a@ Performs a blocking wait for the completion of all enqueued tasks +in the queue. Synchronous errors will be reported through SYCL +exceptions. Any unconsumed <> will be passed to the +<> associated with the queue or enclosing context. +If no user defined [code]#async_handler# is associated with +the queue or enclosing context, then an implementation-defined +default <> is called to handle any errors, as +described in <>. + +a@ +[source] +---- +void throw_asynchronous () +---- +a@ Checks to see if any unconsumed <> have been produced by +the queue and if so reports them by passing them to the +<> associated with the queue or enclosing context. +If no user defined [code]#async_handler# is associated with +the queue or enclosing context, then an implementation-defined +default <> is called to handle any errors, as +described in <>. + +a@ +[source] +---- +template +typename param::return_type get_info() const +---- + a@ Queries this SYCL [code]#queue# for information requested by the + template parameter [code]#param#. + The type alias [code]#param::return_type# must be defined in + accordance with the info parameters in <> to + facilitate returning the type associated with the [code]#param# + parameter. + +a@ +[source] +---- +template +event submit(T cgf) +---- +a@ Submit a <> to the queue, in order to be scheduled +for execution on the device. + +a@ +[source] +---- +template +event submit(T cgf, queue & secondaryQueue) +---- +a@ Submit a <> to the queue, in order to be scheduled +for execution on the device. On a kernel error, this <> +is then scheduled for execution on the secondary queue. Returns an +event, which corresponds to the queue the <> +is being enqueued on. + +a@ +[source] +---- +template +typename param::return_type get_backend_info() const +---- +a@ Queries this SYCL [code]#queue# for <>-specific information +requested by the template parameter [code]#param#. + The type alias [code]#param::return_type# must be defined in + accordance with the <> specification. + Must throw an [code]#exception# with the [code]#errc::backend_mismatch# + error code if the <> that corresponds with [code]#param# is different + from the <> that is associated with this [code]#queue#. + +|==== + + +[[sec:queue-shortcuts]] +==== Queue shortcut functions + +Queue shortcut functions are member functions of the [code]#queue# class +that implicitly create a command group with an implicit command group [code]#handler# +consisting of a single command, +a call to the member function of the handler object with the same signature +(e.g. [code]#queue::single_task# will call [code]#handler::single_task# with the same arguments), +and submit the command group. +The main signature difference comes from the return type: +member functions of the [code]#handler# return [code]#void#, +whereas corresponding queue shortcut functions return an [code]#event# object +that represents the submitted command group. +Queue shortcuts can additionally take a list of events to wait on, +as if passing the event list to [code]#handler::depends_on# for the implicit command group. + +The full list of queue shortcuts is defined in <>. +The list of handler member functions is defined in <>. + +It is not allowed to capture accessors into the implicitly created command group. +If a queue shortcut function launches a kernel +(via [code]#single_task# or [code]#parallel_for#), +only USM pointers are allowed inside such kernels. +However, queue shortcuts that perform non-kernel operations +can be provided with a valid placeholder accessor as an argument. +In that case there is an additional step performed: +the implicit command group [code]#handler# calls [code]#handler::require# +on each accessor passed in as a function argument. + +An example of using queue shortcuts is shown below. + +[[example.queue.shortcuts]] +[source,,linenums] +---- +include::{code_dir}/queueShortcuts.cpp[lines=4..-1] +---- + +[[table.queue.shortcuts]] +.Queue shortcut functions +[width="100%",options="header",separator="@",cols="80%,20%"] +|==== +@ Function definition @ Function type +a@ +[source] +---- +template +event single_task(const KernelType &kernelFunc) +---- +a@ <> +a@ +[source] +---- +template +event single_task(event depEvent, + const KernelType &kernelFunc) +---- +a@ <> +a@ +[source] +---- +template +event single_task(const std::vector &depEvents, + const KernelType &kernelFunc) +---- +a@ <> +a@ +[source] +---- +template +event parallel_for(range numWorkItems, + Rest&&... rest) +---- +a@ <> +a@ +[source] +---- +template +event parallel_for(range numWorkItems, + event depEvent, + Rest&&... rest) +---- +a@ <> +a@ +[source] +---- +template +event parallel_for(range numWorkItems, + const std::vector &depEvents, + Rest&&... rest) +---- +a@ <> +a@ +[source] +---- +template +event parallel_for(nd_range executionRange, + Rest&&... rest) +---- +a@ <> +a@ +[source] +---- +template +event parallel_for(nd_range executionRange, + event depEvent, + Rest&&... rest) +---- +a@ <> +a@ +[source] +---- +template +event parallel_for(nd_range executionRange, + const std::vector &depEvents, + Rest&&... rest) +---- +a@ <> +a@ +[source] +---- +event memcpy(void* dest, const void* src, size_t numBytes) +---- +a@ <> +a@ +[source] +---- +event memcpy(void* dest, const void* src, size_t numBytes, + event depEvent) +---- +a@ <> +a@ +[source] +---- +event memcpy(void* dest, const void* src, size_t numBytes, + const std::vector &depEvents) +---- +a@ <> +a@ +[source] +---- +template +event copy(T* dest, const T* src, size_t count) +---- +a@ <> +a@ +[source] +---- +template +event copy(T* dest, const T* src, size_t count, + event depEvent) +---- +a@ <> +a@ +[source] +---- +template +event copy(T* dest, const T* src, size_t count, + const std::vector &depEvents) +---- +a@ <> +a@ +[source] +---- +event memset(void* ptr, int value, size_t numBytes) +---- +a@ <> +a@ +[source] +---- +event memset(void* ptr, int value, size_t numBytes, + event depEvent) +---- +a@ <> +a@ +[source] +---- +event memset(void* ptr, int value, size_t numBytes, + const std::vector &depEvents) +---- +a@ <> +a@ +[source] +---- +template +event fill(void* ptr, const T& pattern, size_t count) +---- +a@ <> +a@ +[source] +---- +template +event fill(void* ptr, const T& pattern, size_t count, + event depEvent) +---- +a@ <> +a@ +[source] +---- +template +event fill(void* ptr, const T& pattern, size_t count, + const std::vector &depEvents) +---- +a@ <> +a@ +[source] +---- +event prefetch(void* ptr, size_t numBytes) +---- +a@ <> +a@ +[source] +---- +event prefetch(void* ptr, size_t numBytes, + event depEvent) +---- +a@ <> +a@ +[source] +---- +event prefetch(void* ptr, size_t numBytes, + const std::vector &depEvents) +---- +a@ <> +a@ +[source] +---- +event mem_advise(void* ptr, size_t numBytes, int advice) +---- +a@ <> +a@ +[source] +---- +event mem_advise(void* ptr, size_t numBytes, int advice, + event depEvent) +---- +a@ <> +a@ +[source] +---- +event mem_advise(void* ptr, size_t numBytes, int advice, + const std::vector &depEvents) +---- +a@ <> +a@ +[source] +---- +template +event copy(accessor src, + std::shared_ptr dest); +---- +a@ <> +a@ +[source] +---- +template +event +copy(std::shared_ptr src, + accessor dest); +---- +a@ <> +a@ +[source] +---- +template +event copy(accessor src, + T_dest *dest); +---- +a@ <> +a@ +[source] +---- +template +event +copy(const T_src *src, + accessor dest); +---- +a@ <> +a@ +[source] +---- +template +event copy( + accessor src, + accessor dest); +---- +a@ <> +a@ +[source] +---- + template + event update_host(accessor acc); +---- +a@ <> +a@ +[source] +---- + template + event fill(accessor dest, const T &src); +---- +a@ <> + +|==== + + +==== Queue information descriptors + +A <> can be queried for information using the [code]#get_info# +member function of the [code]#queue# class, specifying one of the info +parameters in [code]#info::queue#. Every <> +must produce a valid value for each info parameter. The possible values for +each info parameter and any restriction are defined in the specification of +the <> associated with the <>. All info parameters in +[code]#info::queue# are specified in <> and the synopsis +for [code]#info::queue# is described in <>. + +[[table.queue.info]] +.Queue information descriptors +[width="100%",options="header",separator="@",cols="37%,19%,44%"] +|==== +@ Queue Descriptors @ Return type @ Description +a@ +[source] +---- +info::queue::context +---- + + @ [.code]#context# + a@ Returns the SYCL [code]#context# associated with this SYCL [code]#queue#. + +a@ +[source] +---- +info::queue::device +---- + + @ [.code]#device# + a@ Returns the SYCL <> associated with this SYCL [code]#queue#. + +|==== + + +[[sec:queue-properties]] +==== Queue properties + +The properties that can be provided when constructing the SYCL +[code]#queue# class are describe in +<>. + + +[[table.properties.queue]] +.Properties supported by the SYCL [code]#queue# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Property @ Description +a@ +[source] +---- +property::queue::enable_profiling +---- + a@ The [code]#enable_profiling# property adds the requirement + that the <> must capture profiling information for + the <> that are submitted from this SYCL + [code]#queue# and provide said information via the SYCL + [code]#event# class [code]#get_profiling_info# member + function, if the associated SYCL [code]#device# has + [code]#aspect::queue_profiling#. + +a@ +[source] +---- +property::queue::in_order +---- + a@ The [code]#in_order# property adds the requirement that + the SYCL [code]#queue# provides in-order semantics where + tasks are executed in the order in which they are submitted. + Tasks submitted in this fashion can be viewed as having an + implicit dependence on the previously submitted operation. + +|==== + + +The constructors of the [code]#queue# [code]#property# +classes are listed in <>. + + +[[table.constructors.properties.queue]] +.Constructors of the [code]#queue# [code]#property# classes +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Constructor @ Description +a@ +[source] +---- +property::queue::enable_profiling::enable_profiling() +---- + a@ Constructs a SYCL [code]#enable_profiling# property instance. + +a@ +[source] +---- +property::queue::in_order::in_order() +---- + a@ Constructs a SYCL [code]#in_order# property instance. + +|==== + + + +[[sec:interface.queue.errors]] +==== Queue error handling + +Queue errors come in two forms: + + * *Synchronous Errors* are those that we would expect to be + reported directly at the point of waiting on an event, and hence waiting + for a queue to complete, as well as any immediate errors reported by + enqueuing work onto a queue. Such errors are reported through {cpp} + exceptions. + * <> are those that are produced or detected after + associated host API calls have returned (so can't be thrown as + exceptions by the API call), and that are handled by an + <> through which the errors are reported. Handling of + asynchronous errors from a queue occurs at specific times, as described + by <>. + +Note that if there are <> to be processed when a queue +is destructed, the handler is called and +this might delay or block the destruction, according to the behavior +of the handler. + + +// %%%%%%%%%%%%%%%%%%%%%%%%%%%% end queue_class %%%%%%%%%%%%%%%%%%%%%%%%%%%% + +[[sec:interface.event]] +=== Event class + +An <> in SYCL is an object that represents the status of an operation +that is being executed by the SYCL runtime. + +Typically in SYCL, data dependency and execution order is handled implicitly by +the SYCL runtime. However, in some circumstances developers want fine grain control +of the execution, or want to retrieve properties of a command that is running. + +Note that, although an event represents the status of a particular operation, +the dependencies of a certain event can be used to keep track of multiple steps +required to synchronize said operation. + +A SYCL event is returned by the submission of a <>. +The dependencies of the event returned via the submission of the command group +are the implementation-defined commands associated with the <> +execution. + +The SYCL [code]#event# class provides the common reference semantics +(see <>). + +The constructors and member functions of the SYCL [code]#event# class +are listed in <> and +<>, respectively. The additional common special +member functions and common member functions are listed in +<> and +<>, respectively. + +// Interface for class: event.h +[source,,linenums] +---- +include::{header_dir}/event.h[lines=4..-1] +---- + + +[[table.constructors.event]] +.Constructors of the [code]#event# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Constructor @ Description +a@ +[source] +---- +event () +---- + a@ Constructs an [code]#event# that is immediately ready. The + [code]#event# has no dependencies and no associated commands. + Waiting on this [code]#event# will return immediately and querying + its status will return [code]#info::event_command_status::complete#. + +The event is constructed as though it was created from a default-constructed +[code]#queue#. Therefore, its backend is the same as the backend from the +default device. + +|==== + + + +[[table.members.event]] +.Member functions for the [code]#event# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +backend get_backend() const noexcept +---- + a@ Returns a [code]#backend# identifying the <> associated + with this [code]#event#. + +a@ +[source] +---- +std::vector get_wait_list() +---- + a@ Return the list of events that this event waits for in + the dependence graph. Only direct dependencies are returned, + and not transitive dependencies that direct dependencies wait on. + Whether already completed events are included in the returned list + is implementation-defined. + +a@ +[source] +---- +void wait() +---- + a@ Wait for the event and the command associated with + it to complete. + +a@ +[source] +---- +void wait_and_throw() +---- + a@ Wait for the event and the command associated with + it to complete. + +Any unconsumed <> from any context that the event +was waiting on executions from will be passed to the +<> associated with the context. +If no user defined [code]#async_handler# is associated with +the context, then an implementation-defined +default <> is called to handle any errors, as +described in <>. + +a@ +[source] +---- +static void wait( + const std::vector &eventList) +---- + a@ Synchronously wait on a list of events. + +a@ +[source] +---- +static void wait_and_throw( + const std::vector &eventList) +---- + a@ Synchronously wait on a list of events. + +Any unconsumed <> from any context that the event +was waiting on executions from will be passed to the +<> associated with the context. +If no user defined [code]#async_handler# is associated with +the context, then an implementation-defined +default <> is called to handle any errors, as +described in <>. + +a@ +[source] +---- +template typename param::return_type get_info() const +---- + a@ Queries this SYCL [code]#event# for information requested by the + template parameter [code]#param#. + The type alias [code]#param::return_type# must be defined in + accordance with the info parameters in <> to + facilitate returning the type associated with the [code]#param# + parameter. + +a@ +[source] +---- +template +typename param::return_type get_backend_info() const +---- + a@ Queries this SYCL [code]#event# for <>-specific information + requested by the template parameter [code]#param#. + The type alias [code]#param::return_type# must be defined in + accordance with the <> specification. + Must throw an [code]#exception# with the [code]#errc::backend_mismatch# + error code if the <> that corresponds with [code]#param# is different + from the <> that is associated with this [code]#event#. + +a@ +[source] +---- +template +typename param::return_type get_profiling_info () const +---- + a@ Queries this SYCL [code]#event# for profiling information requested + by the parameter [code]#param#. If the requested profiling information + is unavailable when [code]#get_profiling_info# is called due to + incompletion of <> associated with the [code]#event#, + then the call to [code]#get_profiling_info# will block until + the requested profiling information is available. An example is asking for + [code]#info::event_profiling::command_end# when the associated + <> action has yet to finish execution. + Calls to [code]#get_profiling_info# must throw an [code]#exception# + with the [code]#errc::invalid# error code if the SYCL + [code]#queue# which submitted the <> this + SYCL [code]#event# is associated with was not constructed with + the [code]#property::queue::enable_profiling# property. + The type alias [code]#param::return_type# must be defined in + accordance with the info parameters in + <> to facilitate returning the type + associated with the [code]#param# parameter. + +|==== + + +==== Event information and profiling descriptors + +An <> can be queried for information using the [code]#get_info# +member function of the [code]#event# class, specifying one of the info +parameters in [code]#info::event#. Every <> +must produce a valid value for each info parameter. The possible values for +each info parameter and any restrictions are defined in the specification +of the <> associated with the <>. All info parameters in +[code]#info::event# are specified in <> and the synopsis +for [code]#info::event# is described in <>. + + +[[table.event.info]] +.Event class information descriptors +[width="100%",options="header",separator="@",cols="37%,19%,44%"] +|==== +@ Event Descriptors @ Return type @ Description +a@ +[source] +---- +info::event::command_execution_status +---- + + @ [.code]#info::event_command_status# + a@ Returns the event status of the command group and contained action + (e.g. kernel invocation) associated with this SYCL [code]#event#. + +|==== + + +An <> can be queried for profiling information using the +[code]#get_profiling_info# member function of the [code]#event# class, +specifying one of the profiling info parameters enumerated in +[code]#info::event_profiling#. Every <> must produce a valid value +for each info parameter. The possible values for each info parameter and +any restrictions are defined in the specification of the <> +associated with the <>. All info parameters in +[code]#info::event_profiling# are specified in <> +and the synopsis for [code]#info::event_profiling# is described in +<>. + + +[[table.event.profilinginfo]] +.Profiling information descriptors for the SYCL [code]#event# class +[width="100%",options="header",separator="@",cols="37%,19%,44%"] +|==== +@ Event information profiling descriptor @ Return type @ Description +a@ +[source] +---- +info::event_profiling::command_submit +---- + + @ [.code]#uint64_t# + a@ Returns an implementation-defined 64-bit value describing the time in + nanoseconds when the associated <> was submitted to + the [code]#queue#. + +a@ +[source] +---- +info::event_profiling::command_start +---- + + @ [.code]#uint64_t# + a@ Returns an implementation-defined 64-bit value describing the time in + nanoseconds when the action associated with the <> + (e.g. kernel invocation) started executing on the device. + +a@ +[source] +---- +info::event_profiling::command_end +---- + + @ [.code]#uint64_t# + a@ Returns an implementation-defined 64-bit value describing the time in + nanoseconds when the action associated with the <> + (e.g. kernel invocation) finished executing on the device. + + +|==== + + + +[[sec:data.access.and.storage]] +== Data access and storage in SYCL + +In SYCL, when using <> and <>, +data storage and access are handled by separate classes. +<> and <> handle +storage and ownership of the data, whereas <> handle access to +the data. +Buffers and images in SYCL can be bound to more than one device or context, +including across different <>. +They also handle ownership of the +data, while allowing exception handling for blocking +and non-blocking data transfers. Accessors manage data transfers between the host +and all of the devices in the system, as well as tracking of data dependencies. + +When using <> allocations, data storage is managed by USM allocation functions, and +data access is via pointers. See <> for greater detail. + +=== Host allocation + +A <> may need to allocate temporary objects on the host +to handle some operations (such as copying data from one context to +another). +Allocation on the host is managed using an allocator object, following the +standard {cpp} allocator class definition. +The default allocator for memory objects is implementation-defined, +but the user can supply their own allocator class. + +[source,,linenums] +---- +{ + buffer > b(d); +} +---- + +When an allocator returns a [code]#nullptr#, the runtime cannot allocate data on the +host. Note that in this case the runtime will raise an error if it requires +host memory but it is not available (e.g when moving data across <> +contexts). + +The definition of allocators extends the current functionality of SYCL, +ensuring that users can define allocator functions for specific hardware or +certain complex shared memory mechanisms (e.g. NUMA), and improves +interoperability with STL-based libraries (e.g, Intel's TBB provides an +allocator). + + +[[subsec:default.allocators]] +==== Default allocators + +A default allocator is always defined by the implementation, and it is +guaranteed to return non-[code]#nullptr# and new memory positions every call. +The default allocator for const buffers will remove the const-ness of the +type (therefore, the default allocator for a buffer of type [code]#const int# +will be an [code]#Allocator)#. +This implies that host <> will not synchronize with the pointer given +by the user in the buffer/image constructor, but will use the memory +returned by the [code]#Allocator# itself for that purpose. +The user can implement an allocator that returns the same address as the +one passed in the buffer constructor, but it is the responsibility of the +user to handle the potential race conditions. + + +[[table.default.allocators]] +.SYCL Default Allocators +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Allocators @ Description +a@ +[source] +---- +template +buffer_allocator +---- + a@ It is the default buffer allocator used by the runtime, when no allocator is + defined by the user. + Meets the C++ named requirement [code]#Allocator#. + A buffer of data type [code]#const T# uses [code]#buffer_allocator# by default. + +a@ +[source] +---- +image_allocator +---- + a@ It is the default allocator used by the runtime for the SYCL [code]#unsampled_image# and [code]#sampled_image# classes when no allocator is provided by the user. + The [code]#image_allocator# is required to allocate in elements of [code]#std::byte#. + +|==== + + +See <> for details on manual host-device synchronization. + + +[[subsec:buffers]] +=== Buffers + +The [code]#buffer# class defines a shared array of one, two or three +dimensions that can be used by the SYCL <> and has to be accessed using +<> classes. Buffers are templated on both the type of their data, +and the number of dimensions that the data is stored and accessed through. + +A [code]#buffer# does not map to only one underlying backend +object, and all <> memory objects may be temporary for use +within a command group on a specific device. + +The underlying data type of a buffer [code]#T# must be <> as +defined in <>. Some overloads of the [code]#buffer# +constructor initialize the buffer contents by copying objects from host memory +while other overloads construct the buffer without copying objects from the +host. For the overloads that do not copy host objects, the initial state of +the objects in the buffer depends on whether [code]#T# is an implicit-lifetime +type (as defined in the {cpp} core language). If [code]#T# is an +implicit-lifetime type, objects of that type are implicitly created in the +buffer with indeterminate values. For other types, these constructor overloads +merely allocate uninitialized memory, and the application is responsible for +constructing objects by calling placement-new and for destroying them later +by manually calling the object's destructor. + +A SYCL [code]#buffer# can construct an instance of a SYCL [code]#buffer# +that reinterprets the original SYCL [code]#buffer# with a different +type, dimensionality and range using the member function +[code]#reinterpret#. The reinterpreted SYCL [code]#buffer# that is +constructed must behave as though it were a copy of the SYCL [code]#buffer# +that constructed it (see <>) with the exception +that the type, dimensionality and range of the reinterpreted SYCL +[code]#buffer# must reflect the type, dimensionality and range specified +when calling the [code]#reinterpret# member function. By extension of this, +the class member types [code]#value_type#, [code]#reference# and +[code]#const_reference#, and the member functions [code]#get_range()# +and [code]#size()# of the reinterpreted SYCL [code]#buffer# must +reflect the new type, dimensionality and range. The data that the original SYCL +[code]#buffer# and the reinterpreted SYCL [code]#buffer# manage +remains unaffected, though the representation of the data when accessed through +the reinterpreted SYCL [code]#buffer# may alter to reflect the new type, +dimensionality and range. It is important to note that a reinterpreted SYCL +[code]#buffer# is a copy of the original SYCL [code]#buffer# only, +and not a new SYCL [code]#buffer#. Constructing more than one SYCL +[code]#buffer# managing the same host pointer is still undefined behavior. + +The SYCL [code]#buffer# class template provides the common reference +semantics (see <>). + + +==== Buffer interface + +The constructors and member functions of the SYCL [code]#buffer# class +template are listed in <> and +<>, respectively. The additional common special +member functions and common member functions are listed in +<> and +<>, respectively. + +Each constructor takes as the last parameter an optional SYCL +[code]#property_list# to provide properties to the SYCL +[code]#buffer#. + +The SYCL [code]#buffer# class template takes a template parameter +[code]#AllocatorT# for specifying an allocator which is used by +the <> when allocating temporary memory on the +host. If no template argument is provided, then the default allocator +for the SYCL [code]#buffer# class [code]#buffer_allocator# +will be used (see <>). + +// Interface for class: buffer + +[source,,linenums] +---- +include::{header_dir}/buffer.h[lines=4..-1] +---- + + +[[table.constructors.buffer]] +.Constructors of the [code]#buffer# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Constructor @ Description +a@ +[source] +---- +buffer(const range & bufferRange, +const property_list &propList = {}) +---- + a@ Construct a SYCL [code]#buffer# instance with uninitialized memory. + The constructed SYCL [code]#buffer# will use a default constructed [code]#AllocatorT# when allocating memory on the host. + The range of the constructed SYCL [code]#buffer# is specified by the [code]#bufferRange# parameter provided. + Data is not written back to the host on destruction of the [code]#buffer# unless the [code]#buffer# has a valid non-null pointer specified via the member function [code]#set_final_data()#. + Zero or more properties can be provided to the constructed SYCL [code]#buffer# via an instance of [code]#property_list#. + +a@ +[source] +---- +buffer(const range & bufferRange, +AllocatorT allocator, + const property_list &propList = {}) +---- + a@ Construct a SYCL [code]#buffer# instance with uninitialized memory. + The constructed SYCL [code]#buffer# will use the [code]#allocator# parameter provided when allocating memory on the host. + The range of the constructed SYCL [code]#buffer# is specified by the [code]#bufferRange# parameter provided. + Data is not written back to the host on destruction of the [code]#buffer# unless the [code]#buffer# has a valid non-null pointer specified via the member function [code]#set_final_data()#. + Zero or more properties can be provided to the constructed SYCL [code]#buffer# via an instance of [code]#property_list#. + +a@ +[source] +---- +buffer(T* hostData, +const range & bufferRange, + const property_list &propList = {}) +---- + a@ Construct a SYCL [code]#buffer# instance with the [code]#hostData# parameter provided. + The buffer is initialized with the memory specified by [code]#hostData#. + The ownership of this memory is given to the constructed SYCL [code]#buffer# for the duration of its lifetime. + The constructed SYCL [code]#buffer# will use a default constructed [code]#AllocatorT# when allocating memory on the host. + The range of the constructed SYCL [code]#buffer# is specified by the [code]#bufferRange# parameter provided. + Zero or more properties can be provided to the constructed SYCL [code]#buffer# via an instance of [code]#property_list#. + +a@ +[source] +---- +buffer(T* hostData, +const range & bufferRange, + AllocatorT allocator, + const property_list &propList = {}) +---- + a@ Construct a SYCL [code]#buffer# instance with the [code]#hostData# parameter provided. + The buffer is initialized with the memory specified by [code]#hostData#. + The ownership of this memory is given to the constructed SYCL [code]#buffer# for the duration of its lifetime. + The constructed SYCL [code]#buffer# will use the [code]#allocator# parameter provided when allocating memory on the host. + The range of the constructed SYCL [code]#buffer# is specified by the [code]#bufferRange# parameter provided. + Zero or more properties can be provided to the constructed SYCL [code]#buffer# via an instance of [code]#property_list#. + +a@ +[source] +---- +buffer(const T* hostData, +const range & bufferRange, + const property_list &propList = {}) +---- + a@ Construct a SYCL [code]#buffer# instance with the + [code]#hostData# parameter provided. The ownership of this + memory is given to the constructed SYCL [code]#buffer# for + the duration of its lifetime. + +The constructed SYCL [code]#buffer# will use a default +constructed [code]#AllocatorT# when allocating memory on +the host. + +The host address is [code]#const T#, so the host accesses +can be read-only. However, the [code]#typename T# is not const so +the device accesses can be both read and write accesses. Since +the [code]#hostData# is const, this buffer is only initialized with +this memory and there is no write back after its destruction, +unless the [code]#buffer# has another valid non-null final +data address specified via the member function +[code]#set_final_data()# after construction of the +[code]#buffer#. + +The range of the constructed SYCL [code]#buffer# is +specified by the [code]#bufferRange# parameter provided. + +Zero or more properties can be provided to the constructed SYCL +[code]#buffer# via an instance of +[code]#property_list#. + +a@ +[source] +---- +buffer(const T* hostData, +const range & bufferRange, + AllocatorT allocator, + const property_list &propList = {}) +---- + a@ Construct a SYCL [code]#buffer# instance with the + [code]#hostData# parameter provided. The ownership of this + memory is given to the constructed SYCL [code]#buffer# for + the duration of its lifetime. + +The constructed SYCL [code]#buffer# will use the +[code]#allocator# parameter provided when allocating +memory on the host. + +The host address is [code]#const T#, so the host accesses +can be read-only. However, the [code]#typename T# is not const so +the device accesses can be both read and write accesses. Since, +the [code]#hostData# is const, this buffer is only initialized +with this memory and there is no write back after its +destruction, unless the [code]#buffer# has another valid +non-null final data address specified via the member function +[code]#set_final_data()# after construction of the +[code]#buffer#. + +The range of the constructed SYCL [code]#buffer# is +specified by the [code]#bufferRange# parameter provided. + +Zero or more properties can be provided to the constructed SYCL +[code]#buffer# via an instance of +[code]#property_list#. + + +a@ +[source] +---- +template +buffer(Container &container, + const property_list &propList = {}) +---- + a@ Construct a one dimensional SYCL [code]#buffer# instance + from the elements starting at [code]#std::data(container)# + and containing [code]#std::size(container)# number of elements. + The buffer is initialized with the contents of [code]#container#, + and the ownership of this [code]#Container# is given to the + constructed SYCL [code]#buffer# for + the duration of its lifetime. + +Data is written back to [code]#container# before the completion of +[code]#buffer# destruction if the return type of [code]#std::data(container)# +is not [code]#const#. + +The constructed SYCL [code]#buffer# will use a default constructed [code]#AllocatorT# when allocating memory on the host. + +Zero or more properties can be provided to the constructed SYCL +[code]#buffer# via an instance of +[code]#property_list#. + +This constructor is only defined for a [code]#buffer# parameterized +with [code]#dimensions == 1#, and when [code]#std::data(container)# +is convertible to [code]#T*#. + + +a@ +[source] +---- +template +buffer(Container &container, + AllocatorT allocator, + const property_list &propList = {}) +---- + a@ Construct a one dimensional SYCL [code]#buffer# instance + from the elements starting at [code]#std::data(container)# + and containing [code]#std::size(container)# number of elements. + The buffer is initialized with the contents of [code]#container#, + and the ownership of this [code]#Container# is given to the + constructed SYCL [code]#buffer# for + the duration of its lifetime. + +Data is written back to [code]#container# before the completion of +[code]#buffer# destruction if the return type of [code]#std::data(container)# +is not [code]#const#. + +The constructed SYCL [code]#buffer# will use the [code]#allocator# parameter provided when allocating memory on the host. + +Zero or more properties can be provided to the constructed SYCL +[code]#buffer# via an instance of +[code]#property_list#. + +This constructor is only defined for a [code]#buffer# parameterized +with [code]#dimensions == 1#, and when [code]#std::data(container)# +is convertible to [code]#T*#. + + +a@ +[source] +---- +buffer(const std::shared_ptr &hostData, +const range & bufferRange, + const property_list &propList = {}) +---- + a@ Construct a SYCL [code]#buffer# instance with the [code]#hostData# parameter provided. The ownership of this memory is given to the constructed SYCL [code]#buffer# for the duration of its lifetime. + The constructed SYCL [code]#buffer# will use a default constructed [code]#AllocatorT# when allocating memory on the host. + The range of the constructed SYCL [code]#buffer# is specified by the [code]#bufferRange# parameter provided. + Zero or more properties can be provided to the constructed SYCL [code]#buffer# via an instance of [code]#property_list#. + +a@ +[source] +---- +buffer(const std::shared_ptr &hostData, +const range & bufferRange, + AllocatorT allocator, + const property_list &propList = {}) +---- + a@ Construct a SYCL [code]#buffer# instance with the [code]#hostData# parameter provided. The ownership of this memory is given to the constructed SYCL [code]#buffer# for the duration of its lifetime. + The constructed SYCL [code]#buffer# will use the [code]#allocator# parameter provided when allocating memory on the host. + The range of the constructed SYCL [code]#buffer# is specified by the [code]#bufferRange# parameter provided. + Zero or more properties can be provided to the constructed SYCL [code]#buffer# via an instance of [code]#property_list#. + +a@ +[source,c++] +---- +buffer(const std::shared_ptr &hostData, +const range & bufferRange, + const property_list &propList = {}) +---- + a@ Construct a SYCL [code]#buffer# instance with the [code]#hostData# parameter provided. The ownership of this memory is given to the constructed SYCL [code]#buffer# for the duration of its lifetime. + The constructed SYCL [code]#buffer# will use a default constructed [code]#AllocatorT# when allocating memory on the host. + The range of the constructed SYCL [code]#buffer# is specified by the [code]#bufferRange# parameter provided. + Zero or more properties can be provided to the constructed SYCL [code]#buffer# via an instance of [code]#property_list#. + +a@ +[source,c++] +---- +buffer(const std::shared_ptr &hostData, +const range & bufferRange, + AllocatorT allocator, + const property_list &propList = {}) +---- + a@ Construct a SYCL [code]#buffer# instance with the [code]#hostData# parameter provided. The ownership of this memory is given to the constructed SYCL [code]#buffer# for the duration of its lifetime. + The constructed SYCL [code]#buffer# will use the [code]#allocator# parameter provided when allocating memory on the host. + The range of the constructed SYCL [code]#buffer# is specified by the [code]#bufferRange# parameter provided. + Zero or more properties can be provided to the constructed SYCL [code]#buffer# via an instance of [code]#property_list#. + +a@ +[source] +---- +template +buffer(InputIterator first, InputIterator last, + const property_list &propList = {}) +---- + a@ Create a new allocated 1D buffer initialized from the given elements + ranging from [code]#first# up to one before [code]#last#. + The data is copied to an intermediate memory position by the runtime. + Data is not written back to the same iterator set provided. However, if the [code]#buffer# has a valid non-const iterator specified via the member function [code]#set_final_data()#, data will be copied back to that iterator. + The constructed SYCL [code]#buffer# will use a default constructed [code]#AllocatorT# when allocating memory on the host. + Zero or more properties can be provided to the constructed SYCL [code]#buffer# via an instance of [code]#property_list#. + +a@ +[source] +---- +template +buffer(InputIterator first, InputIterator last, + AllocatorT allocator = {}, + const property_list &propList = {}) +---- + a@ Create a new allocated 1D buffer initialized from the given elements + ranging from [code]#first# up to one before [code]#last#. + The data is copied to an intermediate memory position by the runtime. + Data is not written back to the same iterator set provided. However, if the [code]#buffer# has a valid non-const iterator specified via the member function [code]#set_final_data()#, data will be copied back to that iterator. + The constructed SYCL [code]#buffer# will use the [code]#allocator# parameter provided when allocating memory on the host. + Zero or more properties can be provided to the constructed SYCL [code]#buffer# via an instance of [code]#property_list#. + +a@ +[source] +---- +buffer(buffer &b, const id &baseIndex, + const range &subRange) +---- + a@ Create a new sub-buffer without allocation to have separate + accessors later. [code]#b# is the buffer with the real data, which must not be a sub-buffer. + [code]#baseIndex# specifies the origin of the sub-buffer inside the + buffer [code]#b#. [code]#subRange# specifies the size of the sub-buffer. + The sum of [code]#baseIndex# and [code]#subRange# in any dimension must not + exceed the parent buffer ([code]#b)# size ([code]#bufferRange)# in that dimension, + and an [code]#exception# with the [code]#errc::invalid# error code must be thrown if violated. + +The offset and range specified by [code]#baseIndex# and +[code]#subRange# together must represent a contiguous +region of the original SYCL [code]#buffer#. + +If a non-contiguous region of a buffer is requested when +constructing a sub-buffer, then an [code]#exception# with +the [code]#errc::invalid# error code must be +thrown. + +The origin (based on [code]#baseIndex#) of the sub-buffer being constructed +must be a multiple of the memory base address alignment of each SYCL +[code]#device# which accesses data from the buffer. This value is retrievable +via the SYCL [code]#device# class info query +[code]#info::device::mem_base_addr_align#. Violating this requirement causes +the implementation to throw an [code]#exception# with the [code]#errc::invalid# +error code from the [code]#accessor# constructor (if the accessor is not a +placeholder) or from [code]#handler::require()# (if the accessor is a +placeholder). If the accessor is bound to a <> with a secondary +queue, the sub-buffer's alignment must be compatible with both the primary +queue's device and the secondary queue's device, otherwise this exception is +thrown. + +Must throw an [code]#exception# with the [code]#errc::invalid# error code if +[code]#b# is a sub-buffer. + +|==== + + + +[[table.members.buffer]] +.Member functions for the [code]#buffer# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +range get_range() const +---- + a@ Return a range object representing the + size of the buffer in terms of number + of elements in each dimension as passed + to the constructor. + +a@ +[source] +---- +size_t size() const noexcept +---- + a@ Returns the total number of elements in the buffer. + Equal to [code]#+get_range()[0] * ... * get_range()[dimensions-1]+#. +a@ +[source] +---- +size_t get_count() const +---- + a@ Returns the same value as [code]#size()#. Deprecated. +a@ +[source] +---- +size_t byte_size() const noexcept +---- + a@ Returns the size of the buffer storage in bytes. + Equal to [code]#size()*sizeof(T)#. +a@ +[source] +---- +size_t get_size() const +---- + a@ Returns the same value as [code]#byte_size()#. Deprecated. +a@ +[source] +---- +AllocatorT get_allocator() const +---- + a@ Returns the allocator provided to the buffer. + +a@ +[source] +---- +template +accessor + get_access(handler &commandGroupHandler) +---- + a@ Returns a valid [code]#accessor# to the buffer with the specified + access mode and target in the command group buffer. + The value of target can be [code]#target::device# or + [code]#target::constant_buffer#. + +a@ +[source] +---- +template +accessor + get_access() +---- + a@ Deprecated in SYCL 2020. Use [code]#get_host_access()# instead. + +Returns a valid host [code]#accessor# to the buffer with the specified +access mode and target. + +a@ +[source] +---- +template +accessor + get_access(handler &commandGroupHandler, + range accessRange, + id accessOffset = {}) +---- + a@ Returns a valid [code]#accessor# to the buffer with the specified access + mode and target in the command group buffer. The accessor is a + <>, where the range starts at the given offset from the + beginning of the buffer. The value of target can be + [code]#target::device# or [code]#target::constant_buffer#. + +Throws an [code]#exception# with the [code]#errc::invalid# error code if +the sum of [code]#accessRange# and [code]#accessOffset# exceeds the range of +the buffer in any dimension. + +a@ +[source] +---- +template +accessor + get_access(range accessRange, id accessOffset = {}) +---- + a@ Deprecated in SYCL 2020. Use [code]#get_host_access()# instead. + +Returns a valid host [code]#accessor# to the buffer with the specified access +mode and target. The accessor is a <>, where the range starts +at the given offset from the beginning of the buffer. The value of target can +only be [code]#target::host_buffer#. + +Throws an [code]#exception# with the [code]#errc::invalid# error code if +the sum of [code]#accessRange# and [code]#accessOffset# exceeds the range of +the buffer in any dimension. + +a@ +[source] +---- +template + auto get_access(Ts... args) +---- + a@ Returns a valid [code]#accessor# as if constructed via passing the buffer + and all provided arguments to the [code]#accessor# constructor. + +Possible implementation: + +[code]#+return accessor{*this, args...};+# + +a@ +[source] +---- +template + auto get_host_access(Ts... args) +---- + a@ Returns a valid [code]#host_accessor# as if constructed via passing the + buffer and all provided arguments to the [code]#host_accessor# + constructor. + +Possible implementation: + +[code]#+return host_accessor{*this, args...};+# + +a@ +[source] +---- +template + void set_final_data(Destination finalData = nullptr) +---- + a@ The [code]#finalData# points to where the outcome of all + the buffer processing is going to be copied to at destruction + time, if the buffer was involved with a write accessor. + +Destination can be either an output iterator or a +[code]#std::weak_ptr#. + +Note that a raw pointer is a special case of output iterator and +thus defines the host memory to which the result is to be +copied. + +In the case of a weak pointer, the output is not updated if the +weak pointer has expired. + +If [code]#Destination# is [code]#std::nullptr_t#, then +the copy back will not happen. + +a@ +[source] +---- +void set_write_back(bool flag = true) +---- + a@ This member function allows dynamically forcing or canceling the + write-back of the data of a buffer on destruction according to + the value of [code]#flag#. + +Forcing the write-back is similar to what happens during a +normal write-back as described in <> +and <>. + +If there is nowhere to write-back, using this function does not +have any effect. + +a@ +[source] +---- +bool is_sub_buffer() const +---- + a@ Returns true if this SYCL [code]#buffer# is a sub-buffer, otherwise + returns false. + +a@ +[source] +---- +template + buffer::template rebind_alloc< + ReinterpretT>> + reinterpret(range reinterpretRange) const +---- + a@ Creates and returns a reinterpreted SYCL [code]#buffer# + with the type specified by [code]#ReinterpretT#, + dimensions specified by [code]#ReinterpretDim# and range + specified by [code]#reinterpretRange#. The buffer object + being reinterpreted can be a SYCL sub-buffer that was created + from a SYCL [code]#buffer# and must throw + [code]#exception# with the + [code]#errc::invalid# error code if the total + size in bytes represented by the type and range of the + reinterpreted SYCL [code]#buffer# (or sub-buffer) does not + equal the total size in bytes represented by the type and range + of this SYCL [code]#buffer# (or sub-buffer). + Reinterpreting a sub-buffer provides a reinterpreted view of + the sub-buffer only, and does not change the offset or size of + the sub-buffer view (in bytes) relative to the parent + [code]#buffer#. + +a@ +[source] +---- +template + buffer::template rebind_alloc< + ReinterpretT>> + reinterpret() const +---- + a@ Creates and returns a reinterpreted SYCL [code]#buffer# + with the type specified by [code]#ReinterpretT# and + dimensions specified by [code]#ReinterpretDim#. + Only valid when [code]#(ReinterpretDim == 1)# or when + [code]#\((ReinterpretDim == dimensions) && (sizeof(ReinterpretT) == sizeof(T)))#. + The buffer object being reinterpreted can be a SYCL sub-buffer + that was created from a SYCL [code]#buffer# and + must throw an [code]#exception# with the [code]#errc::invalid# error code + if the total size in bytes represented by the type and range + of the reinterpreted SYCL [code]#buffer# (or sub-buffer) + does not equal the total size in bytes represented by the type and range + of this SYCL [code]#buffer# (or sub-buffer). + Reinterpreting a sub-buffer provides a reinterpreted view + of the sub-buffer only, + and does not change the offset or size of the sub-buffer view (in bytes) + relative to the parent [code]#buffer#. + +|==== + + + +[[sec:buffer-properties]] +==== Buffer properties + +The properties that can be provided when constructing the SYCL +[code]#buffer# class are describe in +<>. + + +[[table.properties.buffer]] +.Properties supported by the SYCL [code]#buffer# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Property @ Description +a@ +[source] +---- +property::buffer::use_host_ptr +---- + a@ The [code]#use_host_ptr# property adds the requirement that the <> must not allocate any memory for the SYCL [code]#buffer# and instead uses the provided host pointer directly. This prevents the <> from allocating additional temporary storage on the host. + +This property has a special guarantee for buffers that are constructed from a +[code]#hostData# pointer. If a [code]#host_accessor# is constructed from such +a buffer, then the address of the [code]#reference# type returned from the +accessor's member functions such as [code]#operator[](id<>)# will be the same +as the corresponding [code]#hostData# address. + +a@ +[source] +---- +property::buffer::use_mutex +---- + a@ The [code]#use_mutex# property is valid for the SYCL + [code]#buffer#, [code]#unsampled_image# and + [code]#sampled_image# classes. The property adds the + requirement that the memory which is owned by the SYCL + [code]#buffer# can be shared with the application via a + [code]#std::mutex# provided to the property. The mutex + [code]#m# is locked by the runtime whenever the data is in + use and unlocked otherwise. Data is synchronized with + [code]#hostData#, when the mutex is unlocked by the runtime. + +a@ +[source] +---- +property::buffer::context_bound +---- + a@ The [code]#context_bound# property adds the requirement that the SYCL [code]#buffer# can only be associated with a single SYCL [code]#context# that is provided to the property. + +|==== + + +The constructors and special member functions of the buffer property +classes are listed in +<> and +<> respectively. + + +[[table.constructors.properties.buffer]] +.Constructors of the [code]#buffer# [code]#property# classes +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Constructor @ Description +a@ +[source] +---- +property::buffer::use_host_ptr::use_host_ptr() +---- + a@ Constructs a SYCL [code]#use_host_ptr# property instance. + +a@ +[source] +---- +property::buffer::use_mutex::use_mutex(std::mutex &mutexRef) +---- + a@ Constructs a SYCL [code]#use_mutex# property instance with a reference to [code]#mutexRef# parameter provided. + +a@ +[source] +---- +property::buffer::context_bound::context_bound(context boundContext) +---- + a@ Constructs a SYCL [code]#context_bound# property instance with a copy of a SYCL [code]#context#. + +|==== + + + +[[table.members.properties.buffer]] +.Member functions of the [code]#buffer# [code]#property# classes +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +std::mutex *property::buffer::use_mutex::get_mutex_ptr() const +---- + a@ Returns the [code]#std::mutex# which was specified when + constructing this SYCL [code]#use_mutex# property. + +a@ +[source] +---- +context property::buffer::context_bound::get_context() const +---- + a@ Returns the [code]#context# which was specified when + constructing this SYCL [code]#context_bound# property. + +|==== + + + +[[sec:buf-sync-rules]] +==== Buffer synchronization rules + +Buffers are reference-counted. When a buffer value is constructed +from another buffer, the two values reference the same buffer and a +reference count is incremented. When a buffer value is destroyed, +the reference count is decremented. Only when there are no more +buffer values that reference a specific buffer is the actual +buffer destroyed and the buffer destruction behavior defined +below is followed. + +If any error occurs on buffer destruction, it is reported +via the associated queue's asynchronous error handling mechanism. + +The basic rule for the blocking behavior of a buffer destructor is +that it blocks if there is some data to write back because a +write accessor on it has been created, or if the buffer was constructed +with attached host memory and is still in use. + +More precisely: + + . A buffer can be constructed with just a size and using the default + buffer allocator. The memory management for this type of buffer is + entirely handled by the SYCL system. The destructor for this type of + buffer does not need to block, even if work on the buffer has not + completed. Instead, the SYCL system frees any storage required for the + buffer asynchronously when it is no longer in use in queues. The initial + contents of the buffer are unspecified. + . A buffer can be constructed with associated host memory and a default + buffer allocator. The buffer will use this host memory for its full + lifetime, but the contents of this host memory are unspecified for the + lifetime of the buffer. If the host memory is modified by the host, or + mapped to another buffer or image during the lifetime of this buffer, + then the results are undefined. The initial contents of the buffer will + be the contents of the host memory at the time of construction. ++ +-- +When the buffer is destroyed, the destructor will block until all +work in queues on the buffer have completed, then copy the contents +of the buffer back to the host memory (if required) and then +return. + + .. If the type of the host data is [code]#const#, then the buffer is + read-only; only read accessors are allowed on the buffer and + no-copy-back to host memory is performed (although the host memory must + still be kept available for use by SYCL). When using the default buffer + allocator, the const-ness of the type will be removed in order to allow + host allocation of memory, which will allow temporary host copies of the + data by the <>, for example for speeding up host + accesses. ++ +When the buffer is destroyed, the destructor will block until all work +in queues on the buffer have completed and then return, as there is no +copy of data back to host. + .. If the type of the host data is not [code]#const# but the pointer + to host data is [code]#const#, then the read-only restriction + applies only on host and not on device accesses. ++ +When the buffer is destroyed, the destructor will block until all work +in queues on the buffer have completed. +-- + . A buffer can be constructed using a [code]#shared_ptr# to host + data. This pointer is shared between the SYCL application and the + runtime. In order to allow synchronization between the application and + the runtime a [code]#mutex# is used which will be locked by the + runtime whenever the data is in use, and unlocked when it is no longer + needed. ++ +-- +The [code]#shared_ptr# reference counting is used in order to prevent +destroying the buffer host data prematurely. If the [code]#shared_ptr# +is deleted from the user application before buffer destruction, the buffer +can continue securely because the pointer hasn't been destroyed yet. It will +not copy data back to the host before destruction, however, as the +application side has already deleted its copy. + +Note that since there is an implicit conversion of a +[code]#std::unique_ptr# to a [code]#std::shared_ptr#, a +[code]#std::unique_ptr# can also be used to pass the ownership to the +<>. +-- + . A buffer can be constructed from a pair of iterator values. In this + case, the buffer construction will copy the data from the data range + defined by the iterator pair. The destructor will not copy back any data + and does not need to block. + + . A buffer can be constructed from a container on which + [code]#std::data(container)# and [code]#std::size(container)# + are well-formed. The initial contents of the buffer will + be the contents of the container at the time of construction. ++ +-- +The buffer may use the memory within the container for its full +lifetime, and the contents of this memory are unspecified for the +lifetime of the buffer. If the container memory is modified by the host +during the lifetime of this buffer, then the results are undefined. + +When the buffer is destroyed, if the return type of +[code]#std::data(container)# is not [code]#const# then the destructor +will block until all work in queues on the buffer have completed, and will +then copy the contents of the buffer to the container (if required) +and then return. +-- + + +If [code]#set_final_data()# is used to change where to write the +data back to, then the destructor of the buffer will block if a +write accessor on it has been created. + +A sub-buffer object can be created which is a sub-range reference to a +base buffer. This sub-buffer can be used to create accessors to the +base buffer, which have access to the range specified at time +of construction of the sub-buffer. Sub-buffers cannot be created from +sub-buffers, but only from a base buffer which is not already a sub-buffer. + +Sub-buffers must be constructed from a contiguous region of memory in a +buffer. This requirement is potentially non-intuitive when working with +buffers that have dimensionality larger than one, but maps to +one-dimensional <> native allocations without performance cost due +to index mapping computation. For example: + +[source,,linenums] +---- +include::{code_dir}/subbuffer.cpp[lines=4..-1] +---- + + +[[subsec:images]] +=== Images + +The classes [code]#unsampled_image# +(<>) and [code]#sampled_image# +(<>) define shared image data of one, +two or three dimensions, that can be used by kernels in queues and have to be +accessed using the image <> classes. + +The constructors and member functions of the SYCL [code]#unsampled_image# +and [code]#sampled_image# class templates are listed in +<>, <>, +<> and <>, +respectively. The additional common special member functions and common member +functions are listed in <> and +<>, respectively. + +Where relevant, it is the responsibility of the user to ensure that the format +of the data matches the format described by [code]#image_format#. + +The allocator template parameter of the SYCL [code]#unsampled_image# and +[code]#sampled_image# classes can be any allocator type including a custom +allocator, however it must allocate in units of [code]#std::byte#. + +For any image that is constructed with the range latexmath:[(r1,r2,r3)] with an element +type size in bytes of _s_, the image row pitch and image slice pitch should be +calculated as follows: + +[[image-row-pitch]] +[latexmath] +++++ +r1 \cdot s +++++ + +[[image-slice-pitch]] +[latexmath] +++++ +r1 \cdot r2 \cdot s +++++ + +The SYCL [code]#unsampled_image# and [code]#sampled_image# class +templates provide the common reference semantics +(see <>). + + +==== Unsampled image interface + +Each constructor of the [code]#unsampled_image# takes an +[code]#image_format# to describe the data layout of the image data. + +Each constructor additionally takes as the last parameter an optional SYCL +[code]#property_list# to provide properties to the SYCL +[code]#unsampled_image#. + +The SYCL [code]#unsampled_image# class template takes a template parameter +[code]#AllocatorT# for specifying an allocator which is used by the +<> when allocating temporary memory on the host. If no template +argument is provided, the default allocator for the SYCL +[code]#unsampled_image# class [code]#image_allocator# is used +(see <>). + +// Interface for class: unsampled image +[source,,linenums] +---- +include::{header_dir}/unsampledImage.h[lines=4..-1] +---- + + +[[table.constructors.unsampledImage]] +.Constructors of the [code]#unsampled_image# class template +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Constructor @ Description +a@ +[source] +---- +unsampled_image(image_format format, +const range &rangeRef, + const property_list &propList = {}) +---- + a@ Construct a SYCL [code]#unsampled_image# instance with + uninitialized memory. + The constructed SYCL [code]#unsampled_image# will use a default + constructed [code]#AllocatorT# when allocating memory on the + host. + The element size of the constructed SYCL [code]#unsampled_image# + will be derived from the [code]#format# parameter. + The range of the constructed SYCL [code]#unsampled_image# is + specified by the [code]#rangeRef# parameter provided. + The pitch of the constructed SYCL [code]#unsampled_image# will be + the default size determined by the <>. + Unless the member function [code]#set_final_data()# is called + with a valid non-null pointer, there will be no write back on + destruction. + Zero or more properties can be provided to the constructed SYCL + [code]#unsampled_image# via an instance of + [code]#property_list#. + +a@ +[source] +---- +unsampled_image(image_format format, +const range &rangeRef, + AllocatorT allocator, + const property_list &propList = {}) +---- + a@ Construct a SYCL [code]#unsampled_image# instance with + uninitialized memory. + The constructed SYCL [code]#unsampled_image# will use the + [code]#allocator# parameter provided when allocating memory on + the host. + The element size of the constructed SYCL [code]#unsampled_image# + will be derived from the [code]#format# parameter. + The range of the constructed SYCL [code]#unsampled_image# is + specified by the [code]#rangeRef# parameter provided. + The pitch of the constructed SYCL [code]#unsampled_image# will be + the default size determined by the <>. + Unless the member function [code]#set_final_data()# is called + with a valid non-null pointer, there will be no write back on + destruction. + Zero or more properties can be provided to the constructed SYCL + [code]#unsampled_image# via an instance of + [code]#property_list#. + +a@ +[source] +---- +unsampled_image(image_format format, +const range &rangeRef, + const range &pitch, + const property_list &propList = {}) +---- + a@ Available only when: [code]#dimensions > 1#. + +Construct a SYCL [code]#unsampled_image# instance with +uninitialized memory. +The constructed SYCL [code]#unsampled_image# will use a default +constructed [code]#AllocatorT# when allocating memory on the +host. +The element size of the constructed SYCL [code]#unsampled_image# +will be derived from the [code]#format# parameter. +The range of the constructed SYCL [code]#unsampled_image# is +specified by the [code]#rangeRef# parameter provided. +The pitch of the constructed SYCL [code]#unsampled_image# will be +the [code]#pitch# parameter provided. +Unless the member function [code]#set_final_data()# is called +with a valid non-null pointer, there will be no write back on +destruction. +Zero or more properties can be provided to the constructed SYCL +[code]#unsampled_image# via an instance of +[code]#property_list#. + +a@ +[source] +---- +unsampled_image(image_format format, +const range &rangeRef, + const range &pitch, + AllocatorT allocator, + const property_list &propList = {}) +---- + a@ Available only when: [code]#dimensions > 1#. + +Construct a SYCL [code]#unsampled_image# instance with +uninitialized memory. +The constructed SYCL [code]#unsampled_image# will use the +[code]#allocator# parameter provided when allocating memory on +the host. +The element size of the constructed SYCL [code]#unsampled_image# +will be derived from the [code]#format# parameter. +The range of the constructed SYCL [code]#unsampled_image# is +specified by the [code]#rangeRef# parameter provided. +The pitch of the constructed SYCL [code]#unsampled_image# will be +the [code]#pitch# parameter provided. +Unless the member function [code]#set_final_data()# is called +with a valid non-null pointer, there will be no write back on +destruction. +Zero or more properties can be provided to the constructed SYCL +[code]#unsampled_image# via an instance of +[code]#property_list#. + +a@ +[source] +---- +unsampled_image(void *hostPointer, +image_format format, + const range &rangeRef, + const property_list &propList = {}) +---- + a@ Construct a SYCL [code]#unsampled_image# instance with the + [code]#hostPointer# parameter provided. The ownership of this + memory is given to the constructed SYCL [code]#unsampled_image# + for the duration of its lifetime. + The constructed SYCL [code]#unsampled_image# will use a default + constructed [code]#AllocatorT# when allocating memory on the + host. + The element size of the constructed SYCL [code]#unsampled_image# + will be derived from the [code]#format# parameter. + The range of the constructed SYCL [code]#unsampled_image# is + specified by the [code]#rangeRef# parameter provided. + The pitch of the constructed SYCL [code]#unsampled_image# will be + the default size determined by the <>. + Unless the member function [code]#set_final_data()# is called + with a valid non-null pointer, any memory allocated by the + <> is written back to [code]#hostPointer#. + Zero or more properties can be provided to the constructed SYCL + [code]#unsampled_image# via an instance of + [code]#property_list#. + +a@ +[source] +---- +unsampled_image(void *hostPointer, +image_format format, + const range &rangeRef, + AllocatorT allocator, + const property_list &propList = {}) +---- + a@ Construct a SYCL [code]#unsampled_image# instance with the + [code]#hostPointer# parameter provided. The ownership of this + memory is given to the constructed SYCL [code]#unsampled_image# + for the duration of its lifetime. + The constructed SYCL [code]#unsampled_image# will use the + [code]#allocator# parameter provided when allocating memory on + the host. + The element size of the constructed SYCL [code]#unsampled_image# + will be derived from the [code]#format# parameter. + The range of the constructed SYCL [code]#unsampled_image# is + specified by the [code]#rangeRef# parameter provided. + The pitch of the constructed SYCL [code]#unsampled_image# will be + the default size determined by the <>. + Unless the member function [code]#set_final_data()# is called + with a valid non-null pointer, any memory allocated by the + <> is written back to [code]#hostPointer#. + Zero or more properties can be provided to the constructed SYCL + [code]#unsampled_image# via an instance of [code]#property_list#. + +a@ +[source] +---- +unsampled_image(void *hostPointer, +image_format format, + const range &rangeRef, + const range &pitch, + const property_list &propList = {}) +---- + a@ Available only when: [code]#dimensions > 1# + +Construct a SYCL [code]#unsampled_image# instance with the +[code]#hostPointer# parameter provided. The ownership of this +memory is given to the constructed SYCL [code]#unsampled_image# +for the duration of its lifetime. +The constructed SYCL [code]#unsampled_image# will use a default +constructed [code]#AllocatorT# when allocating memory on the +host. +The element size of the constructed SYCL [code]#unsampled_image# +will be derived from the [code]#format# parameter. +The range of the constructed SYCL [code]#unsampled_image# is +specified by the [code]#rangeRef# parameter provided. +The pitch of the constructed SYCL [code]#unsampled_image# will be +the [code]#pitch# parameter provided. +Unless the member function [code]#set_final_data()# is called +with a valid non-null pointer, any memory allocated by the +<> is written back to [code]#hostPointer#. +Zero or more properties can be provided to the constructed SYCL +[code]#unsampled_image# via an instance of +[code]#property_list#. + +a@ +[source] +---- +unsampled_image(void *hostPointer, +image_format format, + const range &rangeRef, + const range &pitch, + AllocatorT allocator, + const property_list &propList = {}) +---- + a@ Available only when: [code]#dimensions > 1#. + +Construct a SYCL [code]#unsampled_image# instance with the +[code]#hostPointer# parameter provided. The ownership of this +memory is given to the constructed SYCL [code]#unsampled_image# +for the duration of its lifetime. +The constructed SYCL [code]#unsampled_image# will use the +[code]#allocator# parameter provided when allocating memory on +the host. +The element size of the constructed SYCL [code]#unsampled_image# +will be derived from the [code]#format# parameter. +The range of the constructed SYCL [code]#unsampled_image# is +specified by the [code]#rangeRef# parameter provided. +The pitch of the constructed SYCL [code]#unsampled_image# will be +the [code]#pitch# parameter provided. +Unless the member function [code]#set_final_data()# is called +with a valid non-null pointer, any memory allocated by the +<> is written back to [code]#hostPointer#. +Zero or more properties can be provided to the constructed SYCL +[code]#unsampled_image# via an instance of [code]#property_list#. + +a@ +[source] +---- +unsampled_image(std::shared_ptr& hostPointer, +image_format format, + const range &rangeRef, + const property_list &propList = {}) +---- + a@ Construct a SYCL [code]#unsampled_image# instance with the + [code]#hostPointer# parameter provided. The ownership of this + memory is given to the constructed SYCL [code]#unsampled_image# + for the duration of its lifetime. + The constructed SYCL [code]#unsampled_image# will use a default + constructed [code]#AllocatorT# when allocating memory on the + host. + The element size of the constructed SYCL [code]#unsampled_image# + will be derived from the [code]#format# parameter. + The range of the constructed SYCL [code]#unsampled_image# is + specified by the [code]#rangeRef# parameter provided. + The pitch of the constructed SYCL [code]#unsampled_image# will be + the default size determined by the <>. + Unless the member function [code]#set_final_data()# is called + with a valid non-null pointer, any memory allocated by the + <> is written back to [code]#hostPointer#. + Zero or more properties can be provided to the constructed SYCL + [code]#unsampled_image# via an instance of [code]#property_list#. + +a@ +[source] +---- +unsampled_image(std::shared_ptr& hostPointer, +image_format format, + const range &rangeRef, + AllocatorT allocator, + const property_list &propList = {}) +---- + a@ Construct a SYCL [code]#unsampled_image# instance with the + [code]#hostPointer# parameter provided. The ownership of this + memory is given to the constructed SYCL [code]#unsampled_image# + for the duration of its lifetime. + The constructed SYCL [code]#unsampled_image# will use the + [code]#allocator# parameter provided when allocating memory on + the host. + The element size of the constructed SYCL [code]#unsampled_image# + will be derived from the [code]#format# parameter. + The range of the constructed SYCL [code]#unsampled_image# is + specified by the [code]#rangeRef# parameter provided. + The pitch of the constructed SYCL [code]#unsampled_image# will be + the default size determined by the <>. + Unless the member function [code]#set_final_data()# is called + with a valid non-null pointer, any memory allocated by the + <> is written back to [code]#hostPointer#. + Zero or more properties can be provided to the constructed SYCL + [code]#unsampled_image# via an instance of [code]#property_list#. + +a@ +[source] +---- +unsampled_image(std::shared_ptr& hostPointer, +image_format format, + const range &rangeRef, + const range & pitch, + const property_list &propList = {}) +---- + a@ Construct a SYCL [code]#unsampled_image# instance with the + [code]#hostPointer# parameter provided. The ownership of this + memory is given to the constructed SYCL [code]#unsampled_image# + for the duration of its lifetime. + The constructed SYCL [code]#unsampled_image# will use a default + constructed [code]#AllocatorT# when allocating memory on the + host. + The element size of the constructed SYCL [code]#unsampled_image# + will be derived from the [code]#format# parameter. + The range of the constructed SYCL [code]#unsampled_image# is + specified by the [code]#rangeRef# parameter provided. + The pitch of the constructed SYCL [code]#unsampled_image# will be + the [code]#pitch# parameter provided. + Unless the member function [code]#set_final_data()# is called + with a valid non-null pointer, any memory allocated by the + <> is written back to [code]#hostPointer#. + Zero or more properties can be provided to the constructed SYCL + [code]#unsampled_image# via an instance of [code]#property_list#. + +a@ +[source] +---- +unsampled_image(std::shared_ptr& hostPointer, +image_format format, + const range &rangeRef, + const range & pitch, + AllocatorT allocator, + const property_list &propList = {}) +---- + a@ Construct a SYCL [code]#unsampled_image# instance with the + [code]#hostPointer# parameter provided. The ownership of this + memory is given to the constructed SYCL [code]#unsampled_image# + for the duration of its lifetime. + The constructed SYCL [code]#unsampled_image# will use the + [code]#allocator# parameter provided when allocating memory on + the host. + The element size of the constructed SYCL [code]#unsampled_image# + will be derived from the [code]#format# parameter. + The range of the constructed SYCL [code]#unsampled_image# is + specified by the [code]#rangeRef# parameter provided. + The pitch of the constructed SYCL [code]#unsampled_image# will be + the [code]#pitch# parameter provided. + Unless the member function [code]#set_final_data()# is called + with a valid non-null pointer, any memory allocated by the + <> is written back to [code]#hostPointer#. + Zero or more properties can be provided to the constructed SYCL + [code]#unsampled_image# via an instance of [code]#property_list#. + +|==== + + + +[[table.members.unsampledImage]] +.Member functions of the [code]#unsampled_image# class template +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +range get_range() const +---- + a@ Return a range object representing the + size of the image in terms of the number + of elements in each dimension as passed + to the constructor. + +a@ +[source] +---- +range get_pitch() const +---- + a@ Available only when: [code]#dimensions > 1#. + +Return a range object representing the +pitch of the image in bytes. + +a@ +[source] +---- +size_t size() const noexcept +---- + a@ Returns the total number of elements in the image. + Equal to [code]#+get_range()[0] * ... * get_range()[dimensions-1]+#. + +a@ +[source] +---- +size_t byte_size() const noexcept +---- + a@ Returns the size of the image storage in bytes. The number of + bytes may be greater than [code]#size()*element size# + due to padding of elements, rows and slices of the image for + efficient access. + +a@ +[source] +---- +AllocatorT get_allocator() const +---- + a@ Returns the allocator provided to the image. + +a@ +[source] +---- +template + auto get_access(Ts... args) +---- + a@ Returns a valid [code]#unsampled_image_accessor# as if constructed via + passing the image and all provided arguments to the + [code]#unsampled_image_accessor# constructor. + +Possible implementation: + +[code]#+return unsampled_image_accessor{*this, args...};+# + +a@ +[source] +---- +template + auto get_host_access(Ts... args) +---- + a@ Returns a valid [code]#host_unsampled_image_accessor# as if constructed + via passing the image and all provided arguments to the + [code]#host_unsampled_image_accessor# constructor. + +Possible implementation: + +[code]#+return host_unsampled_image_accessor{*this, args...};+# + +a@ +[source] +---- +template + void set_final_data(Destination finalData = nullptr) +---- + a@ The [code]#finalData# point to where the output of all + the image processing is going to be copied to at destruction + time, if the image was involved with a write accessor. + +Destination can be either an output iterator, a +[code]#std::weak_ptr#. + +Note that a raw pointer is a special case of output iterator and +thus defines the host memory to which the result is to be +copied. + +In the case of a weak pointer, the output is not copied if the +weak pointer has expired. + +If [code]#Destination# is [code]#std::nullptr_t#, then +the copy back will not happen. + +a@ +[source] +---- +void set_write_back(bool flag = true) +---- + a@ This member function allows dynamically forcing or canceling the + write-back of the data of an image on destruction according to + the value of [code]#flag#. + +Forcing the write-back is similar to what happens during a +normal write-back as described in <> +and <>. + +If there is nowhere to write-back, using this function does not +have any effect. + +|==== + + + +==== Sampled image interface + +Each constructor of the [code]#sampled_image# class requires a +pointer to the host data the image will sample, an +[code]#image_format# to describe the data layout and an +[code]#image_sampler# (<>) to describe +how to sample the image data. + +Each constructor additionally takes as the last parameter an optional SYCL +[code]#property_list# to provide properties to the SYCL +[code]#sampled_image#. + +// Interface for class: sampled image +[source,,linenums] +---- +include::{header_dir}/sampledImage.h[lines=4..-1] +---- + + +[[table.constructors.sampledImage]] +.Constructors of the [code]#sampled_image# class template +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Constructor @ Description +a@ +[source] +---- +sampled_image(const void *hostPointer, +image_format format, + image_sampler sampler, + const range &rangeRef, + const property_list &propList = {}) +---- + a@ Construct a SYCL [code]#sampled_image# instance with the + [code]#hostPointer# parameter provided. The ownership of this + memory is given to the constructed SYCL [code]#sampled_image# for + the duration of its lifetime. + The host address is [code]#const#, so the host accesses must be + read-only. Since, the [code]#hostPointer# is [code]#const#, this image is only + initialized with this memory and there is no write after its + destruction. + The element size of the constructed SYCL [code]#sampled_image# + will be derived from the [code]#format# parameter. + Accessors that read the constructed SYCL [code]#sampled_image# will + use the [code]#sampler# parameter to sample the image. + The range of the constructed SYCL [code]#sampled_image# is + specified by the [code]#rangeRef# parameter provided. + The pitch of the constructed SYCL [code]#sampled_image# will be + the default size determined by the <>. + Zero or more properties can be provided to the constructed SYCL + [code]#sampled_image# via an instance of + [code]#property_list#. + +a@ +[source] +---- +sampled_image(const void *hostPointer, +image_format format, + image_sampler sampler, + const range &rangeRef, + const range &pitch, + const property_list &propList = {}) +---- + a@ Available only when: [code]#dimensions > 1#. + +Construct a SYCL [code]#sampled_image# instance with the +[code]#hostPointer# parameter provided. The ownership of this +memory is given to the constructed SYCL [code]#sampled_image# for +the duration of its lifetime. +The host address is [code]#const#, so the host accesses must be +read-only. Since, the [code]#hostPointer# is [code]#const#, this +image is only initialized with this memory and there is no write after +destruction. +The element size of the constructed SYCL [code]#sampled_image# +will be derived from the [code]#format# parameter. +Accessors that read the constructed SYCL [code]#sampled_image# will +use the [code]#sampler# parameter to sample the image. +The range of the constructed SYCL [code]#sampled_image# is +specified by the [code]#rangeRef# parameter provided. +The pitch of the constructed SYCL [code]#sampled_image# will be +the [code]#pitch# parameter provided. +Zero or more properties can be provided to the constructed SYCL +[code]#sampled_image# via an instance of +[code]#property_list#. + +a@ +[source] +---- +sampled_image(std::shared_ptr& hostPointer, +image_format format, + image_sampler sampler, + const range &rangeRef, + const property_list &propList = {}) +---- + a@ Construct a SYCL [code]#sampled_image# instance with the + [code]#hostPointer# parameter provided. The ownership of this + memory is given to the constructed SYCL [code]#sampled_image# for + the duration of its lifetime. + The host address is [code]#const#, so the host accesses must be + read-only. Since, the [code]#hostPointer# is [code]#const#, this image is only + initialized with this memory and there is no write after its + destruction. + The element size of the constructed SYCL [code]#sampled_image# + will be derived from the [code]#format# parameter. + Accessors that read the constructed SYCL [code]#sampled_image# will + use the [code]#sampler# parameter to sample the image. + The range of the constructed SYCL [code]#sampled_image# is + specified by the [code]#rangeRef# parameter provided. + The pitch of the constructed SYCL [code]#sampled_image# will be + the default size determined by the <>. + Zero or more properties can be provided to the constructed SYCL + [code]#sampled_image# via an instance of + [code]#property_list#. + +a@ +[source] +---- +sampled_image(std::shared_ptr& hostPointer, +image_format format, + image_sampler sampler, + const range &rangeRef, + const range & pitch, + const property_list &propList = {}) +---- + a@ Construct a SYCL [code]#sampled_image# instance with the + [code]#hostPointer# parameter provided. The ownership of this + memory is given to the constructed SYCL [code]#sampled_image# for + the duration of its lifetime. + The host address is [code]#const#, so the host accesses can be + read-only. Since, the [code]#hostPointer# is [code]#const#, this image is only + initialized with this memory and there is no write after its + destruction. + The element size of the constructed SYCL [code]#sampled_image# + will be derived from the [code]#format# parameter. + Accessors that read the constructed SYCL [code]#sampled_image# will + use the [code]#sampler# parameter to sample the image. + The range of the constructed SYCL [code]#sampled_image# is + specified by the [code]#rangeRef# parameter provided. + The pitch of the constructed SYCL [code]#sampled_image# will be + the [code]#pitch# parameter provided. + Zero or more properties can be provided to the constructed SYCL + [code]#sampled_image# via an instance of + [code]#property_list#. + +|==== + + + +[[table.members.sampledImage]] +.Member functions of the [code]#sampled_image# class template +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +range get_range() const +---- + a@ Return a range object representing the + size of the image in terms of the number + of elements in each dimension as passed + to the constructor. + +a@ +[source] +---- +range get_pitch() const +---- + a@ Available only when: [code]#dimensions > 1#. + +Return a range object representing the +pitch of the image in bytes. + +a@ +[source] +---- +size_t size() const noexcept +---- + a@ Returns the total number of elements in the image. + Equal to [code]#+get_range()[0] * ... * get_range()[dimensions-1]+#. + +a@ +[source] +---- +size_t byte_size() const noexcept +---- + a@ Returns the size of the image storage in bytes. The number of + bytes may be greater than [code]#size()*element size# + due to padding of elements, rows and slices of the image for + efficient access. + +a@ +[source] +---- +template + auto get_access(Ts... args) +---- + a@ Returns a valid [code]#sampled_image_accessor# as if constructed via + passing the image and all provided arguments to the + [code]#sampled_image_accessor# constructor. + +Possible implementation: + +[code]#+return sampled_image_accessor{*this, args...};+# + +a@ +[source] +---- +template + auto get_host_access(Ts... args) +---- + a@ Returns a valid [code]#host_sampled_image_accessor# as if constructed + via passing the image and all provided arguments to the + [code]#host_sampled_image_accessor# constructor. + +Possible implementation: + +[code]#+return host_sampled_image_accessor{*this, args...};+# + +|==== + + + +[[sec:image-properties]] +==== Image properties + +The properties that can be provided when constructing the SYCL +[code]#unsampled_image# and [code]#sampled_image# classes are +describe in <>. + +// Interface for image properties +[source,,linenums] +---- +include::{header_dir}/imageProperties.h[lines=4..-1] +---- + + +[[table.properties.image]] +.Properties supported by the SYCL image classes +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Property @ Description +a@ +[source] +---- +property::image::use_host_ptr +---- + a@ The [code]#use_host_ptr# property adds the requirement that the <> must not allocate any memory for the [code]#image# and instead uses the provided host pointer directly. This prevents the <> from allocating additional temporary storage on the host. + +a@ +[source] +---- +property::image::use_mutex +---- + a@ The property adds the requirement that the memory which + is owned by the SYCL [code]#image# can be shared with the + application via a [code]#std::mutex# provided to the + property. The [code]#std::mutex# is locked by + the runtime whenever the data is in use and unlocked + otherwise. Data is synchronized with [code]#hostData#, when + the [code]#std::mutex# is unlocked by the runtime. + +a@ +[source] +---- +property::image::context_bound +---- + a@ The [code]#context_bound# property adds the requirement that the SYCL [code]#image# can only be associated with a single SYCL [code]#context# that is provided to the property. + +|==== + + +The constructors and member functions of the image [code]#property# classes +are listed in <> and +<> + + +[[table.constructors.properties.image]] +.Constructors of the image [code]#property# classes +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Constructor @ Description +a@ +[source] +---- +property::image::use_host_ptr::use_host_ptr() +---- + a@ Constructs a SYCL [code]#use_host_ptr# property instance. + +a@ +[source] +---- +property::image::use_mutex::use_mutex(std::mutex &mutexRef) +---- + a@ Constructs a SYCL [code]#use_mutex# property instance with a reference to [code]#mutexRef# parameter provided. + +a@ +[source] +---- +property::image::context_bound::context_bound(context boundContext) +---- + a@ Constructs a SYCL [code]#context_bound# property instance with a copy of a SYCL [code]#context#. + +|==== + + + +[[table.members.properties.image]] +.Member functions of the image [code]#property# classes +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +std::mutex *property::image::use_mutex::get_mutex_ptr() const +---- + a@ Returns the [code]#std::mutex# which was specified when + constructing this SYCL [code]#use_mutex# property. + +a@ +[source] +---- +context property::image::context_bound::get_context() const +---- + a@ Returns the [code]#context# which was specified when + constructing this SYCL [code]#context_bound# property. + +|==== + + + +[[sec:image-sync-rules]] +==== Image synchronization rules + +The rules are similar to those described in <>. + +For the lifetime of the image object, the associated host memory must +be left available to the <> and the contents of the associated +host memory is unspecified until the image object is destroyed. If an +image object value is copied, then only a reference to the underlying +image object is copied. The underlying image object is reference-counted. +Only after all image value references to the underlying image object +have been destroyed is the actual image object itself destroyed. + +If an image object is constructed with associated host memory, then +its destructor blocks until all operations in all SYCL queues on +that image object have completed. Any modifications to the image data +will be copied back, if necessary, to the associated host memory. +Any errors occurring during destruction are reported to any associated +context's asynchronous error handler. If an image object is constructed +with a storage object, then the storage object defines what +synchronization or copying behavior occurs on image object destruction. + + +[[sec:sharing-host-memory-with-dm]] +=== Sharing host memory with the SYCL data management classes + +In order to allow the <> to do memory management and allow +for data dependencies, there are two classes defined, buffer and image. The +default behavior for them is that a "`raw`" pointer is given during the +construction of the data management class, with full ownership to use it until +the destruction of the SYCL object. + +In this section we go in greater detail on sharing or explicitly not +sharing host memory with the SYCL data classes, and we will use the buffer +class as an example. The same rules will apply to images as well. + + +==== Default behavior + +When using a SYCL buffer, the ownership of the pointer passed to the constructor +of the class is, by default, passed to <>, and that pointer cannot be used +on the host side until the buffer or image is destroyed. +A SYCL application can use memory managed by a SYCL buffer within the buffer scope +by using a [code]#host_accessor# as defined in <>. +However, there is no guarantee that the host accessor synchronizes with the +original host address used in its constructor. + +The pointer passed in is the one used to copy data back to the host, if needed, +before buffer destruction. The memory pointed by <> +will not be de-allocated by the runtime, +and the data is copied back from the device if there is +a need for it. + + +==== SYCL ownership of the host memory + +In the case where there is host memory to be used for initialization of data +but there is no intention of using that host memory after the buffer is +destroyed, then the buffer can take full ownership of that host memory. + +When a buffer owns the <> there is no copy back, by +default. In this situation, the SYCL application may pass a unique +pointer to the host data, which will be then used by the runtime +internally to initialize the data in the device. + +For example, the following could be used: + +[source,,linenums] +---- +{ + auto ptr = std::make_unique(-1234); + buffer b { std::move(ptr), range { 1 } }; + // ptr is not valid anymore. + // There is nowhere to copy data back +} +---- + +However, optionally the [code]#buffer::set_final_data()# can be +set to a [code]#std::weak_ptr# to enable copying data +back, to another host memory address that is going to be valid after +buffer construction. + +[source,,linenums] +---- +{ + auto ptr = std::make_unique(-42); + buffer b { std::move(ptr), range { 1 } }; + // ptr is not valid anymore. + // There is nowhere to copy data back. + // To get copy back, a location can be specified: + b.set_final_data(std::weak_ptr { .... }) +} +---- + + +==== Shared SYCL ownership of the host memory + +When an instance of [code]#std::shared_ptr# is passed to the buffer +constructor, then the buffer object and the developer's application share +the memory region. If the shared pointer is still used on the application's +side then the data will be copied back from the buffer or image and will be +available to the application after the buffer or image is destroyed. + +If the [code]#shared_ptr# is not empty, the contents of the referenced +memory are used to initialize the buffer. If the [code]#shared_ptr# is +empty, then the buffer is created with uninitialized memory. + +When the buffer is destroyed and the data have potentially been updated, if +the number of copies of the shared pointer outside the runtime is 0, there +is no user-side shared pointer to read the data. Therefore the data is not +copied out, and the buffer destructor does not need to wait for the data +processes to be finished, as the outcome is not needed on the application's +side. + +This behavior can be overridden using the [code]#set_final_data()# +member function of the buffer class, which will by any means force the buffer +destructor to wait until the data is copied to wherever the +[code]#set_final_data()# member function has put the data (or not wait nor copy +if set final data is [code]#nullptr)#. + +[source,,linenums] +---- +{ + std::shared_ptr ptr { data }; + { + buffer b { ptr, range<2>{ 10, 10 } }; + // update the data + [...] + } // Data is copied back because there is an user side shared_ptr +} +---- + +[source,,linenums] +---- +{ + std::shared_ptr ptr { data }; + { + buffer b { ptr, range<2>{ 10, 10 } }; + // update the data + [...] + ptr.reset(); + } // Data is not copied back, there is no user side shared_ptr. +} +---- + + +[[subsec:mutex]] +=== Synchronization primitives + +When the user wants to use the [code]#buffer# simultaneously in +the <> and their own code (e.g. a multi-threaded +mechanism) and wants to use manual synchronization without using a +[code]#host_accessor#, a [code]#std::mutex# can be passed to the +[code]#buffer# constructor via the right [code]#property#. + +The runtime promises to lock the mutex whenever the data is in use and +unlock it when it no longer needs it. + +[source,,linenums] +---- +{ + std::mutex m; + auto shD = std::make_shared(42) + sycl::buffer b { shD, { sycl::property::buffer::use_mutex { m } } }; + { + std::lock_guard lck { m }; + // User accesses the data + do_something(shD); + /* m is unlocked when lck goes out of scope, by normal end of this + block but also if an exception is thrown for example */ + } +} +---- + +When the runtime releases the mutex the user is guaranteed that the data was +copied back on the shared pointer --- unless the final data destination has been +changed using the member function [code]#set_final_data()#. + + +[[subsec:accessors]] +=== Accessors + +// \input{accessors} +// %%%%%%%%%%%%%%%%%%%%%%%%%%%% begin accessors %%%%%%%%%%%%%%%%%%%%%%%%%%%% + +<> provide three different capabilities: they provide +access to the data managed by a <> or <>, they provide access +to local memory on a <>, and they define the *requirements* to memory +objects which determine the scheduling of <> (see +<>). + +A memory object requirement is created when an accessor is constructed, unless +the accessor is a placeholder in which case the requirement is created when +the accessor is bound to a <> by calling [code]#handler::require()#. + +There are several different {cpp} classes that implement accessors: + +* The [code]#accessor# class provides access to data in a [code]#buffer# from + within a <>. + +* The [code]#host_accessor# class provides access to data in a [code]#buffer# + from host code that is outside of a <>. These accessors are + typically used in <>. + +* The [code]#local_accessor# class provides access to device local memory from + within a <>. + +* The [code]#unsampled_image_accessor# and [code]#sampled_image_accessor# + classes provide access to data in an [code]#unsampled_image# and + [code]#sampled_image# from within a <>. + +* The [code]#host_unsampled_image_accessor# and + [code]#host_sampled_image_accessor# classes provide access to data in an + [code]#unsampled_image# and [code]#sampled_image# from host code that is + outside of a <>. These accessors are typically used in + <>. + +Accessor objects must always be constructed in host code, either in +<> or in <>. Whether the constructor +blocks waiting for data to synchronize depends on the type of accessor. Those +accessors which provide access to data within a <> do not block. +Instead, these accessors define a requirement which influences the scheduling +of the <>. Those accessors which provide access to data from host +code do block until the data is available on the host. + +For those accessors which provide access to data within a <>, the +member functions which access data should only be called from within the +<>. Programs which call these member functions from outside of the +<> are ill formed. The sections below describe exactly which member +functions fall into this category. + + +==== Data type + +All accessors have a [code]#dataT# template parameter which specifies the type +of each element that the accessor accesses. For [code]#accessor# and +[code]#host_accessor#, this type must either match the type of each element in +the underlying [code]#buffer#, or it must be a [code]#const# qualified version +of that type. + +For the image accessors ([code]#unsampled_image_accessor#, +[code]#sampled_image_accessor#, [code]#host_unsampled_image_accessor#, and +[code]#host_sampled_image_accessor#), [code]#dataT# must be one of: + +* [code]#int4# ([code]#vec#), +* [code]#uint4# ([code]#vec#), +* [code]#float4# ([code]#vec#), or +* [code]#half4# ([code]#vec#) + +For [code]#local_accessor# see <> for the allowable +[code]#dataT# types. + + +==== Access modes + +Most accessors have an [code]#accessMode# template parameter which specifies +whether the accessor can read or write the underlying data. This information +is used by the runtime when defining the requirements for the associated +<>, and it tells the runtime whether data needs to be transferred to +or from a device before data can be accessed through the accessor. + +The [code]#access_mode# enumeration, shown in <>, +describes the potential modes of an accessor. However, not all accessor +classes support all modes, so see the description of each class for more +details. + +[source,,linenums] +---- +include::{header_dir}/accessMode.h[lines=4..-1] +---- + +[[table.accessors.accessmode]] +.Enumeration of access modes available to accessors +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ access_mode @ Description +a@ +[source] +---- +access_mode::read +---- + a@ Read-only access. + +a@ +[source] +---- +access_mode::write +---- + a@ Write-only access. + +a@ +[source] +---- +access_mode::read_write +---- + a@ Read and write access. + +|==== + + +==== Deduction tags + +Some accessor constructors take a [code]#TagT# parameter, which is used to +deduce template arguments for the constructor's class. Each of the access +modes in <> has an associated tag, but there are +additional tags which set other template parameters in addition to the access +mode. The synopsis below shows the namespace scope variables that the +implementation provides as possible values for the [code]#TagT# parameter. + +[source,,linenums] +---- +include::{header_dir}/accessTags.h[lines=4..-1] +---- + +The precise meaning of these tags depends on the specific accessor class +that is being constructed, so they are described more fully below in the +section that pertains to each of the accessor types. + + +==== Properties + +All accessor constructors accept a [code]#property_list# parameter, which +affects the semantics of the accessor. <> shows +the set of all possible accessor properties and tells which properties are +allowed when constructing each accessor class. + +[source,,linenums] +---- +include::{header_dir}/accessProperties.h[lines=4..-1] +---- + +[[table.accessors.properties]] +.Properties supported by accessors +[width="100%",options="header",cols="20%,35%,45%"] +|==== +|Property |Allowed with |Description + +|[code]#property::no_init# +|[code]#accessor# + + [code]#host_accessor# + + [code]#unsampled_image_accessor# + + [code]#host_unsampled_image_accessor# +|This property is useful when an application expects to write new values to all +of the accessor's elements without reading their previous values. The +implementation can use this information to avoid copying the accessor's data in +some cases. Following is a more formal description. + +This property is allowed only for accessors with [code]#access_mode::write# or +[code]#access_mode::read_write# access modes. Attempting to construct an +[code]#access_mode::read# accessor with this property causes an +[code]#exception# with the [code]#errc::invalid# error code to be thrown. + +The usage of this property is different depending on whether the accessor's +underlying data type [code]#dataT# is an implicit-lifetime type (as defined in +the {cpp} core language). If it is an implicit-lifetime type, the accessor +implicitly creates objects of that type with indeterminate values. The +application is not required to write values to each element of the accessor, +but unwritten elements of the accessor's buffer or image receive indeterminate +values, even if those buffer or image elements previously had defined values. +If this is a <>, this applies only to the elements within the +accessor's range. The values of unwritten elements outside of this range are +preserved. + +If [code]#dataT# is not an implicit-lifetime type, the accessor merely +allocates uninitialized memory, and the application is responsible for +constructing objects in that memory (e.g. by calling placement-new). The +application must create an object in each element of the accessor unless the +corresponding element of the underlying buffer did not previously contain an +object. If this is a <>, this applies only to the elements +within the accessor's range. The content of objects in the buffer outside of +this range is preserved. +|==== + +[NOTE] +==== +As stated above, the [code]#property::no_init# property requires the +application to construct an object for each accessor element when the element's +type is not an implicit-lifetime type (except in the case when the +corresponding buffer element did not previously contain an object). The reason +for this requirement is to avoid the possibility of overwriting a valid object +with indeterminate bytes, for example, when a <> using the accessor +completes. This means that the implementation can unconditionally copy memory +from the device back to the host when the <> completes, regardless of +whether the [code]#dataT# type is an implicit-lifetime type. +==== + +The constructors of the accessor property classes are listed in +<>. + +[[table.accessors.properties.constructors]] +.Constructors of the accessor property classes +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Constructor @ Description +a@ +[source] +---- +property::no_init::no_init() +---- + a@ Constructs a [code]#no_init# property instance. + +|==== + + +==== Read only accessors + +Accessors which have an [code]#accessMode# template parameter can be declared +as read-only by specifying [code]#access_mode::read# for the template +parameter. A read-only accessor provides read-only access to the underlying +data and provides a "read" requirement for the memory object when it is +constructed. + +The [code]#dataT# template parameter for a read-only accessor can optionally +be [code]#const# qualified, and the semantics of the accessor are unchanged. +For example, an accessor declared with [code]#const dataT# and +[code]#access_mode::read# has the same semantics as an accessor declared with +[code]#dataT# and [code]#access_mode::read#. + +As detailed in the sections below, some accessor types have a default value +for [code]#accessMode#, which depends on whether the [code]#dataT# parameter +is [code]#const# qualified. This provides a convenient way to declare a +read-only accessor without explicitly specifying the access mode. + +A [code]#const# qualified [code]#dataT# is only allowed for a read-only +accessor. Programs which specify a [code]#const# qualified [code]#dataT# and +any access mode other than [code]#access_mode::read# are ill formed, and the +implementation must issue a diagnostic in this case. + +Each accessor class also provides implicit conversions between the two forms +of read-only accessors. This makes it possible, for example, to assign an +accessor whose type has [code]#const dataT# and [code]#access_mode::read# to an +accessor whose type has [code]#dataT# and [code]#access_mode::read#, so long as +the other template parameters are the same. There is also an implicit +conversion from a read-write accessor to either of the forms of a read-only +accessor. These implicit conversions are described in detail for each accessor +class in the sections that follow. + + +==== Accessing elements of an accessor + +Accessors of type [code]#accessor#, [code]#host_accessor#, and +[code]#local_accessor# can have zero, one, two, or three dimensions. A zero +dimension accessor provides access to a single scalar element via an implicit +conversion operator to the underlying type of that element. + +One, two, or three dimensional specializations of these accessors provide +access to the elements they contain in two ways. The first way is through a +subscript operator that takes an instance of an [code]#id# class which has the +same dimensionality as the accessor. The second way is by passing a single +[code]#size_t# value to multiple consecutive subscript operators as specified +in <>. + +In all these cases, the reference to the contained element is of type +[code]#const dataT &# for read-only accessors and of type [code]#dataT &# for +other accessors. + +Accessors of all types have a range that defines the set of indices that may be +used to access elements. For buffer accessors, this is the range of the +underlying buffer, unless it is a <> in which case the range +comes from the accessor's constructor. For image accessors, this is the range +of the underlying image. Local accessors specify the range when the accessor +is constructed. Any attempt to access an element via an index that is outside +of this range produces undefined behavior. + + +==== Container interface + +Accessors of type [code]#accessor#, [code]#host_accessor#, and +[code]#local_accessor# meet the {cpp} requirement of +[code]#ReversibleContainer#. The exception to this is that only +[code]#local_accessor# owns the underlying data, meaning that its destructor +destroys elements and frees the memory. The [code]#accessor# and +[code]#host_accessor# types don't destroy any elements or free the memory on +destruction. The iterator for the container interface meets the {cpp} +requirement of [code]#LegacyRandomAccessIterator# and the underlying +pointers/references correspond to the address space specified by the accessor +type. For multidimensional accessors the iterator linearizes the data +according to <>. + + +[[sec:accessors.ranged]] +==== Ranged accessors + +Accessors of type [code]#accessor# and [code]#host_accessor# can be constructed +from a sub-range of a [code]#buffer# by providing a range and offset to the +constructor. This limits the elements that can be accessed to the specified +sub-range, which allows the implement to perform certain optimizations such +as reducing the amount of memory that needs to be copied to or from a device. + +If the ranged accessor is multi-dimensional, the sub-range is allowed to +describe a region of memory in the underlying buffer that is not contiguous +in the linear address space. It is also legal to construct several ranged +accessors for the same underlying buffer, either overlapping or +non-overlapping. + +A ranged accessor still creates a requisite for the entire underlying buffer, +even for the portions not within the range. For example, if one command writes +through a ranged accessor to one region of a buffer and a second command reads +through a ranged accessor from a non-overlapping region of the same buffer, the +second command must still be scheduled after the first because the requisites +for the two commands are on the entire buffer, not on the sub-ranges of the +ranged accessors. + +Most of the accessor member functions which provide a reference to the +underlying buffer elements are affected by a ranged accessor's offset and +range. For example, calling [code]#operator[](0)# on a one-dimensional ranged +accessor returns a reference to the element at the position specified by the +accessor's offset, which is not necessarily the first element in the buffer. +In addition, the accessor's iterator functions iterate only over the elements +that are within the sub-range. + +The only exceptions are the [code]#get_pointer# and [code]#get_multi_ptr# +member functions, which return a pointer to the beginning of the underlying +buffer regardless of the accessor's offset. Applications using these functions +must take care to manually add the offset before dereferencing the pointer +because accessing an element that is outside of the accessor's range results +in undefined behavior. + + +==== Buffer accessor for commands + +The [code]#accessor# class provides access to data in a [code]#buffer# from +within a <> or from within a <>. When used in +a <>, it accesses the contents of the buffer via the +device's <>. These two forms of the accessor are distinguished +by the [code]#accessTarget# template parameter as shown in +<>. Both forms support the +following values for the [code]#accessMode# template parameter: +[code]#access_mode::read#, [code]#access_mode::write# and +[code]#access_mode::read_write#. + +[[table.accessors.command.buffer.capabilities]] +.Description of access targets for buffer accessors +[width="100%",options="header",cols="25%,75%"] +|==== +| Access target | Meaning +| [code]#target::device# + | Access a buffer from a <> via device global memory. +| [code]#target::host_task# + | Access a buffer from a <>. +|==== + +Programs which specify the access target as [code]#target::device# and then use +the [code]#accessor# from a <> are ill formed. Likewise, programs +which specify the access target as [code]#target::host_task# and then use the +[code]#accessor# from a <> are ill formed. + +The dimensionality of the accessor must match the underlying buffer, however, +there is a special case if the buffer is one-dimensional. In this case, the +accessor may either be one-dimensional or it may be zero-dimensional. A +zero-dimensional accessor has access to just the first element of the buffer, +whereas a one-dimensional buffer has access to the entire buffer. + +Certain [code]#accessor# constructors create a "placeholder" accessor. Such +an accessor is bound to a [code]#buffer# and its semantics such as access +target and access mode are defined. However, a placeholder accessor is not +yet bound to a <>. Before such an accessor can be used in a +<>, it must be bound by calling [code]#handler::require()#. If a +placeholder accessor is passed as an argument to a <> without first +being bound to a <> with [code]#handler::require()#, the +implementation throws a synchronous [code]#exception# with the +[code]#errc::kernel_argument# error code when the <> is submitted. + + +===== Interface for buffer command accessors + +A synopsis of the [code]#accessor# class is provided below, showing the +interface when it is specialized with [code]#target::device# or +[code]#target::host_task#. Since some of the class types and member functions +have the same name and meaning as other accessors, the common types and +functions are described in <>. The member types +are listed in <> and +<>. The constructors are listed in +<>, and the member functions are +listed in <> and +<>. + +The additional common special member functions and common member functions are +listed in <> in +<> and +<>, respectively. For valid implicit +conversions between accessor types refer to +<>. Additionally, accessors of the +same type must be equality comparable both in the host application and also in +<>. + +[source,,linenums] +---- +include::{header_dir}/accessorBuffer.h[lines=4..-1] +---- + + +[[table.accessors.command.buffer.types]] +.Member types of the [code]#accessor# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member types @ Description +a@ +[source] +---- +template +accessor_ptr +---- + a@ If [code]#(accessTarget == target::device)#: + [code]#multi_ptr#. + +The definition of this type is not specified when +[code]#(accessTarget == target::host_task)#. + +|==== + + +[[table.accessors.command.buffer.constructors]] +.Constructors of the [code]#accessor# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Constructor @ Description +a@ +[source] +---- +accessor() +---- + a@ Constructs an empty accessor which fulfills the following + post-conditions: +-- + * [code]#(empty() == true)# + * All size queries return [code]#0#. + * The only iterator that can be obtained is [code]#nullptr#. + * Trying to access the underlying memory is undefined behavior. + +A default constructed accessor can be passed to a <> +but it is not valid to register it with the command group handler. +-- + +a@ +[source] +---- +template +accessor(buffer &bufferRef, + const property_list &propList = {}) +---- + a@ Available only when [code]#(dimensions == 0)#. + +Constructs a placeholder [code]#accessor# for accessing the first element of a +[code]#buffer#. The optional [code]#property_list# provides properties for the +constructed accessor. + +a@ +[source] +---- +template +accessor(buffer &bufferRef, + handler &commandGroupHandlerRef, + const property_list &propList = {}) +---- + a@ Available only when [code]#(dimensions == 0)#. + +Constructs an [code]#accessor# for accessing the first element of a +[code]#buffer# within a <> on the [code]#queue# +associated with [code]#commandGroupHandlerRef#. The optional +[code]#property_list# provides properties for the constructed accessor. + +a@ +[source] +---- +template +accessor(buffer &bufferRef, + const property_list &propList = {}) +---- + a@ Available only when [code]#(dimensions > 0)#. + +Constructs a placeholder [code]#accessor# for accessing a [code]#buffer#. The +optional [code]#property_list# provides properties for the constructed +accessor. + +a@ +[source] +---- +template +accessor(buffer &bufferRef, + TagT tag, const property_list &propList = {}) +---- + a@ Available only when [code]#(dimensions > 0)#. + +Constructs a placeholder [code]#accessor# for accessing a [code]#buffer#. The +[code]#tag# is used to deduce template arguments of the accessor as described +in <>. The optional [code]#property_list# +provides properties for the constructed accessor. + +a@ +[source] +---- +template +accessor(buffer &bufferRef, + handler &commandGroupHandlerRef, + const property_list &propList = {}) +---- + a@ Available only when [code]#(dimensions > 0)#. + +Constructs an [code]#accessor# for accessing a [code]#buffer# within a +<> on the [code]#queue# associated with +[code]#commandGroupHandlerRef#. The optional [code]#property_list# provides +properties for the constructed accessor. + +a@ +[source] +---- +template +accessor(buffer &bufferRef, + handler &commandGroupHandlerRef, + TagT tag, const property_list &propList = {}) +---- + a@ Available only when [code]#(dimensions > 0)#. + +Constructs an [code]#accessor# for accessing a [code]#buffer# within a +<> on the [code]#queue# associated with +[code]#commandGroupHandlerRef#. The [code]#tag# is used to deduce template +arguments of the accessor as described in <>. +The optional [code]#property_list# provides properties for the constructed +accessor. + +a@ +[source] +---- +template +accessor(buffer &bufferRef, + range accessRange, + const property_list &propList = {}) +---- + a@ Available only when [code]#(dimensions > 0)#. + +Constructs a placeholder [code]#accessor# that is a <>, where +the range starts at the beginning of the [code]#buffer#. The optional +[code]#property_list# provides properties for the constructed accessor. + +Throws an [code]#exception# with the [code]#errc::invalid# error code if +[code]#accessRange# exceeds the range of [code]#bufferRef# in any dimension. + +a@ +[source] +---- +template +accessor(buffer &bufferRef, + range accessRange, + TagT tag, const property_list &propList = {}) +---- + a@ Available only when [code]#(dimensions > 0)#. + +Constructs a placeholder [code]#accessor# that is a <>, where +the range starts at the beginning of the [code]#buffer#. The [code]#tag# is +used to deduce template arguments of the accessor as described in +<>. The optional [code]#property_list# +provides properties for the constructed accessor. + +Throws an [code]#exception# with the [code]#errc::invalid# error code if +[code]#accessRange# exceeds the range of [code]#bufferRef# in any dimension. + +a@ +[source] +---- +template +accessor(buffer &bufferRef, + range accessRange, + id accessOffset, + const property_list &propList = {}) +---- + a@ Available only when [code]#(dimensions > 0)#. + +Constructs a placeholder [code]#accessor# that is a <>, where +the range starts at an offset from the beginning of the [code]#buffer#. The +optional [code]#property_list# provides properties for the constructed +accessor. + +Throws an [code]#exception# with the [code]#errc::invalid# error code if +the sum of [code]#accessRange# and [code]#accessOffset# exceeds the range of +[code]#bufferRef# in any dimension. + +a@ +[source] +---- +template +accessor(buffer &bufferRef, + range accessRange, + id accessOffset, + TagT tag, const property_list &propList = {}) +---- + a@ Available only when [code]#(dimensions > 0)#. + +Constructs a placeholder [code]#accessor# that is a <>, where +the range starts at an offset from the beginning of the [code]#buffer#. The +[code]#tag# is used to deduce template arguments of the accessor as described +in <>. The optional [code]#property_list# +provides properties for the constructed accessor. + +Throws an [code]#exception# with the [code]#errc::invalid# error code if +the sum of [code]#accessRange# and [code]#accessOffset# exceeds the range of +[code]#bufferRef# in any dimension. + +a@ +[source] +---- +template +accessor(buffer &bufferRef, + handler &commandGroupHandlerRef, + range accessRange, + const property_list &propList = {}) +---- + a@ Available only when [code]#(dimensions > 0)#. + +Constructs an [code]#accessor# that is a <>, where the range +starts at the beginning of the [code]#buffer#. The accessor can only be used +in a <> on the [code]#queue# associated with +[code]#commandGroupHandlerRef#. The optional [code]#property_list# provides +properties for the constructed accessor. + +Throws an [code]#exception# with the [code]#errc::invalid# error code if +[code]#accessRange# exceeds the range of [code]#bufferRef# in any dimension. + +a@ +[source] +---- +template +accessor(buffer &bufferRef, + handler &commandGroupHandlerRef, + range accessRange, + TagT tag, const property_list &propList = {}) +---- + a@ Available only when [code]#(dimensions > 0)#. + +Constructs an [code]#accessor# that is a <>, where the range +starts at the beginning of the [code]#buffer#. The accessor can only be used +in a <> on the [code]#queue# associated with +[code]#commandGroupHandlerRef#. The [code]#tag# is used to deduce template +arguments of the accessor as described in <>. +The optional [code]#property_list# provides properties for the constructed +accessor. + +Throws an [code]#exception# with the [code]#errc::invalid# error code if +[code]#accessRange# exceeds the range of [code]#bufferRef# in any dimension. + +a@ +[source] +---- +template +accessor(buffer &bufferRef, + handler &commandGroupHandlerRef, + range accessRange, + id accessOffset, + const property_list &propList = {}) +---- + a@ Available only when [code]#(dimensions > 0)#. + +Constructs an [code]#accessor# that is a <>, where the range +starts at an offset from the beginning of the [code]#buffer#. The accessor can +only be used in a <> on the [code]#queue# associated with +[code]#commandGroupHandlerRef#. The optional [code]#property_list# provides +properties for the constructed accessor. + +Throws an [code]#exception# with the [code]#errc::invalid# error code if +the sum of [code]#accessRange# and [code]#accessOffset# exceeds the range of +[code]#bufferRef# in any dimension. + +a@ +[source] +---- +template +accessor(buffer &bufferRef, + handler &commandGroupHandlerRef, + range accessRange, + id accessOffset, + TagT tag, const property_list &propList = {}) +---- + a@ Available only when [code]#(dimensions > 0)#. + +Constructs an [code]#accessor# that is a <>, where the range +starts at an offset from the beginning of the [code]#buffer#. The accessor can +only be used in a <> on the [code]#queue# associated with +[code]#commandGroupHandlerRef#. The [code]#tag# is used to deduce template +arguments of the accessor as described in <>. +The optional [code]#property_list# provides properties for the constructed +accessor. + +Throws an [code]#exception# with the [code]#errc::invalid# error code if +the sum of [code]#accessRange# and [code]#accessOffset# exceeds the range of +[code]#bufferRef# in any dimension. + +|==== + + +[[table.accessors.command.buffer.members]] +.Member functions of the [code]#accessor# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +void swap(accessor &other); +---- + a@ Swaps the contents of the current accessor with the contents of + [code]#other#. + +a@ +[source] +---- +bool is_placeholder() const +---- + a@ Returns [code]#true# if the accessor was constructed as a placeholder. + Otherwise returns [code]#false#. + +a@ +[source] +---- +id get_offset() const +---- + a@ Available only when [code]#(dimensions > 0)#. + +If this is a <>, returns the offset that was specified when the +accessor was constructed. For other accessors, returns the default constructed +[code]#id{}#. + +a@ +[source] +---- +template +accessor_ptr get_multi_ptr() const noexcept +---- + a@ Returns a [code]#multi_ptr# to the start of this accessor's underlying + buffer, even if this is a <> whose range does not start + at the beginning of the buffer. + +This function may only be called from within a <>. + +|==== + + +[[sec:accessor.command.buffer.tags]] +===== Deduction tags for buffer command accessors + +Some [code]#accessor# constructors take a [code]#TagT# parameter, which is used +to deduce template arguments. The permissible values for this parameter are +listed in <> along with the access mode and +accessor target that they imply. + +[[table.accessors.command.buffer.tags]] +.Enumeration of tags available for [code]#accessor# construction +[width="100%",options="header",cols="33%,33%,34%"] +|==== +| Tag value | Access mode | Accessor target +| [code]#read_write# + | [code]#access_mode::read_write# + | [code]#target::device# +| [code]#read_only# + | [code]#access_mode::read# + | [code]#target::device# +| [code]#write_only# + | [code]#access_mode::write# + | [code]#target::device# +| [code]#read_write_host_task# + | [code]#access_mode::read_write# + | [code]#target::host_task# +| [code]#read_only_host_task# + | [code]#access_mode::read# + | [code]#target::host_task# +| [code]#write_only_host_task# + | [code]#access_mode::write# + | [code]#target::host_task# +|==== + + +[[sec:accessor.command.buffer.conversions]] +===== Read only buffer command accessors and implicit conversions + +<> shows the specializations of +[code]#accessor# with [code]#target::device# or +[code]#target::host_task# that are read-only accessors. There is an implicit +conversion between any of these specializations, provided that all other +template parameters are the same. + +[[table.accessors.command.buffer.read-only]] +.Specializations of [code]#accessor# that are read-only +[width="100%",options="header",cols="50%,50%"] +|==== +| Data type | Access mode +| not const-qualified | [code]#access_mode::read# +| const-qualified | [code]#access_mode::read# +|==== + +There is also an implicit conversion from the read-write specialization shown +in <> to any of the read-only +specializations shown in <>, provided +that all other template parameters are the same. + +[[table.accessors.command.buffer.read-write]] +.Specializations of [code]#host_accessor# that are read-write +[width="100%",options="header",cols="50%,50%"] +|==== +| Data type | Access mode +| not const-qualified | [code]#access_mode::read_write# +|==== + + +===== Deprecated features of the [code]#accessor# class + +All of the features defined in this section are deprecated and will likely be +removed from a future version of the specification. + + +====== Aliased names + +The enumerated value [code]#target::global_buffer# is an alias for [code]#target:::device#. +It has the same type and value as its alias. + +The enumerated type [code]#access::target# is an alias for [code]#target#, and +the enumerated type [code]#access::mode# is an alias for [code]#access_mode#. + + +====== Discard access modes + +An [code]#accessor# instance specialized with access mode +[code]#access_mode::discard_write# has the same behavior as an [code]#accessor# +instance of mode [code]#access_mode::write# that is constructed with the +property [code]#property::no_init#. + +An [code]#accessor# instance specialized with access mode +[code]#access_mode::discard_read_write# has the same behavior as an +[code]#accessor# instance of mode [code]#access_mode::read_write# that is +constructed with the property [code]#property::no_init#. + + +====== Placeholder template parameter + +The [code]#accessor# template parameter [code]#isPlaceholder# is allowed to be +specified, but it has no bearing on whether the [code]#accessor# instance is a +placeholder. This is determined solely by the constructor used to create the +instance. + +The associated type [code]#access::placeholder# is also deprecated. + + +====== Additional member functions for [code]#target::device# specialization + +Specializations of the [code]#accessor# class with [code]#target::device# have +the additional member functions described in +<>. + +[[table.accessors.deprecated.command.buffer.members]] +.Deprecated member functions of the [code]#accessor# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +size_t get_size() const +---- + a@ Returns the same value as [code]#byte_size()#. +a@ +[source] +---- +size_t get_count() const +---- + a@ Returns the same value as [code]#size()#. + +|==== + + +====== Accessor specialization with [code]#target::constant_buffer# + +The [code]#accessor# class may be specialized with target +[code]#target::constant_buffer#, which results in an accessor that can be used +within a <> to access the contents of a buffer through +the device's <>. + +As with other [code]#accessor# specializations, the dimensionality must match +the underlying buffer, however there is a special case if the buffer is +one-dimensional. In this case, the accessor may either be one-dimensional or +it may be zero-dimensional. A zero-dimensional accessor has access to just the +first element of the buffer, whereas a one-dimensional buffer has access to the +entire buffer. + +This specialization of [code]#accessor# is available only for the access mode +[code]#access_mode::read#. + +This accessor type can be constructed as a "placeholder" accessor. As with +other [code]#accessor# specializations that are placeholders, +[code]#handler::require()# must be called before passing a placeholder accessor +to a <>. If the application neglects to call +[code]#handler::require()# on a placeholder accessor, the implementation throws +a synchronous [code]#exception# with the [code]#errc::kernel_argument# error +code when the <> is submitted. + +A synopsis for this specialization of [code]#accessor# is provided below. +Since some of the class types and member functions have the same name and +meaning as other accessors, the common types and functions are described in +<>. The member types are listed in +<>. The constructors are listed in +<>, and the member functions +are listed in <> and +<>. + +The additional common special member functions and common member functions are +listed in <> in +<> and +<>, respectively. Additionally, +accessors of the same type must be equality comparable. + +[source,,linenums] +---- +include::{header_dir}/accessorDeprecatedConstant.h[lines=4..-1] +---- + + +[[table.accessors.deprecated.constant.constructors]] +.Constructors of the deprecated constant accessor +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Constructor @ Description +a@ +[source] +---- +template +accessor(buffer &bufferRef, + const property_list &propList = {}) +---- + a@ Available only when [code]#(dimensions == 0)#. + +Constructs a placeholder [code]#accessor# for accessing the first element of a +[code]#buffer#. The optional [code]#property_list# provides properties for the +constructed accessor. + +a@ +[source] +---- +template +accessor(buffer &bufferRef, + handler &commandGroupHandlerRef, + const property_list &propList = {}) +---- + a@ Available only when [code]#(dimensions == 0)#. + +Constructs an [code]#accessor# for accessing the first element of a +[code]#buffer# within a <> on the [code]#queue# +associated with [code]#commandGroupHandlerRef#. The optional +[code]#property_list# provides properties for the constructed accessor. + +a@ +[source] +---- +template +accessor(buffer &bufferRef, + const property_list &propList = {}) +---- + a@ Available only when [code]#(dimensions > 0)#. + +Constructs a placeholder [code]#accessor# for accessing a [code]#buffer#. The +optional [code]#property_list# provides properties for the constructed +accessor. + +a@ +[source] +---- +template +accessor(buffer &bufferRef, + handler &commandGroupHandlerRef, + const property_list &propList = {}) +---- + a@ Available only when [code]#(dimensions > 0)#. + +Constructs an [code]#accessor# for accessing a [code]#buffer# within a +<> on the [code]#queue# associated with +[code]#commandGroupHandlerRef#. The optional [code]#property_list# provides +properties for the constructed accessor. + +a@ +[source] +---- +template +accessor(buffer &bufferRef, + range accessRange, + const property_list &propList = {}) +---- + a@ Available only when [code]#(dimensions > 0)#. + +Constructs a placeholder [code]#accessor# that is a <>, where +the range starts at the beginning of the [code]#buffer#. The optional +[code]#property_list# provides properties for the constructed accessor. + +Throws an [code]#exception# with the [code]#errc::invalid# error code if +[code]#accessRange# exceeds the range of [code]#bufferRef# in any dimension. +a@ +[source] +---- +template +accessor(buffer &bufferRef, + range accessRange, + id accessOffset, + const property_list &propList = {}) +---- + a@ Available only when [code]#(dimensions > 0)#. + +Constructs a placeholder [code]#accessor# that is a <>, where +the range starts at an offset from the beginning of the [code]#buffer#. The +optional [code]#property_list# provides properties for the constructed +accessor. + +Throws an [code]#exception# with the [code]#errc::invalid# error code if +the sum of [code]#accessRange# and [code]#accessOffset# exceeds the range of +[code]#bufferRef# in any dimension. + +a@ +[source] +---- +template +accessor(buffer &bufferRef, + handler &commandGroupHandlerRef, + range accessRange, + const property_list &propList = {}) +---- + a@ Available only when [code]#(dimensions > 0)#. + +Constructs an [code]#accessor# that is a <>, where the range +starts at the beginning of the [code]#buffer#. The accessor can only be used +in a <> on the [code]#queue# associated with +[code]#commandGroupHandlerRef#. The optional [code]#property_list# provides +properties for the constructed accessor. + +Throws an [code]#exception# with the [code]#errc::invalid# error code if +[code]#accessRange# exceeds the range of [code]#bufferRef# in any dimension. + +a@ +[source] +---- +template +accessor(buffer &bufferRef, + handler &commandGroupHandlerRef, + range accessRange, + id accessOffset, + const property_list &propList = {}) +---- + a@ Available only when [code]#(dimensions > 0)#. + +Constructs an [code]#accessor# that is a <>, where the range +starts at an offset from the beginning of the [code]#buffer#. The accessor can +only be used in a <> on the [code]#queue# associated with +[code]#commandGroupHandlerRef#. The optional [code]#property_list# provides +properties for the constructed accessor. + +Throws an [code]#exception# with the [code]#errc::invalid# error code if +the sum of [code]#accessRange# and [code]#accessOffset# exceeds the range of +[code]#bufferRef# in any dimension. + +|==== + + +[[table.accessors.deprecated.constant.members]] +.Member functions of the deprecated constant accessor +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +id get_offset() const +---- + a@ Available only when [code]#(dimensions > 0)#. + +If this is a <>, returns the offset that was specified when +the accessor was constructed, otherwise returns the default constructed +[code]#id{}#. + +a@ +[source] +---- +constant_ptr get_pointer() const noexcept +---- + a@ Returns a [code]#multi_ptr# to the start of this accessor's underlying + buffer, even if this is a <> whose range does not start + at the beginning of the buffer. + +|==== + +====== Accessor specialization with [code]#target::host_buffer# + +The [code]#accessor# class may be specialized with target +[code]#target::host_buffer#, which results in a host accessor similar to +[code]#host_accessor#. This specialization provides access to data in a +[code]#buffer# from host code that is outside of a <>, and +constructors of this specialization block until the requested data is available +on the host. + +As with other [code]#accessor# specializations, the dimensionality must match +the underlying buffer, however there is a special case if the buffer is +one-dimensional. In this case, the accessor may either be one-dimensional or +it may be zero-dimensional. A zero-dimensional accessor has access to just the +first element of the buffer, whereas a one-dimensional buffer has access to the +entire buffer. + +This specialization of [code]#accessor# is available for all access modes +except for [code]#access_mode::atomic#. + +A synopsis for this specialization of [code]#accessor# is provided below. +Since some of the class types and member functions have the same name and +meaning as other accessors, the common types and functions are described in +<>. The member types are listed in +<>. The constructors are listed in +<>, and the member functions are +listed in <> and +<>. + +The additional common special member functions and common member functions are +listed in <> in +<> and +<>, respectively. Additionally, +accessors of the same type must be equality comparable. + +[source,,linenums] +---- +include::{header_dir}/accessorDeprecatedHost.h[lines=4..-1] +---- + + +[[table.accessors.deprecated.host.constructors]] +.Constructors of the deprecated host buffer accessor +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Constructor @ Description +a@ +[source] +---- +template +accessor(buffer &bufferRef, + const property_list &propList = {}) +---- + a@ Available only when [code]#(dimensions == 0)#. + +Constructs an [code]#accessor# for accessing the first element of a +[code]#buffer# immediately on the host. The optional [code]#property_list# +provides properties for the constructed accessor. + +a@ +[source] +---- +template +accessor(buffer &bufferRef, + const property_list &propList = {}) +---- + a@ Available only when [code]#(dimensions > 0)#. + +Constructs an [code]#accessor# for accessing a [code]#buffer# immediately on +the host. The optional [code]#property_list# provides properties for the +constructed accessor. + +a@ +[source] +---- +template +accessor(buffer &bufferRef, + range accessRange, + const property_list &propList = {}) +---- + a@ Available only when [code]#(dimensions > 0)#. + +Constructs an [code]#accessor# that is a <> which accesses a +buffer immediately on the host, where the range starts at the beginning of the +buffer. The optional [code]#property_list# provides properties for the +constructed accessor. + +Throws an [code]#exception# with the [code]#errc::invalid# error code if +[code]#accessRange# exceeds the range of [code]#bufferRef# in any dimension. + +a@ +[source] +---- +template +accessor(buffer &bufferRef, + range accessRange, + id accessOffset, + const property_list &propList = {}) +---- + a@ Available only when [code]#(dimensions > 0)#. + +Constructs an [code]#accessor# that is a <> which accesses a +buffer immediately on the host, where the range starts at an offset from the +beginning of the buffer. The optional [code]#property_list# provides +properties for the constructed accessor. + +Throws an [code]#exception# with the [code]#errc::invalid# error code if +the sum of [code]#accessRange# and [code]#accessOffset# exceeds the range of +[code]#bufferRef# in any dimension. + +|==== + + +[[table.accessors.deprecated.host.members]] +.Member functions of the deprecated host buffer accessor +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +id get_offset() const +---- + a@ Available only when [code]#(dimensions > 0)#. + +If this is a <>, returns the offset that was specified when +the accessor was constructed, otherwise returns the default constructed +[code]#id{}#. + +a@ +[source] +---- +std::add_pointer_t get_pointer() const noexcept +---- + a@ Returns a pointer to the start of this accessor's underlying buffer, even + if this is a <> whose range does not start at the + beginning of the buffer. + +|==== + + +====== Accessor specialization with [code]#target::local# + +The [code]#accessor# class may be specialized with target +[code]#target::local#, which results in a local accessor that has the same +semantics and restrictions as [code]#local_accessor#. + +This specialization of [code]#accessor# is only available for access modes +[code]#access_mode::read_write# and [code]#access_mode::atomic#. + +A synopsis for this specialization of [code]#accessor# is provided below. +Since some of the class types and member functions have the same name and +meaning as other accessors, the common types and functions are described in +<>. The member types are listed in +<>. The constructors are listed in +<>, and the member functions +are listed in <> and +<>. + +The additional common special member functions and common member functions are +listed in <> in +<> and +<>, respectively. Additionally, +accessors of the same type must be equality comparable. + +[source,,linenums] +---- +include::{header_dir}/accessorDeprecatedLocal.h[lines=4..-1] +---- + + +[[table.accessors.deprecated.local.constructors]] +.Constructors of the deprecated local accessor +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Constructor @ Description +a@ +[source] +---- +accessor(handler &commandGroupHandlerRef, + const property_list &propList = {}) +---- + a@ Available only when [code]#(dimensions == 0)#. + +Constructs an [code]#accessor# instance for accessing <> of a +single [code]#dataT# element within a <> on the queue +associated with [code]#commandGroupHandlerRef#. The optional +[code]#property_list# provides properties for the constructed accessor. + +a@ +[source] +---- +accessor(range allocationSize, + handler &commandGroupHandlerRef, + const property_list &propList = {}) +---- + a@ Available only when [code]#(dimensions > 0)#. + +Constructs an [code]#accessor# instance for accessing <> of an +array of [code]#dataT# elements within a <> on the queue +associated with [code]#commandGroupHandlerRef#. The number of elements in the +array is defined by [code]#allocationSize#. The optional [code]#property_list# +provides properties for the constructed accessor. + +|==== + + +[[table.accessors.deprecated.local.members]] +.Member functions of the deprecated local accessor +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +operator atomic() const +---- + a@ Available only when + [code]#(accessMode == access_mode::atomic && dimensions == 0)#. + +Returns an instance of [code]#atomic# of type [code]#dataT# providing atomic +access to the element stored within the work-group's local memory allocation +that this accessor is accessing. + +a@ +[source] +---- +atomic operator[](id index) const +---- + a@ Available only when + [code]#(accessMode == access_mode::atomic && dimensions > 0)#. + +Returns an instance of [code]#atomic# of type [code]#dataT# providing atomic +access to the element stored within the work-group's local memory allocation +that this accessor is accessing, at the index specified by [code]#index#. + +a@ +[source] +---- +atomic operator[](size_t index) const +---- + a@ Available only when + [code]#(accessMode == access_mode::atomic && dimensions == 1)#. + +Returns an instance of [code]#atomic# of type [code]#dataT# providing atomic +access to the element stored within the work-group's local memory allocation +that this accessor is accessing, at the index specified by [code]#index#. + +a@ +[source] +---- +local_ptr get_pointer() const noexcept +---- + a@ Returns a [code]#multi_ptr# to the work-group's local memory allocation + that this accessor is accessing. + +|==== + + +[[sec:accessor.deprecated.common.members]] +====== Common members for deprecated accessors + +Specializations of the [code]#accessor# class with +[code]#target::constant_buffer#, [code]#target::host_buffer# and +[code]#target::local# have many member types and member functions with the same +name and meaning. <> describes these +common types and <> describes the +common member functions. + + +[[table.accessors.deprecated.common.types]] +.Common member types of the deprecated accessors +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member types @ Description +a@ +[source] +---- +value_type +---- + a@ If [code]#(accessMode == access_mode::read)#, equal to + [code]#const dataT#, otherwise equal to [code]#dataT#. + +a@ +[source] +---- +reference +---- + a@ Equal to [code]#value_type&#. + +a@ +[source] +---- +const_reference +---- + a@ Equal to [code]#const dataT&#. + +|==== + + +[[table.accessors.deprecated.common.members]] +.Common member functions of the deprecated accessors +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +bool is_placeholder() const +---- + a@ Tells if this is a placeholder accessor. + +When [code]#accessTarget# is [code]#target::constant_buffer#, returns +[code]#true# if the accessor was constructed as a placeholder and returns +[code]#false# otherwise. + +When [code]#accessTarget# is [code]#target::host_buffer# or +[code]#target::local#, always returns [code]#false#. + +a@ +[source] +---- +size_t get_size() const noexcept +---- + a@ Returns the size in bytes of the memory region this accessor may access. + +When [code]#accessTarget# is [code]#target::constant_buffer# or +[code]#target::host_buffer#, the returned value is the size of the elements in +the underlying buffer, unless this is a <> in which case it is +the size of the elements within the accessor's range. + +When [code]#accessTarget# is [code]#target::local#, the returned value is the +size in bytes of the accessor's local memory allocation, per work-group. + +a@ +[source] +---- +size_t get_count() const noexcept +---- + a@ Returns the number of [code]#dataT# elements of the memory region this + accessor may access. + +When [code]#accessTarget# is [code]#target::constant_buffer# or +[code]#target::host_buffer#, the returned value is the number of elements in +the underlying buffer, unless this is a <> in which case it is +the number of elements within the accessor's range. + +When [code]#accessTarget# is [code]#target::local#, the returned value is the +number of elements in the accessor's local memory allocation, per work-group. + +a@ +[source] +---- +range get_range() const +---- + a@ Available only when [code]#(dimensions > 0)#. + +Returns a [code]#range# object which represents the number of elements of +[code]#dataT# per dimension that this accessor may access. + +When [code]#accessTarget# is [code]#target::constant_buffer# or +[code]#target::host_buffer#, the returned value is the range of the underlying +buffer, unless this is a <> in which case it is the range that +was specified when the accessor was constructed. + +When [code]#accessTarget# is [code]#target::local#, the returned value is the +the range that was specified when the accessor was constructed. + +a@ +[source] +---- +operator reference() const +---- + a@ When [code]#accessTarget# is [code]#target::constant_buffer# or + [code]#target::host_buffer#, available only when + [code]#(dimensions == 0)#. + +When [code]#accessTarget# is [code]#target::local#, available only when +[code]#(accessMode == access_mode::read_write && dimensions == 0)#. + +Returns a reference to the single element that is accessed by this accessor. + +a@ +[source] +---- +reference operator[](id index) const +---- + a@ When [code]#accessTarget# is [code]#target::constant_buffer# or + [code]#target::host_buffer#, available only when + [code]#(dimensions > 0)#. + +When [code]#accessTarget# is [code]#target::local#, available only when +[code]#(accessMode == access_mode::read_write && dimensions > 0)#. + +Returns a reference to the element at the location specified by [code]#index#. +If this is a <>, the element is determined by adding +[code]#index# to the accessor's offset. + +a@ +[source] +---- +__unspecified__ &operator[](size_t index) const +---- + a@ Available only when [code]#(dimensions > 1)#. + +Returns an instance of an undefined intermediate type representing this +accessor, with the dimensionality [code]#dimensions-1# and containing an +implicit [code]#id# with index [code]#dimensions# set to [code]#index#. The +intermediate type returned must provide all available subscript operators which +take a [code]#size_t# parameter defined by this accessor class that are +appropriate for the type it represents (including this subscript operator). + +If this is a <>, the implicit [code]#id# in the returned +instance also includes the accessor's offset. + +a@ +[source] +---- +reference operator[](size_t index) const +---- + a@ When [code]#accessTarget# is [code]#target::constant_buffer# or + [code]#target::host_buffer#, available only when + [code]#(dimensions == 1)#. + +When [code]#accessTarget# is [code]#target::local#, available only when +[code]#(accessMode == access_mode::read_write && dimensions == 1)#. + +Returns a reference to the element at the location specified by [code]#index#. +If this is a <>, the element is determined by adding +[code]#index# to the accessor's offset. + +|==== + + +====== Accessor specialization with [code]#access_mode::atomic# + +The [code]#accessor# class may be specialized with target +[code]#target::device# and access mode [code]#access_mode::atomic#. +This specialization provides additional member functions beyond those that are +provided for other [code]#target::device# specializations as described +in <>. + + +[[table.accessors.deprecated.atomic.members]] +.Deprecated atomic member functions of the [code]#accessor# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +operator atomic() const +---- + a@ Available only when + [code]#(accessMode == access_mode::atomic && dimensions == 0)#. + +Returns an instance of [code]#atomic# of type [code]#dataT# providing atomic +access to the single element that is accessed by this accessor. + +a@ +[source] +---- +atomic operator[]( + id index) const +---- + a@ Available only when + [code]#(accessMode == access_mode::atomic && dimensions > 0)#. + +Returns an instance of [code]#atomic# of type [code]#dataT# providing atomic +access to the element stored within the accessor's buffer at the index +specified by [code]#index#. + +If this is a <>, the returned [code]#atomic# instance +provides access to the buffer element whose location is determined by adding +the accessor's offset to [code]#index#. + +a@ +[source] +---- +atomic operator[]( + size_t index) const +---- + a@ Available only when + [code]#(accessMode == access_mode::atomic && dimensions == 1)#. + +Returns an instance of [code]#atomic# of type [code]#dataT# providing atomic +access to the element stored within the accessor's buffer at the index +specified by [code]#index#. + +If this is a <>, the returned [code]#atomic# instance +provides access to the buffer element whose location is determined by adding +the accessor's offset to [code]#index#. + +|==== + + +==== Buffer accessor for host code + +The [code]#host_accessor# class provides access to data in a [code]#buffer# +from host code that is outside of a <> (i.e. do not use this class to +access a buffer inside a host task). + +As with [code]#accessor#, the dimensionality of [code]#host_accessor# must +match the underlying buffer, however, there is a special case if the buffer is +one-dimensional. In this case, the accessor may either be one-dimensional or +it may be zero-dimensional. A zero-dimensional accessor has access to just the +first element of the buffer, whereas a one-dimensional buffer has access to the +entire buffer. + +The [code]#host_accessor# class supports the following access modes: +[code]#access_mode::read#, [code]#access_mode::write# and +[code]#access_mode::read_write#. + + +===== Interface for buffer host accessors + +A synopsis of the [code]#host_accessor# class is provided below. Since some of +the class types and member functions have the same name and meaning as other +accessors, the common types and functions are described in +<>. The member types are listed in +<>. +The constructors are listed in <>, +and the member functions are listed in <> and +<>. + +The additional common special member functions and common member functions are +listed in <> in +<> and +<>, respectively. For valid implicit +conversions between accessor types refer to +<>. Additionally, accessors of the same +type must be equality comparable. + +[source,,linenums] +---- +include::{header_dir}/accessorHost.h[lines=4..-1] +---- + + +[[table.accessors.host.buffer.constructors]] +.Constructors of the [code]#host_accessor# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Constructor @ Description +a@ +[source] +---- +host_accessor() +---- + a@ Constructs an empty accessor which fulfills the following + post-conditions: +-- + * [code]#(empty() == true)# + * All size queries return [code]#0#. + * The only iterator that can be obtained is [code]#nullptr#. + * Trying to access the underlying memory is undefined behavior. +-- + +a@ +[source] +---- +template +host_accessor(buffer &bufferRef, + const property_list &propList = {}) +---- + a@ Available only when [code]#(dimensions == 0)#. + +Constructs a [code]#host_accessor# for accessing the first element of a +[code]#buffer# immediately on the host. The optional [code]#property_list# +provides properties for the constructed accessor. + +a@ +[source] +---- +template +host_accessor( + buffer &bufferRef, + const property_list &propList = {}) +---- + a@ Available only when [code]#(dimensions > 0)#. + +Constructs a [code]#host_accessor# for accessing a [code]#buffer# immediately +on the host. The optional [code]#property_list# provides properties for the +constructed accessor. + +a@ +[source] +---- +template +host_accessor( + buffer &bufferRef, + TagT tag, const property_list &propList = {}) +---- + a@ Available only when [code]#(dimensions > 0)#. + +Constructs a [code]#host_accessor# for accessing a [code]#buffer# immediately +on the host. The [code]#tag# is used to deduce template arguments of the +accessor as described in <>. The optional +[code]#property_list# provides properties for the constructed accessor. + +a@ +[source] +---- +template +host_accessor( + buffer &bufferRef, + range accessRange, + const property_list &propList = {}) +---- + a@ Available only when [code]#(dimensions > 0)#. + +Constructs a [code]#host_accessor# that is a <> which accesses +a buffer immediately on the host, where the range starts at the beginning of +the [code]#buffer#. The optional [code]#property_list# provides properties for +the constructed accessor. + +Throws an [code]#exception# with the [code]#errc::invalid# error code if +[code]#accessRange# exceeds the range of [code]#bufferRef# in any dimension. + +a@ +[source] +---- +template +host_accessor( + buffer &bufferRef, + range accessRange, + TagT tag, const property_list &propList = {}) +---- + a@ Available only when [code]#(dimensions > 0)#. + +Constructs a [code]#host_accessor# that is a <> which accesses +a buffer immediately on the host, where the range starts at the beginning of +the [code]#buffer#. The [code]#tag# is used to deduce template arguments of +the accessor as described in <>. The optional +[code]#property_list# provides properties for the constructed accessor. + +Throws an [code]#exception# with the [code]#errc::invalid# error code if +[code]#accessRange# exceeds the range of [code]#bufferRef# in any dimension. + +a@ +[source] +---- +template +host_accessor( + buffer &bufferRef, + range accessRange, + id accessOffset, + const property_list &propList = {}) +---- + a@ Available only when [code]#(dimensions > 0)#. + +Constructs a [code]#host_accessor# that is a <> which accesses +a buffer immediately on the host, where the range starts at an offset from the +beginning of the buffer. The optional [code]#property_list# provides +properties for the constructed accessor. + +Throws an [code]#exception# with the [code]#errc::invalid# error code if +the sum of [code]#accessRange# and [code]#accessOffset# exceeds the range of +[code]#bufferRef# in any dimension. + +a@ +[source] +---- +template +host_accessor( + buffer &bufferRef, + range accessRange, + id accessOffset, + TagT tag, const property_list &propList = {}) +---- + a@ Available only when [code]#(dimensions > 0)#. + +Constructs a [code]#host_accessor# that is a <> which accesses +a buffer immediately on the host, where the range starts at an offset from the +beginning of the buffer. The [code]#tag# is used to deduce template arguments +of the accessor as described in <>. The +optional [code]#property_list# provides properties for the constructed +accessor. + +Throws an [code]#exception# with the [code]#errc::invalid# error code if +the sum of [code]#accessRange# and [code]#accessOffset# exceeds the range of +[code]#bufferRef# in any dimension. + +|==== + + +[[table.accessors.host.buffer.members]] +.Member functions of the [code]#host_accessor# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +void swap(host_accessor &other); +---- + a@ Swaps the contents of the current accessor with the contents of + [code]#other#. + +a@ +[source] +---- +id get_offset() const +---- + a@ Available only when [code]#(dimensions > 0)#. + +If this is a <>, returns the offset that was specified when the +accessor was constructed. For other accessors, returns the default constructed +[code]#id{}#. + +|==== + + +[[sec:accessor.host.buffer.tags]] +===== Deduction tags for buffer host accessors + +Some [code]#host_accessor# constructors take a [code]#TagT# parameter, which is +used to deduce template arguments. The permissible values for this parameter +are listed in <> along with the access mode +that they imply. + +[[table.accessors.host.buffer.tags]] +.Enumeration of tags available for [code]#host_accessor# construction +[width="100%",options="header",cols="50%,50%"] +|==== +| Tag value | Access mode +| [code]#read_write# + | [code]#access_mode::read_write# +| [code]#read_only# + | [code]#access_mode::read# +| [code]#write_only# + | [code]#access_mode::write# +|==== + + +[[sec:accessor.host.buffer.conversions]] +===== Read only buffer host accessors and implicit conversions + +<> shows the specializations of +[code]#host_accessor# that are read-only accessors. There is an implicit +conversion between any of these specializations, provided that all other +template parameters are the same. + +[[table.accessors.host.buffer.read-only]] +.Specializations of [code]#host_accessor# that are read-only +[width="100%",options="header",cols="50%,50%"] +|==== +| Data type | Access mode +| not const-qualified | [code]#access_mode::read# +| const-qualified | [code]#access_mode::read# +|==== + +There is also an implicit conversion from the read-write [code]#host_accessor# +type shown in <> to any of the read-only +accessors in <>, provided that all other +template parameters are the same. + +[[table.accessors.host.buffer.read-write]] +.Specializations of [code]#host_accessor# that are read-write +[width="100%",options="header",cols="50%,50%"] +|==== +| Data type | Access mode +| not const-qualified | [code]#access_mode::read_write# +|==== + + +[[sec:accessor.local]] +==== Local accessor + +The [code]#local_accessor# class allocates device local memory and provides +access to this memory from within a <>. The +<> that is allocated is shared between all +<> of a <>. If multiple work-groups execute +simultaneously in an implementation, each work-group receives its own +independent copy of the allocated local memory. + +The underlying [code]#dataT# type can be any {cpp} type. If [code]#dataT# is +an implicit-lifetime type (as defined in the {cpp} core language), the local +accessor implicitly creates objects of that type with indeterminate values. +For other types, the local accessor merely allocates uninitialized memory, and +the application is responsible for constructing objects in that memory (e.g. by +calling placement-new). + +A local accessor must not be used in a <> that is invoked +via [code]#single_task# or via the simple form of [code]#parallel_for# that +takes a [code]#range# parameter. In these cases submitting the kernel to +a queue must throw a synchronous [code]#exception# with the +[code]#errc::kernel_argument# error code. + + +===== Interface for local accessors + +A synopsis of the [code]#local_accessor# class is provided below. Since some +of the class types and member functions have the same name and meaning as other +accessors, the common types and functions are described in +<>. The member types are listed in +<> and <>. +The constructors are listed in <>, +and the member functions are listed in <> and +<>. + +The additional common special member functions and common member functions are +listed in <> in +<> and +<>, respectively. For valid implicit +conversions between accessor types refer to <>. +Additionally, accessors of the same type must be equality comparable. + +[source,,linenums] +---- +include::{header_dir}/accessorLocal.h[lines=4..-1] +---- + + +[[table.accessors.local.types]] +.Member types of the [code]#local_accessor# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member types @ Description +a@ +[source] +---- +template +accessor_ptr +---- + a@ Equal to + [code]#multi_ptr#. + +|==== + + +[[table.accessors.local.constructors]] +.Constructors of the [code]#local_accessor# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Constructor @ Description +a@ +[source] +---- +local_accessor() +---- + a@ Constructs an empty local accessor which fulfills the following + post-conditions: +-- + * [code]#(empty() == true)# + * All size queries return [code]#0#. + * The only iterator that can be obtained is [code]#nullptr#. + * Trying to access the underlying memory is undefined behavior. +-- + +a@ +[source] +---- +local_accessor(handler &commandGroupHandlerRef, + const property_list &propList = {}) +---- + a@ Available only when [code]#(dimensions == 0)#. + +Constructs a [code]#local_accessor# for accessing <> of a single +[code]#dataT# element within a <> on the queue associated +with [code]#commandGroupHandlerRef#. The optional [code]#property_list# +provides properties for the constructed accessor. + +a@ +[source] +---- +local_accessor(range allocationSize, + handler &commandGroupHandlerRef, + const property_list &propList = {}) +---- + a@ Available only when [code]#(dimensions > 0)#. + +Constructs a [code]#local_accessor# for accessing <> of an array +of [code]#dataT# elements within a <> on the queue +associated with [code]#commandGroupHandlerRef#. The number of elements in the +array is defined by [code]#allocationSize#. The optional [code]#property_list# +provides properties for the constructed accessor. + +|==== + + +[[table.accessors.local.members]] +.Member functions of the [code]#local_accessor# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +void swap(local_accessor &other); +---- + a@ Swaps the contents of the current accessor with the contents of + [code]#other#. + +a@ +[source] +---- +template +accessor_ptr get_multi_ptr() const noexcept +---- + a@ Returns a [code]#multi_ptr# to the start of the accessor's local memory + region which corresponds to the calling work-group. + +This function may only be called from within a <>. + +|==== + + +[[sec:accessor.local.conversions]] +===== Read only local accessors and implicit conversions + +Since [code]#local_accessor# has no template parameter for the access mode, the +only specialization for a read-only local accessor is by providing a +[code]#const# qualified [code]#dataT# parameter. Specializations with a +non-[code]#const# qualified [code]#dataT# parameter are read-write. There is +an implicit conversion from the read-write specialization to the read-only +specialization, provided that all other template parameters are the same. + + +[[sec:accessor.common.members]] +==== Common members for buffer and local accessors + +The [code]#accessor#, [code]#host_accessor#, and [code]#local_accessor# classes +have many member types and member functions with the same name and meaning. +<> describes these common types and +<> describes the common member functions. + + +[[table.accessors.common.types]] +.Common buffer and local accessor member types +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member types @ Description +a@ +[source] +---- +value_type +---- + a@ If the accessor is read-only, equal to [code]#const dataT#, otherwise + equal to [code]#dataT#. + +See <>, +<> and <> +for which accessors are considered read-only. + +a@ +[source] +---- +reference +---- + a@ Equal to [code]#value_type&#. + +a@ +[source] +---- +const_reference +---- + a@ Equal to [code]#const dataT&#. + +a@ +[source] +---- +iterator +---- + a@ Iterator that can provide ranged access. Cannot be written to if the + accessor is read-only. The underlying pointer is address space qualified + for [code]#accessor# specializations with [code]#target::device# and for + [code]#local_accessor#. + +a@ +[source] +---- +const_iterator +---- + a@ Iterator that can provide ranged access. Cannot be written to. The + underlying pointer is address space qualified for [code]#accessor# + specializations with [code]#target::device# and for + [code]#local_accessor#. + +a@ +[source] +---- +reverse_iterator +---- + a@ Iterator adaptor that reverses the direction of [code]#iterator#. + +a@ +[source] +---- +const_reverse_iterator +---- + a@ Iterator adaptor that reverses the direction of [code]#const_iterator#. + +a@ +[source] +---- +difference_type +---- + a@ Equal to + [code]#typename std::iterator_traits::difference_type#. + +a@ +[source] +---- +size_type +---- + a@ Equal to [code]#size_t#. + +|==== + + +[[table.accessors.common.members]] +.Common buffer and local accessor member functions +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +size_type byte_size() const noexcept +---- + a@ Returns the size in bytes of the memory region this accessor may access. + +For a buffer accessor this is the size of the underlying buffer, unless it is a +<> in which case it is the size of the elements within the +accessor's range. + +For a local accessor this is the size of the accessor's local memory +allocation, per work-group. + +a@ +[source] +---- +size_type size() const noexcept +---- + a@ Returns the number of [code]#dataT# elements of the memory region this + accessor may access. + +For a buffer accessor this is the number of elements in the underlying buffer, +unless it is a <> in which case it is the number of elements +within the accessor's range. + +For a local accessor this is the number of elements in the accessor's local +memory allocation, per work-group. + +a@ +[source] +---- +size_type max_size() const noexcept +---- + a@ Returns the maximum number of elements any accessor of this type would be + able to access. + +a@ +[source] +---- +bool empty() const noexcept +---- + a@ Returns [code]#true# if [code]#(size() == 0)#. + +a@ +[source] +---- +range get_range() const +---- + a@ Available only when [code]#(dimensions > 0)#. + +Returns a [code]#range# object which represents the number of elements of +[code]#dataT# per dimension that this accessor may access. + +For a buffer accessor this is the range of the underlying buffer, unless it is +a <> in which case it is the range that was specified when the +accessor was constructed. + +a@ +[source] +---- +operator reference() const +---- + a@ For [code]#accessor# available only when + [code]#(accessMode != access_mode::atomic && dimensions == 0)#. + +For [code]#host_accessor# and [code]#local_accessor# available only when +[code]#(dimensions == 0)#. + +Returns a reference to the single element that is accessed by this accessor. + +For [code]#accessor# and [code]#local_accessor#, this function may only be +called from within a <>. + +a@ +[source] +---- +reference operator[](id index) const +---- + a@ For [code]#accessor# available only when + [code]#(accessMode != access_mode::atomic && dimensions > 0)#. + +For [code]#host_accessor# and [code]#local_accessor# available only when +[code]#(dimensions > 0)#. + +Returns a reference to the element at the location specified by [code]#index#. +If this is a <>, the element is determined by adding +[code]#index# to the accessor's offset. + +For [code]#accessor# and [code]#local_accessor#, this function may only be +called from within a <>. + +a@ +[source] +---- +__unspecified__ &operator[](size_t index) const +---- + a@ Available only when [code]#(dimensions > 1)#. + +Returns an instance of an undefined intermediate type representing this +accessor, with the dimensionality [code]#dimensions-1# and containing an +implicit [code]#id# with index [code]#dimensions# set to [code]#index#. The +intermediate type returned must provide all available subscript operators which +take a [code]#size_t# parameter defined by this accessor class that are +appropriate for the type it represents (including this subscript operator). + +If this is a <>, the implicit [code]#id# in the returned +instance also includes the accessor's offset. + +For [code]#accessor# and [code]#local_accessor#, this function may only be +called from within a <>. + +a@ +[source] +---- +reference operator[](size_t index) const +---- + a@ For [code]#accessor# available only when + [code]#(accessMode != access_mode::atomic && dimensions == 1)#. + +For [code]#host_accessor# and [code]#local_accessor# available only when +[code]#(dimensions == 1)#. + +Returns a reference to the element at the location specified by [code]#index#. +If this is a <>, the element is determined by adding +[code]#index# to the accessor's offset. + +For [code]#accessor# and [code]#local_accessor#, this function may only be +called from within a <>. + +a@ +[source] +---- +std::add_pointer_t get_pointer() const noexcept +---- + a@ Returns a pointer to the start of this accessor's memory. + +For a buffer accessor this is a pointer to the start of the underlying buffer, +even if this is a <> whose range does not start at the +beginning of the buffer. + +For [code]#accessor# and [code]#local_accessor#, this function may only be +called from within a <>. + +a@ +[source] +---- +iterator begin() const noexcept +---- + a@ Returns an iterator to the first element of the memory this accessor may + access. + +For a buffer accessor this is an iterator to the first element of the +underlying buffer, unless this is a <> in which case it is an +iterator to first element within the accessor's range. + +For [code]#accessor# and [code]#local_accessor#, this function may only be +called from within a <>. + +a@ +[source] +---- +iterator end() const noexcept +---- + a@ Returns an iterator to one element past the last element of the memory + this accessor may access. + +For a buffer accessor this is an iterator to one element past the last element +in the underlying buffer, unless this is a <> in which case +it is an iterator to one element past the last element within the accessor's +range. + +For [code]#accessor# and [code]#local_accessor#, this function may only be +called from within a <>. + +a@ +[source] +---- +const_iterator cbegin() const noexcept +---- + a@ Returns a const iterator to the first element of the memory this accessor + may access. + +For a buffer accessor this is a const iterator to the first element of the +underlying buffer, unless this is a <> in which case it is a +const iterator to first element within the accessor's range. + +For [code]#accessor# and [code]#local_accessor#, this function may only be +called from within a <>. + +a@ +[source] +---- +const_iterator cend() const noexcept +---- + a@ Returns a const iterator to one element past the last element of the + memory this accessor may access. + +For a buffer accessor this is a const iterator to one element past the last +element in the underlying buffer, unless this is a <> in which +case it is a const iterator to one element past the last element within the +accessor's range. + +For [code]#accessor# and [code]#local_accessor#, this function may only be +called from within a <>. + +a@ +[source] +---- +reverse_iterator rbegin() const noexcept +---- + a@ Returns an iterator adaptor to the last element of the memory this + accessor may access. + +For a buffer accessor this is an iterator adaptor to the last element of the +underlying buffer, unless this is a <> in which case it is an +iterator adaptor to the last element within the accessor's range. + +For [code]#accessor# and [code]#local_accessor#, this function may only be +called from within a <>. + +a@ +[source] +---- +reverse_iterator rend() const noexcept +---- + a@ Returns an iterator adaptor to one element before the first element of + the memory this accessor may access. + +For a buffer accessor this is an iterator adaptor to one element before the +first element in the underlying buffer, unless this is a <> in +which case it is an iterator adaptor to one element before the first element +within the accessor's range. + +For [code]#accessor# and [code]#local_accessor#, this function may only be +called from within a <>. + +a@ +[source] +---- +const_reverse_iterator crbegin() const noexcept +---- + a@ Returns a const iterator adaptor to the last element of the memory this + accessor may access. + +For a buffer accessor this is a const iterator adaptor to the last element of +the underlying buffer, unless this is a <> in which case it is +an const iterator adaptor to last element within the accessor's range. + +For [code]#accessor# and [code]#local_accessor#, this function may only be +called from within a <>. + +a@ +[source] +---- +const_reverse_iterator crend() const noexcept +---- + a@ Returns a const iterator adaptor to one element before the first element of + the memory this accessor may access. + +For a buffer accessor this is a const iterator adaptor to one element before the +first element in the underlying buffer, unless this is a <> in +which case it is a const iterator adaptor to one element before the first element +within the accessor's range. + +For [code]#accessor# and [code]#local_accessor#, this function may only be +called from within a <>. + +|==== + + +==== Unsampled image accessors + +There are two classes which implement accessors for unsampled images, +[code]#unsampled_image_accessor# and [code]#host_unsampled_image_accessor#. +The former provides access from within a <> or from +within a <>. The latter provides access from host code that is +outside of a <>. + +The dimensionality of an unsampled image accessor must match the dimensionality +of the underlying image to which it provides access. Unsampled image accessors +support only two access modes: [code]#access_mode::read# and +[code]#access_mode::write#. + +The [code]#accessTarget# template parameter dictates how the +[code]#unsampled_image_accessor# can be used: [code]#image_target::device# +means the accessor can be used in a <> while +[code]#image_target::host_task# means the accessor can be used in a +<>. Programs which specify this template parameter as +[code]#image_target::device# and then use the [code]#unsampled_image_accessor# +from a <> are ill formed. Likewise, programs which specify this +template parameter as [code]#image_target::host_task# and then use the +[code]#unsampled_image_accessor# from a <> are ill +formed. + + +===== Interface for unsampled image accessors + +A synopsis of the two unsampled image accessor classes is provided below. Both +classes have member types with the same name, which are described in +<>. The constructors for the two +classes are described in <> and +<>. Both classes also have +member functions with the same name, which are described in +<>. + +The additional common special member functions and common member functions are +listed in <> in +<> and +<>, respectively. For valid implicit +conversions between unsampled accessor types refer to +<>. + +Two [code]#unsampled_image_accessor# objects of the same type must be equality +comparable in both the host code and in SYCL kernel functions. Two +[code]#host_unsampled_image_accessor# objects of the same type must be equality +comparable in the host code. + +[source,,linenums] +---- +include::{header_dir}/accessorUnsampledImage.h[lines=4..-1] +---- + + +[[table.accessors.unsampled.image.types]] +.Member types of the unsampled image classes +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member types @ Description +a@ +[source] +---- +value_type +---- + a@ If the accessor is read-only, equal to [code]#const dataT#, otherwise + equal to [code]#dataT#. + +See <> for which accessors are +considered read-only. + +a@ +[source] +---- +reference +---- + a@ Equal to [code]#value_type&#. + +a@ +[source] +---- +const_reference +---- + a@ Equal to [code]#const dataT&#. + +|==== + + +[[table.accessors.unsampled.image.constructors]] +.Constructors of the [code]#unsampled_image_accessor# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Constructor @ Description +a@ +[source] +---- +template +unsampled_image_accessor( + unsampled_image &imageRef, + handler &commandGroupHandlerRef, + const property_list &propList = {}) +---- + a@ Constructs an [code]#unsampled_image_accessor# for accessing an + [code]#unsampled_image# within a <> on the [code]#queue# + associated with [code]#commandGroupHandlerRef#. The optional + [code]#property_list# provides properties for the constructed object. + +If [code]#accessTarget# is [code]#image_target::device#, throws an +[code]#exception# with the [code]#errc::feature_not_supported# error code if +the device associated with [code]#commandGroupHandlerRef# does not have +[code]#aspect::image#. + +a@ +[source] +---- +template +unsampled_image_accessor( + unsampled_image &imageRef, + handler &commandGroupHandlerRef, TagT tag, + const property_list &propList = {}) +---- + a@ Constructs an [code]#unsampled_image_accessor# for accessing an + [code]#unsampled_image# within a <> on the [code]#queue# + associated with [code]#commandGroupHandlerRef#. The [code]#tag# is used + to deduce template arguments of the [code]#unsampled_image_accessor# as + described in <>. The optional + [code]#property_list# provides properties for the constructed object. + +If [code]#accessTarget# is [code]#image_target::device#, throws an +[code]#exception# with the [code]#errc::feature_not_supported# error code if +the device associated with [code]#commandGroupHandlerRef# does not have +[code]#aspect::image#. + +|==== + + +[[table.accessors.host.unsampled.image.constructors]] +.Constructors of the [code]#host_unsampled_image_accessor# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Constructor @ Description +a@ +[source] +---- +template +host_unsampled_image_accessor( + unsampled_image &imageRef, + const property_list &propList = {}) +---- + a@ Constructs a [code]#host_unsampled_image_accessor# for accessing an + [code]#unsampled_image# immediately on the host. The optional + [code]#property_list# provides properties for the constructed object. + +a@ +[source] +---- +template +host_unsampled_image_accessor( + unsampled_image &imageRef, + TagT tag, const property_list &propList = {}) +---- + a@ Constructs a [code]#host_unsampled_image_accessor# for accessing an + [code]#unsampled_image# immediately on the host. The [code]#tag# is used + to deduce template arguments of the [code]#host_unsampled_image_accessor# + as described in <>. The optional + [code]#property_list# provides properties for the constructed object. + +|==== + + +[[table.accessors.unsampled.image.members]] +.Member functions of the unsampled image classes +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +size_t size() const noexcept +---- + a@ Returns the number of elements of the underlying [code]#unsampled_image# + that this accessor is accessing. + +a@ +[source] +---- +template +dataT read(const coordT &coords) const +---- + a@ Available only when [code]#(accessMode == access_mode::read)#. + +Reads and returns an element of the [code]#unsampled_image# at the coordinates +specified by [code]#coords#. Permitted types for [code]#coordT# are +[code]#int# when [code]#dimensions == 1#, [code]#int2# when +[code]#dimensions == 2# and [code]#int4# when [code]#dimensions == 3#. + +For [code]#unsampled_image_accessor#, this function may only be called from +within a <>. + +a@ +[source] +---- +template +void write(const coordT &coords, const dataT &color) const +---- + a@ Available only when [code]#(accessMode == access_mode::write)#. + +Writes the value specified by [code]#color# to the element of the image at the +coordinates specified by [code]#coords#. Permitted types for [code]#coordT# +are [code]#int# when [code]#dimensions == 1#, [code]#int2# when +[code]#dimensions == 2# and [code]#int4# when [code]#dimensions == 3#. + +For [code]#unsampled_image_accessor#, this function may only be called from +within a <>. + +|==== + + +[[sec:accessor.unsampled.image.tags]] +===== Deduction tags for unsampled image accessors + +Some [code]#unsampled_image_accessor# constructors take a [code]#TagT# +parameter, which is used to deduce template arguments. The permissible values +for this parameter are listed in <> along +with the access mode and accessor target that they imply. + +[[table.accessors.unsampled.image.tags]] +.Enumeration of tags available for [code]#unsampled_image_accessor# construction +[width="100%",options="header",cols="33%,33%,34%"] +|==== +| Tag value | Access mode | Accessor target +| [code]#read_only# + | [code]#access_mode::read# + | [code]#image_target::device# +| [code]#write_only# + | [code]#access_mode::write# + | [code]#image_target::device# +| [code]#read_only_host_task# + | [code]#access_mode::read# + | [code]#image_target::host_task# +| [code]#write_only_host_task# + | [code]#access_mode::write# + | [code]#image_target::host_task# +|==== + +Some [code]#host_unsampled_image_accessor# constructors also take a +[code]#TagT# parameter. The permissible values for this parameter are listed +in <> along with the access mode +that they imply. + +[[table.accessors.host.unsampled.image.tags]] +.Enumeration of tags available for [code]#host_unsampled_image_accessor# construction +[width="100%",options="header",cols="50%,50%"] +|==== +| Tag value | Access mode +| [code]#read_only# + | [code]#access_mode::read# +| [code]#write_only# + | [code]#access_mode::write# +|==== + + +[[sec:accessor.unsampled.image.conversions]] +===== Read only unsampled image accessors and implicit conversions + +All specializations of unsampled image accessors with [code]#access_mode::read# +are read-only regardless of whether [code]#dataT# is [code]#const# qualified. +There is an implicit conversion between the [code]#const# qualified and +non-[code]#const# qualified specializations, provided that all other template +parameters are the same. + + +==== Sampled image accessors + +There are two classes which implement accessors for sampled images, +[code]#sampled_image_accessor# and [code]#host_sampled_image_accessor#. +The former provides access from within a <> or from +within a <>. The latter provides access from host code that is +outside of a <>. + +The dimensionality of a sampled image accessor must match the dimensionality +of the underlying image to which it provides access. Sampled image accessors +are always read-only. + +The [code]#accessTarget# template parameter dictates how the +[code]#sampled_image_accessor# can be used: [code]#image_target::device# means +the accessor can be used in a <> while +[code]#image_target::host_task# means the accessor can be used in a +<>. Programs which specify this template parameter as +[code]#image_target::device# and then use the [code]#sampled_image_accessor# +from a <> are ill formed. Likewise, programs which specify this +template parameter as [code]#image_target::host_task# and then use the +[code]#sampled_image_accessor# from a <> are ill formed. + + + +===== Interface for sampled image accessors + +A synopsis of the two sampled image accessor classes is provided below. Both +classes have member types with the same name, which are described in +<>. The constructors for the two +classes are described in <> and +<>. Both classes also have +member functions with the same name, which are described in +<>. + +The additional common special member functions and common member functions are +listed in <> in +<> and +<>, respectively. For valid implicit +conversions between sampled accessor types refer to +<>. + +Two [code]#sampled_image_accessor# objects of the same type must be equality +comparable in both the host code and in SYCL kernel functions. Two +[code]#host_sampled_image_accessor# objects of the same type must be equality +comparable in the host code. + +[source,,linenums] +---- +include::{header_dir}/accessorSampledImage.h[lines=4..-1] +---- + + +[[table.accessors.sampled.image.types]] +.Member types of the sampled image classes +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member types @ Description +a@ +[source] +---- +value_type +---- + a@ Equal to [code]#const dataT#. + +a@ +[source] +---- +reference +---- + a@ Equal to [code]#const dataT&#. + +a@ +[source] +---- +const_reference +---- + a@ Equal to [code]#const dataT&#. + +|==== + + +[[table.accessors.sampled.image.constructors]] +.Constructors of the [code]#sampled_image_accessor# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Constructor @ Description +a@ +[source] +---- +template +sampled_image_accessor( + sampled_image &imageRef, + handler &commandGroupHandlerRef, + const property_list &propList = {}) +---- + a@ Constructs a [code]#sampled_image_accessor# for accessing a + [code]#sampled_image# within a <> on the [code]#queue# + associated with [code]#commandGroupHandlerRef#. The optional + [code]#property_list# provides properties for the constructed object. + +If [code]#accessTarget# is [code]#image_target::device#, throws an +[code]#exception# with the [code]#errc::feature_not_supported# error code if +the device associated with [code]#commandGroupHandlerRef# does not have +[code]#aspect::image#. + +a@ +[source] +---- +template +sampled_image_accessor( + sampled_image &imageRef, + handler &commandGroupHandlerRef, TagT tag, + const property_list &propList = {}) +---- + a@ Constructs a [code]#sampled_image_accessor# for accessing a + [code]#sampled_image# within a <> on the [code]#queue# + associated with [code]#commandGroupHandlerRef#. The [code]#tag# is used + to deduce template arguments of the [code]#sampled_image_accessor# as + described in <>. The optional + [code]#property_list# provides properties for the constructed object. + +If [code]#accessTarget# is [code]#image_target::device#, throws an +[code]#exception# with the [code]#errc::feature_not_supported# error code if +the device associated with [code]#commandGroupHandlerRef# does not have +[code]#aspect::image#. + +|==== + + +[[table.accessors.host.sampled.image.constructors]] +.Constructors of the [code]#host_sampled_image_accessor# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Constructor @ Description +a@ +[source] +---- +template +host_sampled_image_accessor( + sampled_image &imageRef, + const property_list &propList = {}) +---- + a@ Constructs a [code]#host_sampled_image_accessor# for accessing a + [code]#sampled_image# immediately on the host. The optional + [code]#property_list# provides properties for the constructed object. + +|==== + + +[[table.accessors.sampled.image.members]] +.Member functions of the sampled image classes +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +size_t size() const noexcept +---- + a@ Returns the number of elements of the underlying [code]#sampled_image# + that this accessor is accessing. + +a@ +[source] +---- +template +dataT read(const coordT &coords) const +---- + a@ Reads and returns a sampled element of the [code]#sampled_image# at the + coordinates specified by [code]#coords#. Permitted types for + [code]#coordT# are [code]#float# when [code]#dimensions == 1#, + [code]#float2# when [code]#dimensions == 2# and [code]#float4# when + [code]#dimensions == 3#. + +For [code]#sampled_image_accessor#, this function may only be called from +within a <>. + +|==== + + +[[sec:accessor.sampled.image.tags]] +===== Deduction tags for sampled image accessors + +Some [code]#sampled_image_accessor# constructors take a [code]#TagT# parameter, +which is used to deduce template arguments. The permissible values for this +parameter are listed in <> along with the +accessor target that they imply. + +[[table.accessors.sampled.image.tags]] +.Enumeration of tags available for [code]#sampled_image_accessor# construction +[width="100%",options="header",cols="50%,50%"] +|==== +| Tag value | Accessor target +| [code]#read_only# + | [code]#image_target::device# +| [code]#read_only_host_task# + | [code]#image_target::host_task# +|==== + + +[[sec:accessor.sampled.image.conversions]] +===== Read only sampled image accessors and implicit conversions + +All specializations of sampled image accessors are read-only regardless of +whether [code]#dataT# is [code]#const# qualified. There is an implicit +conversion between the [code]#const# qualified and non-[code]#const# qualified +specializations, provided that all other template parameters are the same. + + +// %%%%%%%%%%%%%%%%%%%%%%%%%%%% end accessors %%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +=== Address space classes + +In SYCL, there are five different address spaces: global, local, constant, +private and generic. In a SYCL generic implementation, types are not +affected by the address spaces. However, there are situations where users +need to explicitly carry address spaces in the type. For example: + + * For performance tuning and genericness. Even if the platform supports + the representation of the generic address space, this may come at some + performance sacrifice. In order to help the target compiler, it can be + useful to track specifically which address space a pointer is + addressing. + * When linking SYCL kernels with <>-specific functions. In this + case, it might be necessary to specify the address space for any pointer + parameters. + +Direct declaration of pointers with address spaces is discouraged as the +definition is implementation-defined. Users must rely on the +[code]#multi_ptr# class to handle address space boundaries and +interoperability. + + +[[sec:multiptr]] +==== Multi-pointer class + +The multi-pointer class is the common interface for the explicit pointer +classes, defined in <>. + +There are situations where a user may want to make their type address space dependent. +This allows performing generic programming that depends on the address space associated +with their data. An example might be wrapping a pointer inside a class, where +a user may need to template the class according to the address space of the +pointer the class is initialized with. In this case, the [code]#multi_ptr# +class enables users to do this in a portable and stable way. + +The [code]#multi_ptr# class exposes 3 flavors of the same interface. +If the value of [code]#access::decorated# is [code]#access::decorated::no#, +the interface exposes pointers and references type that are not decorated by an address space. +If the value of [code]#access::decorated# is [code]#access::decorated::yes#, +the interface exposes pointers and references type that are decorated by an address space. +The decoration is implementation dependent and relies on device compiler extensions. +The decorated type may be distinct from the non-decorated one. +For interoperability with the <>, users should rely on types exposed +by the decorated version. +If the value of [code]#access::decorated# is [code]#access::decorated::legacy#, +the 1.2.1 interface is exposed. +This interface is deprecated. + +The template traits [code]#remove_decoration# and type alias +[code]#remove_decoration_t# retrieve the non-decorated pointer or +reference from a decorated one. Using this template trait with a +non-decorated type is safe and returns the same type. + + +It is possible to use the [code]#void# type for the [code]#multi_ptr# +class, but in that case some functionality is disabled. +[code]#multi_ptr# does not provide the [code]#reference# or +[code]#const_reference# types, the access operators +([code]#operator*()#, [code]#+operator->()+#), the arithmetic +operators or [code]#prefetch# member function. +Conversions from [code]#multi_ptr# to [code]#multi_ptr# of the +same address space are allowed, and will occur implicitly. +Conversions from [code]#multi_ptr# to any other +[code]#multi_ptr# type of the same address space +are allowed, but must be explicit. +The same rules apply to [code]#multi_ptr#. + +An overview of the interface provided for the [code]#multi_ptr# class +follows. + +[source,,linenums] +---- +include::{header_dir}/multipointer.h[lines=4..-1] +---- + + +[[table.constructors.multiptr]] +.Constructors of the SYCL [code]#multi_ptr# class template +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Constructor @ Description +a@ +[source] +---- +multi_ptr() +---- + a@ Default constructor. + +a@ +[source] +---- +multi_ptr(const multi_ptr &) +---- + a@ Copy constructor. + +a@ +[source] +---- +multi_ptr(multi_ptr&&) +---- + a@ Move constructor. + +a@ +[source] +---- +multi_ptr(multi_ptr::pointer) +---- + a@ Constructor that takes as an argument a decorated pointer. + +a@ +[source] +---- +multi_ptr(std::nullptr_t) +---- + a@ Constructor from a [code]#nullptr#. + +a@ +[source] +---- +template +multi_ptr(accessor); +---- + a@ Available only when: + [code]#Space == access::address_space::global_space || Space == access::address_space::generic_space#. + +Constructs a [code]#multi_ptr# from an accessor of +[code]#target::device#. + +This constructor may only be called from within a <>. + +a@ +[source] +---- +template +multi_ptr(local_accessor) +---- + a@ Available only when: + [code]#Space == access::address_space::global_space || Space == access::address_space::generic_space#. + +Constructs a [code]#multi_ptr# from a [code]#local_accessor#. + +This constructor may only be called from within a <>. + +a@ +[source] +---- +template +multi_ptr(accessor); +---- + a@ Deprecated in SYCL 2020. Use the overload with + [code]#local_accessor# instead. + +Available only when: +[code]#Space == access::address_space::global_space || Space == access::address_space::generic_space#. + +Constructs a [code]#multi_ptr# from an accessor of [code]#target::local#. + +This constructor may only be called from within a <>. + +a@ +[source] +---- +template + multi_ptr make_ptr(ElementType* pointer) +---- + a@ Global function to create a [code]#multi_ptr# instance depending + on the address space of the [code]#pointer# argument. + An implementation must return [code]#nullptr# if the run-time value of + [code]#pointer# is not compatible with [code]#Space#, and must issue a + compile-time diagnostic if the deduced address space is not compatible + with [code]#Space#. + +|==== + + + +[[table.multiptr.operators]] +.Operators of [code]#multi_ptr# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Operators @ Description +a@ +[source] +---- +template + multi_ptr &operator=(const multi_ptr&) +---- + a@ Copy assignment operator. + +a@ +[source] +---- +template + multi_ptr &operator=(multi_ptr&&) +---- + a@ Move assignment operator. + +a@ +[source] +---- +template + multi_ptr &operator=(std::nullptr_t) +---- + a@ Assigns [code]#nullptr# to the [code]#multi_ptr#. + +a@ +[source] +---- +template + multi_ptr &operator=(const multi_ptr&) +---- + a@ Available only when: [code]#Space == access::address_space::generic_space && ASP != access::address_space::constant_space#. + +Assigns the value of the left hand side [code]#multi_ptr# into the [code]#generic_ptr#. + +a@ +[source] +---- +template + multi_ptr &operator=(multi_ptr&& +---- + a@ Available only when: + [code]#Space == access::address_space::generic_space && ASP != access::address_space::constant_space#. + +Move the value of the left hand side [code]#multi_ptr# into the [code]#generic_ptr#. + +a@ +[source] +---- +template + pointer operator->() const +---- + a@ Available only when: [code]#!std::is_void::value#. + +Returns the underlying pointer. + +a@ +[source] +---- +template + reference operator*() const +---- + a@ Available only when: [code]#!std::is_void::value#. + +Returns a reference to the pointed value. + +a@ +[source] +---- +template + operator pointer() const +---- + a@ Implicit conversion to the underlying pointer type. + *Deprecated:* The member function [code]#get# should be used instead + +a@ +[source] +---- +template + operator multi_ptr() const +---- + a@ Available only when: + [code]#Space == access::address_space::generic_space#. + +Conversion from [code]#generic_ptr# to [code]#private_ptr#. +The result is undefined if the pointer does not address the private +address space. + +a@ +[source] +---- +template + operator multi_ptr() const +---- + a@ Available only when: + [code]#Space == access::address_space::generic_space#. + +Conversion from [code]#generic_ptr# to [code]#private_ptr#. +The result is undefined if the pointer does not address the private +address space. + +a@ +[source] +---- +template + operator multi_ptr() const +---- + a@ Available only when: + [code]#Space == access::address_space::generic_space#. + +Conversion from [code]#generic_ptr# to [code]#global_ptr#. +The result is undefined if the pointer does not address the global +address space. + +a@ +[source] +---- +template + operator multi_ptr() const +---- + a@ Available only when: + [code]#Space == access::address_space::generic_space#. + +Conversion from [code]#generic_ptr# to [code]#global_ptr#. +The result is undefined if the pointer does not address the global +address space. + +a@ +[source] +---- +template + operator multi_ptr() const +---- + a@ Available only when: + [code]#Space == access::address_space::generic_space#. + +Conversion from [code]#generic_ptr# to [code]#local_ptr#. +The result is undefined if the pointer does not address the local +address space. + +a@ +[source] +---- +template + operator multi_ptr() const +---- + a@ Available only when: + [code]#Space == access::address_space::generic_space#. + +Conversion from [code]#generic_ptr# to [code]#local_ptr#. +The result is undefined if the pointer does not address the local +address space. + +a@ +[source] +---- +template + operator multi_ptr() const +---- + a@ Available only when: + [code]#!std::is_void::value && !std::is_const::value#. + +Implicit conversion to a [code]#multi_ptr# of type [code]#void#. + +a@ +[source] +---- +template + operator multi_ptr() const +---- + a@ Available only when: + [code]#!std::is_void::value && std::is_const::value#. + +Implicit conversion to a [code]#multi_ptr# of type [code]#const void#. + +a@ +[source] +---- +template + operator multi_ptr() const +---- + a@ Implicit conversion to a [code]#multi_ptr# + of type [code]#const value_type#. + +a@ +[source] +---- + + operator multi_ptr() const +---- + a@ Available only when: + [code]#is_decorated == true#. + +Implicit conversion to the equivalent [code]#multi_ptr# object that does not expose +decorated pointers or references. + +a@ +[source] +---- + + operator multi_ptr() const +---- + a@ Available only when: + [code]#is_decorated == false#. + +Implicit conversion to the equivalent [code]#multi_ptr# object that exposes +decorated pointers and references. + +|==== + + + +[[table.multiptr.members]] +.Member functions of [code]#multi_ptr# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +pointer get() const +---- + a@ Returns the underlying pointer. + Whether the pointer is decorated depends on the value of [code]#DecorateAddress#. + +a@ +[source] +---- +__unspecified__ * get_decorated() const +---- + a@ Returns the underlying pointer decorated by the address space that it addresses. + Note that the support involves implementation-defined device compiler extensions. + +a@ +[source] +---- +std::add_pointer_t get_raw() const +---- + a@ Returns the underlying pointer, always undecorated. + +a@ +[source] +---- +void prefetch(size_t numElements) const +---- + a@ Available only when: [code]#Space == access::address_space::global_space#. + +Prefetches a number of elements specified by [code]#numElements# into +the <> cache. This operation is an implementation-defined +optimization and does not effect the functional behavior of the SYCL +kernel function. + +|==== + + + +[[table.multipointer.hiddenfriendfunctions]] +.Hidden friend functions of the [code]#multi_ptr# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Hidden friend function @ Description +a@ +[source] +---- +reference operator*(const multi_ptr& mp) +---- + a@ Available only when: [code]#!std::is_void::value#. + +Operator that returns a reference to the [code]#value_type# +of [code]#mp#. + +a@ +[source] +---- +multi_ptr& operator++(multi_ptr& mp) +---- + a@ Available only when: [code]#!std::is_void::value#. + +Increments [code]#mp# by [code]#1# and returns [code]#mp#. + +a@ +[source] +---- +multi_ptr operator++(multi_ptr& mp, int) +---- + a@ Available only when: [code]#!std::is_void::value#. + +Increments [code]#mp# by [code]#1# and returns a new [code]#multi_ptr# +with the value of the original [code]#mp#. + +a@ +[source] +---- +multi_ptr& operator--(multi_ptr& mp) +---- + a@ Available only when: [code]#!std::is_void::value#. + +Decrements [code]#mp# by [code]#1# and returns [code]#mp#. + +a@ +[source] +---- +multi_ptr operator--(multi_ptr& mp, int) +---- + a@ Available only when: [code]#!std::is_void::value#. + +Decrements [code]#mp# by [code]#1# and returns a new [code]#multi_ptr# +with the value of the original [code]#mp#. + +a@ +[source] +---- +multi_ptr& operator+=(multi_ptr& lhs, difference_type r) +---- + a@ Available only when: [code]#!std::is_void::value#. + +Moves [code]#mp# forward by [code]#r# and returns [code]#lhs#. + +a@ +[source] +---- +multi_ptr& operator-=(multi_ptr& lhs, difference_type r) +---- + a@ Available only when: [code]#!std::is_void::value#. + +Moves [code]#mp# backward by [code]#r# and returns [code]#lhs#. + +a@ +[source] +---- +multi_ptr operator+(const multi_ptr& lhs, difference_type r) +---- + a@ Available only when: [code]#!std::is_void::value#. + +Creates a new [code]#multi_ptr# that points [code]#r# forward +compared to [code]#lhs#. + +a@ +[source] +---- +multi_ptr operator-(const multi_ptr& lhs, difference_type r) +---- + a@ Available only when: [code]#!std::is_void::value#. + +Creates a new [code]#multi_ptr# that points [code]#r# backward +compared to [code]#lhs#. + +a@ +[source] +---- +bool operator==(const multi_ptr& lhs, const multi_ptr& rhs) +---- + a@ Comparison operator [code]#==# for [code]#multi_ptr# class. + +a@ +[source] +---- +bool operator!=(const multi_ptr& lhs, const multi_ptr& rhs) +---- + a@ Comparison operator [code]#!=# for [code]#multi_ptr# class. + +a@ +[source] +---- +bool operator<(const multi_ptr& lhs, const multi_ptr& rhs) +---- + a@ Comparison operator [code]#<# for [code]#multi_ptr# class. + +a@ +[source] +---- +bool operator>(const multi_ptr& lhs, const multi_ptr& rhs) +---- + a@ Comparison operator [code]#># for [code]#multi_ptr# class. + +a@ +[source] +---- +bool operator<=(const multi_ptr& lhs, const multi_ptr& rhs) +---- + a@ Comparison operator [code]#+<=+# for [code]#multi_ptr# class. + +a@ +[source] +---- +bool operator>=(const multi_ptr& lhs, const multi_ptr& rhs) +---- + a@ Comparison operator [code]#>=# for [code]#multi_ptr# class. + +a@ +[source] +---- +bool operator==(const multi_ptr& lhs, std::nullptr_t) +---- + a@ Comparison operator [code]#==# for [code]#multi_ptr# class with a + [code]#std::nullptr_t#. + +a@ +[source] +---- +bool operator!=(const multi_ptr& lhs, std::nullptr_t) +---- + a@ Comparison operator [code]#!=# for [code]#multi_ptr# class with a + [code]#std::nullptr_t#. + +a@ +[source] +---- +bool operator<(const multi_ptr& lhs, std::nullptr_t) +---- + a@ Comparison operator [code]#<# for [code]#multi_ptr# class with a + [code]#std::nullptr_t#. + +a@ +[source] +---- +bool operator>(const multi_ptr& lhs, std::nullptr_t) +---- + a@ Comparison operator [code]#># for [code]#multi_ptr# class with a + [code]#std::nullptr_t#. + +a@ +[source] +---- +bool operator<=(const multi_ptr& lhs, std::nullptr_t) +---- + a@ Comparison operator [code]#+<=+# for [code]#multi_ptr# class with a + [code]#std::nullptr_t#. + +a@ +[source] +---- +bool operator>=(const multi_ptr& lhs, std::nullptr_t) +---- + a@ Comparison operator [code]#>=# for [code]#multi_ptr# class with a + [code]#std::nullptr_t#. + +a@ +[source] +---- +bool operator==(std::nullptr_t, const multi_ptr& rhs) +---- + a@ Comparison operator [code]#==# for [code]#multi_ptr# class with a + [code]#std::nullptr_t#. + +a@ +[source] +---- +bool operator!=(std::nullptr_t, const multi_ptr& rhs) +---- + a@ Comparison operator [code]#!=# for [code]#multi_ptr# class with a + [code]#std::nullptr_t#. + +a@ +[source] +---- +bool operator<(std::nullptr_t, const multi_ptr& rhs) +---- + a@ Comparison operator [code]#<# for [code]#multi_ptr# class with a + [code]#std::nullptr_t#. + +a@ +[source] +---- +bool operator>(std::nullptr_t, const multi_ptr& rhs) +---- + a@ Comparison operator [code]#># for [code]#multi_ptr# class with a + [code]#std::nullptr_t#. + +a@ +[source] +---- +bool operator<=(std::nullptr_t, const multi_ptr& rhs) +---- + a@ Comparison operator [code]#+<=+# for [code]#multi_ptr# class with a + [code]#std::nullptr_t#. + +a@ +[source] +---- +bool operator>=(std::nullptr_t, const multi_ptr& rhs) +---- + a@ Comparison operator [code]#>=# for [code]#multi_ptr# class with a + [code]#std::nullptr_t#. + +|==== + + +The following is the overview of the legacy interface from 1.2.1 provided +for the [code]#multi_ptr# class. + +This legacy class supports the deprecated [code]#address_space::constant_space# +address space, which can be used to represent a pointer to <>. +Pointers to <> have an implementation-defined address space, +and each implementation can define whether it is legal to assign such a pointer +to a generic address pointer. + +[source,,linenums] +---- +include::{header_dir}/multipointerlegacy.h[lines=4..-1] +---- + + +[[sec:pointerclasses]] +==== Explicit pointer aliases + +SYCL provides aliases to the [code]#multi_ptr# class template (see +<>) for each specialization of [code]#access::address_space#. + +A synopsis of the SYCL [code]#multi_ptr# class template +aliases is provided below. + +// Interface of the explicit pointer classes +[source,,linenums] +---- +include::{header_dir}/pointer.h[lines=4..-1] +---- + +Note that using [code]#global_ptr#, [code]#local_ptr#, +[code]#constant_ptr# or [code]#private_ptr# +without specifying the decoration is deprecated. +The default argument is provided for compatibility with 1.2.1. + + +[[subsec:samplers]] +=== Image samplers + +The SYCL [code]#image_sampler# struct contains a configuration for sampling a +[code]#sampled_image#. The members of this struct are defined by the following +tables. + +// Interface of the sampler class +[source,,linenums] +---- +include::{header_dir}/imageSampler.h[lines=4..-1] +---- + + +[[table.addressing.mode.sampler]] +.Addressing modes description +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ addressing_mode @ Description +a@ +[source] +---- +mirrored_repeat +---- + a@ Out of range coordinates will be flipped at every integer junction. This addressing mode + can only be used with normalized coordinates. If normalized coordinates are not used, this + addressing mode may generate image coordinates that are undefined. + +a@ +[source] +---- +repeat +---- + a@ Out of range image coordinates are wrapped to the valid range. This addressing mode can only + be used with normalized coordinates. If normalized coordinates are not used, this + addressing mode may generate image coordinates that are undefined. + +a@ +[source] +---- +clamp_to_edge +---- + a@ Out of range image coordinates are clamped to the extent. + +a@ +[source] +---- +clamp +---- + a@ Out of range image coordinates will return a border color. + +a@ +[source] +---- +none +---- + a@ For this addressing mode the programmer guarantees that the image coordinates used to + sample elements of the image refer to a location inside the image; otherwise the results are + undefined. + +|==== + + + +[[table.filtering.mode.sampler]] +.Filtering modes description +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ filtering_mode @ Description +a@ +[source] +---- +nearest +---- + a@ Chooses a color of nearest pixel. + +a@ +[source] +---- +linear +---- + a@ Performs a linear sampling of adjacent pixels. + +|==== + + + +[[table.normalization.mode.sampler]] +.Coordinate normalization modes description +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ coordinate_normalization_mode @ Description +a@ +[source] +---- +normalized +---- + a@ Normalizes image coordinates. + +a@ +[source] +---- +unnormalized +---- + a@ Does not normalize image coordinates. + +|==== + + +// \input{usm} + +// %%%%%%%%%%%%%%%%%%%%%%%%%%%% begin usm %%%%%%%%%%%%%%%%%%%%%%%%%%%% + +[[sec:usm]] +== Unified shared memory (USM) + +This section describes properties and routines for pointer-based +memory management interfaces in SYCL. These routines augment, rather +than replace, the buffer-based interfaces in SYCL. + +Unified Shared Memory (<>) provides a pointer-based alternative to +the buffer programming model. USM enables: + + * Easier integration into existing code bases by representing allocations + as pointers rather than buffers, with full support for pointer + arithmetic into allocations. + * Fine-grain control over ownership and accessibility of allocations, to + optimally choose between performance and programmer convenience. + * A simpler programming model, by automatically migrating some allocations + between SYCL devices and the host. + +To show the differences with example from <>, the +following source code example shows how shared memory can be used +between host and device: + +[source,,linenums] +---- +include::{code_dir}/usm_shared.cpp[lines=4..-1] +---- + +By comparison, the following source code example uses less capable +device memory, which requires explicit copy between the device and the +host: +[source,,linenums] +---- +include::{code_dir}/usm_device.cpp[lines=4..-1] +---- + + +=== Unified addressing + +Unified Addressing guarantees that all devices will use a unified address +space. Pointer values in the unified address space will always refer to the +same location in memory. The unified address space encompasses the host and +one or more devices. Note that this does not require addresses in the +unified address space to be accessible on all devices, just that pointer +values will be consistent. + + +=== Kinds of unified shared memory + +<> is a capability that, when available, provides the ability +to create allocations that are visible to both host and device(s). +USM builds upon Unified Addressing to define a shared address space +where pointer values in this space always refer to the same location +in memory. USM defines three types of memory allocations +described in <>. + +[[table.USM.allocation]] +.Type of USM allocations +[width="100%",options="header",cols="20%,80%"] +|==== +| USM allocation type | Description +| [code]#host# + | Allocations in host memory that are accessible by a device +| [code]#device# + | Allocations in device memory that are *not* accessible by the host +| [code]#shared# + | Allocations in shared memory that are accessible by both host and + device +|==== + +The following [code]#enum# is used to refer to the different types of allocations +inside of a SYCL program: + +[source,,linenums] +---- +namespace sycl { + namespace usm { + enum class alloc { + host, + device, + shared, + unknown + }; + } +} +---- + +USM is an optional feature which may not be supported by all devices, and +devices that support USM may not support all types of USM allocation. A SYCL +application can use the [code]#device::has()# function to determine the +level of USM support for a device. See <> in +<> for more details. + +The characteristics of USM allocations are summarized in +<>. + +[[table.USM.allocation.characteristics]] +.Characteristics of the different kinds of USM allocation +[width="100%",options="header",cols="16%,16%,16%,16%,16%,16%"] +|==== +| Allocation Type | Initial Location | Accessible By | | Migratable To | +.3+| [code]#device# .3+| [code]#device# | [code]#host# | No | [code]#host# | No +| [code]#device# | Yes | [code]#device# | N/A +| Another [code]#device# | Optional (P2P)| Another [code]#device#| No + +.2+| [code]#host# .2+| [code]#host# | [code]#host# | Yes | [code]#host# | N/A +| Any [code]#device# | Yes | [code]#device# | No + +.3+| [code]#shared# .3+| Unspecified | [code]#host# | Yes | [code]#host# | Yes +| [code]#device# | Yes | [code]#device# | Yes +| Another [code]#device# | Optional | Another [code]#device#| Optional +|==== + +USM allocations are only guaranteed to be valid in the SYCL context in which +they were created. The behavior of accessing a USM allocation in a different +context from which it was created is undefined. Attempting to access a kind +of USM allocation that is not supported by the device results in undefined +behavior. + +Device allocations are used for explicitly managing device memory. +Programmers directly allocate device memory and explicitly copy data +between host memory and a device allocation. Device allocations are obtained +through SYCL USM device allocation routines instead of system allocation +routines like [code]#std::malloc# or {cpp} [code]#new#. Device +allocations are not accessible on the host, but the pointer values remain +consistent on account of Unified Addressing. The size of device allocations +will be limited by the amount of memory in a device. Support for device +allocations on a specific device can be queried through +[code]#aspect::usm_device_allocations#. + +Device allocations must be explicitly copied between the host and a device. +The member functions to copy and initialize data are found in +<> and <>, and these +functions may be used on device allocations if a device supports +[code]#aspect::usm_device_allocations#. + +Host allocations allow devices to directly read and write host memory +inside of a kernel. This can be useful for several reasons, such as when the +overhead of moving a small amount of data is not worth paying over the cost of a +remote access or when the size of a data set exceeds the size of a device's memory. +Host allocations must also be obtained using SYCL routines instead +of system allocation routines. While a device may remotely read and +write a host allocation, the allocation does not migrate to the device - +it remains in host memory. Users should take care to properly synchronize +access to host allocations between host execution and kernels. The total +size of host allocations will be limited by the amount of pinnable-memory +on the host on most systems. Support for host allocations on a specific +device can be queried through [code]#aspect::usm_host_allocations#. +Support for atomic modification of host allocations +on a specific device can be queried through +[code]#aspect::usm_atomic_host_allocations#. + +Shared allocations implicitly share data between the host +and devices. Data may move to where it is being used without the programmer +explicitly informing the runtime. It is up to the runtime and backends +to make sure that a shared allocation is available where it is used. +Shared allocations must also be obtained using SYCL allocation routines +instead of the system allocator. The maximum size of a shared allocation +on a specific device, and the total size of all shared allocations in a +context, are implementation-defined. +Support for shared allocations on a +specific device can be queried through [code]#aspect::usm_shared_allocations#. + +Not all devices may support concurrent access of a shared allocation +with the host. If a device does not support this, +host execution and device code must take turns accessing the allocation, so +the host must not access a shared allocation while a kernel is executing. +Host access to a shared allocation which is also accessed +by an executing kernel on a device that does not support +concurrent access results in undefined behavior. If a device does +support concurrent access, both the host and and the device may atomically +modify the same data inside an allocation. Allocations, or pieces of allocations, +are now free to migrate to different devices in the same context +that also support this capability. Additionally, many devices that support +concurrent access may support a working set of shared allocations +larger than device memory. +Users may query whether a device supports concurrent access with atomic +modification of shared allocations through the aspect +[code]#aspect::usm_atomic_shared_allocations#. +See <> in <> for more details. + +Performance hints for shared allocations may be specified by the user +by enqueueing [code]#prefetch# operations on a device. These operations +inform the SYCL runtime that the specified shared allocation is +likely to be accessed on the device in the future, and that it is free +to migrate the allocation to the device. +More about [code]#prefetch# is found in <> and +<>. If a device supports concurrent access to +shared allocations, then [code]#prefetch# operations may be overlapped +with kernel execution. + +Additionally, users may use the [code]#mem_advise# member function to annotate +shared allocations with [code]#advice#. Valid [code]#advice# is defined by the +device and its associated backend. See <> and +<> for more information. + +In the most capable systems, users do not need to use SYCL USM allocation functions +to create shared allocations. The system allocator ([code]#malloc#/[code]#new#) may +instead be used. Likewise, [code]#std::free# and +[code]#delete# are used instead of [code]#sycl::free#. Note that +host and device allocations are unaffected by this +change and must still be allocated using their respective USM functions in +order to guarantee their behavior. Users may query the device to determine +if system allocations are supported for use on the device, through +[code]#aspect::usm_system_allocations#. + + + +=== USM allocations + +USM provides several allocation functions. These functions accept a [code]#property_list# parameter, which is provided for future extensibility. This specification does not yet define any USM allocation properties. + +==== {cpp} allocator interface + +USM provides an allocator class that aligns with the {cpp} allocator interface. This is useful when +using USM with things like {cpp} containers or routines like [code]#std::allocate_shared#. However, due +to how {cpp} library routines that use allocators tend to assume that any memory allocated by an allocator +may be accessed on the host, the [code]#usm_allocator# class is not required to support +allocating [code]#usm::alloc::device# allocations. + +[source,,linenums] +---- +template +class usm_allocator { +public: + using value_type = T; + using propagate_on_container_copy_assignment = std::true_type; + using propagate_on_container_move_assignment = std::true_type; + using propagate_on_container_swap = std::true_type; + +public: + template struct rebind { + typedef usm_allocator other; + }; + + usm_allocator() noexcept = delete; + usm_allocator(const context &ctxt, + const device &dev, + const property_list &propList = {}) noexcept; + usm_allocator(const queue &q, + const property_list &propList = {}) noexcept; + usm_allocator(const usm_allocator &other) noexcept = default; + usm_allocator(usm_allocator &&) noexcept = default; + usm_allocator &operator=(const usm_allocator &) = delete; + usm_allocator &operator=(usm_allocator &&) = default; + + + template + usm_allocator(usm_allocator const &) noexcept; + + /// Allocate memory + T *allocate(size_t count); + + /// Deallocate memory + void deallocate(T *Ptr, size_t count); + + /// Equality Comparison + /// + /// Allocators only compare equal if they are of the same USM kind, alignment, + /// context, and device + template + friend bool operator==(const usm_allocator &, + const usm_allocator &); + + /// Inequality Comparison + /// Allocators only compare unequal if they are not of the same USM kind, alignment, + /// context, or device + template + friend bool operator!=(const usm_allocator &, + const usm_allocator &); +}; +---- + +While the modern {cpp} [code]#usm_allocator# interface is sufficient for +specifying USM allocations and deallocations, many programmers may prefer +C-style [code]#malloc-influenced# APIs. As a convenience to +programmers, [code]#malloc-style# APIs are also defined. Additionally, +other utility functions are specified in the following sections to perform +various operations such as memory copies and initializations as well as to +provide performance hints. + +If the user attempts to allocate a kind of USM allocation on a device that does +not support it, the allocation functions will throw a synchronous [code]#exception# with the +[code]#errc::feature_not_supported# error code. + +==== Device allocation functions + +[[table.usm.device.allocs]] +.USM Device Memory Allocation Functions +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Function @ Description +a@ +[source] +---- +void* sycl::malloc_device(size_t numBytes, + const device& syclDevice, + const context& syclContext, + const property_list &propList = {}) +---- +a@ Returns a pointer to the newly allocated memory on [code]#syclDevice# on +success. The allocation size is specified in bytes. This memory is not +accessible on the host. Memory allocated by [code]#sycl::malloc_device# +must be deallocated with [code]#sycl::free# to avoid memory leaks. On failure, +returns [code]#nullptr#. Zero or more properties can be provided to the +allocation function via an instance of [code]#property_list#. Throws a +synchronous [code]#exception# with the [code]#errc::feature_not_supported# +error code if the [code]#syclDevice# does not have +[code]#aspect::usm_device_allocations#. + +a@ +[source] +---- +template +T* sycl::malloc_device(size_t count, + const device& syclDevice, + const context& syclContext, + const property_list &propList = {}) +---- +a@ Returns a pointer to the newly allocated memory on [code]#syclDevice# on +success. The allocation size is specified in number of elements of type +[code]#T#. This memory is not accessible on the host. Memory allocated +by [code]#sycl::malloc_device# must be deallocated with +[code]#sycl::free# to avoid memory leaks. On failure, returns [code]#nullptr#. +Zero or more properties can be provided to the allocation function +via an instance of [code]#property_list#. +Throws a synchronous [code]#exception# with the +[code]#errc::feature_not_supported# error code if the [code]#syclDevice# +does not have [code]#aspect::usm_device_allocations#. + +a@ +[source] +---- +void* sycl::malloc_device(size_t numBytes, + const queue& syclQueue, + const property_list &propList = {}) +---- +a@ Simplified form where [code]#syclQueue# provides the [code]#device# +and [code]#context#. +Zero or more properties can be provided to the allocation function +via an instance of [code]#property_list#. +Throws a synchronous [code]#exception# with the +[code]#errc::feature_not_supported# error code if the device +does not have [code]#aspect::usm_device_allocations#. + +a@ +[source] +---- +template +T* sycl::malloc_device(size_t count, + const queue& syclQueue, + const property_list &propList = {}) +---- +a@ Simplified form where [code]#syclQueue# provides the [code]#device# +and [code]#context#. +Zero or more properties can be provided to the allocation function +via an instance of [code]#property_list#. +Throws a synchronous [code]#exception# with the +[code]#errc::feature_not_supported# error code if the device +does not have [code]#aspect::usm_device_allocations#. + +a@ +[source] +---- +void* +sycl::aligned_alloc_device(size_t alignment, + size_t numBytes, + const device& syclDevice, + const context& syclContext, + const property_list &propList = {}) +---- +a@ Returns a pointer to the newly allocated memory on +the specified [code]#device# with [code]#alignment#-byte alignment on success. +The allocation size is specified in bytes. This memory is not accessible on +the host. Memory allocated by [code]#sycl::aligned_alloc_device# must be +deallocated with [code]#sycl::free# to avoid memory leaks. On failure, returns +[code]#nullptr#. Devices may only permit certain alignments. Zero or more +properties can be provided to the allocation function via an instance of +[code]#property_list#. Throws a synchronous [code]#exception# with the +[code]#errc::feature_not_supported# error code if the [code]#syclDevice# +does not have [code]#aspect::usm_device_allocations#. + +a@ +[source] +---- +template +T* +sycl::aligned_alloc_device(size_t alignment, + size_t count, + const device& syclDevice, + const context& syclContext, + const property_list &propList = {}) +---- +a@ Returns a pointer to the newly allocated memory on +the specified [code]#device# with [code]#alignment#-byte alignment on success. +The allocation size is specified in elements of type [code]#T#. This memory is +not accessible on the host. Memory allocated by +[code]#sycl::aligned_alloc_device# must be deallocated with [code]#sycl::free# +to avoid memory leaks. On failure, returns [code]#nullptr#. Devices may only +permit certain alignments. Zero or more properties can be provided to the +allocation function via an instance of [code]#property_list#. Throws a +synchronous [code]#exception# with the [code]#errc::feature_not_supported# +error code if the [code]#syclDevice# does not have +[code]#aspect::usm_device_allocations#. + +a@ +[source] +---- +void* +sycl::aligned_alloc_device(size_t alignment, + size_t numBytes, + const queue& syclQueue, + const property_list &propList = {}) +---- +a@ Simplified form where [code]#syclQueue# provides the [code]#device# +and [code]#context#. +Zero or more properties can be provided to the allocation function +via an instance of [code]#property_list#. +Throws a synchronous [code]#exception# with the +[code]#errc::feature_not_supported# error code if the device +does not have [code]#aspect::usm_device_allocations#. + +a@ +[source] +---- +template +T* +sycl::aligned_alloc_device(size_t alignment, + size_t count, + const queue& syclQueue, + const property_list &propList = {}) +---- +a@ Simplified form where [code]#syclQueue# provides the [code]#device# +and [code]#context#. +Zero or more properties can be provided to the allocation function +via an instance of [code]#property_list#. +Throws a synchronous [code]#exception# with the +[code]#errc::feature_not_supported# error code if the device +does not have [code]#aspect::usm_device_allocations#. + +|==== + +==== Host allocation functions + +[[table.usm.host.allocs]] +.USM Host Memory Allocation Functions +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Function @ Description +a@ +[source] +---- +void* sycl::malloc_host(size_t numBytes, + const context& syclContext, + const property_list &propList = {}) +---- +a@ Returns a pointer to the newly allocated host memory on +success. This allocation is specified in bytes. The allocation is +accessible on the host and devices contained in the specified [code]#context#. +Memory allocated by [code]#sycl::malloc_host# must be +deallocated with [code]#sycl::free# to avoid memory leaks. On +failure, returns [code]#nullptr#. +Zero or more properties can be provided to the allocation function +via an instance of [code]#property_list#. +Only devices that have [code]#aspect::usm_host_allocations# may access the +memory allocated by this function. Attempting to access the memory from +a device that does not have the aspect results in undefined behavior. + +a@ +[source] +---- +template +T* sycl::malloc_host(size_t count, + const context& syclContext, + const property_list &propList = {}) +---- +a@ Returns a pointer to the newly allocated host memory on +success. This allocation is specified in number of elements of type [code]#T#. +The allocation is accessible on the host and devices contained in the +specified [code]#context#. +Memory allocated by [code]#sycl::malloc_host# must be +deallocated with [code]#sycl::free# to avoid memory leaks. On +failure, returns [code]#nullptr#. +Zero or more properties can be provided to the allocation function +via an instance of [code]#property_list#. +Only devices that have [code]#aspect::usm_host_allocations# may access the +memory allocated by this function. Attempting to access the memory from +a device that does not have the aspect results in undefined behavior. + +a@ +[source] +---- +void* sycl::malloc_host(size_t numBytes, + const queue& syclQueue, + const property_list &propList = {}) +---- +a@ Simplified form where [code]#syclQueue# provides the [code]#context#. +Zero or more properties can be provided to the allocation function +via an instance of [code]#property_list#. +Only devices that have [code]#aspect::usm_host_allocations# may access the +memory allocated by this function. Attempting to access the memory from +a device that does not have the aspect results in undefined behavior. + +a@ +[source] +---- +template +T* sycl::malloc_host(size_t count, + const queue& syclQueue, + const property_list &propList = {}) +---- +a@ Simplified form where [code]#syclQueue# provides the [code]#context#. +Zero or more properties can be provided to the allocation function +via an instance of [code]#property_list#. +Only devices that have [code]#aspect::usm_host_allocations# may access the +memory allocated by this function. Attempting to access the memory from +a device that does not have the aspect results in undefined behavior. + +a@ +[source] +---- +void* +sycl::aligned_alloc_host(size_t alignment, + size_t numBytes, + const context& syclContext, + const property_list &propList = {}) +---- +a@ Returns a pointer to the newly allocated host memory on +success. This allocation is specified in bytes and aligned to the specified +alignment. The allocation is accessible on the host and devices contained +in the specified [code]#context#. +Memory allocated by [code]#sycl::malloc_host# must be +deallocated with [code]#sycl::free# to avoid memory leaks. On +failure, returns [code]#nullptr#. +Zero or more properties can be provided to the allocation function +via an instance of [code]#property_list#. +Only devices that have [code]#aspect::usm_host_allocations# may access the +memory allocated by this function. Attempting to access the memory from +a device that does not have the aspect results in undefined behavior. + +a@ +[source] +---- +template +T* +sycl::aligned_alloc_host(size_t alignment, + size_t count, + const context& syclContext, + const property_list &propList = {}) +---- +a@ Returns a pointer to the newly allocated host memory on +success. This allocation is specified in elements of type [code]#T# and +aligned to the specified alignment. The allocation is accessible on the +host and devices contained in the specified [code]#context#. +Memory allocated by [code]#sycl::malloc_host# must be +deallocated with [code]#sycl::free# to avoid memory leaks. On +failure, returns [code]#nullptr#. +Zero or more properties can be provided to the allocation function +via an instance of [code]#property_list#. +Only devices that have [code]#aspect::usm_host_allocations# may access the +memory allocated by this function. Attempting to access the memory from +a device that does not have the aspect results in undefined behavior. + +a@ +[source] +---- +void* +sycl::aligned_alloc_host(size_t alignment, + size_t numBytes, + const queue& syclQueue, + const property_list &propList = {}) +---- +a@ Simplified form where [code]#syclQueue# provides the [code]#context#. +Zero or more properties can be provided to the allocation function +via an instance of [code]#property_list#. +Only devices that have [code]#aspect::usm_host_allocations# may access the +memory allocated by this function. Attempting to access the memory from +a device that does not have the aspect results in undefined behavior. + +a@ +[source] +---- +template +void* +sycl::aligned_alloc_host(size_t alignment, + size_t count, + const queue& syclQueue, + const property_list &propList = {}) +---- +a@ Simplified form where [code]#syclQueue# provides the [code]#context#. +Zero or more properties can be provided to the allocation function +via an instance of [code]#property_list#. +Only devices that have [code]#aspect::usm_host_allocations# may access the +memory allocated by this function. Attempting to access the memory from +a device that does not have the aspect results in undefined behavior. + +|==== + +==== Shared allocation functions + +[[table.usm.shared.allocs]] +.USM Shared Memory Allocation Functions +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Function @ Description +a@ +[source] +---- +void* sycl::malloc_shared(size_t numBytes, + const device& syclDevice, + const context& syclContext, + const property_list &propList = {}) +---- +a@ Returns a shared allocation that is accessible on the host and +on [code]#syclDevice#. [code]#syclContext# must contain [code]#syclDevice#. +This allocation is specified in bytes. This memory +must be deallocated with [code]#sycl::free# to avoid memory leaks. On failure, +returns [code]#nullptr#. +Zero or more properties can be provided to the allocation function +via an instance of [code]#property_list#. +Throws a synchronous [code]#exception# with the +[code]#errc::feature_not_supported# error code if the [code]#syclDevice# +does not have [code]#aspect::usm_shared_allocations#. + +a@ +[source] +---- +template +T* sycl::malloc_shared(size_t count, + const device& syclDevice, + const context& syclContext, + const property_list &propList = {}) +---- +a@ Returns a shared allocation that is accessible on the host and +on [code]#syclDevice#. [code]#syclContext# must contain [code]#syclDevice#. +This allocation is specified in number of elements of +type [code]#T#. This memory must be deallocated with [code]#sycl::free# to avoid +memory leaks. On failure, returns [code]#nullptr#. +Zero or more properties can be provided to the allocation function +via an instance of [code]#property_list#. +Throws a synchronous [code]#exception# with the +[code]#errc::feature_not_supported# error code if the [code]#syclDevice# +does not have [code]#aspect::usm_shared_allocations#. + +a@ +[source] +---- +void* sycl::malloc_shared(size_t numBytes, + const queue& syclQueue, + const property_list &propList = {}) +---- +a@ Simplified form where [code]#syclQueue# provides the [code]#device# and +[code]#context#. +Zero or more properties can be provided to the allocation function +via an instance of [code]#property_list#. +Throws a synchronous [code]#exception# with the +[code]#errc::feature_not_supported# error code if the device +does not have [code]#aspect::usm_shared_allocations#. + +a@ +[source] +---- +template +T* sycl::malloc_shared(size_t count, + const queue& syclQueue, + const property_list &propList = {}) +---- +a@ Simplified form where [code]#syclQueue# provides the [code]#device# and +[code]#context#. +Zero or more properties can be provided to the allocation function +via an instance of [code]#property_list#. +Throws a synchronous [code]#exception# with the +[code]#errc::feature_not_supported# error code if the device +does not have [code]#aspect::usm_shared_allocations#. + +a@ +[source] +---- +void* +sycl::aligned_alloc_shared(size_t alignment, + size_t numBytes, + const device& syclDevice, + const context& syclContext, + const property_list &propList = {}) +---- +a@ Returns a shared allocation that is accessible on the host and +on [code]#syclDevice#. [code]#syclContext# must contain [code]#syclDevice#. +This allocation is specified in bytes and aligned to the +specified alignment. This memory +must be deallocated with [code]#sycl::free# to avoid memory leaks. On failure, +returns [code]#nullptr#. +Zero or more properties can be provided to the allocation function +via an instance of [code]#property_list#. +Throws a synchronous [code]#exception# with the +[code]#errc::feature_not_supported# error code if the [code]#syclDevice# +does not have [code]#aspect::usm_shared_allocations#. + +a@ +[source] +---- +template +T* +sycl::aligned_alloc_shared(size_t alignment, + size_t count, + const device& syclDevice, + const context& syclContext, + const property_list &propList = {}) +---- +a@ Returns a shared allocation that is accessible on the host and +on [code]#syclDevice#. [code]#syclContext# must contain [code]#syclDevice#. +This allocation is specified in number of elements of type [code]#T# and aligned to the +specified alignment. This memory +must be deallocated with [code]#sycl::free# to avoid memory leaks. On failure, +returns [code]#nullptr#. +Zero or more properties can be provided to the allocation function +via an instance of [code]#property_list#. +Throws a synchronous [code]#exception# with the +[code]#errc::feature_not_supported# error code if the [code]#syclDevice# +does not have [code]#aspect::usm_shared_allocations#. + +a@ +[source] +---- +void* +sycl::aligned_alloc_shared(size_t alignment, + size_t numBytes, + const queue& syclQueue, + const property_list &propList = {}) +---- +a@ Simplified form where [code]#syclQueue# provides the [code]#device# and +[code]#context#. +Zero or more properties can be provided to the allocation function +via an instance of [code]#property_list#. +Throws a synchronous [code]#exception# with the +[code]#errc::feature_not_supported# error code if the device +does not have [code]#aspect::usm_shared_allocations#. + +a@ +[source] +---- +template +T* +sycl::aligned_alloc_shared(size_t alignment, + size_t count, + const queue& syclQueue, + const property_list &propList = {}) +---- +a@ Simplified form where [code]#syclQueue# provides the [code]#device# and +[code]#context#. +Zero or more properties can be provided to the allocation function +via an instance of [code]#property_list#. +Throws a synchronous [code]#exception# with the +[code]#errc::feature_not_supported# error code if the device +does not have [code]#aspect::usm_shared_allocations#. + +|==== + +==== Parameterized allocation functions + +Device aspects define the set of legal allocation [code]#kind# in the +parameterized allocation functions that follow. [code]#usm:alloc::host# +allocations require a device to have [code]#aspect::usm_host_allocations#. +[code]#usm:alloc::device# allocations require a device to have +[code]#aspect::usm_device_allocations#. +[code]#usm:alloc::shared# allocations require a device to have +[code]#aspect::usm_shared_allocations#. Allocating a [code]#kind# +on a device that doesn't have the appropriate aspect results in +the allocation function throwing a synchronous [code]#exception# +with the [code]#errc::feature_not_supported# error code, or +undefined behavior in the case of use of a host allocation on +a device that doesn't have [code]#aspect::usm_host_allocations#. + + +[[table.usm.param.allocs]] +.USM Parameterized Allocation Functions +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Function @ Description +a@ +[source] +---- +void *sycl::malloc(size_t numBytes, + const device& syclDevice, + const context& syclContext, + usm::alloc kind, + const property_list &propList = {}) +---- +a@ Returns a [code]#kind# allocation. If [code]#kind# is [code]#usm::alloc::host#, +[code]#syclDevice# is ignored. If not, [code]#syclContext# must contain +[code]#syclDevice#. +This allocation is specified in bytes. This memory +must be deallocated with [code]#sycl::free# to avoid memory leaks. On failure, +returns [code]#nullptr#. +Zero or more properties can be provided to the allocation function +via an instance of [code]#property_list#. + +a@ +[source] +---- +template +T *sycl::malloc(size_t count, + const device& syclDevice, + const context& syclContext, + usm::alloc kind, + const property_list &propList = {}) +---- +a@ Returns a [code]#kind# allocation. If [code]#kind# is [code]#usm::alloc::host#, +[code]#syclDevice# is ignored. If not, [code]#syclContext# must contain +[code]#syclDevice#. +This allocation is specified in number of elements of type [code]#T#. +This memory must be deallocated with [code]#sycl::free# to avoid memory leaks. +On failure, returns [code]#nullptr#. +Zero or more properties can be provided to the allocation function +via an instance of [code]#property_list#. + + +a@ +[source] +---- +void *sycl::malloc(size_t numBytes, + const queue& syclQueue, + usm::alloc kind, + const property_list &propList = {}) +---- +a@ Simplified form where [code]#syclQueue# provides the [code]#context# +and any necessary [code]#device#. +Zero or more properties can be provided to the allocation function +via an instance of [code]#property_list#. + +a@ +[source] +---- +template +T *sycl::malloc(size_t count, + const queue& syclQueue, + usm::alloc kind, + const property_list &propList = {}) +---- +a@ Simplified form where [code]#syclQueue# provides the [code]#context# +and any necessary [code]#device#. +Zero or more properties can be provided to the allocation function +via an instance of [code]#property_list#. + +a@ +[source] +---- +void *sycl::aligned_alloc(size_t alignment, + size_t numBytes, + const device& syclDevice, + const context& syclContext, + usm::alloc kind, + const property_list &propList = {}) +---- +a@ Returns a [code]#kind# allocation. If [code]#kind# is [code]#usm::alloc::host#, +[code]#syclDevice# is ignored. If not, [code]#syclContext# must contain +[code]#syclDevice#. +This allocation is specified in bytes and aligned to the +specified alignment. This memory +must be deallocated with [code]#sycl::free# to avoid memory leaks. On failure, +returns [code]#nullptr#. +Zero or more properties can be provided to the allocation function +via an instance of [code]#property_list#. + +a@ +[source] +---- +template +T* sycl::aligned_alloc(size_t alignment, + size_t count, + const device& syclDevice, + const context& syclContext, + usm::alloc kind, + const property_list &propList = {}) +---- +a@ Returns a [code]#kind# allocation. If [code]#kind# is [code]#usm::alloc::host#, +[code]#syclDevice# is ignored. If not, [code]#syclContext# must contain +[code]#syclDevice#. +This allocation is specified in number of elements of type [code]#T# and aligned +to the specified alignment. This memory +must be deallocated with [code]#sycl::free# to avoid memory leaks. On failure, +returns [code]#nullptr#. +Zero or more properties can be provided to the allocation function +via an instance of [code]#property_list#. + +a@ +[source] +---- +void *sycl::aligned_alloc(size_t alignment, + size_t numBytes, + const queue& syclQueue, + usm::alloc kind, + const property_list &propList = {}) +---- +a@ Simplified form where [code]#syclQueue# provides the [code]#context# +and any necessary [code]#device#. +Zero or more properties can be provided to the allocation function +via an instance of [code]#property_list#. + +a@ +[source] +---- +template +T* sycl::aligned_alloc(size_t alignment, + size_t count, + const queue& syclQueue, + usm::alloc kind, + const property_list &propList = {}) +---- +a@ Simplified form where [code]#syclQueue# provides the [code]#context# +and any necessary [code]#device#. +Zero or more properties can be provided to the allocation function +via an instance of [code]#property_list#. + +|==== + + +==== Memory deallocation functions + +[[table.usm.free]] +.USM Deallocation Functions +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Function @ Description +a@ +[source] +---- +void sycl::free(void* ptr, sycl::context& syclContext) +---- +a@ Frees an allocation. The memory pointed to by [code]#ptr# must have been +allocated using one of the USM allocation routines. [code]#syclContext# must +be the same [code]#context# that was used to allocate the memory. + +a@ +[source] +---- +void sycl::free(void* ptr, sycl::queue& syclQueue) +---- +a@ Alternate form where [code]#syclQueue# provides the [code]#context#. + +|==== + +=== Unified shared memory pointer queries + +Since USM pointers look like raw {cpp} pointers, users cannot deduce what kind of +USM allocation a given pointer may be from examining its type. However, two +functions are defined that let users query the type of a USM allocation and, if +applicable, the [code]#device# on which it was allocated. These query functions +are only supported on the host. + +[[table.usm.ptr.query]] +.USM Pointer Query Functions +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Function @ Description +a@ +[source] +---- +usm::alloc get_pointer_type(const void *ptr, + const context &ctxt) +---- +a@ Returns the USM allocation type for [code]#ptr# if [code]#ptr# +falls inside a valid USM allocation. Returns [code]#usm::alloc::unknown# if +[code]#ptr# is not a valid USM allocation. + +a@ +[source] +---- +sycl::device get_pointer_device(const void *ptr, + const context &ctxt) +---- +a@ Returns the [code]#device# associated with the USM allocation. If +[code]#ptr# is an allocation of type [code]#usm::alloc::host#, returns the +first device in [code]#ctxt#. Throws an error if [code]#ptr# is not a valid +USM allocation. + +|==== + +// %%%%%%%%%%%%%%%%%%%%%%%%%%%% begin expressingParallelism %%%%%%%%%%%%%%%%%%%%%%%%%%%% + +[[sec:expr-parall-thro]] +== Expressing parallelism through kernels + + +[[ranges-identifiers]] +=== Ranges and index space identifiers + +The data parallelism of the SYCL kernel execution model requires +instantiation of a parallel execution over a +range of iteration space coordinates. To achieve this, SYCL exposes types +to define the range of execution and to identify a given execution +instance's point in the iteration space. + +The following types are defined: [code]#range#, +[code]#nd_range#, [code]#id#, [code]#item#, [code]#h_item#, +[code]#nd_item# and [code]#group#. + +When constructing multi-dimensional ids or ranges from integers, the elements +are written such that the right-most element varies fastest in a linearization +of the multi-dimensional space (see <>). + + +[[table.id.summary]] +.Summary of types used to identify points in an index space, and ranges over which those points can vary +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Type @ Description +a@ +[source] +---- +id +---- + a@ A point within a range + +a@ +[source] +---- +range +---- + a@ Bounds over which an [code]#id# may vary + +a@ +[source] +---- +item +---- + a@ Pairing of an [code]#id# (specific point) and the + [code]#range# that it is bounded by + +a@ +[source] +---- +nd_range +---- + a@ Encapsulates both global and local (work-group size) + [code]#ranges# over which work-item [code]#ids# will + vary + +a@ +[source] +---- +nd_item +---- + a@ Encapsulates two [code]#items#, one for global + [code]#id# and [code]#range#, and one for local [code]#id# + and [code]#range# + +a@ +[source] +---- +h_item +---- + a@ Index point queries within hierarchical parallelism + ([code]#parallel_for_work_item)#. Encapsulates physical global and + local [code]#ids# and [code]#ranges#, as well as a + logical local [code]#id# and [code]#range# defined by hierarchical + parallelism + +a@ +[source] +---- +group +---- + a@ Work-group queries within hierarchical parallelism + ([code]#parallel_for_work_group)#, and exposes the + [code]#parallel_for_work_item# construct that identifies code to be + executed by each work-item. Encapsulates work-group [code]#ids# + and [code]#ranges# + +|==== + + + +[[range-class]] +==== [code]#range# class + +[code]#range# +is a 1D, 2D or 3D vector that defines +the iteration domain of either a single work-group in a parallel +dispatch, or the overall dimensions of the dispatch. It can be +constructed from integers. + +The SYCL [code]#range# class template provides the common by-value +semantics (see <>). + +A synopsis of the SYCL [code]#range# class is provided below. The +constructors, member functions and non-member functions of the SYCL +[code]#range# class are listed in +<>, <> and +<> respectively. The additional common +special member functions and common member functions are listed in +<> in +<> and +<> respectively. + +[source,,linenums] +---- +include::{header_dir}/range.h[lines=4..-1] +---- + + +[[table.constructors.range]] +.Constructors of the [code]#range# class template +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Constructor @ Description +a@ +[source] +---- +range(size_t dim0) +---- + a@ Construct a 1D range with value dim0. + Only valid when the template parameter [code]#dimensions# is equal + to 1. + +a@ +[source] +---- +range(size_t dim0, size_t dim1) +---- + a@ Construct a 2D range with values dim0 and dim1. + Only valid when the template parameter [code]#dimensions# is equal + to 2. + +a@ +[source] +---- +range(size_t dim0, size_t dim1, size_t dim2) +---- + a@ Construct a 3D range with values dim0, dim1 and dim2. + Only valid when the template parameter [code]#dimensions# is equal + to 3. + +|==== + + + +[[table.members.range]] +.Member functions of the [code]#range# class template +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +size_t get(int dimension) const +---- + a@ Return the value of the specified dimension of the + [code]#range#. + +a@ +[source] +---- +size_t &operator[](int dimension) +---- + a@ Return the l-value of the specified dimension of the + [code]#range#. + +a@ +[source] +---- +size_t operator[](int dimension) const +---- + a@ Return the value of the specified dimension of the + [code]#range#. + +a@ +[source] +---- +size_t size() const +---- + a@ Return the size of the range computed as dimension0*...*dimensionN. + +|==== + + + +[[table.functions.range]] +.Hidden friend functions of the SYCL [code]#range# class template +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Hidden friend function @ Description +a@ +[source] +---- +range operatorOP(const range &lhs, const range &rhs) +---- + a@ Where [code]#OP# is: [code]#pass:[+]#, [code]#-#, [code]#*#, + [code]#/#, [code]#%#, [code]#<<#, [code]#>>#, + [code]#&#, [code]#|#, [code]#^#, + [code]#&&#, [code]#||#, + [code]#<#, [code]#>#, [code]#+<=+#, + [code]#>=#. + +Constructs and returns a new instance of the SYCL [code]#range# class +template with the same dimensionality as [code]#lhs# [code]#range#, +where each element of the new SYCL [code]#range# instance is the +result of an element-wise [code]#OP# operator between each element of +[code]#lhs# [code]#range# and each element of the [code]#rhs# +[code]#range#. If the operator returns a [code]#bool#, the result +is the cast to [code]#size_t#. + +a@ +[source] +---- +range operatorOP(const range &lhs, const size_t &rhs) +---- + a@ Where [code]#OP# is: [code]#pass:[+]#, [code]#-#, [code]#*#, + [code]#/#, [code]#%#, [code]#<<#, [code]#>>#, + [code]#&#, [code]#|#, [code]#^#, + [code]#&&#, [code]#||#, + [code]#<#, [code]#>#, [code]#+<=+#, + [code]#>=#. + +Constructs and returns a new instance of the SYCL [code]#range# class +template with the same dimensionality as [code]#lhs# [code]#range#, +where each element of the new SYCL [code]#range# instance is the result +of an element-wise [code]#OP# operator between each element of this +SYCL [code]#range# and the [code]#rhs# [code]#size_t#. If +the operator returns a [code]#bool#, the result is the cast to +[code]#size_t#. + +a@ +[source] +---- +range &operatorOP(range &lhs, const range &rhs) +---- + a@ Where [code]#OP# is: [code]#pass:[+=]#, [code]#-=#,[code]#*=#, [code]#/=#, [code]#%=#, [code]#+<<=+#, [code]#>>=#, [code]#&=#, [code]#|=#, [code]#^=#. + +Assigns each element of [code]#lhs# [code]#range# instance with the +result of an element-wise [code]#OP# operator between each element +of [code]#lhs# [code]#range# and each element of the [code]#rhs# +[code]#range# and returns [code]#lhs# [code]#range#. If the operator returns a [code]#bool#, the result is the cast +to [code]#size_t#. + +a@ +[source] +---- +range &operatorOP(range &lhs, const size_t &rhs) +---- + a@ Where [code]#OP# is: [code]#pass:[+=]#, [code]#-=#,[code]#*=#, [code]#/=#, [code]#%=#, [code]#+<<=+#, [code]#>>=#, [code]#&=#, [code]#|=#, [code]#^=#. + +Assigns each element of [code]#lhs# [code]#range# instance with the +result of an element-wise [code]#OP# operator between each element +of [code]#lhs# [code]#range# and the [code]#rhs# [code]#size_t# and returns [code]#lhs# [code]#range#. If the +operator returns a [code]#bool#, the result is the cast to +[code]#size_t#. + +a@ +[source] +---- +range operatorOP(const size_t &lhs, const range &rhs) +---- + a@ Where [code]#OP# is: [code]#pass:[+]#, [code]#-#, [code]#*#, + [code]#/#, [code]#%#, [code]#<<#, [code]#>>#, + [code]#&#, [code]#|#, [code]#^#, + [code]#&&#, [code]#||#, + [code]#<#, [code]#>#, [code]#+<=+#, + [code]#>=#. + +Constructs and returns a new instance of the SYCL [code]#range# class +template with the same dimensionality as the [code]#rhs# SYCL +[code]#range#, where each element of the new SYCL [code]#range# +instance is the result of an element-wise [code]#OP# operator between +the [code]#lhs# [code]#size_t# and each element of the +[code]#rhs# SYCL [code]#range#. If the operator returns a +[code]#bool#, the result is the cast to [code]#size_t#. + +a@ +[source] +---- +range operatorOP(const range &rhs) +---- + a@ Where [code]#OP# is: unary [code]#pass:[+]#, unary [code]#-#. + +Constructs and returns a new instance of the SYCL [code]#range# class +template with the same dimensionality as the [code]#rhs# SYCL +[code]#range#, where each element of the new SYCL [code]#range# +instance is the result of an element-wise [code]#OP# operator on +the [code]#rhs# SYCL [code]#range#. + +a@ +[source] +---- +range & operatorOP(range &rhs) +---- + a@ Where [code]#OP# is: prefix [code]#pass:[++]#, prefix [code]#--#. + +Assigns each element of the [code]#rhs# [code]#range# instance with the result +of an element-wise [code]#OP# operator on each element of the [code]#rhs# +[code]#range# and returns this [code]#range#. + +a@ +[source] +---- +range operatorOP(range &lhs, int) +---- + a@ Where [code]#OP# is: postfix [code]#pass:[++]#, postfix [code]#--#. + +Make a copy of the [code]#lhs# [code]#range#. +Assigns each element of the [code]#lhs# [code]#range# instance with the result +of an element-wise [code]#OP# operator on each element of the [code]#lhs# +[code]#range#. +Then return the initial copy of the [code]#range#. + +|==== + + + + +[[subsubsec:nd-range-class]] +==== [code]#nd_range# class + +// Interface for class: nd_range +[source,,linenums] +---- +include::{header_dir}/ndRange.h[lines=4..-1] +---- + +[code]#nd_range# +defines the iteration domain of both +the work-groups and the overall dispatch. To define this the +[code]#nd_range# comprises two ranges: the whole range over which +the kernel is to be executed, and the range of each work +group. + +The SYCL [code]#nd_range# class template provides the common by-value +semantics (see <>). + +A synopsis of the SYCL [code]#nd_range# class is provided below. The +constructors and member functions of the SYCL [code]#nd_range# class +are listed in <> and +<> respectively. The additional common special +member functions and common member functions are listed in +<> in <> +and <> respectively. + + +[[table.constructors.ndrange]] +.Constructors of the [code]#nd_range# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Constructor @ Description +a@ +[source] +---- +nd_range( + range globalSize, + range localSize) + id offset = id()) +---- + a@ Construct an [code]#nd_range# from the local and global + constituent ranges. Supplying the option offset is + deprecated in SYCL 2020. + If the offset is not provided it will default to no offset. + +|==== + + + +[[table.members.ndrange]] +.Member functions for the [code]#nd_range# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +range get_global_range() const +---- + a@ Return the constituent global range. + +a@ +[source] +---- +range get_local_range() const +---- + a@ Return the constituent local range. + +a@ +[source] +---- +range get_group_range() const +---- + a@ Return a range representing the number of groups in each + dimension. This range would result from + [code]#globalSize/localSize# as provided on construction. + +a@ +[source] +---- +id get_offset() const +// Deprecated in SYCL 2020. +---- + a@ Deprecated in SYCL 2020. + Return the constituent offset. + +|==== + + + +[[id-class]] +==== [code]#id# class + +[code]#id# is a vector of dimensions that is used to +represent an <> into a global or local +[code]#range#. It can be used as an index in an accessor of the +same rank. The subscript operator ([code]#operator[](n)#) returns the component +[code]#n# as a [code]#size_t#. + +The SYCL [code]#id# class template provides the common by-value semantics +(see <>). + +A synopsis of the SYCL [code]#id# class is provided below. The +constructors, member functions and non-member functions of the SYCL +[code]#id# class are listed in <>, +<> and <> respectively. The +additional common special member functions and common member functions are +listed in <> in +<> and +<> respectively. + +[source,,linenums] +---- +include::{header_dir}/id.h[lines=4..-1] +---- + + +[[table.constructors.id]] +.Constructors of the [code]#id# class template +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Constructor @ Description +a@ +[source] +---- +id() +---- + a@ Construct a SYCL [code]#id# with the value [code]#0# for each dimension. + +a@ +[source] +---- +id(size_t dim0) +---- + a@ Construct a 1D [code]#id# with value dim0. + Only valid when the template parameter [code]#dimensions# is equal + to 1. + +a@ +[source] +---- +id(size_t dim0, size_t dim1) +---- + a@ Construct a 2D [code]#id# with values dim0, dim1. + Only valid when the template parameter [code]#dimensions# is equal + to 2. + +a@ +[source] +---- +id(size_t dim0, size_t dim1, size_t dim2) +---- + a@ Construct a 3D [code]#id# with values dim0, dim1, dim2. + Only valid when the template parameter [code]#dimensions# is equal + to 3. + +a@ +[source] +---- +id(const range &range) +---- + a@ Construct an [code]#id# from the dimensions of [code]#range#. + +a@ +[source] +---- +id(const item &item) +---- + a@ Construct an [code]#id# from [code]#item.get_id()#. + +|==== + + + +[[table.members.id]] +.Member functions of the [code]#id# class template +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +size_t get(int dimension) const +---- + a@ Return the value of the [code]#id# for dimension + [code]#dimension#. + +a@ +[source] +---- +size_t &operator[](int dimension) +---- + a@ Return a reference to the requested dimension of the [code]#id# + object. + +a@ +[source] +---- +size_t operator[](int dimension) const +---- + a@ Return the value of the requested dimension of the [code]#id# + object. + +a@ +[source] +---- +operator size_t() const +---- + a@ Available only when: [code]#dimensions == 1# + +Returns the same value as [code]#get(0)#. + +|==== + +[[table.functions.id]] +.Hidden friend functions of the [code]#id# class template +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Hidden friend function @ Description +a@ +[source] +---- +id operatorOP(const id &lhs, const id &rhs) +---- + a@ Where [code]#OP# is: [code]#pass:[+]#, [code]#-#, [code]#*#, [code]#/#, [code]#%#, [code]#<<#, [code]#>>#, + [code]#&#, [code]#|#, [code]#^#, [code]#&&#, [code]#||#, [code]#<#, [code]#>#, [code]#+<=+#, [code]#>=#. + +Constructs and returns a new instance of the SYCL [code]#id# class +template with the same dimensionality as [code]#lhs# [code]#id#, where +each element of the new SYCL [code]#id# instance is the result of an +element-wise [code]#OP# operator between each element of [code]#lhs# +[code]#id# and each element of the [code]#rhs# [code]#id#. +If the operator returns a [code]#bool# the result is the cast to +[code]#size_t#. + +a@ +[source] +---- +id operatorOP(const id &lhs, const size_t &rhs) +---- + a@ Where [code]#OP# is: [code]#pass:[+]#, [code]#-#, [code]#*#, [code]#/#, [code]#%#, [code]#<<#, [code]#>>#, + [code]#&#, [code]#|#, [code]#^#, [code]#&&#, [code]#||#, [code]#<#, [code]#>#, [code]#+<=+#, [code]#>=#. + +Constructs and returns a new instance of the SYCL [code]#id# class +template with the same dimensionality as [code]#lhs# [code]#id#, where +each element of the new SYCL [code]#id# instance is the result of an +element-wise [code]#OP# operator between each element of [code]#lhs# +[code]#id# and the [code]#rhs# [code]#size_t#. If the +operator returns a [code]#bool# the result is the cast to +[code]#size_t#. + +a@ +[source] +---- +id &operatorOP(id &lhs, const id &rhs) +---- + a@ Where [code]#OP# is: [code]#pass:[+=]#, [code]#-=#,[code]#*=#, [code]#/=#, [code]#%=#, + [code]#+<<=+#, [code]#>>=#, [code]#&=#, [code]#|=#, [code]#^=#. + +Assigns each element of [code]#lhs# [code]#id# instance with the +result of an element-wise [code]#OP# operator between each element +of [code]#lhs# [code]#id# and each element of the [code]#rhs# +[code]#id# and returns [code]#lhs# [code]#id#. If +the operator returns a [code]#bool# the result is the cast to +[code]#size_t#. + +a@ +[source] +---- +id &operatorOP(id &lhs, const size_t &rhs) +---- + a@ Where [code]#OP# is: [code]#pass:[+=]#, [code]#-=#,[code]#*=#, [code]#/=#, [code]#%=#, + [code]#+<<=+#, [code]#>>=#, [code]#&=#, [code]#|=#, [code]#^=#. + +Assigns each element of [code]#lhs# [code]#id# instance with the +result of an element-wise [code]#OP# operator between each element +of [code]#lhs# [code]#id# and the [code]#rhs# [code]#size_t# +and returns [code]#lhs# [code]#id#. If the operator +returns a [code]#bool# the result is the cast to [code]#size_t#. + +a@ +[source] +---- +id operatorOP(const size_t &lhs, const id &rhs) +---- + a@ Where [code]#OP# is: [code]#pass:[+]#, [code]#-#, [code]#*#, [code]#/#, [code]#%#, [code]#<<#, [code]#>>#, + [code]#&#, [code]#|#, [code]#^#, [code]#&&#, [code]#||#, [code]#<#, [code]#>#, [code]#+<=+#, [code]#>=#. + +Constructs and returns a new instance of the SYCL [code]#id# class +template with the same dimensionality as the [code]#rhs# SYCL +[code]#id#, where each element of the new SYCL [code]#id# +instance is the result of an element-wise [code]#OP# operator between +the [code]#lhs# [code]#size_t# and each element of the +[code]#rhs# SYCL [code]#id#. If the operator returns a +[code]#bool# the result is the cast to [code]#size_t#. + +a@ +[source] +---- +id operatorOP(const id &rhs) +---- + a@ Where [code]#OP# is: unary [code]#pass:[+]#, unary [code]#-#. + +Constructs and returns a new instance of the SYCL [code]#id# class +template with the same dimensionality as the [code]#rhs# SYCL +[code]#id#, where each element of the new SYCL [code]#id# +instance is the result of an element-wise [code]#OP# operator on +the [code]#rhs# SYCL [code]#id#. + +a@ +[source] +---- +id & operatorOP(id &rhs) +---- + a@ Where [code]#OP# is: prefix [code]#pass:[++]#, prefix [code]#--#. + +Assigns each element of the [code]#rhs# [code]#id# instance with the result +of an element-wise [code]#OP# operator on each element of the [code]#rhs# +[code]#id# and returns this [code]#id#. + +a@ +[source] +---- +id operatorOP(id &lhs, int) +---- + a@ Where [code]#OP# is: postfix [code]#pass:[++]#, postfix [code]#--#. + +Make a copy of the [code]#lhs# [code]#id#. +Assigns each element of the [code]#lhs# [code]#id# instance with the result +of an element-wise [code]#OP# operator on each element of the [code]#lhs# +[code]#id#. +Then return the initial copy of the [code]#id#. + +|==== + + + +[[subsec:item.class]] +==== [code]#item# class + +<> identifies an instance of the function object +executing at each point in a [code]#range#. It is passed to a +[code]#parallel_for# call or returned by member functions of [code]#h_item#. +It encapsulates enough information to identify the work-item's range +of possible values and its ID in that range. It can optionally carry the offset of the +range if provided to the [code]#parallel_for#; note this is deprecated in SYCL 2020. +Instances of the [code]#item# class are +not user-constructible and are passed by the runtime to each instance +of the function object. + +The SYCL [code]#item# class template provides the common by-value semantics +(see <>). + +A synopsis of the SYCL [code]#item# class is provided below. The member +functions of the SYCL [code]#item# class are listed in +<>. The additional common special member functions +and common member functions are listed in <> in +<> and +<> respectively. + +// Interface for class: item +[source,,linenums] +---- +include::{header_dir}/item.h[lines=4..-1] +---- + + +[[table.members.item]] +.Member functions for the [code]#item# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +id get_id() const +---- + a@ Return the constituent [code]#id# + representing the work-item's position in the iteration space. + +a@ +[source] +---- +size_t get_id(int dimension) const +---- + a@ Return the same value as [code]#get_id()[dimension]#. + +a@ +[source] +---- +size_t operator[](int dimension) const +---- + a@ Return the same value as [code]#get_id(dimension)#. + +a@ +[source] +---- +range get_range() const +---- + a@ Returns a [code]#range# representing the dimensions of the + range of possible values of the [code]#item#. + +a@ +[source] +---- +size_t get_range(int dimension) const +---- + a@ Return the same value as [code]#get_range().get(dimension)#. + +a@ +[source] +---- +id get_offset() const +// Deprecated in SYCL 2020. +---- + a@ Deprecated in SYCL 2020. + Returns an [code]#id# representing the _n_-dimensional offset + provided to the [code]#parallel_for# and that is added by + the runtime to the global-ID of each work-item, if this item + represents a global range. For an item converted from an item with + no offset this will always return an [code]#id# of all 0 values. + +This member function is only available if [code]#with_offset# is [code]#true#. + +a@ +[source] +---- +operator item() const +---- + a@ Available only when: [code]#with_offset == false# + +Returns an [code]#item# representing the same information as the object holds +but also includes the offset set to 0. This conversion allow users to seamlessly +write code that assumes an offset and still provides an offset-less [code]#item#. + +a@ +[source] +---- +operator size_t() const +---- + a@ Available only when: [code]#dimensions == 1# + +Returns the same value as [code]#get(0)#. + +a@ +[source] +---- +size_t get_linear_id() const +---- + a@ Return the id as a linear index value. Calculating a linear + address from the multi-dimensional index follows + <>. + +|==== + + + +[[nditem-class]] +==== [code]#nd_item# class + +[code]#nd_item# identifies an instance of the function object +executing at each point in an [code]#nd_range# passed to a +[code]#parallel_for# call. It encapsulates enough +information to identify the <>'s local and global <>, the +<> and also provides access to the [code]#group# and +[code]#sub_group# classes. Instances of the [code]#nd_item# class are not user-constructible and are passed by the runtime to +each instance of the function object. + +The SYCL [code]#nd_item# class template provides the common by-value +semantics (see <>). + +A synopsis of the SYCL [code]#nd_item# class is provided below. The +member functions of the SYCL [code]#nd_item# class are listed in +<>. The additional common special member +functions and common member functions are listed in +<> in <> +and <> respectively. + +% interface for nd_item class +[source,,linenums] +---- +include::{header_dir}/nditem.h[lines=4..-1] +---- + + +[[table.members.nditem]] +.Member functions for the [code]#nd_item# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +id get_global_id() const +---- + a@ Return the constituent <> representing the + work-item's position in the global iteration space. + +a@ +[source] +---- +size_t get_global_id(int dimension) const +---- + a@ Return the constituent element of the <> + representing the work-item's position in the <> + in the given [code]#dimension#. + +a@ +[source] +---- +size_t get_global_linear_id() const +---- + a@ Return the constituent <> as a linear index value, representing the work-item's + position in the global iteration space. The linear address is calculated from the + multi-dimensional index by first subtracting the offset and then following + <>. + +a@ +[source] +---- +id get_local_id() const +---- + a@ Return the constituent <> representing the + work-item's position within the current <>. + +a@ +[source] +---- +size_t get_local_id(int dimension) const +---- + a@ Return the constituent element of the <> representing the + work-item's position within the current <> in the given + [code]#dimension#. + +a@ +[source] +---- +size_t get_local_linear_id() const +---- + a@ Return the constituent <> as a linear index value, representing the work-item's + position within the current <>. The linear address is calculated from the + multi-dimensional index following <>. + +a@ +[source] +---- +group get_group() const +---- + a@ Return the constituent <>, [code]#group# + representing the <>'s position within the overall + <>. + +a@ +[source] +---- +sub_group get_sub_group() const +---- + a@ Return a [code]#sub_group# representing the <> to which the work-item belongs. + +a@ +[source] +---- +size_t get_group(int dimension) const +---- + a@ Return the constituent element of the group [code]#id# representing + the work-group's position within the overall [code]#nd_range# in the + given [code]#dimension#. + +a@ +[source] +---- +size_t get_group_linear_id() const +---- + a@ Return the group id as a linear index value. Calculating a linear address + from a multi-dimensional index follows <>. + +a@ +[source] +---- +range get_group_range() const +---- + a@ Returns the number of <> in the iteration space. + +a@ +[source] +---- +size_t get_group_range(int dimension) const +---- + a@ Return the number of <> for [code]#dimension# in the + iteration space. + +a@ +[source] +---- +range get_global_range() const +---- + a@ Returns a [code]#range# representing the dimensions of the + global iteration space. + +a@ +[source] +---- +size_t get_global_range(int dimension) const +---- + a@ Return the same value as [code]#get_global_range().get(dimension)#. + +a@ +[source] +---- +range get_local_range() const +---- + a@ Returns a [code]#range# representing the dimensions of the current + work-group. + +a@ +[source] +---- +size_t get_local_range(int dimension) const +---- + a@ Return the same value as [code]#get_local_range().get(dimension)#. + +a@ +[source] +---- +id get_offset() const +// Deprecated in SYCL 2020. +---- + a@ Deprecated in SYCL 2020. + Returns an <> representing the n-dimensional offset + provided to the constructor of the [code]#nd_range# and that + is added by the runtime to the <> of each <>. + +a@ +[source] +---- +nd_range get_nd_range() const +---- + a@ Returns the [code]#nd_range# of the current execution. + +a@ +[source] +---- +template + device_event async_work_group_copy( + decorated_local_ptr dest, decorated_global_ptr src, + size_t numElements) const +---- + a@ Permitted types for [code]#dataT# are all scalar and vector types. + Asynchronously copies a number of elements specified by [code]#numElements# from the source pointer [code]#src# to destination + pointer [code]#dest# and returns a SYCL [code]#device_event# + which can be used to wait on the completion of the copy. + +a@ +[source] +---- +template + device_event async_work_group_copy( + decorated_global_ptr dest, decorated_local_ptr src, + size_t numElements) const +---- + a@ Permitted types for [code]#dataT# are all scalar and vector types. + Asynchronously copies a number of elements specified by [code]#numElements# from the source pointer [code]#src# to destination + pointer [code]#dest# and returns a SYCL [code]#device_event# + which can be used to wait on the completion of the copy. + +a@ +[source] +---- +template + device_event async_work_group_copy( + decorated_local_ptr dest, decorated_global_ptr src, + size_t numElements, size_t srcStride) const +---- + a@ Permitted types for [code]#dataT# are all scalar and vector types. + Asynchronously copies a number of elements specified by [code]#numElements# from the source pointer [code]#src# to destination + pointer [code]#dest# with a source stride specified by + [code]#srcStride# and returns a SYCL [code]#device_event# + which can be used to wait on the completion of the copy. + +a@ +[source] +---- +template + device_event async_work_group_copy( + decorated_global_ptr dest, decorated_local_ptr src, + size_t numElements, size_t destStride) const +---- + a@ Permitted types for [code]#dataT# are all scalar and vector types. + Asynchronously copies a number of elements specified by [code]#numElements# from the source pointer [code]#src# to destination + pointer [code]#dest# with a destination stride specified by + [code]#destStride# and returns a SYCL [code]#device_event# + which can be used to wait on the completion of the copy. + +a@ +[source] +---- +template + void wait_for(eventTN... events) const +---- + a@ Permitted type for [code]#eventTN# is [code]#device_event#. + Waits for the asynchronous operations associated with each [code]#device_event# to complete. + +|==== + + + +[[hitem-class]] +==== [code]#h_item# class + +[code]#h_item# identifies an instance of a +[code]#group::parallel_for_work_item# function object executing at each +point in a local [code]#range# passed to a +[code]#parallel_for_work_item# call or to the corresponding +[code]#parallel_for_work_group# call if no [code]#range# is passed +to the [code]#parallel_for_work_item# call. It encapsulates enough +information to identify the <>'s local and global <> +according to the information given to [code]#parallel_for_work_group# +(physical ids) as well as the <>'s logical local <> +in the logical local range. All returned <> objects are +offset-less. Instances of the [code]#h_item# class are +not user-constructible and are passed by the runtime to each instance of the +function object. + +The SYCL [code]#h_item# class template provides the common by-value +semantics (see <>). + +A synopsis of the SYCL [code]#h_item# class is provided below. The +member functions of the SYCL [code]#h_item# class are listed in +<>. The additional common special member +functions and common member functions are listed in +<> in <> +and <> respectively. + +[source,,linenums] +---- +include::{header_dir}/hitem.h[lines=4..-1] +---- + + +[[table.members.hitem]] +.Member functions for the [code]#h_item# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +item get_global() const +---- + a@ Return the constituent global <> representing the + work-item's position in the global iteration space as provided upon kernel invocation. + +a@ +[source] +---- +item get_local() const +---- + a@ Return the same value as [code]#get_logical_local()#. + +a@ +[source] +---- +item get_logical_local() const +---- + a@ Return the constituent element of the logical local <> + work-item's position in the local iteration space as provided upon the invocation of the + [code]#group::parallel_for_work_item#. + +If the [code]#group::parallel_for_work_item# was called without any logical local range +then the member function returns the physical local <>. + +A physical id can be computed from a logical id by getting the remainder of the integer division +of the logical id and the physical range: +[code]#get_logical_local().get() % get_physical_local.get_range() == get_physical_local().get()#. + +a@ +[source] +---- +item get_physical_local() const +---- + a@ Return the constituent element of the physical local <> + work-item's position in the local iteration space as provided (by the user or the runtime) + upon the kernel invocation. + +a@ +[source] +---- +range get_global_range() const +---- + a@ Return the same value as [code]#get_global().get_range()# + +a@ +[source] +---- +size_t get_global_range(int dimension) const +---- + a@ Return the same value as [code]#get_global().get_range(dimension)# + +a@ +[source] +---- +id get_global_id() const +---- + a@ Return the same value as [code]#get_global().get_id()# + +a@ +[source] +---- +size_t get_global_id(int dimension) const +---- + a@ Return the same value as [code]#get_global().get_id(dimension)# + +a@ +[source] +---- +range get_local_range() const +---- + a@ Return the same value as [code]#get_local().get_range()# + +a@ +[source] +---- +size_t get_local_range(int dimension) const +---- + a@ Return the same value as [code]#get_local().get_range(dimension)# + +a@ +[source] +---- +id get_local_id() const +---- + a@ Return the same value as [code]#get_local().get_id()# + +a@ +[source] +---- +size_t get_local_id(int dimension) const +---- + a@ Return the same value as [code]#get_local().get_id(dimension)# + +a@ +[source] +---- +range get_logical_local_range() const +---- + a@ Return the same value as [code]#get_logical_local().get_range()# + +a@ +[source] +---- +size_t get_logical_local_range(int dimension) const +---- + a@ Return the same value as [code]#get_logical_local().get_range(dimension)# + +a@ +[source] +---- +id get_logical_local_id() const +---- + a@ Return the same value as [code]#get_logical_local().get_id()# + +a@ +[source] +---- +size_t get_logical_local_id(int dimension) const +---- + a@ Return the same value as [code]#get_logical_local().get_id(dimension)# + +a@ +[source] +---- +range get_physical_local_range() const +---- + a@ Return the same value as [code]#get_physical_local().get_range()# + +a@ +[source] +---- +size_t get_physical_local_range(int dimension) const +---- + a@ Return the same value as [code]#get_physical_local().get_range(dimension)# + +a@ +[source] +---- +id get_physical_local_id() const +---- + a@ Return the same value as [code]#get_physical_local().get_id()# + +a@ +[source] +---- +size_t get_physical_local_id(int dimension) const +---- + a@ Return the same value as [code]#get_physical_local().get_id(dimension)# + +|==== + + + +[[group-class]] +==== [code]#group# class + +The [code]#group# encapsulates all functionality +required to represent a particular <> within a +parallel execution. It is not user-constructible. + +The local range stored in the group class is provided either by +the programmer, when it is passed as an optional parameter to +[code]#parallel_for_work_group#, or by the runtime system when it +selects the optimal work-group size. This allows the developer to +always know how many concurrent work-items are active in each +executing work-group, even through the abstracted iteration range of the +[code]#parallel_for_work_item# loops. + +The SYCL [code]#group# class template provides the common by-value +semantics (see <>). + +A synopsis of the SYCL [code]#group# class is provided below. The +member functions of the SYCL [code]#group# class are listed in +<>. The additional common special member +functions and common member functions are listed in +<> in <> +and <> respectively. + +// Interface for class: group +[source,,linenums] +---- +include::{header_dir}/group.h[lines=4..-1] +---- + +[[table.members.group]] +.Member functions for the [code]#group# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +id get_group_id() const +---- + a@ Return an <> representing the index of the work-group + within the <> for every dimension. + +a@ +[source] +---- +size_t get_group_id(int dimension) const +---- + a@ Return the same value as [code]#get_id()[dimension]#. + +a@ +[source] +---- +id get_local_id() const +---- + a@ Return a SYCL [code]#id# representing the calling work-item's position + within the <>. + +It is undefined behavior for this member function to be invoked from within +a [code]#parallel_for_work_item# context. + +a@ +[source] +---- +size_t get_local_id(int dimension) const +---- + a@ Return the calling work-item's position within the <> in the specified dimension. + +It is undefined behavior for this member function to be invoked from within +a [code]#parallel_for_work_item# context. + +a@ +[source] +---- +range get_local_range() const +---- + a@ Return a SYCL [code]#range# representing all dimensions of the local range. + This local range may have been provided by the programmer, or chosen by the <>. + +a@ +[source] +---- +size_t get_local_range(int dimension) const +---- + a@ Return the dimension of the local range specified by the [code]#dimension# parameter. + +a@ +[source] +---- +range get_group_range() const +---- + a@ Return a [code]#range# representing the number of <> in the [code]#nd_range#. + +a@ +[source] +---- +size_t get_group_range(int dimension) const +---- + a@ Return element [code]#dimension# from the constituent group range. + +a@ +[source] +---- +size_t operator[](int dimension) const +---- + a@ Return the same value as [code]#get_id(dimension)#. + +a@ +[source] +---- +range get_max_local_range() const +---- + a@ Return a [code]#range# representing the maximum number of work-items in any <> + in the [code]#nd_range#. + +a@ +[source] +---- +size_t get_group_linear_id() const +---- + a@ Get a linearized version of the <>. + Calculating a linear <> + from a multi-dimensional index follows <>. + +a@ +[source] +---- +size_t get_group_linear_range() const +---- + a@ Return the total number of <>s in the [code]#nd_range#. + +a@ +[source] +---- +size_t get_local_linear_id() const +---- + a@ Get a linearized version of the calling work-item's <>. + Calculating a linear <> + from a multi-dimensional index follows <>. + +It is undefined behavior for this member function to be invoked from within +a [code]#parallel_for_work_item# context. + +a@ +[source] +---- +size_t get_local_linear_range() const +---- + a@ Return the total number of work-items in the <>. + +a@ +[source] +---- +bool leader() const +---- + a@ Return true for exactly one work-item in the <>, if the + calling work-item is the leader of the work-group, and false for all + other work-items in the work-group. + +The leader of the work-group is determined during construction of the +work-group, and is invariant for the lifetime of the work-group. The +leader of the work-group is guaranteed to be the work-item with a +local id of 0. + +a@ +[source] +---- +template + void parallel_for_work_item(const workItemFunctionT &func) const +---- + a@ Launch the work-items for this work-group. + +[code]#func# is a function object type with a public member function +[code]#void F::operator()(h_item)# +representing the work-item computation. + +This member function can only be invoked within a +[code]#parallel_for_work_group# context. It is +undefined behavior for this member function to be invoked +from within the [code]#parallel_for_work_group# form that +does not define work-group size, because then the number of +work-items that should execute the code is not defined. It is +expected that this form of [code]#parallel_for_work_item# +is invoked within the [code]#parallel_for_work_group# form +that specifies the size of a work-group. + +a@ +[source] +---- +template + void parallel_for_work_item(range + logicalRange, const workItemFunctionT &func) const +---- + a@ Launch the work-items for this work-group using a logical local range. + The function object [code]#func# is executed as if the kernel were + invoked with [code]#logicalRange# as the local range. This new local + range is emulated and may not map one-to-one with the physical range. + +[code]#logicalRange# is the new local range to be used. +This range can be smaller or larger than the one used to invoke the kernel. +[code]#func# is a function object type with a public member function +[code]#void F::operator()(h_item)# +representing the work-item computation. + +Note that the logical range does not need to be uniform +across all work-groups in a kernel. For example the logical range may depend on +a work-group varying query (e.g. [code]#group::get_linear_id)#, +such that different work-groups in the same kernel invocation execute +different logical range sizes. + +This member function can only be invoked within a +[code]#parallel_for_work_group# context. + +a@ +[source] +---- +template + device_event async_work_group_copy( + decorated_local_ptr dest, decorated_global_ptr src, + size_t numElements) const +---- + a@ Permitted types for [code]#dataT# are all scalar and vector types. + Asynchronously copies a number of elements specified by [code]#numElements# from the source pointer [code]#src# to destination + pointer [code]#dest# and returns a SYCL [code]#device_event# + which can be used to wait on the completion of the copy. + +a@ +[source] +---- +template + device_event async_work_group_copy( + decorated_global_ptr dest, decorated_local_ptr src, + size_t numElements) const +---- + a@ Permitted types for [code]#dataT# are all scalar and vector types. + Asynchronously copies a number of elements specified by [code]#numElements# from the source pointer [code]#src# to destination + pointer [code]#dest# and returns a SYCL [code]#device_event# + which can be used to wait on the completion of the copy. + +a@ +[source] +---- +template + device_event async_work_group_copy( + decorated_local_ptr dest, decorated_global_ptr src, + size_t numElements, size_t srcStride) const +---- + a@ Permitted types for [code]#dataT# are all scalar and vector types. + Asynchronously copies a number of elements specified by [code]#numElements# from the source pointer [code]#src# to destination + pointer [code]#dest# with a source stride specified by + [code]#srcStride# and returns a SYCL [code]#device_event# + which can be used to wait on the completion of the copy. + +a@ +[source] +---- +template + device_event async_work_group_copy( + decorated_global_ptr dest, decorated_local_ptr src, + size_t numElements, size_t destStride) const +---- + a@ Permitted types for [code]#dataT# are all scalar and vector types. + Asynchronously copies a number of elements specified by [code]#numElements# from the source pointer [code]#src# to destination + pointer [code]#dest# with a destination stride specified by + [code]#destStride# and returns a SYCL [code]#device_event# + which can be used to wait on the completion of the copy. + +a@ +[source] +---- +template + void wait_for(eventTN... events) const +---- + a@ Permitted type for [code]#eventTN# is [code]#device_event#. + Waits for the asynchronous operations associated with each [code]#device_event# to complete. + +|==== + + + +[[sub-group-class]] +==== [code]#sub_group# class + +The [code]#sub_group# class encapsulates all functionality +required to represent a particular <> within a +parallel execution. It is not user-constructible. + +The SYCL [code]#sub_group# class provides the common by-value +semantics (see <>). + +A synopsis of the SYCL [code]#sub_group# class is provided below. The +member functions of the SYCL [code]#sub_group# class are listed in +<>. The additional common special member +functions and common member functions are listed in +<> in <> +and <> respectively. + +// Interface for class: subgroup +[source,,linenums] +---- +include::{header_dir}/subgroup.h[lines=4..-1] +---- + + +[[table.members.subgroup]] +.Member functions for the [code]#sub_group# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +id<1> get_group_id() const +---- + a@ Return an <> representing the index of the sub-group + within the <>. + +a@ +[source] +---- +id<1> get_local_id() const +---- + a@ Return a SYCL [code]#id# representing the calling work-item's position + within the <>. + +a@ +[source] +---- +range<1> get_local_range() const +---- + a@ Return a [code]#range# representing the size of the <>. + This size may be less than the value returned by + [code]#get_max_local_range()#, depending on the position of the + sub-group within its parent <> and the manner in which + sub-groups are constructed by the implementation. + +a@ +[source] +---- +range<1> get_group_range() const +---- + a@ Return a [code]#range# representing the number of <>s in the + <>. + +a@ +[source] +---- +range<1> get_max_local_range() const +---- + a@ Return a [code]#range# representing the maximum number of work-items + permitted in a <> for the executing kernel. This value may + have been chosen by the programmer via an attribute, or chosen by the + <>. + +a@ +[source] +---- +uint32_t get_group_linear_id() const +---- + a@ Equivalent to [code]#get_group_id()#. + +a@ +[source] +---- +uint32_t get_group_linear_range() const +---- + a@ Equivalent to [code]#get_group_range()#. + +a@ +[source] +---- +uint32_t get_local_linear_id() const +---- + a@ Equivalent to [code]#get_local_id()#. + +a@ +[source] +---- +uint32_t get_local_linear_range() const +---- + a@ Equivalent to [code]#get_local_range()#. + +a@ +[source] +---- +bool leader() const +---- + a@ Return true for exactly one work-item in the <>, if the + calling work-item is the leader of the sub-group, and false for all + other work-items in the sub-group. + +The leader of the sub-group is determined during construction of the +sub-group, and is invariant for the lifetime of the sub-group. The +leader of the sub-group is guaranteed to be the work-item with a +local id of 0. + +|==== + + +[[sec:reduction]] +=== Reduction variables + +All functionality related to <> is captured by the +[code]#reducer# class and the [code]#reduction# function. + +The example below demonstrates how to write a <> +kernel that performs two reductions simultaneously on the same input values, +computing both the sum of all values in a buffer and the maximum value in the +buffer. For each reduction variable passed to [code]#parallel_for#, a +reference to a [code]#reducer# object is passed as a parameter to the kernel +function in the same order. + +[source,,linenums] +---- +include::{code_dir}/reduction.cpp[lines=4..-1] +---- + +Reductions are supported for all trivially copyable types (as defined by the +{cpp} core language). If the reduction operator is non-associative or +non-commutative, the behavior of a reduction may be non-deterministic. If +multiple reductions reference the same reduction variable, or a reduction +variable is accessed directly during the lifetime of a reduction (e.g. via an +[code]#accessor# or USM pointer), the behavior is undefined. + +Certain implementations of reductions can be made more efficient if the +identity value associated with the reduction operator is known. For standard +binary operators (e.g. [code]#plus# on arithmetic types), an implementation +must determine the correct identity value automatically in order to avoid +performance penalties. For user-defined reduction operators, an implementation +should issue a compile-time warning if the user does not provide an identity +value and this is known to negatively impact performance. + +If an implementation can identify the identity value for a given combination of +accumulator type and function object type, the value is defined as a member of +the [code]#known_identity# trait class. Whether this member value exists can +be tested using the [code]#has_known_identity# trait class. + +[source,,linenums] +---- +include::{header_dir}/identity.h[lines=4..-1] +---- + +The reduction interface is limited to reduction variables whose size can be +determined at compile-time. As such, [code]#buffer# and USM pointer arguments +are interpreted by the reduction interface as describing a single variable. +A reduction operation associated with a [code]#span# represents an array +reduction. An array reduction of size _N_ is functionally equivalent to +specifying _N_ independent scalar reductions. The combination operations +performed by an array reduction are limited to the extent of a USM allocation +described by a [code]#span#, and access to elements outside of these regions +results in undefined behavior. + +[NOTE] +==== +Since a [code]#span# is one-dimensional, there is currently no way to describe +an array reduction with more than one dimension. This is expected to change in +a future version of the SYCL specification, but depends on the introduction of +a multi-dimensional [code]#span#. +==== + +[[reduction-interface]] +==== [code]#reduction# interface + +The [code]#reduction# interface is used to attach <> semantics +to a variable, by specifying: the reduction variable, the +reduction operator and an optional identity value associated with the operator. +The overloads of the interface are described in <>. +The return value of the [code]#reduction# interface is an +implementation-defined object of unspecified type, which is interpreted by +[code]#parallel_for# to construct an appropriate [code]#reducer# +type as detailed in <>. + +The initial value of the reduction variable is included +in the reduction operation, unless the [code]#property::reduction::initialize_to_identity# +property was specified when the [code]#reduction# interface was invoked. + +The reduction variable +is updated so as to contain the result of the reduction when the kernel finishes +execution. + +[source,,linenums] +---- +include::{header_dir}/reduction.h[lines=4..-1] +---- + + +[[table.reduction]] +.Overloads of the [code]#reduction# interface +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Function @ Description +a@ +[source] +---- +reduction(BufferT vars, handler& cgh, +BinaryOperation combiner, const property_list &propList = {}) +---- + a@ Construct an unspecified object representing a reduction + of the variable(s) described by [code]#vars# using the combination + operation specified by [code]#combiner#. Zero or more properties can be + provided via an instance of [code]#property_list#. + Throws an [code]#exception# with the [code]#errc::invalid# + error code if the range of the [code]#vars# buffer is not 1. + +a@ +[source] +---- +reduction(T* var, +BinaryOperation combiner, const property_list &propList = {}) +---- + a@ Construct an unspecified object representing a reduction + of the variable described by [code]#var# using the combination + operation specified by [code]#combiner#. Zero or more properties + can be provided via an instance of [code]#property_list#. + +a@ +[source] +---- +reduction(span vars, +BinaryOperation combiner, const property_list &propList = {}) +---- + a@ Available only when [code]#Extent != std::dynamic_extent#. + Construct an unspecified object representing a reduction + of the variable(s) described by [code]#vars# using the combination + operation specified by [code]#combiner#. Zero or more properties + can be provided via an instance of [code]#property_list#. + +a@ +[source] +---- +reduction(BufferT vars, handler& cgh, +const BufferT::value_type& identity, BinaryOperation combiner, +const property_list &propList = {}) +---- + a@ Available only when [code]#has_known_identity::value# is [code]#false#. + Construct an unspecified object representing a reduction + of the variable(s) described by [code]#vars# using the combination + operation specified by [code]#combiner#. The value of + [code]#identity# may be used by the implementation to initialize + temporary accumulation variables; using an [code]#identity# value + that is not the identity value of the combination operation specified + by [code]#combiner# results in undefined behavior. Zero or more + properties can be provided via an instance of [code]#property_list#. + Throws an [code]#exception# with the [code]#errc::invalid# + error code if the range of the [code]#vars# buffer is not 1. + +a@ +[source] +---- +reduction(T* var, const T& identity, +BinaryOperation combiner, const property_list &propList = {}) +---- + a@ Available only when [code]#has_known_identity::value# + is [code]#false#. + Construct an unspecified object representing a reduction + of the variable described by [code]#var# using the combination + operation specified by [code]#combiner#. The value of + [code]#identity# may be used by the implementation to initialize + temporary accumulation variables; using an [code]#identity# value + that is not the identity value of the combination operation specified + by [code]#combiner# results in undefined behavior. Zero or more + properties can be provided via an instance of [code]#property_list#. + +a@ +[source] +---- +reduction(span vars, const T& identity, +BinaryOperation combiner, const property_list &propList = {}) +---- + a@ Available only when [code]#has_known_identity::value# + is [code]#false# and [code]#Extent != std::dynamic_extent#. + Construct an unspecified object representing a reduction + of the variable(s) described by [code]#vars# using the combination + operation specified by [code]#combiner#. The value of + [code]#identity# may be used by the implementation to initialize + temporary accumulation variables; using an [code]#identity# value + that is not the identity value of the combination operation specified + by [code]#combiner# results in undefined behavior. Zero or more + properties can be provided via an instance of [code]#property_list#. + +|==== + +[[sec:reduction-properties]] +==== Reduction properties + +The properties that can be provided when using the [code]#reduction# interface +are described in <>. + + +[[table.properties.reduction]] +.Properties supported by the [code]#reduction# interface +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Property @ Description +a@ +[source] +---- +property::reduction::initialize_to_identity +---- + a@ The [code]#initialize_to_identity# property adds the requirement that the + <> must initialize the [code]#reduction# variable to the + identity value of its associated reduction operator. If the identity + value of the reduction operator cannot be determined, the compiler must + raise a diagnostic. When this property is set, the original value of the + reduction variable is not included + in the reduction. + +|==== + + +The constructors of the reduction property classes are listed in +<>. + +[[table.constructors.properties.reduction]] +.Constructors of the [code]#reduction# [code]#property# classes +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Constructor @ Description +a@ +[source] +---- +property::reduction::initialize_to_identity::initialize_to_identity() +---- + a@ Constructs an [code]#initialize_to_identity# property instance. + +|==== + + +[[reducer-class]] +==== [code]#reducer# class + +The [code]#reducer# class defines the interface between a work-item and a +reduction variable during the execution of a SYCL kernel, restricting access to +the underlying reduction variable. The intermediate values of a reduction +variable cannot be inspected during kernel execution, and the variable cannot +be updated using anything other than the reduction's specified combination +operation. The combination order of different reducers is unspecified, as are +when and how the value of each reducer is combined with the original reduction +variable. + +To enable compile-time specialization of reduction algorithms, the +implementation of the [code]#reducer# class is unspecified, +except for the functions and operators defined in <> +and <>. As such, developers should not specify the +template arguments of a [code]#reducer# directly, and should instead employ +generic programming techniques that allow kernel functions to accept a +reference to a variable of any [code]#reducer# type. Kernels written as +lambdas should employ [code]#auto&# or [code]#+auto&...+#, and kernels written as +function objects should employ template parameters or template parameter packs. + +An implementation must guarantee that it is safe for each concurrently +executing work-item in a kernel to call the combine function of a +[code]#reducer# in parallel. An implementation is free to re-use reducer +variables (e.g. across work-groups scheduled to the same compute unit) if it +can guarantee that it is safe to do so. + +The member functions of the [code]#reducer# class are listed in +<>. Additional shorthand operators may be made +available for certain combinations of reduction variable type and combination +operation, as described in <>. + +[source,,linenums] +---- +include::{header_dir}/reducer.h[lines=4..-1] +---- + +[[table.members.reducer]] +.Member functions of the [code]#reducer# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +void combine(const T& partial) const +---- + a@ Combine the value of [code]#partial# with the reduction variable + associated with this [code]#reducer#. + +a@ +[source] +---- +__unspecified__ &operator[](size_t index) const +---- + a@ Available only when: [code]#Dimensions > 1#. + Returns an instance of an undefined intermediate type representing + a [code]#reducer# of the same type as this [code]#reducer#, + with the dimensionality [code]#Dimensions-1# and containing an + implicit SYCL [code]#id# with index [code]#Dimensions# set + to [code]#index#. The intermediate type returned must provide + all member functions and operators defined by the [code]#reducer# + class that are appropriate for the type it represents (including this + subscript operator). + +a@ +[source] +---- +T identity() const +---- + a@ Return the identity value of the combination operation associated with + this [code]#reducer#. Only available if the identity value is known + to the implementation. + +|==== + +[[table.operators.reducer]] +.Operators of the [code]#reducer# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Operator @ Description +a@ +[source] +---- +template + void operator+=(reducer,0>& accum, const T& partial) +---- + a@ Equivalent to calling [code]#accum.combine(partial)#. + +a@ +[source] +---- +template + void operator*=(reducer,0>& accum, const T& partial) +---- + a@ Equivalent to calling [code]#accum.combine(partial)#. + +a@ +[source] +---- +template + void operator|=(reducer,0>& accum, const T& partial) +---- + a@ Equivalent to calling [code]#accum.combine(partial)#. + Only available for integral types. + +a@ +[source] +---- +template + void operator&=(reducer,0>& accum, const T& partial) +---- + a@ Equivalent to calling [code]#accum.combine(partial)#. + Only available for integral types. + +a@ +[source] +---- +template + void operator^=(reducer,0>& accum, const T& partial) +---- + a@ Equivalent to calling [code]#accum.combine(partial)#. + Only available for integral types. + +a@ +[source] +---- +template + void operator++(reducer,0>& accum) +---- + a@ Equivalent to calling [code]#accum.combine(1)#. + Only available for integral types. + +|==== + + +[[sec:command.group.scope]] +=== Command group scope + +A <>, as defined in <>, +may execute a single <> such as invoking a kernel, copying memory, +or executing a host task. It is legal for a <> to +statically contain more than one call to a <> function, but any +single execution of the <> may execute no more +than one <>. The statements that call <> together with +the statements that define the requirements for a kernel form the +<>. The command group +function object takes as a parameter an instance of the <> class which +encapsulates all the member functions executed in the command group scope. +The member functions and objects defined in this scope will define the requirements for the +kernel execution or explicit memory operation, and will be used by the <> +to evaluate if the operation is ready for execution. +Host code within a <> (typically setting up +requirements) is executed once, before the command group submit call returns. +This abstraction of the kernel +execution unifies the data with its processing, and consequently allows more +abstraction and flexibility in the parallel programming models that can be +implemented on top of SYCL. + +The <> and the [code]#handler# class +serve as an interface for the encapsulation of <>. +A <> is defined as a function object. All the device data accesses are +defined inside this group and any transfers are managed by the <>. The +rules for the data transfers regarding device and +host data accesses are better described in <>, +where buffers (<>) and accessor (<>) classes +are described. The overall memory model of the SYCL application is described in +<>. + +It is possible to obtain events for the start of the <>, +the kernel starting, and the command group completing. +These events are useful for +profiling and synchronization of kernels. +When using buffers, safe synchronization in SYCL requires synchronization on +buffer availability, not on kernel completion. This is because +the memory that data is stored in upon kernel +completion is not rigidly specified. The events are provided at the submission of the +<> to the queue to be executed on. + +It is possible for a <> to fail to enqueue to a queue, +or for it to fail to execute correctly. A user can therefore supply a secondary +queue when submitting a command group to the primary queue. If the <> +fails to enqueue or execute a command group on a primary queue, it can attempt +to run the command group on the secondary queue. The circumstances in which it +is, or is not, possible for a <> to fall-back from primary to +secondary queue are unspecified in the specification. Even if a command group +is run on the secondary queue, the requirement that host code within the command group +is executed exactly once remains, regardless of whether the fallback queue is used for +execution. + +The command group [code]#handler# class provides the interface +for all of the member functions that are able to be executed inside the command group +scope, and it is also provided as a scoped object to all of the data access +requests. The <> class provides the interface +in which every command in the command group scope will be submitted to a queue. + + +[[sec:handlerClass]] +=== Command group [code]#handler# class + +A <> object can only be constructed by the SYCL +runtime. All of the accessors defined in <> take as a +parameter an instance of the <>, and all the +kernel invocation functions are member functions of this class. + +The constructors of the SYCL [code]#handler# class are described in +<>. + +It is disallowed for an instance of the SYCL [code]#handler# class to +be moved or copied. + +// Interface for class: handler +[source,,linenums] +---- +include::{header_dir}/commandGroupHandler.h[lines=4..-1] +---- + + +[[table.constructors.handler]] +.Constructors of the [code]#handler# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Constructor @ Description +a@ +[source] +---- +handler(___unspecified___) +---- + a@ Unspecified implementation-defined constructor. + +|==== + + +[[sub.section.requirement]] +==== SYCL functions for adding requirements + +When an accessor is created from a <>, a *requirement* is +implicitly added to the <> for the accessor's data. However, +this does not happen when creating a [keyword]#placeholder# accessor. In order +to create a *requirement* for a [keyword]#placeholder# accessor, code +must call the [code]#handler::require()# member function. + +SYCL events may also be used to create requirements for a <>. +Such requirements state that the actions represented by the events must +complete before the <> may execute. Such requirements +are added when code calls the [code]#handler::depends_on()# member function. + +[[table.members.handler.requirements]] +.Member functions of the [code]#handler# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +template + void require(accessor + acc) +---- + a@ Requires access to the memory object associated with the accessor. + +The <> now has a *requirement* to gain access +to the given memory object before executing the kernel. +If the accessor has already been registered with the <>, +calling this function has no effect. + +Throws [code]#exception# with the [code]#errc::invalid# error code +if [code]#(acc.empty() == true)#. + +a@ +[source] +---- +void depends_on(event depEvent) +---- +a@ The <> now has a *requirement* that the action represented +by [code]#depEvent# must complete before executing this +<> action. + +a@ +[source] +---- +void depends_on(const std::vector &depEvents) +---- +a@ The <> now has a *requirement* that the actions represented +by each event in [code]#depEvents# must complete before executing this +<> action. + +|==== + + +[[subsec:invokingkernels]] +==== SYCL functions for invoking kernels + +<> can be invoked as [keyword]#single tasks#, basic +[keyword]#data-parallel# <>, <> in +<>, or [keyword]#hierarchical parallelism#. + +Each function takes an optional kernel name template parameter. The user +may optionally provide a <>, otherwise an implementation-defined name +will be generated for the kernel. + +All the functions for invoking kernels are member functions of the command group +[code]#handler# class (<>), which +is used to encapsulate all the member functions provided in a command group scope. +<> lists all the members of the +[code]#handler# class related to the kernel invocation. + + +[[table.members.handler.kernel]] +.Member functions of the [code]#handler# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +template + void set_arg(int argIndex, T &&arg) +---- + a@ This function must only be used to set arguments for a kernel that + was constructed using a backend specific interoperability function + or for a device built-in kernel. Attempting to use this function to set + arguments for other kernels results in undefined behavior. The precise + semantics of this function are defined by each SYCL backend + specification. + +a@ +[source] +---- +template + void set_args(Ts &&... args) +---- + a@ Set all arguments for a given kernel, as if each argument in + [code]#args# was passed to [code]#set_arg# in the same order and + with an increasing index starting at 0. + +a@ +[source] +---- +template + void single_task(const KernelType &kernelFunc) +---- + a@ Defines and invokes a <> as a lambda function + or a named function object type. + Specification of a <> ([code]#typename KernelName#), as + described in <>, is optional. + The callable + [code]#KernelType# can optionally take a [code]#kernel_handler# + in which case the <> will construct an instance of + [code]#kernel_handler# and pass it to [code]#KernelType#. + +a@ +[source] +---- +template + void parallel_for( + range numWorkItems, + Rest&&... rest) +---- + a@ Defines and invokes a <> as a lambda function + or a named function object type, + for the specified range and given an item or integral type (e.g [code]#int#, + [code]#size_t)#, if range is 1-dimensional, for indexing in the indexing + space defined by range. Generic kernel functions are permitted, + in that case the argument type is an [code]#item#. + Specification of a <> ([code]#typename KernelName#), as + described in <>, is optional. + The [code]#rest# parameter pack consists of 0 or more objects created by + the [code]#reduction# function, followed by a callable. For each + object in [code]#rest#, the kernel function must take an additional + reference parameter corresponding to that object's [code]#reducer# type, + in the same order. + The callable can optionally take a [code]#kernel_handler# + as its last parameter, in which case the <> will + construct an instance of [code]#kernel_handler# and pass it to + the callable. + +a@ +[source] +---- +template + void parallel_for( + range numWorkItems, + id workItemOffset, + const KernelType &kernelFunc) +// Deprecated in SYCL 2020. +---- + a@ Deprecated in SYCL 2020. + Defines and invokes a <> as a lambda function + or a named function object type, + for the specified range and offset and given an item or integral type + (e.g [code]#int#, [code]#size_t)#, if range is 1-dimensional, + for indexing in the indexing space defined by range. Generic kernel functions + are permitted, in that case the argument type is an [code]#item#. + Specification of a <> ([code]#typename KernelName#), as + described in <>, is optional. + The [code]#rest# parameter pack consists of 0 or more objects created by + the [code]#reduction# function, followed by a callable. For each + object in [code]#rest#, the kernel function must take an additional + reference parameter corresponding to that object's [code]#reducer# type, + in the same order. + The callable can optionally take a [code]#kernel_handler# + as its last parameter, in which case the <> will + construct an instance of [code]#kernel_handler# and pass it to + the callable. +a@ +[source] +---- +template + void parallel_for( + nd_range executionRange, + Rest&&... rest) +---- + a@ Defines and invokes a <> as a lambda function + or a named function object type, + for the specified <> and given an <> + for indexing in the indexing space defined by the <>. + Generic kernel functions are permitted, in that case the argument type is + an <>. + Specification of a <> ([code]#typename KernelName#), as + described in <>, is optional. + The [code]#rest# parameter pack consists of 0 or more objects created by + the [code]#reduction# function, followed by a callable. For each + object in [code]#rest#, the kernel function must take an additional + reference parameter corresponding to that object's [code]#reducer# type, + in the same order. + The callable can optionally take a [code]#kernel_handler# + as its last parameter, in which case the <> will + construct an instance of [code]#kernel_handler# and pass it to + the callable. + +a@ +[source] +---- +template + void parallel_for_work_group( + range numWorkGroups, + const WorkgroupFunctionType &kernelFunc) +---- + a@ Defines and invokes a hierarchical kernel as a lambda function + encoding the body of each work-group to launch. Generic kernel + functions are permitted, in that case the argument type is a [code]#group#. May + contain multiple calls to [code]#parallel_for_work_item(..)# member functions + representing the execution on each work-item. Launches + [code]#num_work_groups# work-groups of runtime-defined + size. Described in detail in <>. The callable + [code]#WorkgroupFunctionType# can optionally take a + [code]#kernel_handler# as it's last parameter, in which case the + <> will construct an instance of + [code]#kernel_handler# and pass it to [code]#WorkgroupFunctionType#. + +a@ +[source] +---- +template + void parallel_for_work_group( + range numWorkGroups, + range workGroupSize, + const WorkgroupFunctionType &kernelFunc) +---- + a@ Defines and invokes a hierarchical kernel as a lambda function + encoding the body of each work-group to launch. Generic kernel + functions are permitted, in that case the argument type is a [code]#group#. + May contain multiple calls to [code]#parallel_for_work_item# member functions + representing the execution on each work-item. Launches + [code]#num_work_groups# work-groups of + [code]#work_group_size# work-items each. Described in + detail in <>. The callable + [code]#WorkgroupFunctionType# can optionally take a + [code]#kernel_handler# as it's last parameter, in which case the + <> will construct an instance of [code]#kernel_handler# + and pass it to [code]#WorkgroupFunctionType#. + +a@ +[source] +---- +void single_task(const kernel &kernelObject) +---- + a@ This function must only be used to invoke a kernel that was constructed + using a backend specific interoperability function or to invoke a device + built-in kernel. Attempting to use this function to invoke other kernels + results in undefined behavior. The precise semantics of this function + are defined by each SYCL backend specification, but the intent is that + the kernel should execute exactly once. + +This invocation function ignores any [code]#kernel_bundle# that was bound to +this command group handler via [code]#handler::use_kernel_bundle()# and instead +implicitly uses the kernel bundle that contains the [code]#kernelObject#. +Throws an [code]#exception# with the [code]#errc::kernel_not_supported# error +code if the [code]#kernelObject# is not compatible with either the device +associated with the primary queue of the <> or with the device +associated with the secondary queue (if specified). + +a@ +[source] +---- +template void parallel_for( + range numWorkItems, + const kernel &kernelObject) +---- + a@ This function must only be used to invoke a kernel that was constructed + using a backend specific interoperability function or to invoke a device + built-in kernel. Attempting to use this function to invoke other kernels + results in undefined behavior. The precise semantics of this function + are defined by each SYCL backend specification, but the intent is that + the kernel should be invoked for the specified range of index values. + +This invocation function ignores any [code]#kernel_bundle# that was bound to +this command group handler via [code]#handler::use_kernel_bundle()# and instead +implicitly uses the kernel bundle that contains the [code]#kernelObject#. +Throws an [code]#exception# with the [code]#errc::kernel_not_supported# error +code if the [code]#kernelObject# is not compatible with either the device +associated with the primary queue of the <> or with the device +associated with the secondary queue (if specified). + +a@ +[source] +---- +template void parallel_for( + nd_range ndRange, + const kernel &kernelObject) +---- + a@ This function must only be used to invoke a kernel that was constructed + using a backend specific interoperability function or to invoke a device + built-in kernel. Attempting to use this function to invoke other kernels + results in undefined behavior. The precise semantics of this function + are defined by each SYCL backend specification, but the intent is that + the kernel should be invoked for the specified [code]#ndrange#. + +This invocation function ignores any [code]#kernel_bundle# that was bound to +this command group handler via [code]#handler::use_kernel_bundle()# and instead +implicitly uses the kernel bundle that contains the [code]#kernelObject#. +Throws an [code]#exception# with the [code]#errc::kernel_not_supported# error +code if the [code]#kernelObject# is not compatible with either the device +associated with the primary queue of the <> or with the device +associated with the secondary queue (if specified). + +|==== + + +// Interface for apis +// include headers/parallelFor.h ? + + +===== [code]#single_task# invoke + +SYCL provides a simple interface to enqueue a kernel that will be +sequentially executed on a device. Only one instance of the +kernel will be executed. This interface is useful as a primitive for more +complicated parallel algorithms, as it can easily create a chain of +sequential tasks on a SYCL device with each of them managing its +own data transfers. + +This function can only be called inside a command group using the +[code]#handler# object created by the runtime. +Any accessors that are used in a kernel should be defined inside the +same command group. + +Local accessors are disallowed for single task invocations. + +[source,,linenums] +---- +include::{code_dir}/singletask.cpp[lines=4..-1] +---- + +For single tasks, the kernel member function takes no parameters, as there +is no need for <> in a unary index space. + +A [code]#kernel_handler# can optionally be passed as a parameter +to the <> that is invoked by +[code]#single_task# for the purpose explained +in <>. + +[source,,linenums] +---- +include::{code_dir}/singleTaskWithKernelHandler.cpp[lines=4..-1] +---- + + +===== [code]#parallel_for# invoke + +The [code]#parallel_for# member function of the SYCL +[code]#handler# class provides an interface to define and invoke a SYCL +kernel function in a command group, to execute in parallel execution over a +3 dimensional index space. There are three overloads of the +[code]#parallel_for# member function which provide variations of this +interface, each with a different level of complexity and providing a +different set of features. + +For the simplest case, users need only provide the global range (the total +number of work-items in the index space) via a SYCL [code]#range# +parameter. In this case the function object that represents the SYCL kernel +function must take one of: +1) a single SYCL [code]#item# parameter, 2) single generic parameter +([code]#template# parameter or [code]#auto)#, 3) any other type +implicitly converted from SYCL [code]#item#, representing the currently +executing work-item within the range specified by the [code]#range# +parameter. + +The execution of the kernel function is the same whether the parameter to +the SYCL kernel function is a SYCL [code]#id# or a SYCL +[code]#item#. What differs is the functionality that is available to +the SYCL kernel function via the respective interfaces. + +Below is an example of invoking a SYCL kernel function with +[code]#parallel_for# using a lambda function, and passing a SYCL +[code]#id# parameter. In this case, only the global id is available. +This variant of [code]#parallel_for# is designed for when it is not +necessary to query the global range of the index space being executed across. + +[source,,linenums] +---- +include::{code_dir}/basicparallelfor.cpp[lines=4..-1] +---- + +Below is an example of invoking a SYCL kernel function with +[code]#parallel_for# using a lambda function and passing a SYCL +[code]#item# parameter. In this case, both the global id and global +range are queryable. This variant of [code]#parallel_for# is designed +for when it is necessary to query the global range of the index space +being executed across. + +[source,,linenums] +---- +include::{code_dir}/basicParallelForItem.cpp[lines=4..-1] +---- + +Below is an example of invoking a SYCL kernel function with +[code]#parallel_for# using a lambda function and passing +[code]#auto# parameter, treated as [code]#item#. In this case, both +the global id and global range are queryable. The same effect can be +achieved using class with templatized [code]#operator()#. This variant +of [code]#parallel_for# is designed for when it is necessary to query +the global range within which the global id will vary. + +[source,,linenums] +---- +include::{code_dir}/basicParallelForGeneric.cpp[lines=4..-1] +---- + +Below is an example of invoking a SYCL kernel function with +[code]#parallel_for# using a lambda function and passing integral type +(e.g. [code]#int#, [code]#size_t#) parameter. This example is only +valid when calling [code]#parallel_for# with [code]#range<1>#. In +this case only the global id is available. This variant of +[code]#parallel_for# is designed for when it is not necessary to query +the global range of the index space being executed across. + +[source,,linenums] +---- +include::{code_dir}/basicParallelForIntegral.cpp[lines=4..-1] +---- + +The [code]#parallel_for# overload without an offset can be called with +either a number or a [code]#braced-init-list# with 1-3 elements. In that +case the following calls are equivalent: + + * [code]#parallel_for(N, some_kernel)# has same effect as + [code]#parallel_for(range<1>(N), some_kernel)# + * [code]#parallel_for({N}, some_kernel)# has same effect as + [code]#parallel_for(range<1>(N), some_kernel)# + * [code]#parallel_for({N1, N2}, some_kernel)# has same effect as + [code]#parallel_for(range<2>(N1, N2), some_kernel)# + * [code]#parallel_for({N1, N2, N3}, some_kernel)# has same effect + as [code]#parallel_for(range<3>(N1, N2, N3), some_kernel)# + +Below is an example of invoking [code]#parallel_for# with a number +instead of an explicit [code]#range# object. + +[source,,linenums] +---- +include::{code_dir}/basicParallelForNumber.cpp[lines=4..-1] +---- + +For SYCL kernel functions invoked via the above described overload of the +[code]#parallel_for# member function, it is disallowed to use local +accessors or to use a <>. + +The following two examples show how a kernel function object can be launched +over a 3D grid, with 3 elements in each dimension. In the first case +work-item ids range from 0 to 2 inclusive, and in the second case +work-item ids run from 1 to 3. + +[source,,linenums] +---- +include::{code_dir}/parallelfor.cpp[lines=4..-1] +---- + +The last case of a parallel_for invocation enables low-level functionality +of work-items and work-groups. This becomes valuable when an execution +requires groups of work-items that communicate and synchronize. These are +exposed in SYCL through [code]#+parallel_for (nd_range,...)+# and the +[code]#nd_item# class. In this case, the developer needs to define the +[code]#nd_range# that the kernel will execute on in order to have fine +grained control of the enqueuing of the kernel. This variation of +parallel_for expects an [code]#nd_range#, specifying both local and +global ranges, defining the global number of work-items and the number in +each cooperating work-group. The resulting function object is passed an +[code]#nd_item# instance making all the information available, as well +as <> to synchronize between the <>s in +the <>. + +The following example shows how sixty-four work-items may be launched +in a three-dimensional grid with four in each dimension, and divided +into eight work-groups. Each group of work-items synchronizes with a +<>. + +[source,,linenums] +---- +include::{code_dir}/parallelforbarrier.cpp[lines=4..-1] +---- + +In all of these cases the underlying <> will be created +and the kernel defined as a function object will be created and enqueued +as part of the command group scope. + +Some forms of [code]#parallel_for# accept an offset parameter of type +[code]#id#, where the number of dimensions of the [code]#id# is the same +as the number of dimensions of the [code]#range# that determines the iteration space. +These forms of [code]#parallel_for# execute the same number of iterations as the form +with no offset. The difference is that the [code]#id# or [code]#item# parameter passed +to the kernel function has the value of [code]#offset# implicitly added. +This offset parameter is deprecated in SYCL 2020. + +An offset can also be passed to the forms of [code]#parallel_for# that accept an +[code]#nd_range# via the third parameter to the [code]#nd_range# constructor. These +forms of [code]#parallel_for# also execute the same number of iterations as if no offset +was specified. The difference is that the [code]#nd_item# parameter passed to the kernel +function has the value of the offset implicitly added to the constituent <>. +This offset parameter is deprecated in SYCL 2020. + + +A [code]#kernel_handler# can optionally be passed as a parameter to the +<> that is invoked by both variants of +[code]#parallel_for#. + +[source,,linenums] +---- +include::{code_dir}/parallelForWithKernelHandler.cpp[lines=4..-1] +---- + + +===== Parallel for hierarchical invoke + +The hierarchical parallel kernel execution interface provides the same +functionality as is available from the <> interface, but +exposed differently. To execute the same sixty-four work-items in +sixteen work-groups that we saw in the previous example, we execute an +outer [code]#parallel_for_work_group# call to create the +groups. The member function +[code]#handler::parallel_for_work_group# is parameterized by the +number of work-groups, such that the size of each group is chosen by +the runtime, or by the number of work-groups and number of work-items +for users who need more control. + +The body of the outer [code]#parallel_for_work_group# call +consists of a lambda function or function object. The body of this +function object contains code that is executed only once for the +entire work-group. If the code has no side-effects and the compiler +heuristic suggests that it is more efficient to do so, this code will be +executed for each work-item. + +Within this region any variable declared will have the semantics of +<>, shared between all <> in the +<>. If the +device compiler can prove that an array of such variables is accessed only by +a single work-item throughout the lifetime of the work-group, for +example if access is derived from the id of the work-item with no +transformation, then it can allocate the data in private memory or +registers instead. + +To guarantee use of private per-work-item memory, the +[code]#private_memory# class can be used to wrap the data. +This class simply constructs private data for a given group across the +entire group. The id of the current work-item is passed to any access +to grab the correct data. + +The [code]#private_memory# class has the following interface: + +[[paragraph.private.memory]] +.Private memory class +[source,,linenums] +---- +include::{header_dir}/priv.h[lines=4..-1] +---- + +[[table.constructors.private.memory]] +.Constructor of the [code]#private_memory# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Constructor @ Description +a@ +[source] +---- +private_memory(const group &) +---- + a@ Place an object of type [code]#T# in the underlying private memory of each <>. + The type [code]#T# must be default constructible. + The underlying constructor will be called for each <>. + +|==== + +[[table.members.private.memory]] +.Member functions of the [code]#private_memory# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member functions @ Description +a@ +[source] +---- +T &operator()(const h_item &id) +---- + a@ Retrieve a reference to the object for the <>. + +|==== + +<> is allocated per underlying <>, not per +iteration of the [code]#parallel_for_work_item# loop. The number +of instances of a private memory object is only under direct control +if a work-group size is passed to the +[code]#parallel_for_work_group# call. If the underlying +work-group size is chosen by the runtime, the number of private memory +instances is opaque to the program. Explicit private memory +declarations should therefore be used with care and with a full +understanding of which instances of a +[code]#parallel_for_work_item# loop will share the same +underlying variable. + +Also within the lambda body can be a sequence of calls to +[code]#parallel_for_work_item#. At the edges of these inner parallel +executions the work-group synchronizes. As a result the pair of +[code]#parallel_for_work_item# calls in the code below is equivalent to +the parallel execution with a <> in the earlier +example. + +[source,,linenums] +---- +include::{code_dir}/parallelforworkgroup.cpp[lines=4..-1] +---- + +It is valid to use more flexible dimensions of the work-item loops. In +the following example we issue 8 work-groups but let the runtime +choose their size, by not passing a work-group size to the +[code]#parallel_for_work_group# call. The +[code]#parallel_for_work_item# loops may also vary in size, with +their execution ranges unrelated to the dimensions of the work-group, +and the compiler generating an appropriate iteration space to fill the +gap. In this case, the [code]#h_item# provides access to local ids and +ranges that reflect both kernel and [code]#parallel_for_work_item# invocation ranges. + +[source,,linenums] +---- +include::{code_dir}/parallelforworkgroup2.cpp[lines=4..-1] +---- + +This interface offers a more intuitive way for tiling parallel +programming paradigms. In summary, the hierarchical model allows a +developer to distinguish the execution at work-group level and at +work-item level using the [code]#parallel_for_work_group# and the nested +[code]#parallel_for_work_item# functions. It also provides this visibility +to the compiler without the need for difficult loop fission such that +host execution may be more efficient. + +A [code]#kernel_handler# can optionally be passed as a parameter to the +<> that is invoked by any variant of +[code]#parallel_for_work_group#. + +[source,,linenums] +---- +include::{code_dir}/parallelForWorkGroupWithKernelHandler.cpp[lines=4..-1] +---- + +// \input{sycl_explicit_memory} + +// %%%%%%%%%%%%%%%%%%%%%%%%%%%% begin sycl_explicit_memory %%%%%%%%%%%%%%%%%%%%%%%%%%%% + +[[subsec:explicitmemory]] +==== SYCL functions for explicit memory operations + +In addition to <>, <> objects can also be used to +perform manual operations on host and device memory by using the +[keyword]#copy# API of the <>. +Manual copy operations can be seen as specialized kernels executing on the +device, except that typically this operations will be implemented using a +host API that exists as part of a backend (e.g, OpenCL enqueue copy operations). + +The SYCL memory objects involved in a copy operation are specified using +buffer accessors. +Explicit copy operations have a source and a destination. +When an accessor is the _source_ of the operation, the destination can be +a host pointer or another accessor. +The _source_ accessor can have either [code]#read# or +[code]#read_write# access mode. + +When an accessor is the _destination_ of the explicit copy operation, +the source can be a host pointer or another accessor. +The _destination_ accessor can have either +[code]#write#, [code]#read_write#, [code]#discard_write#, +[code]#discard_read_write# access modes. + +When accessors are both the origin and the destination, +the operation is executed on objects controlled by the SYCL runtime. +The SYCL runtime is allowed to not perform an explicit in-copy operation +if a different path to update the data is available according to +the SYCL application memory model. + +The most recent copy of the memory object may reside on any context controlled +by the SYCL runtime, or on the host in a pointer controlled by the +SYCL runtime. The SYCL runtime will ensure that data is copied to the destination +once the <> has completed execution. + +Whenever a host pointer is used as either the host or the destination of these +explicit memory operations, it is the responsibility +of the user for that pointer to have at least as much memory allocated as +the accessor is giving access to, e.g: if an accessor accesses a range +of 10 elements of [code]#int# type, the host pointer must at least have +[code]#10 * sizeof(int)# bytes of memory allocated. + +A special case is the [code]#update_host# member function. +This member function only requires an accessor, and instructs the runtime to update +the internal copy of the data in the host, if any. This is particularly +useful when users use manual synchronization with host pointers, e.g. +via mutex objects on the [code]#buffer# constructors. + +<> describes the interface for the +explicit copy operations. + + +[[table.members.handler.copy]] +.Member functions of the [code]#handler# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +template +void copy(accessor src, + std::shared_ptr dest) +---- +a@ Copies the contents of the memory object accessed by +[code]#src# into the memory pointed to by [code]#dest#. +[code]#dest# must have at least as many bytes as the +range accessed by [code]#src#. + +a@ +[source] +---- +template +void copy(std::shared_ptr src, + accessor dest) +---- +a@ Copies the contents of the memory pointed to by [code]#src# +into the memory object accessed by [code]#dest#. +[code]#src# must have at least as many bytes as the +range accessed by [code]#dest#. + +a@ +[source] +---- +template +void copy(accessor src, + T_dest * dest) +---- +a@ Copies the contents of the memory object accessed by +[code]#src# into the memory pointed to by [code]#dest#. +[code]#dest# must have at least as many bytes as the +range accessed by [code]#src#. + +a@ +[source] +---- +template +void copy(const T_src * src, + accessor dest) +---- +a@ Copies the contents of the memory pointed to by [code]#src# +into the memory object accessed by [code]#dest#. +[code]#src# must have at least as many bytes as the +range accessed by [code]#dest#. + +a@ +[source] +---- +template +void copy(accessor src, + accessor dest) +---- +a@ Copies the contents of the memory object accessed by [code]#src# +into the memory object accessed by [code]#dest#. The size of the [code]#src# +accessor determines the number of bytes that are copied, and [code]#dest# must +have at least this many bytes. If the size of [code]#dest# is too small, the +implementation throws a synchronous [code]#exception# with the +[code]#errc::invalid_object# error code. + +a@ +[source] +---- +template +void update_host(accessor acc) +---- +a@ The contents of the memory object accessed via [code]#acc# +on the host are guaranteed to be up-to-date after this +<> object execution is complete. + +a@ +[source] +---- +template +void fill(accessor dest, + const T& src) +---- +a@ Replicates the value of [code]#src# into the +memory object accessed by [code]#dest#. +T must be a scalar value or a SYCL vector type. + +a@ +[source] +---- +void memcpy(void* dest, const void* src, size_t numBytes) +---- +a@ Copies [code]#numBytes# of data from the pointer +[code]#src# to the pointer [code]#dest#. +Both [code]#dest# and [code]#src# may be either +host or USM pointers. +For more detail on USM, please see <>. + +a@ +[source] +---- +template +void copy(T* dest, const T* src, size_t count) +---- +a@ Copies [code]#count# elements of type [code]#T# from the pointer +[code]#src# to the pointer [code]#dest#. +Both [code]#dest# and [code]#src# may be either +host or USM pointers. +For more detail on USM, please see <>. + +a@ +[source] +---- +void memset(void* ptr, int value, size_t numBytes) +---- +a@ Fills [code]#numBytes# bytes of memory beginning at address [code]#ptr# +with [code]#value#. [code]#ptr# must be a USM allocation. +Note that [code]#value# is interpreted as an +[code]#unsigned char#. For more detail on USM, please see <>. + +a@ +[source] +---- +template +void fill(void* ptr, const T& pattern, size_t count) +---- +a@ Replicates the provided [code]#pattern# into the target +USM pointer [code]#ptr#. [code]#ptr# must be a USM allocation. +[code]#pattern# is filled [code]#count# +times. +For more detail on USM, please see <>. + +a@ +[source] +---- +void prefetch(void* ptr, size_t numBytes) +---- +a@ Enqueues a prefetch of [code]#num_bytes# of data pointed to by +the USM pointer [code]#ptr#. +For more detail on USM, please see <>. + +a@ +[source] +---- +void mem_advise(void* ptr, size_t numBytes, int advice) +---- +a@ Provides information to the SYCL runtime about the USM allocation +at [code]#ptr#. Acceptable values of [code]#advice# are +device-defined. A value of [code]#0# reverts the advice for +[code]#ptr# to the default behavior. +For more detail on USM, please see <>. + +|==== + + +The listing below illustrates how to use explicit copy +operations in SYCL. The example copies half of the contents of +a [code]#std::vector# into the device, leaving the rest of the +contents of the buffer on the device unchanged. + +[source,,linenums] +---- +include::{code_dir}/explicitcopy.cpp[lines=4..-1] +---- + + +// %%%%%%%%%%%%%%%%%%%%%%%%%%%% end sycl_explicit_memory %%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +[[sec:handler.usekernelbundle]] +==== Functions for using a kernel bundle + +[source,,linenums] +---- +include::{header_dir}/handler/useKernelBundle.h[lines=4..-1] +---- + +_Effects:_ The <> associated with the [code]#handler# will use +<> of the [code]#kernel_bundle# [code]#execBundle# +in any of its <>. If the +[code]#kernel_bundle# contains multiple <> that are +compatible with the <> to which the kernel is submitted, then the +<> chosen is implementation-defined. + +If the <> attempts to invoke a kernel that is not contained by +a compatible device image in [code]#execBundle#, the +<> throws a synchronous [code]#exception# with the +[code]#errc::kernel_not_supported# error code. If the <> has a +secondary queue, then the [code]#execBundle# must contain a kernel that is +compatible with both the primary queue's device and the secondary queue's +device, otherwise the <> throws this exception. + +Since the handler method for setting specialization constants is incompatible +with the kernel bundle method, applications should not call this function if +[code]#handler::set_specialization_constant()# has been previously called for +this same <>. + +_Throws:_ + + * An [code]#exception# with the [code]#errc::invalid# error code if + the <> associated with the <> via its associated + <> is different from the <> associated with the + <> specified by [code]#execBundle#. + + * An [code]#exception# with the [code]#errc::invalid# error code if + [code]#handler::set_specialization_constant()# has been called for this + <>. + + +=== Specialization constants + +Device code can make use of <> +which represent constants whose values can be set dynamically during execution +of the <>. The values of these constants are fixed when a +<> is invoked, and they do not change during the +execution of the kernel. However, the application is able to set a new value +for a specialization constant each time a kernel is invoked, so the values can +be tuned differently for each invocation. + +There are two methods for an application to use specialization constants, one +method requires creating a [code]#kernel_bundle# object and the other does not. +The syntax for both methods is mostly the same. Both methods declare +specialization constants in the same way, and kernels read their values in the +same way. The main difference is whether their values are set via +[code]#handler::set_specialization_constant()# or via +[code]#kernel_bundle::set_specialization_constant()#. These two methods are +incompatible with one another, so they may not both be used by the same +<>. + +[NOTE] +==== +Implementations that support online compilation of kernel bundles will likely +implement both methods of specialization constants using kernel bundles. +Therefore, applications should expect that there is some overhead associated +with invoking a kernel with new values for its specialization constants. A +typical implementation records the values of specialization constants set via +[code]#handler::set_specialization_constant()# and remembers these values until +a kernel is invoked (e.g. via [code]#parallel_for()#). At this point, the +implementation determines the bundle that contains the invoked kernel. If +that bundle has already been compiled for the handler's device and compiled +with the correct values for the specialization constants, the kernel is +scheduled for invocation. Otherwise, the implementation compiles the +bundle before scheduling the kernel for invocation. Therefore, applications +that frequently change the values of specialization constants may see an +overhead associated with recompilation of the kernel's bundle. +==== + + +==== Declaring a specialization constant + +Specialization constants must be declared using the [code]#specialization_id# +class, and the declaration must be outside of <> using static +storage duration. The declaration must be in either namespace scope or class +scope. + +A synopsis of this class is shown below. The template parameter [code]#T# must +be a forward-declarable type. + +[source,,linenums] +---- +include::{header_dir}/expressingParallelism/classSpecializationId.h[lines=4..-1] +---- + +===== Constructors + +[source] +---- +template +explicit constexpr specialization_id(Args&&... args); +---- + +_Constraints:_ Available only when [code]#+std::is_constructible_v+# +evaluates to [code]#true#. + +_Effects:_ Constructs a [code]#specialization_id# containing an instance of +[code]#T# initialized with [code]#+args...+#, which represents the +specialization constant's default value. + +===== Special member functions + +[source] +---- +specialization_id(const specialization_id& rhs) = delete; // (1) +specialization_id(specialization_id&& rhs) = delete; // (2) +specialization_id &operator=(const specialization_id& rhs) = delete; // (3) +specialization_id &operator=(specialization_id&& rhs) = delete; // (4) +---- + + . Deleted copy constructor. + . Deleted move constructor. + . Deleted copy assignment operator. + . Deleted move assignment operator. + + +==== Setting and getting the value of a specialization constant + +If the application uses specialization constants without creating a +[code]#kernel_bundle# object, it can set and get their values from +<> by calling member functions of the [code]#handler# +class. These member functions have a template parameter [code]#SpecName# whose +value must be a reference to a variable of type [code]#specialization_id#, +which defines the type and default value of the specialization constant. + +When not using a kernel bundle, the value of a specialization constant that is +used in a kernel invoked from a <> is affected by calls to set +its value from that same <>, but it is not affected by calls +from other <> even if those calls are from +another invocation of the same <>. + +[source] +---- +template +void set_specialization_constant( + typename std::remove_reference_t::type value); +---- + +_Effects:_ Sets the value of the specialization constant whose address is +[code]#SpecName# for this handler's <>. If the specialization +constant's value was previously set in this same <>, the value +is overwritten. + +This function may be called even if the specialization constant +[code]#SpecName# isn't used by the kernel that is invoked by this handler's +<>. Doing so has no effect on the invoked kernel. + +_Throws:_ + + * An [code]#exception# with the [code]#errc::invalid# error code if + a kernel bundle has been bound to the [code]#handler# via + [code]#use_kernel_bundle()#. + +[source] +---- +template +typename std::remove_reference_t::type get_specialization_constant(); +---- + +_Returns:_ The value of the specialization constant whose address is +[code]#SpecName# for this handler's <>. If the value was +previously set in this handler's <>, that value is returned. +Otherwise, the specialization constant's default value is returned. + +_Throws:_ + + * An [code]#exception# with the [code]#errc::invalid# error code if + a kernel bundle has been bound to the [code]#handler# via + [code]#use_kernel_bundle()#. + + +[[sec:spec-constants.device-code]] +==== Reading the value of a specialization constant from device code + +In order to read the value of a specialization constant from device code, the +<> must be declared to take an object of type +[code]#kernel_handler# as its last parameter. The <> constructs +this object, which has a member function for reading the specialization +constant's value. A synopsis of this class is shown below. + +[source,,linenums] +---- +include::{header_dir}/expressingParallelism/classKernelHandler.h[lines=4..-1] +---- + + +===== Member functions + +[source,,linenums] +---- +template +typename std::remove_reference_t::type get_specialization_constant(); +---- + +_Returns:_ The value of the <> whose address is +[code]#SpecName#. For a kernel invoked from a <> that was not +bound to a kernel bundle, the value is the same as what would have been +returned if [code]#handler::get_specialization_constant()# was called +immediately before invoking the kernel. For a kernel invoked from a +<> that was bound to a kernel bundle, the value is the same as +what would be returned if [code]#kernel_bundle::get_specialization_constant()# +was called on the bound bundle. + + +==== Example usage + +The following example performs a convolution and uses +<> to set the values of the +coefficients. + +[source,,linenums] +---- +include::{code_dir}/usingSpecConstants.cpp[lines=4..-1] +---- + + +[[subsec:interfaces.hosttasks]] +== Host tasks + + +[[sec:interfaces.hosttasks.overview]] +=== Overview + +A <> is a native {cpp} callable which is scheduled by the +<>. A <> is submitted to a <> via a +<> by a <>. + +When a <> is submitted to a <> it is scheduled +based on its data dependencies with other <> including +<> and asynchronous copies, resolving any +requisites created by <> attached to the <> as +defined in <>. + +Since a <> is invoked directly by the <> rather +than being compiled as a <>, it does not have the same +restrictions as a <>, and can therefore contain any +arbitrary {cpp} code. However, capturing or using any SYCL class with reference +semantics (see <>) is undefined behavior. + +A <> can be enqueued on any <> and the callable will be +invoked directly by the SYCL runtime, regardless of which <> the +<> is associated with. + +A <> is enqueued on a <> via the [code]#host_task# +member function of the [code]#handler# class. + +A <> can optionally be used to interoperate with the +<> associated with the <> executing the +<>, the <> that the <> is associated with, the +<> that the <> is associated with and the <> +that have been captured in the callable, via an optional +[code]#interop_handle# parameter. + +This allows <> to be used for two purposes: either as a +task which can perform arbitrary {cpp} code within the scheduling of the +<> or as a task which can perform interoperability at a point +within the scheduling of the <>. + +For the former use case, construct a buffer accessor with +[code]#target::host_task# or an image accessor with +[code]#image_target::host_task#. This makes the buffer or image available +on the host during execution of the <>. + +For the latter case, construct a buffer accessor with +[code]#target::device# or [code]#target::constant_buffer#, or construct +an image accessor with [code]#image_target::device#. This makes the buffer or +image available on the device that is associated with the queue used to submit +the <>, so that it can be accessed via interoperability member +functions provided by the [code]#interop_handle# class. + +Local <> cannot be used within a <>. + +// TODO: access mode/target resolution rules + +[source,,linenums] +---- +include::{header_dir}/hostTask/hostTaskSynopsis.h[lines=4..-1] +---- + + +[[subsec:interfaces.hosttasks.interophandle]] +=== Class [code]#interop_handle# + +The [code]#interop_handle# class is an abstraction over the <> +which is being used to invoke the <> and its associated +<> and <>. It also represents the state of the +<> dependency model at the point the <> is invoked. + +The [code]#interop_handle# class provides access to the +<> associated with the <>, <>, +<> and any <> or <> that are captured in +the callable being invoked in order to allow a <> to be used +for interoperability purposes. + +An [code]#interop_handle# cannot be constructed by user-code, only by the +<>. + +[source,,linenums] +---- +include::{header_dir}/hostTask/classInteropHandle.h[lines=4..-1] +---- + + +[[subsec:interfaces.hosttask.interophandle.ctrs]] +==== Constructors + +[source,,linenums] +---- +include::{header_dir}/hostTask/classInteropHandle/constructors.h[lines=4..-1] +---- + + . Private implementation-defined constructor with unspecified arguments so + that the <> can construct a [code]#interop_handle#. + . Explicitly deleted default constructor. + +[[subsec:interfaces.hosttask.interophandle.getbackend]] +==== Member functions + +[source,,linenums] +---- +include::{header_dir}/hostTask/classInteropHandle/getbackend.h[lines=4..-1] +---- + + . _Returns:_ Returns a [code]#backend# identifying the <> associated + with the <> associated with this [code]#interop_handle#. + +[[subsec:interfaces.hosttask.interophandle.getnative]] +==== Template member functions [code]#get_native_*# + +[source,,linenums] +---- +include::{header_dir}/hostTask/classInteropHandle/getnativeX.h[lines=4..-1] +---- + + . _Constraints:_ Available only if the optional interoperability + function [code]#get_native# taking a [code]#buffer# is + available and if [code]#accTarget# is + [code]#target::device#. ++ +-- +_Returns:_ The <> interoperability +<> associated with the <> +[code]#bufferAcc#. The <> returned must +be in a state where it represents the memory in its current state within the +<> dependency model and is capable of being used in a way +appropriate for the associated <>. It is undefined behavior to +use the <> outside of the scope of the +<>. + +_Throws:_ An [code]#exception# with the [code]#errc::invalid# error code if the +<> [code]#bufferAcc# was not registered with the +<> which contained the <>. Must throw an [code]#exception# with the +[code]#errc::backend_mismatch# error code if [code]#Backend != get_backend()#. +-- + . _Constraints:_ Available only if the optional interoperability + function [code]#get_native# taking an [code]#unsampled_image# + is available. ++ +-- +_Returns:_ The <> interoperability +<> associated with the <> +[code]#imageAcc#. The <> returned must be +in a state where it represents the memory in its current state within the +<> dependency model and is capable of being used in a way +appropriate for the associated <>. It is undefined behavior to +use the <> outside of the scope of the +<>. + +_Throws:_ An [code]#exception# with the [code]#errc::invalid# error code if the +<> [code]#imageAcc# was not registered with the +<> which contained the <>. +-- + . _Constraints:_ Available only if the optional interoperability + function [code]#get_native# taking an [code]#sampled_image# + is available. ++ +-- +_Returns:_ The <> interoperability +<> associated with the <> +[code]#imageAcc#. The <> returned must be +in a state where it represents the memory in its current state within the +<> dependency model and is capable of being used in a way +appropriate for the associated <>. It is undefined behavior to +use the <> outside of the scope of the +<>. + +_Throws:_ An [code]#exception# with the [code]#errc::invalid# error code if the +<> [code]#imageAcc# was not registered with the +<> which contained the <>. Must throw an [code]#exception# with the +[code]#errc::backend_mismatch# error code if [code]#Backend != get_backend()#. +-- + . _Constraints:_ Available only if the optional interoperability + function [code]#get_native# taking a [code]#queue# is + available. ++ +-- +_Returns:_ The <> interoperability +<> associated with the <> that the +<> was submitted to. If the <> was submitted +with a secondary <> and the fall-back was triggered, the +<> that is associated with the [code]#interop_handle# must be +the fall-back <>. The <> returned must be +in a state where it is capable of being used in a way appropriate for the +associated <>. It is undefined behavior to use the +<> outside of the scope of the <>. + +_Throws:_ Must throw an [code]#exception# with the +[code]#errc::backend_mismatch# error code if [code]#Backend != get_backend()#. +-- + . _Constraints:_ Available only if the optional interoperability + function [code]#get_native# taking a [code]#device# is + available. ++ +-- +_Returns:_ The <> interoperability +<> associated with the <> that is +associated with the <> that the <> was submitted to. +The <> returned must be in a state where it is +capable of being used in a way appropriate for the associated <>. +It is undefined behavior to use the <> outside of +the scope of the <>. + +_Throws:_ Must throw an [code]#exception# with the +[code]#errc::backend_mismatch# error code if [code]#Backend != get_backend()#. +-- + . _Constraints:_ Available only if the optional interoperability + function [code]#get_native# taking a [code]#context# is + available. ++ +-- +_Returns:_ The <> interoperability +<> associated with the <> that is +associated with the <> that the <> was submitted to. +The <> returned must be in a state where it is +capable of being used in a way appropriate for the associated <>. +It is undefined behavior to use the <> outside of +the scope of the <>. + +_Throws:_ Must throw an [code]#exception# with the +[code]#errc::backend_mismatch# error code if [code]#Backend != get_backend()#. +-- + + +[[subsec:interfaces.hosttask.handler]] +=== Additions to the [code]#handler# class + +This section describes member functions in the <> class that are +used with host tasks. + +[source,,linenums] +---- +include::{header_dir}/hostTask/classHandler/hostTask.h[lines=4..-1] +---- + + . _Effects:_ Enqueues an implementation-defined command to the + <> to invoke [code]#hostTaskCallable# exactly once. The + scheduling of the invocation of [code]#hostTaskCallable# in relation to + other <> enqueued to the <> must be in accordance + with the dependency model described in <>. + Initializes an [code]#interop_handle# object and passes it to + [code]#hostTaskCallable# when it is invoked if + [code]#std::is_invocable_v# evaluates to + [code]#true#, otherwise invokes [code]#hostTaskCallable# as a + nullary function. + + +[[sec:interfaces.bundles]] +== Kernel bundles + +Kernel bundles provide several features to a <>. For +implementations that support an online compiler, they provide fine grained +control over the online compilation of device code. For example, an +application can use a kernel bundle to compile its <> at a +specific time during the application's execution (such as during its +initialization), rather than relying on the implementation's default behavior +(which may not compile kernels until they are submitted). + +Kernel bundles also provide a way for the application to set the values of +specialization constants in many kernels before any of them are submitted to +a device, which could potentially be more efficient in some cases. + +Kernel bundles provide a way for the application to introspect its kernels. +For example, an application can use a bundle to query a kernel's work-group +size when it is run on a specific device. + +Finally, kernel bundles provide an extension point to interoperate with backend +and device specific features. Some examples of this include invocation of +device specific built-in kernels, online compilation of kernel code with vendor +specific options, or interoperation with kernels created with backend APIs. + + +=== Overview + +A kernel bundle is a high-level abstraction which represents a set of +<> that are associated with a <> and can be executed +on a number of <>, where each device is associated with that +same context. Depending on how a bundle is obtained, it could represent all of +the <> in the <>, +or a certain subset of them. + +A kernel bundle is composed of one or more <>, +where each device image is an indivisible unit of compilation and/or linking. +When the <> compiles or links one of the kernels represented by +the device image, it must also compile or link any other kernels the device +image represents. Once a device image is compiled and linked, any of the other +kernels which that device image represents may be invoked without further +compilation or linking. + +Each <> a bundle represents must reside in at least one +of the bundle's device images. However, it is not necessary for each device +image to contain all of the kernel functions that the bundle represents. The +granularity in which kernel functions are grouped into device images is an +implementation detail. + +[NOTE] +==== +To illustrate the intent of device images, a hypothetical implementation could +represent an application's kernel functions in both the SPIR-V format and also +in a native device code format. The implementation's ahead-of-time compiler +in this example produces device images with native code for certain devices and +also produces SPIR-V device images for use with other devices. Note that in +such an implementation, a particular kernel function could be represented in +more than one device image. + +An implementation could choose to have all kernel functions from all +translation units grouped together in a single device image, to have each +kernel function represented in its own device image, or to group kernel +functions in some other way. +==== + +Each device associated with a kernel bundle must have at least one compatible +device image, meaning that the implementation can either invoke the image's +kernel functions directly on the device or that the implementation can +translate the device image into a format that allows it to invoke the kernel +functions. + +An outcome of this definition is that each kernel function in a bundle must be +invocable on at least one of the devices associated with the bundle. However, +it is not necessary for every kernel function in the bundle to be invocable on +every associated device. + +[NOTE] +==== +One common reason why a kernel function might not be invocable on every device +associated with a bundle is if the kernel uses optional device features. It's +possible that these features are available to only some devices in the bundle. + +The use of optional device features could affect how the implementation groups +kernels into device images, depending on how these features are represented. +For example, consider an implementation where the optional feature is +represented in SPIR-V but translation of that SPIR-V into native code will fail +if the target device does not support the feature. In such an implementation, +kernels that use optional features should not be grouped into the same device +image as kernels that do not use these features. Since a device image is an +indivisible unit of compilation, doing so would cause a compilation failure if +a kernel K1 is invoked on a device D1 if K1 happened to reside in the same +device image as another kernel K2 that used a feature which is not supported on +device D1. + +See <> for more about optional device features. +==== + +A <> can obtain a kernel bundle by calling one of the +overloads of the [code]#get_kernel_bundle()# free function. Certain backends +may provide additional mechanisms for obtaining bundles with other +representations. If this is supported, the backend specification document will +describe the details. + +Once a kernel bundle has been obtained there are a number of free functions for +performing compilation, linking and joining. Once a bundle is compiled and +linked, the application can invoke kernels from the bundle by calling +[code]#handler::use_kernel_bundle()# as described in +<>. + + +[[sec:interfaces.bundles.overview.synopsis]] +=== Synopsis + +[source,,linenums] +---- +include::{header_dir}/bundle/freeFunctions.h[lines=4..-1] +---- + + +=== Fixed-function built-in kernels + +SYCL allows a <> to expose fixed functionality as non-programmable +built-in kernels. The availability and behavior of these built-in kernels are +backend specific and are not required to follow the SYCL execution and memory +models. However, the basic interface is common to all backends. + + +[[sec:interfaces.bundles.bundlestate]] +=== Bundle states + +A <> can be in one of three different +<> which are represented by an enum class called +[code]#bundle_state#. <> describes the semantics of +these three states. + +The states form a progression. A bundle in [code]#bundle_state::input# can +be translated into [code]#bundle_state::object# by online compilation of the +bundle. A bundle in [code]#bundle_state::object# can be translated into +[code]#bundle_state::executable# by online linking. + +[NOTE] +==== +Each implementation is free to define the "online compilation" and "online +linking" operations as it sees fit, so long as this progression of bundle +states is preserved and so long as the bundles in each state behave as +specified. +==== + +There is no requirement that an implementation must expose kernels in +[code]#bundle_state::input# or [code]#bundle_state::object#. In fact, an +implementation could expose some kernels in these states but not others. For +example, this behavior could be controlled by implementation specific options +to the ahead-of-time compiler. Kernels that are not exposed in these states +cannot be online compiled or online linked by the application. + +All kernels defined in the <>, however, must be exposed in +[code]#bundle_state::executable# because this is the only state that allows a +kernel to be invoked on a device. Device built-in kernels are also exposed +in [code]#bundle_state::executable#. + +If an application exposes a bundle in [code]#bundle_state::input# for a device +D, then the implementation must also provide an online compiler for device D. +Therefore, an application need not explicitly test for +[code]#aspect::online_compiler# if it successfully obtains a bundle in +[code]#bundle_state::input# for that device. Likewise, an implementation must +provide an online linker for device D if it exposes a bundle in +[code]#bundle_state::object# for device D. + +[[table.bundles.states]] +.Enumeration of possible bundle states +[width="100%",options="header",separator="@",cols="35%,65%"] +|==== +@ Bundle State @ Description +a@ +[source] +---- +bundle_state::input +---- + a@ The <> in the kernel bundle have a format + that must be compiled and linked before their kernels can be invoked. + For example, an implementation could use this state for device images + that are stored in an intermediate language format or for device images + that are stored as source code strings. + +a@ +[source] +---- +bundle_state::object +---- + a@ The <> in the kernel bundle have a format + that must be linked before their kernels can be invoked. + +a@ +[source] +---- +bundle_state::executable +---- + a@ The <> in the kernel bundle are in a format + that allows them to be invoked on a device. For example, an + implementation could use this state for device images that have been + compiled into the device's native code. + +|==== + + +=== Kernel identifiers + +Some of the functions related to kernel bundles take an input parameter of type +[code]#kernel_id# which identifies a kernel. A synopsis of the +[code]#kernel_id# class is shown below along with a description of its member +functions. Additionally, this class provides the common special member +functions and common member functions that are listed in +<> in <> and +<>, respectively. + +There is no public default constructor for this class. + +[source,,linenums] +---- +include::{header_dir}/bundle/kernelIdClass.h[lines=4..-1] +---- + +[source] +---- +const char *get_name() const noexcept; +---- + +_Returns:_ An implementation-defined null-terminated string containing the +name of the kernel. There is no guarantee that this name is unique amongst +all the kernels, nor is there a guarantee that the name is stable from one +run of the application to another. The lifetime of the memory containing the +name is unspecified. + +[NOTE] +==== +In practice, the lifetime of the memory containing the name will typically +extend until the application terminates, unless the kernel associated with +the name comes from a dynamic library. In this case, the lifetime of the +memory may end if the dynamic library is unloaded. +==== + + +=== Obtaining a kernel identifier + +An application can obtain an identifier for a kernel that is defined in the +application by calling one of the following free functions, or it may obtain an +identifier for a device's built-in kernels by querying the device with +[code]#info::device::built_in_kernel_ids#. + +[source] +---- +template +kernel_id get_kernel_id(); +---- + +_Preconditions:_ The template parameter [code]#KernelName# must be the +<> of a kernel that is defined in the <>. +Since lambda functions have no standard type name, kernels defined as lambda +functions must specify a [code]#KernelName# in their +<> in order to obtain their identifier via this +function. Applications which call [code]#get_kernel_id()# for a +[code]#KernelName# that is not defined are ill formed, and the implementation +must issue a diagnostic in this case. + +_Returns:_ The identifier of the kernel associated with [code]#KernelName#. + +[source] +---- +std::vector get_kernel_ids(); +---- + +_Returns:_ A vector with the identifiers for all kernels defined in the +<>. This does not include identifiers for any device +built-in kernels. + + +=== Obtaining a kernel bundle + +A <> can obtain a kernel bundle by calling one of the +overloads of the free function [code]#get_kernel_bundle()#. The implementation +may return a bundle that consists of device images that were created by the +ahead-of-time compiler, or it may call the online compiler or linker to create +the bundle's device images in the requested state. A bundle may also contain +device images that represent a device's built-in kernels. + +[source] +---- +template +kernel_bundle get_kernel_bundle(const context &ctxt, const std::vector &devs); +---- + +_Returns:_ A kernel bundle in state [code]#State# which contains all of the +<> in the application which are compatible with at least one of +the devices in [code]#devs#. This does not include any device built-in kernels. +The bundle's set of associated devices is [code]#devs#. + +Since the implementation may not represent all kernels in +[code]#bundle_state::input# or [code]#bundle_state::object#, calling this +function with one of those states may return a bundle that is missing some of +the application's kernels. + +_Throws:_ + + * An [code]#exception# with the [code]#errc::invalid# error code if any of + the devices in [code]#devs# is not in the list of devices associated with + the context [code]#ctxt#. + * An [code]#exception# with the [code]#errc::invalid# error code if + [code]#State# is [code]#bundle_state::input# and any device in [code]#devs# + does not have [code]#aspect::online_compiler#. + * An [code]#exception# with the [code]#errc::invalid# error code if + [code]#State# is [code]#bundle_state::object# and any device in [code]#devs# + does not have [code]#aspect::online_linker#. + * An [code]#exception# with the [code]#errc::build# error code if + [code]#State# is [code]#bundle_state::object# or + [code]#bundle_state::executable#, if the implementation needs to perform an + online compile or link, and if the online compile or link fails. + +[source] +---- +template +kernel_bundle get_kernel_bundle(const context &ctxt, const std::vector &devs, + const std::vector &kernelIds); +---- + +_Returns:_ A kernel bundle in state [code]#State# which contains all of the +device images that are compatible with at least one of the devices in +[code]#devs#, further filtered to contain only those device images that contain +kernels with the given identifiers. These identifiers may represent kernels +that are defined in the application, device built-in kernels, or a mixture of +the two. Since the device images may group many kernels together, the returned +bundle may contain additional kernels beyond those that are requested in +[code]#kernelIds#. The bundle's set of associated devices is [code]#devs#. + +Since the implementation may not represent all kernels in +[code]#bundle_state::input# or [code]#bundle_state::object#, calling this +function with one of those states may return a bundle that is missing some of +the kernels in [code]#kernelIds#. The application can test for this via +[code]#kernel_bundle::has_kernel()#. + +_Throws:_ + + * An [code]#exception# with the [code]#errc::invalid# error code if any of + the kernels are incompatible with all devices in [code]#devs#. + * An [code]#exception# with the [code]#errc::invalid# error code if any of + the devices in [code]#devs# is not in the list of devices associated with + the context [code]#ctxt#. + * An [code]#exception# with the [code]#errc::invalid# error code if + [code]#State# is [code]#bundle_state::input# and any device in [code]#devs# + does not have [code]#aspect::online_compiler#. + * An [code]#exception# with the [code]#errc::invalid# error code if + [code]#State# is [code]#bundle_state::object# and any device in [code]#devs# + does not have [code]#aspect::online_linker#. + * An [code]#exception# with the [code]#errc::build# error code if + [code]#State# is [code]#bundle_state::object# or + [code]#bundle_state::executable#, if the implementation needs to perform an + online compile or link, and if the online compile or link fails. + +[source] +---- +template +kernel_bundle get_kernel_bundle(const context &ctxt, + const std::vector &devs, + Selector selector); +---- + +_Preconditions:_ The [code]#selector# must be a unary predicate whose return +value is convertible to [code]#bool# and whose parameter is +[code]#const device_image &#. + +_Effects:_ The predicate function [code]#selector# is called once for every +device image in the application of state [code]#State# which is compatible +with at least one of the devices in [code]#devs#. The function's return value +determines whether a device image is included in the new kernel bundle. The +[code]#Selector# is called only for device images that contain kernels defined +in the application, not for device images that contain device built-in kernels. + +_Returns:_ A kernel bundle in state [code]#State# which contains all of the +device images for which the [code]#selector# returns [code]#true#. + +_Throws:_ + + * An [code]#exception# with the [code]#errc::invalid# error code if any of + the devices in [code]#devs# is not in the list of devices associated with + the context [code]#ctxt#. + * An [code]#exception# with the [code]#errc::invalid# error code if + [code]#State# is [code]#bundle_state::input# and any device in [code]#devs# + does not have [code]#aspect::online_compiler#. + * An [code]#exception# with the [code]#errc::invalid# error code if + [code]#State# is [code]#bundle_state::object# and any device in + [code]#devs# does not have [code]#aspect::online_linker#. + +[NOTE] +==== +This function is intended to be used in conjunction with backend specific APIs +that allow the application to choose device images based on backend specific +criteria. + +This function does not call the online compiler or linker to translate device +images into state [code]#State#. If the application wants to select specific +device images and also compile or link them into the desired state, it can do +this by calling [code]#compile()# or [code]#link()# and then optionally joining +several bundles together with [code]#join()#. +==== + +[source] +---- +template // (1) +kernel_bundle get_kernel_bundle(const context &ctxt); + +template // (2) +kernel_bundle get_kernel_bundle(const context &ctxt, + const std::vector &kernelIds); + +template // (3) +kernel_bundle get_kernel_bundle(const context &ctxt, Selector selector); +---- + + . Equivalent to [code]#get_kernel_bundle(ctxt, ctxt.get_devices())#. + . Equivalent to + [code]#get_kernel_bundle(ctxt, ctxt.get_devices(), kernelIds)#. + . Equivalent to + [code]#get_kernel_bundle(ctxt, ctxt.get_devices(), selector)#. + +[source] +---- +template // (1) +kernel_bundle get_kernel_bundle(const context &ctxt); + +template // (2) +kernel_bundle get_kernel_bundle(const context &ctxt, const std::vector &devs); +---- + +_Preconditions:_ The template parameter [code]#KernelName# must be the +<> of a kernel that is defined in the <>. +Since lambda functions have no standard type name, kernels defined as lambda +functions must specify a [code]#KernelName# in their +<> in order to use these functions. Applications +which call these functions for a [code]#KernelName# that is not defined are ill +formed, and the implementation must issue a diagnostic in this case. + + . Equivalent to + [code]#get_kernel_bundle(ctxt, ctxt.get_devices(), {get_kernel_id()})#. + . Equivalent to + [code]#get_kernel_bundle(ctxt, devs, {get_kernel_id()})#. + + +=== Querying if a kernel bundle exists + +Most overloads of [code]#get_kernel_bundle()# have a matching overload of the +free function [code]#has_kernel_bundle()# which checks to see if a kernel +bundle with the requested characteristics exists. + +[source] +---- +template +bool has_kernel_bundle(const context &ctxt, const std::vector &devs); +---- + +_Returns:_ [code]#true# only if all of the following are true: + + * The application defines at least one <> that is compatible with + at least one of the devices in [code]#devs#, and that kernel can be + represented in a device image of state [code]#State#. + * If [code]#State# is [code]#bundle_state::input#, all devices in + [code]#devs# have [code]#aspect::online_compiler#. + * If [code]#State# is [code]#bundle_state::object#, all devices in + [code]#devs# have [code]#aspect::online_linker#. + +_Throws:_ + + * An [code]#exception# with the [code]#errc::invalid# error code if any of + the devices in [code]#devs# is not in the list of devices associated with + the context [code]#ctxt#. + +[source] +---- +template +bool has_kernel_bundle(const context &ctxt, const std::vector &devs, + const std::vector &kernelIds); +---- + +_Returns:_ [code]#true# only if all of the following are true: + + * Each of the kernels in [code]#kernelIds# can be represented in a device + image of state [code]#State#. + * Each of the kernels in [code]#kernelIds# is compatible with at least one + of the devices in [code]#devs#. + * If [code]#State# is [code]#bundle_state::input#, all devices in + [code]#devs# have [code]#aspect::online_compiler#. + * If [code]#State# is [code]#bundle_state::object#, all devices in + [code]#devs# have [code]#aspect::online_linker#. + +_Throws:_ + + * An [code]#exception# with the [code]#errc::invalid# error code if any of + the devices in [code]#devs# is not in the list of devices associated with + the context [code]#ctxt#. + +[source] +---- +template // (1) +bool has_kernel_bundle(const context &ctxt); + +template // (2) +bool has_kernel_bundle(const context &ctxt, const std::vector &kernelIds); +---- + + . Equivalent to [code]#has_kernel_bundle(ctxt, ctxt.get_devices())#. + . Equivalent to + [code]#has_kernel_bundle(ctxt, ctxt.get_devices(), kernelIds)#. + +[source] +---- +template // (1) +bool has_kernel_bundle(const context &ctxt); + +template // (2) +bool has_kernel_bundle(const context &ctxt, const std::vector &devs); +---- + +_Preconditions:_ The template parameter [code]#KernelName# must be the +<> of a kernel that is defined in the <>. +Since lambda functions have no standard type name, kernels defined as lambda +functions must specify a [code]#KernelName# in their +<> in order to use these functions. Applications +which call these functions for a [code]#KernelName# that is not defined are ill +formed, and the implementation must issue a diagnostic in this case. + + . Equivalent to + [code]#has_kernel_bundle(ctxt, {get_kernel_id()})#. + . Equivalent to + [code]#has_kernel_bundle(ctxt, devs, {get_kernel_id()})#. + + +=== Querying if a kernel is compatible with a device + +The following free functions allow an application to test whether a particular +kernel is compatible with a device. A kernel that is defined in the +application is compatible with a device unless it uses optional features which +are not supported on the device, as described in +<>. A device built-in kernel is only compatible +with the device for which it is built-in. + +[source] +---- +bool is_compatible(const std::vector &kernelIds, const device &dev); +---- + +_Returns:_ [code]#true# if all of the kernels identified by [code]#kernelIds# +are compatible with the device [code]#dev#. + +[source] +---- +template +bool is_compatible(const device &dev); +---- + +_Preconditions:_ The template parameter [code]#KernelName# must be the +<> of a kernel that is defined in the <>. +Since lambda functions have no standard type name, kernels defined as lambda +functions must specify a [code]#KernelName# in their +<> in order to use this function. Applications +which call this function for a [code]#KernelName# that is not defined are ill +formed, and the implementation must issue a diagnostic in this case. + +Equivalent to +[code]#is_compatible({get_kernel_id()}, dev)#. + + +=== Joining kernel bundles + +Two or more kernel bundles of the same state may be joined together into a +single composite bundle. Joining bundles together is not the same as online +compiling or linking because it produces a new bundle in the same state as its +inputs. Rather, joining creates the union of all the devices images from the +input bundles, eliminates duplicate copies of the same device image, and +creates a new bundle from the result. + +[source] +---- +template +kernel_bundle join(const std::vector> &bundles); +---- + +_Returns:_ A new kernel bundle that represents the union of all the device +images in the input [code]#bundles# with duplicates removed. + + +[[sec:bundles.compile-link]] +=== Online compiling and linking + +If the implementation provides an online compiler or linker, a +<> can use the free functions defined in this section to +transform a kernel bundle from [code]#bundle_state::input# into a bundle of +state [code]#bundle_state::object# or to transform a bundle from +[code]#bundle_state::object# into a bundle of state +[code]#bundle_state::executable#. + +An application can query whether the implementation provides an online compiler +or linker by querying a device for [code]#aspect::online_compiler# or +[code]#aspect::online_linker#. + +All of the functions in this section accept a [code]#property_list# parameter, +which can affect the semantics of the compilation or linking operation. The +<> does not currently define any such properties, but vendors may +specify these properties as an extension. + +[source] +---- +kernel_bundle +compile(const kernel_bundle &inputBundle, + const std::vector &devs, + const property_list &propList = {}); +---- + +_Effects:_ The device images from [code]#inputBundle# are translated into one +or more new device images of state [code]#bundle_state::object#, and a new +kernel bundle is created to contain these new device images. The new bundle +represents all of the <> in [code]#inputBundles# that are +compatible with at least one of the devices in [code]#devs#. Any remaining +kernels (those that are not compatible with any of the devices [code]#devs#) +are not compiled and not represented in the new kernel bundle. + +The new bundle has the same associated context as [code]#inputBundle#, and the +new bundle's set of associated devices is [code]#devs#. + +_Returns:_ The new kernel bundle. + +_Throws:_ + + * An [code]#exception# with the [code]#errc::invalid# error code if any of + the devices in [code]#devs# are not in the set of associated devices for + [code]#inputBundle# (as defined by [code]#kernel_bundle::get_devices()#). + * An [code]#exception# with the [code]#errc::build# error code if the online + compile operation fails. + +[source] +---- +kernel_bundle +link(const std::vector> &objectBundles, + const std::vector &devs, + const property_list &propList = {}); +---- + +_Effects:_ Duplicate device images from [code]#objectBundles# are eliminated +as though they were joined via [code]#join()#, then the remaining device images +are translated into one or more new device images of state +[code]#bundle_state::executable#, and a new kernel bundle is created to contain +these new device images. The new bundle represents all of the +<> in [code]#objectBundles# that are compatible with at least +one of the devices in [code]#devs#. Any remaining kernels (those that are not +compatible with any of the devices in [code]#devs#) are not linked and not +represented in the new bundle. + +The new bundle has the same associated context as those in +[code]#objectBundles#, and the new bundle's set of associated devices is +[code]#devs#. + +_Returns:_ The new kernel bundle. + +_Throws:_ + + * An [code]#exception# with the [code]#errc::invalid# error code if the + bundles in [code]#objectBundles# do not all have the same associated + context. + * An [code]#exception# with the [code]#errc::invalid# error code if any of + the devices in [code]#devs# are not in the set of associated devices for + any of the bundles in [code]#objectBundles# (as defined by + [code]#kernel_bundle::get_devices()#). + * An [code]#exception# with the [code]#errc::build# error code if the online + link operation fails. + +[source] +---- +kernel_bundle +build(const kernel_bundle &inputBundle, + const std::vector &devs, + const property_list &propList = {}); +---- + +_Effects:_ This function performs both an online compile and link operation, +translating a kernel bundle of state [code]#bundle_state::input# into a bundle +of state [code]#bundle_state::executable#. The device images from +[code]#inputBundle# are translated into one or more new device images of state +[code]#bundle_state::executable#, and a new bundle is created to contain these +new device images. The new bundle represents all of the <> in +[code]#inputBundle# that are compatible with at least one of the devices in +[code]#devs#. Any remaining kernels (those that are not compatible with any of +the devices [code]#devs#) are not compiled or linked and are not represented in +the new bundle. + +The new bundle has the same associated context as [code]#inputBundle#, and the +new bundle's set of associated devices is [code]#devs#. + +_Returns:_ The new kernel bundle. + +_Throws:_ + + * An [code]#exception# with the [code]#errc::invalid# error code if any of + the devices in [code]#devs# are not in the set of associated devices for + [code]#inputBundle# (as defined by [code]#kernel_bundle::get_devices()#). + * An [code]#exception# with the [code]#errc::build# error code if the online + compile or link operations fail. + +[source] +---- +kernel_bundle // (1) +compile(const kernel_bundle &inputBundle, + const property_list &propList = {}); + +kernel_bundle // (2) +link(const kernel_bundle &objectBundle, + const std::vector &devs, + const property_list &propList = {}); + +kernel_bundle // (3) +link(const std::vector> &objectBundles, + const property_list &propList = {}); + +kernel_bundle // (4) +link(const kernel_bundle &objectBundle, + const property_list &propList = {}); + +kernel_bundle // (5) +build(const kernel_bundle &inputBundle, + const property_list &propList = {}); +---- + + . Equivalent to + [code]#compile(inputBundle, inputBundle.get_devices(), propList)#. + + . Equivalent to [code]#link({objectBundle}, devs, propList)#. + + . Equivalent to [code]#link(objectBundles, devs, propList)#, where + [code]#devs# is the intersection of associated devices in common for all + bundles in [code]#objectBundles#. + + . Equivalent to + [code]#link({objectBundle}, objectBundle.get_devices(), propList)#. + + . Equivalent to + [code]#build(inputBundle, inputBundle.get_devices(), propList)#. + + +=== The [code]#kernel_bundle# class + +A synopsis of the [code]#kernel_bundle# class is shown below. Additionally, +this class provides the common special member functions and common member +functions that are listed in <> in +<> and +<>, respectively. + +As with all SYCL objects that have the common reference semantics, kernel +bundles are equality comparable. Two bundles of the same <> are +considered to be equal if they are associated with the same context, have the +same set of associated devices, and contain the same set of device images. + +There is no public default constructor for this class. + +[source,,linenums] +---- +include::{header_dir}/bundle/kernelBundleClass.h[lines=4..-1] +---- + +[[sec:bundles.query]] +==== Queries + +The following member functions provide various queries for a <>. + +[source] +---- +bool empty() const noexcept; +---- + +_Returns:_ [code]#true# only if the kernel bundle contains no device images. + +[source] +---- +backend get_backend() const noexcept; +---- + +_Returns:_ The backend that is associated with the kernel bundle. + +[source] +---- +context get_context() const noexcept; +---- + +_Returns:_ The context that is associated with the kernel bundle. + +[source] +---- +std::vector get_devices() const noexcept; +---- + +_Returns:_ The set of devices that is associated with the kernel bundle. + +[source] +---- +bool has_kernel(const kernel_id &kernelId) const noexcept; // (1) +bool has_kernel(const kernel_id &kernelId, const device &dev) const noexcept; // (2) +---- + + . _Returns:_ [code]#true# only if the kernel bundle contains the kernel + identified by [code]#kernelId#. + . _Returns:_ [code]#true# only if the kernel bundle contains the kernel + identified by [code]#kernelId# and if that kernel is compatible with the + device [code]#dev#. + +[source] +---- +std::vector get_kernel_ids() const; +---- + +_Returns:_ A vector of the identifiers for all kernels that are contained in +the kernel bundle. + +[source] +---- +kernel get_kernel(const kernel_id &kernelId) const; +---- + +_Preconditions:_ This member function is only available if the kernel bundle's +state is [code]#bundle_state::executable#. + +_Returns:_ A [code]#kernel# object representing the kernel identified by +[code]#kernelId#, which resides in the bundle. + +_Throws:_ + + * An [code]#exception# with the [code]#errc::invalid# error code if the + kernel bundle does not contain the kernel identified by [code]#kernelId#. + +==== Specialization constant support + +The following member functions allow an application to manipulate +<> that are used in the +device images of a <>. Applications can set the value of +specialization constants in a kernel bundle whose state is +[code]#bundle_state::input# and then online compile that bundle into +[code]#bundle_state::object# or [code]#bundle_state::executable#. The value of +the specialization constants then become fixed in the compiled bundle and +cannot be changed. Specialization constants that have not had their values set +by the time the bundle is compiled take their default values. + +[NOTE] +==== +It is expected that many implementations will use an intermediate language +representation for a bundle in state [code]#bundle_state::input# such as +SPIR-V, and the intermediate language will have native support for +specialization constants. However, implementations that do not have such +native support must still support specialization constants in some other way. +==== + +[source] +---- +bool contains_specialization_constants() const noexcept; +---- + +_Returns:_ [code]#true# only if the kernel bundle contains at least one device +image which uses a specialization constant. + +[source] +---- +bool native_specialization_constant() const noexcept; +---- + +_Returns:_ [code]#true# only if all specialization constants used in the kernel +bundle are <> +in all of the bundle's device images. + +[source] +---- +template +bool has_specialization_constant() const noexcept; +---- + +_Returns:_ [code]#true# if any device image in the kernel bundle uses the +specialization constant whose address is [code]#SpecName#. + +[source] +---- +template +void set_specialization_constant( + typename std::remove_reference_t::type value); +---- + +_Preconditions:_ This member function is only available if the kernel bundle's +state is [code]#bundle_state::input#. + +_Effects:_ Sets the value of the <> whose address is +[code]#SpecName# for this bundle. If the specialization constant's value was +previously set in this bundle, the value is overwritten. + +The new value applies to all device images in the bundle. It is allowed to set +the value of a specialization constant even if no device image in the bundle +uses it; doing so has no effect on the execution of kernels from that bundle. + +[source] +---- +template +typename std::remove_reference_t::type get_specialization_constant() const; +---- + +_Returns:_ The value of the <> whose address is +[code]#SpecName# for this kernel bundle. The value returned is as follows: + +* If the value of this specialization constant was previously set in this + bundle, that value is returned. Otherwise, + +* If this bundle is the result of compiling, linking or joining another + bundle and this specialization constant was set in that other bundle prior + to compiling, linking or joining; then that value is returned. Otherwise, + +* The specialization constant's default value is returned. + +==== Device image support + +The following member type and functions allow iteration over the +<> contained by the kernel bundle. + +[source] +---- +using device_image_iterator = __unspecified__; +---- + +An iterator type that satisfies the {cpp} requirements of +[code]#LegacyForwardIterator#. The iterator's referenced type is +[code]#const device_image#, where [code]#State# is the same state as the +containing [code]#kernel_bundle#. + +[source] +---- +device_image_iterator begin() const; // (1) +device_image_iterator end() const; // (2) +---- + + . _Returns:_ An iterator to the first <> contained by the + kernel bundle. + . _Returns:_ An iterator to one past the last <> contained by + the kernel bundle. + + +=== The [code]#kernel# class + +A synopsis of the [code]#kernel# class is shown below. Additionally, +this class provides the common special member functions and common member +functions that are listed in <> in +<> and +<>, respectively. + +There is no public default constructor for this class. + +[source,,linenums] +---- +include::{header_dir}/bundle/kernelClass.h[lines=4..-1] +---- + +==== Queries + +The following member functions provide various queries for a <>. + +[source] +---- +backend get_backend() const noexcept; +---- + +_Returns:_ The backend associated with this kernel. + +[source] +---- +context get_context() const; +---- + +_Returns:_ The context associated with this kernel. + +[source] +---- +kernel_bundle get_kernel_bundle() const; +---- + +_Returns:_ The kernel bundle that contains this kernel. + +[source] +---- +template +typename param::return_type get_info() const; +---- + +_Preconditions:_ The [code]#param# must be one of the [code]#info::kernel# +descriptors defined in <>, and the type alias +[code]#param::return_type# must be defined in accordance with that table. + +_Returns:_ Information about the kernel that is not specific to the device on +which it is invoked. + +[source] +---- +template +typename param::return_type get_info(const device &dev) const; +---- + +_Preconditions:_ The [code]#param# must be one of the +[code]#info::kernel_device_specific# descriptors defined in +<>, and the type alias +[code]#param::return_type# must be defined in accordance with that table. + +_Returns:_ Information about the kernel that applies when the kernel is invoked +on the device [code]#dev#. + +_Throws:_ + + * An [code]#exception# with the [code]#errc::invalid# error code if the + kernel is not compatible with device [code]#dev# (as defined by + [code]#is_compatible()#). + +[source] +---- +template +typename param::return_type get_backend_info() const; +---- + +_Preconditions:_ The [code]#param# must be one of a descriptor defined by a +<> specification. + +_Returns:_ Backend specific information about the kernel that is not specific +to the device on which it is invoked. + +_Throws:_ + + * An [code]#exception# with the [code]#errc::backend_mismatch# error code if + the <> that corresponds with [code]#param# is different from the + <> that is associated with this kernel bundle. + +==== Kernel information descriptors + +A <> can be queried for information using the [code]#get_info()# +member function, specifying one of the info parameters in [code]#info::kernel#. +Every kernel must produce a valid value for each info parameter. All info +parameters in [code]#info::kernel# are specified in <> and +the synopsis for [code]#info::kernel# is described in +<>. + +[[table.kernel.info]] +.Kernel class information descriptors +[width="100%",options="header",separator="@",cols="37%,19%,44%"] +|==== +@ Kernel Descriptors @ Return type @ Description +a@ +[source] +---- +info::kernel::num_args +---- + + @ [code]#uint32_t# + a@ This descriptor is only meaningful when used to query a kernel that + resides in a kernel bundle that was constructed using a backend specific + interoperability function. Attempting to use this query for other + kernels returns an unspecified value. The semantics of this descriptor + are defined by each SYCL backend specification. + +a@ +[source] +---- +info::kernel::attributes +---- + + @ [code]#std::string# + a@ Return any attributes specified on a kernel function (as defined in + <>). + +|==== + +A <> can also be queried for device specific information using the +[code]#get_info()# member function, specifying one of the info +parameters in [code]#info::kernel_device_specific#. Every kernel must produce +a valid value for each info parameter. All info parameters in +[code]#info::kernel_device_specific# are specified in +<>. The synopsis for +[code]#info::kernel_device_specific# is described in +<>. + +[[table.kernel.devicespecificinfo]] +.Device-specific kernel information descriptors +[width="100%",options="header",separator="@",cols="37%,19%,44%"] +|==== +@ Device-specific Kernel Information Descriptors @ Return type @ Description +a@ +[source] +---- +info::kernel_device_specific::global_work_size +---- + + @ [code]#range<3># + a@ Returns the maximum global work size. Only valid if device type is + [code]#device_type::custom# or the kernel is a built-in kernel. + +a@ +[source] +---- +info::kernel_device_specific::work_group_size +---- + + @ [code]#size_t# + a@ Returns the maximum number of work-items in a work-group that can be used + to execute a kernel on a specific device. + +a@ +[source] +---- +info::kernel_device_specific::compile_work_group_size +---- + + @ [code]#range<3># + a@ Returns the work-group size specified by the device compiler if applicable, + otherwise returns [code]#{0,0,0}#. + +a@ +[source] +---- +info::kernel_device_specific::preferred_work_group_size_multiple +---- + + @ [code]#size_t# + a@ Returns a value, of which work-group size is preferred to be a multiple, + for executing a kernel on a particular device. This is a performance + hint. The value must be less than or equal to that returned by + [code]#info::kernel_device_specific::work_group_size#. + +a@ +[source] +---- +info::kernel_device_specific::private_mem_size +---- + + @ [code]#size_t# + a@ Returns the minimum amount of private memory, in bytes, used by each work-item + in the kernel. This value may include any private memory needed by an + implementation to execute the kernel, including that used by the language + built-ins and variables declared inside the kernel in the private address + space. + +a@ +[source] +---- +info::kernel_device_specific::max_num_sub_groups +---- + + @ [code]#uint32_t# + a@ Returns the maximum number of sub-groups for this kernel. + +a@ +[source] +---- +info::kernel_device_specific::compile_num_sub_groups +---- + + @ [code]#uint32_t# + a@ Returns the number of sub-groups specified by the kernel, or 0 (if not specified). + +a@ +[source] +---- +info::kernel_device_specific::max_sub_group_size +---- + + @ [code]#uint32_t# + a@ Returns the maximum sub-group size for this kernel. + +a@ +[source] +---- +info::kernel_device_specific::compile_sub_group_size +---- + + @ [code]#uint32_t# + a@ Returns the required sub-group size specified by the kernel, or 0 (if not specified). + +|==== + + +=== The [code]#device_image# class + +A synopsis of the [code]#device_image# class is shown below. Additionally, +this class provides the common special member functions and common member +functions that are listed in <> in +<> and +<>, respectively. + +[source,,linenums] +---- +include::{header_dir}/bundle/deviceImageClass.h[lines=4..-1] +---- + +There is no public constructor for this class. + +[source] +---- +bool has_kernel(const kernel_id &kernelId) const noexcept; // (1) +bool has_kernel(const kernel_id &kernelId, const device &dev) const noexcept; // (2) +---- + + . _Returns:_ [code]#true# only if the device image contains the kernel + identified by [code]#kernelId#. + . _Returns:_ [code]#true# only if the device image contains the kernel + identified by [code]#kernelId# and if that kernel is compatible with the + device [code]#dev#. + + +=== Example usage + +This section provides some examples showing typical use cases for kernel +bundles. These examples are intended to clarify the definition of the kernel +bundle interfaces, but the content of this section is non-normative. + +==== Controlling the timing of online compilation + +In some cases an application may want to pre-compile its kernels before +submitting them to a device. This gives the application control over when the +overhead of online compilation happens, rather than relying on the default +behavior (which may cause the online compilation to happen at the point when +the kernel is submitted to a device). The following example shows how this can +be achieved. + +[source,,linenums] +---- +include::{code_dir}/bundle-pre-compile.cpp[lines=4..-1] +---- + +==== Specialization constants + +An application can use a kernel bundle to set the values of specialization +constants in several kernels before any of them are submitted for execution. + +[source,,linenums] +---- +include::{code_dir}/bundle-spec-constants.cpp[lines=4..-1] +---- + +==== Kernel introspection + +Applications can use kernel bundles to introspect its kernels and use that +information to tune the arguments passed when invoking it. + +[source,,linenums] +---- +include::{code_dir}/bundle-kernel-introspection.cpp[lines=4..-1] +---- + +==== Invoking a device built-in kernel + +An application can use kernel bundles to invoke a device's built-in kernels. + +[source,,linenums] +---- +include::{code_dir}/bundle-builtin-kernel.cpp[lines=4..-1] +---- + + +== Defining kernels + +In SYCL, functions that are executed on a SYCL device are referred to +as <>. A <> containing such a +<> is enqueued on a device queue in order to +be executed on that particular device. + +The return type of the <> is [code]#void#, and all memory +accesses between host and device are through <> or through +<>. + +There are two ways of defining kernels: as named function objects or as +lambda functions. A backend may also provide interoperability interfaces for +defining kernels. + + +[[sec:interfaces.kernels.as.function-objects]] +=== Defining kernels as named function objects + +A kernel can be defined as a named function object type. These function objects +provide the same functionality as any {cpp} function object, with the +restriction that they need to follow SYCL rules to be <>. +The kernel function can be templated via templating the kernel +function object type. For details on restrictions for kernel naming, +please refer to <>. + +The [code]#operator()# member function must be const-qualified, and it may take +different parameters depending on the data accesses defined for the specific +kernel. If the [code]#operator()# function writes to any of the member variables, +the behavior is undefined. + +The following example defines a <>, +_RandomFiller_, which initializes a buffer with a random number. The +random number is generated during the construction of the function object +while processing the command group. The [code]#operator()# member +function of the function object receives an [code]#item# object. This +member function will be called for each work item of the execution range. The value +of the random number will be assigned to each element of the buffer. In this +case, the accessor and the scalar random number are members of the function +object and therefore will be arguments to the device kernel. Usual +restrictions of passing arguments to kernels apply. + +[source,,linenums] +---- +include::{code_dir}/myfunctor.cpp[lines=4..-1] +---- + + +[[sec:interfaces.kernels.as.lambdas]] +=== Defining kernels as lambda functions + +In {cpp}, function objects can be defined using lambda functions. Kernels may be +defined as lambda functions in SYCL. The name of a lambda function +in SYCL may optionally be specified by passing it as a template parameter to the invoking +member function, and in that case, the lambda name is a [keyword]#{cpp} typename# which must +be forward declarable at namespace scope. If the lambda +function relies on template arguments, then if specified, +the name of the lambda function must contain those template arguments which must +also be forward declarable at namespace scope. The +class used for the name of a lambda function is only used for naming purposes +and is not required to be defined. For details on restrictions for kernel +naming, please refer to <>. + +The kernel function for the lambda function is the lambda function itself. +The kernel lambda must use copy for all of its captures (i.e. [code]#[=]#), and +the lambda must not use the [code]#mutable# specifier. + +[source,,linenums] +---- +include::{code_dir}/mykernel.cpp[lines=4..-1] +---- + +Explicit lambda naming is shown in the following code example, +including an illegal case that uses a class within the kernel +name which is not forward declarable ([code]#std::complex#). + +[source,,linenums] +---- +include::{code_dir}/lambdaNameExamples.cpp[lines=4..-1] +---- + +=== [code]#is_device_copyable# type trait + +.... +namespace sycl { + template + struct is_device_copyable; + + template + inline constexpr bool is_device_copyable_v = is_device_copyable::value; +}; +.... + +[code]#is_device_copyable# is a user specializable class template to indicate +that a type [code]#T# is <>. + + * [code]#is_device_copyable# must meet the Cpp17UnaryTrait requirements. + * If [code]#is_device_copyable# is specialized such that + [code]#is_device_copyable_v == true# on a [code]#T# that does not + satisfy all the requirements of a device copyable type, the results are + unspecified. + +If the application defines a type [code]#UDT# that satisfies the requirements of +a <> type (as defined in <>) but the type +is not implicitly device copyable as defined in that section, then the +application must provide a specialization of [code]#is_device_copyable# that +derives from [code]#std:true_type# in order to use that type in a context that +requires a device copyable type. Such a specialization can be declared like +this: + +.... +template<> +struct sycl::is_device_copyable : std::true_type {}; +.... + +It is legal to provide this specialization even if the implementation does not +define [code]#SYCL_DEVICE_COPYABLE# to [code]#1#, but the type cannot be used +as a device copyable type in that case and the specialization is ignored. + + +[[sec:kernel.parameter.passing]] +=== Rules for parameter passing to kernels + +In a case where a kernel is a named function object or a lambda function, any +member variables encapsulated within the function object or variables captured by +the lambda function must be treated according to the following rules: + + * Any accessor must be passed as an argument to the device kernel in a + form that allows the device kernel to access the data in the specified + way. + * The <> and compiler(s) must produce the necessary + conversions to enable accessor arguments from the host to be converted + to the correct type of parameter on the device. + * The device compiler(s) must validate that the layout of any data + shared between the host and the device(s) (e.g. value kernel arguments + or data accessed through an accessor or USM) is compatible with the + layout of that data on the host. If there is a layout mismatch that the + implementation cannot or will not correct for (to make the layouts + compatible), then the device compiler must issue an error and + compilation must fail. + * A local accessor provides access to work-group-local memory. The + accessor is not constructed with any buffer, but instead constructed + with a size and base data type. The runtime must ensure that the + work-group-local memory is allocated per work-group and available to be + used by the kernel via the local accessor. + * <> types must be passed by value to the + kernel. + * Types that are not <> must not be passed as arguments to a + kernel that is compiled for a device. + * It is illegal to pass a buffer or image (instead of an accessor + class) as an argument to a kernel. Generation of a compiler error in + this illegal case is optional. + * It is illegal to pass a reference argument to a kernel. + Generation of a compiler error in this illegal case is optional. + * If a pointer passed to a kernel is [code]#nullptr# or points to a <> + allocation, it must be passed through to the device unmodified. It is legal + to pass other pointers to a kernel, but dereferencing such pointers or + performing pointer arithmetic results in undefined behavior. + * Any aggregate types such as structs or classes should follow the rules + above recursively. It is not necessary to separate struct or class + members into separate kernel parameters if all members of the aggregate + type are unaffected by the rules above. + +// %%%%%%%%%%%%%%%%%%%%%%%%%%%% end expressingParallelism %%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +[[error-handling]] +== Error handling + +=== Error handling rules + +Error handling in a SYCL application (host code) uses {cpp} exceptions. If an error +occurs, it will be thrown by the API function call and may be caught by the user +through standard {cpp} exception handling mechanisms. + +SYCL applications are asynchronous in the sense that host and device code executions +are decoupled from one another except at specific points. For example, device code +executions often begin when dependencies in the SYCL task graph are satisfied, which +occurs asynchronously from host code execution. As a result of this the errors +that occur on a device cannot be thrown directly from a host API call, because the call +enqueueing a device action has typically already returned by the time that the error +occurs. Such errors are not detected until the error-causing task executes or tries to +execute, and we refer to these as <>. + + +[[subsubsec:exception.async]] +==== Asynchronous error handler + +The queue and context classes can optionally take an asynchronous handler object +<> on construction, which is a callable such as a function class +or lambda, with an [code]#exception_list# as a parameter. +Invocation of an <> may be triggered by the queue member functions +[code]#queue::wait_and_throw()# or [code]#queue::throw_asynchronous()#, by +the event member function [code]#event::wait_and_throw()#, or +automatically on destruction of a queue or context that contains unconsumed +asynchronous errors. When invoked, an <> is called and receives an +[code]#exception_list# argument containing a list of exception objects representing +any unconsumed <> associated with the queue or context. + +When an <> instance has been passed to an <>, then +that instance of the error has been consumed for handling and is not reported on +any subsequent invocations of the <>. + +The <> may be a named function object type, a lambda +function or a [code]#std::function#. The [code]#exception_list# +object passed to the <> is constructed by the <>. + + +[[subsubsec:exception.nohandler]] +==== Behavior without an <> + +If an asynchronous error occurs in a queue or context that has no user-supplied +asynchronous error handler object <>, then an implementation-defined +default <> is called to handle the error in the same situations that +a user-supplied <> would be, as defined in +<>. The default <> must in some way +report all errors passed to it, when possible, and must then invoke +[code]#std::terminate# or equivalent. + +==== Priorities of <> + +If the SYCL runtime can associate an <> with a specific queue, +then: + + * If the queue was constructed with an <>, that handler + is invoked to handle the error. + * Otherwise if the context enclosed by the queue was constructed with an + <>, that handler is invoked to handle the error. + * Otherwise when no handler was passed to either queue or context on + construction, then a default handler is invoked to handle the error, as + described by <>. + * All handler invocations in this list occur at times as defined by + <>. + +If the SYCL runtime cannot associate an <> with a specific queue, +then: + + * If the context in which the error occurred was constructed with an + <>, then that handler is invoked to handle the error. + * Otherwise when no handler was passed to the associated context on + construction, then a default handler is invoked to handle the error, as + described by <>. + * All handler invocations in this list occur at times as defined by + <>. + + +==== Asynchronous errors with a secondary queue + +If an <> occurs when running or enqueuing a command group which has +a secondary queue specified, then the command group may be enqueued +to the secondary queue instead of the primary queue. The error handling in this +case is also configured using the <> provided for both +queues. If there is no <> given on any of the queues, +then no asynchronous error reporting is done and no exceptions are thrown. If +the primary queue fails and there is an <> given at +this queue's construction, which populates the [code]#exception_list# +parameter, then any errors will be added and can be thrown whenever the user +chooses to handle those exceptions. Since there were errors on the primary +queue and a secondary queue was given, then the execution of the kernel is +re-scheduled to the secondary queue and any error reporting for the kernel +execution on that queue is done through that queue, in the same way as +described above. The secondary queue may fail as well, and the errors will be +thrown if there is an <> and either +[code]#wait_and_throw()# or [code]#throw()# are called on that queue. +The <> event returned by that function will be +relevant to the queue where the kernel has been enqueued. + +Below is an example of catching a SYCL [code]#exception# and printing out +the error message. + +[source,,linenums] +---- +include::{code_dir}/handlingException.cpp[lines=4..-1] +---- + +Below is an example of catching a SYCL [code]#exception# with the +[code]#errc::invalid# error code and printing out the error message. + +[source,,linenums] +---- +include::{code_dir}/handlingErrorCode.cpp[lines=4..-1] +---- + +Below is an example of catching a SYCL [code]#exception#, checking for the +<> by inspecting the category and handling the OpenCL <> +error codes if the category is that of the OpenCL <> otherwise +checking the standard error code. + +[source,,linenums] +---- +include::{code_dir}/handlingBackendErrorCode.cpp[lines=4..-1] +---- + + +[[subsec:exception.class]] +=== Exception class interface + +[source,,linenums] +---- +include::{header_dir}/exception.h[lines=4..-1] +---- + +The SYCL [code]#exception_list# +class is also available in order to provide a list of synchronous and +asynchronous exceptions. + +Errors can occur both in the SYCL library and SYCL host side, or may come +directly from a <>. The member functions on these exceptions provide the +corresponding information. +<> can provide additional exception class objects as long as they derive +from [code]#sycl::exception# object, or any of its derived classes. + +A specialization of [code]#std::is_error_condition_enum# must be defined +for [code]#sycl::errc# inheriting from [code]#std::true_type#. + +A specialization of [code]#std::is_error_code_enum# must be defined +for [code]#sycl::errc# and [code]#backend_traits::errc# +inheriting from [code]#std::true_type# for each [code]#Backend#, where +[code]#backend# is each enumeration of the enum class [code]#backend#. + + +[[table.members.exception]] +.Member functions of the SYCL [code]#exception# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +exception(std::error_code ec, const std::string& what_arg) +---- + a@ Constructs an [code]#exception#. The string returned by [code]#what()# is guaranteed to contain [code]#what_arg# as a substring. + +a@ +[source] +---- +exception(std::error_code ec, const char* what_arg) +---- + a@ Constructs an [code]#exception#. The string returned by [code]#what()# is guaranteed to contain [code]#what_arg# as a substring. + +a@ +[source] +---- +exception(std::error_code ec) +---- + a@ Constructs an [code]#exception#. + +a@ +[source] +---- +exception(int ev, const std::error_category& ecat, const std::string& what_arg) +---- + a@ Constructs an [code]#exception# with the error code ev and the underlying error category [code]#ecat#. The string returned by [code]#what()# is guaranteed to contain [code]#what_arg# as a substring. + +a@ +[source] +---- +exception(int ev, const std::error_category& ecat, const char* what_arg) +---- + a@ Constructs an [code]#exception# with the error code ev and the underlying error category [code]#ecat#. The string returned by [code]#what()# is guaranteed to contain [code]#what_arg# as a substring. + +a@ +[source] +---- +exception(int ev, const std::error_category& ecat) +---- + a@ Constructs an [code]#exception# with the error code ev and the underlying error category [code]#ecat#. + +a@ +[source] +---- +exception(context ctx, std::error_code ec, const std::string& what_arg) +---- + a@ Constructs an [code]#exception# with an associated SYCL context [code]#ctx#. The string returned by [code]#what()# is guaranteed to contain [code]#what_arg# as a substring. + +a@ +[source] +---- +exception(context ctx, std::error_code ec, const char* what_arg) +---- + a@ Constructs an [code]#exception# with an associated SYCL context [code]#ctx#. The string returned by [code]#what()# is guaranteed to contain [code]#what_arg# as a substring. + +a@ +[source] +---- +exception(context ctx, std::error_code ec) +---- + a@ Constructs an [code]#exception# with an associated SYCL context [code]#ctx#. + +a@ +[source] +---- +exception(context ctx, int ev, const std::error_category& ecat, const std::string& what_arg) +---- + a@ Constructs an [code]#exception# with an associated SYCL context [code]#ctx#, the error code ev and the underlying error category [code]#ecat#. The string returned by [code]#what()# is guaranteed to contain [code]#what_arg# as a substring. + +a@ +[source] +---- +exception(context ctx, int ev, const std::error_category& ecat, const char* what_arg) +---- + a@ Constructs an [code]#exception# with an associated SYCL context [code]#ctx#, the error code ev and the underlying error category [code]#ecat#. The string returned by [code]#what()# is guaranteed to contain [code]#what_arg# as a substring. + +a@ +[source] +---- +exception(context ctx, int ev, const std::error_category& ecat) +---- + a@ Constructs an [code]#exception# with an associated SYCL context [code]#ctx#, the error code ev and the underlying error category [code]#ecat#. + +a@ +[source] +---- +const std::error_code& code() const noexcept +---- + a@ Returns the error code stored inside the exception. + +a@ +[source] +---- +const std::error_category& category() const noexcept +---- + a@ Returns the error category of the error code stored inside the exception. + +a@ +[source] +---- +const char *what() const +---- + a@ Returns an implementation-defined non-null constant C-style string that describes the error that triggered the exception. + +a@ +[source] +---- +bool has_context() const +---- + a@ Returns [code]#true# if this SYCL [code]#exception# has an associated SYCL [code]#context# and [code]#false# if it does not. + +a@ +[source] +---- +context get_context() const +---- + a@ Returns the SYCL [code]#context# that is associated with this SYCL [code]#exception# if one is available. Must throw an [code]#exception# with the [code]#errc::invalid# error code if this SYCL [code]#exception# does not have a SYCL [code]#context#. + +|==== + + + +[[table.members.exceptionlist]] +.Member functions of the [code]#exception_list# +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +size_t size() const +---- + a@ Returns the size of the list + +a@ +[source] +---- +iterator begin() const +---- + a@ Returns an iterator to the beginning of the list of asynchronous exceptions. + +a@ +[source] +---- +iterator end() const +---- + a@ Returns an iterator to the end of the list of asynchronous exceptions. + +|==== + + + +[[table.errc.values]] +.Values of the SYCL [code]#errc# enum +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Standard SYCL Error Codes @ Description +a@ +[source] +---- +runtime +---- + a@ Generic runtime error. + +a@ +[source] +---- +kernel +---- + a@ Error that occurred before or while enqueuing the SYCL kernel. + +a@ +[source] +---- +nd_range +---- + a@ Error regarding the SYCL [code]#nd_range# specified for the SYCL kernel + +a@ +[source] +---- +accessor +---- + a@ Error regarding the SYCL <> objects defined. + +a@ +[source] +---- +event +---- + a@ Error regarding associated SYCL [code]#event# objects. + +a@ +[source] +---- +kernel_argument +---- + a@ The application has passed an invalid argument to a + <>. This includes captured variables if the + <> is a lambda function. + +a@ +[source] +---- +build +---- + a@ Error from an online compile or link operation when compiling, linking, + or building a kernel bundle for a device. + +a@ +[source] +---- +invalid +---- + a@ A catchall error which is used when the application passes an invalid + value as a parameter to a SYCL API function or calls a SYCL API function + in some invalid way. + +a@ +[source] +---- +memory_allocation +---- + a@ Error on memory allocation on the SYCL device for a SYCL kernel. + +a@ +[source] +---- +platform +---- + a@ The SYCL platform will trigger this exception on error. + +a@ +[source] +---- +profiling +---- + a@ The <> will trigger this error if there is an error when profiling info + is enabled. + +a@ +[source] +---- +feature_not_supported +---- + a@ Exception thrown when host code uses an optional feature that is not + supported by a device. + +a@ +[source] +---- +kernel_not_supported +---- + a@ Exception thrown when a kernel uses an optional feature that is not + supported on the device to which it is enqueued. This exception is also + thrown if a <> is bound to a <>, and the + bundle does not contain the kernel invoked by the command group. + +a@ +[source] +---- +backend_mismatch +---- + a@ The application has called a backend interoperability function with + mismatched backend information. For example, requesting information + specific to backend A from a SYCL object that comes from backend B causes + this error. + +|==== + +[[table.error.helpers]] +.SYCL error code helper functions +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ SYCL Error Code Helpers @ Description +a@ +[source] +---- +std::error_condition make_error_condition(errc e) noexcept; +---- + a@ Constructs an error condition using [code]#e# and [code]#sycl_category()#. + +a@ +[source] +---- +std::error_code make_error_code(errc e) noexcept; +---- + a@ Constructs an error code using [code]#e# and [code]#sycl_category()#. + +|==== + + + +== Data types + +SYCL as a {cpp} programming model supports the {cpp} core language data types, +and it also provides the ability for all SYCL applications to be executed on SYCL +compatible devices. The scalar and vector data types that +are supported by the SYCL system are defined below. More details about the SYCL +device compiler support for fundamental and backend interoperability types are found +in <>. + + +=== Scalar data types + +The fundamental {cpp} data types which are supported in SYCL are described in +<>. Note these types are fundamental and therefore +do not exist within the [code]#sycl# namespace. + +Additional scalar data types which are supported by SYCL within the +[code]#sycl# namespace are described in +<>. + + +[[table.types.additional]] +.Additional scalar data types supported by SYCL +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Scalar data type @ Description +a@ +[source] +---- +byte +---- + a@ An unsigned 8-bit integer. This is deprecated in SYCL 2020 since {cpp17} + [code]#std::byte# can be used instead. + +a@ +[source] +---- +half +---- + a@ A 16-bit floating-point. The half data type must conform to the IEEE + 754-2008 half precision storage format. This type is only supported + on devices that have [code]#aspect::fp16#. + +|==== + + +// \input{vec_class} + +// %%%%%%%%%%%%%%%%%%%%%%%%%%%% begin vec_class %%%%%%%%%%%%%%%%%%%%%%%%%%%% + +[[sec:vector.type]] +=== Vector types + +SYCL provides a cross-platform class template that works +efficiently on SYCL devices as well as in host {cpp} code. This type +allows sharing of vectors between the host and its SYCL devices. The +vector supports member functions that allow construction of a new vector from a +swizzled set of component elements. + +[code]#vec# +is a vector type +that compiles down to a <> built-in vector types on SYCL devices, +where possible, and provides compatible support on the host or when it is +not possible. The [code]#vec# class is templated on its number of +elements and its element type. The number of elements parameter, +_numElements_, can be one of: 1, 2, 3, 4, 8 or 16. Any other value shall +produce a compilation failure. The element type parameter, _dataT_, must +be one of the basic scalar types supported in device code. + +The SYCL [code]#vec# class template provides interoperability with the +underlying vector type defined by [code]#vector_t# which is +available only when compiled for the device. The SYCL [code]#vec# class can +be constructed from an instance of [code]#vector_t# and can implicitly +convert to an instance of [code]#vector_t# in order to support +interoperability with native <> functions from a SYCL kernel function. + +An instance of the SYCL [code]#vec# class template can also be +implicitly converted to an instance of the data type when the number of +elements is [code]#1# in order to allow single element vectors and +scalars to be convertible with each other. + +==== Vec interface + +The constructors, member functions and non-member functions of the SYCL +[code]#vec# class template are listed in +<>, <> and +<> respectively. + +// Interface for class: vec +[source,,linenums] +---- +include::{header_dir}/vec.h[lines=4..-1] +---- + + +[[table.constructors.vec]] +.Constructors of the SYCL [code]#vec# class template +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Constructor @ Description +a@ +[source] +---- +vec() +---- + a@ Default construct a vector with element type [code]#dataT# and + with [code]#numElements# dimensions by default construction of + each of its elements. + +a@ +[source] +---- +explicit vec(const dataT &arg) +---- + a@ Construct a vector of element type [code]#dataT# and + [code]#numElements# dimensions by setting each value to [code]#arg# by + assignment. + +a@ +[source] +---- +template + vec(const argTN&... args) +---- + a@ Construct a SYCL [code]#vec# instance from any combination of scalar and SYCL [code]#vec# parameters of the same element type, providing the total number of elements for all parameters sum to [code]#numElements# of this [code]#vec# specialization. + +a@ +[source] +---- +vec(const vec &rhs) +---- + a@ Construct a vector of element type [code]#dataT# and number of elements [code]#numElements# by copy from another similar vector. + +a@ +[source] +---- +vec(vector_t nativeVector) +---- + a@ Available only when: compiled for the device. + +Constructs a SYCL [code]#vec# instance from an instance of the underlying backend-native vector type defined by [code]#vector_t#. + +|==== + + + +[[table.members.vec]] +.Member functions for the SYCL [code]#vec# class template +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +operator vector_t() const +---- + a@ Available only when: compiled for the device. + +Converts this SYCL [code]#vec# instance to the underlying backend-native vector type +defined by [code]#vector_t#. + +a@ +[source] +---- +operator dataT() const +---- + a@ Available only when: [code]#numElements == 1#. + +Converts this SYCL [code]#vec# instance to an instance of [code]#dataT# with +the value of the single element in this SYCL [code]#vec# instance. + +The SYCL [code]#vec# instance shall be implicitly convertible to the same data types, +to which [code]#dataT# is implicitly convertible. +Note that conversion operator shall not be templated +to allow standard conversion sequence for implicit conversion. + +a@ +[source] +---- +static constexpr size_t size() noexcept +---- + a@ Returns the number of elements of this SYCL [code]#vec#. +a@ +[source] +---- +size_t get_count() const +---- + a@ Returns the same value as [code]#size()#. Deprecated. +a@ +[source] +---- +static constexpr size_t byte_size() noexcept +---- + a@ Returns the size of this SYCL [code]#vec# in bytes. + +3-element vector size matches 4-element vector size to provide +interoperability with OpenCL vector types. The same rule applies to vector +alignment as described in <>. +a@ +[source] +---- +size_t get_size() const +---- + a@ Returns the same value as [code]#byte_size()#. Deprecated. +a@ +[source] +---- +template + vec convert() const +---- + a@ Converts this SYCL [code]#vec# to a SYCL [code]#vec# of a different element type specified by [code]#convertT# using the rounding mode specified by [code]#roundingMode#. The new SYCL [code]#vec# type must have the same number of elements as this SYCL [code]#vec#. The different rounding modes are described in <>. + +a@ +[source] +---- +template + asT as() const +---- + a@ Bitwise reinterprets this SYCL [code]#vec# as a SYCL [code]#vec# of a different element type and number of elements specified by [code]#asT#. The new SYCL [code]#vec# type must have the same storage size in bytes as this SYCL [code]#vec#. + +a@ +[source] +---- +template + __swizzled_vec__ swizzle() const +---- + a@ Return an instance of the implementation-defined intermediate class template [code]#+__swizzled_vec__+# representing an index sequence which can be used to apply the swizzle in a valid expression as described in <>. + +a@ +[source] +---- +__swizzled_vec__ XYZW_ACCESS() const +---- + a@ Available only when: [code]#+numElements <= 4+#. + +Returns an instance of the implementation-defined intermediate class template [code]#+__swizzled_vec__+# representing an index sequence which can be used to apply the swizzle in a valid expression as described in <>. + +Where [code]#XYZW_ACCESS# is: [code]#x# for [code]#numElements == 1#, +[code]#x, y# for +[code]#numElements == 2#, +[code]#x, y, z# for +[code]#numElements == 3# and +[code]#x, y, z, w# for +[code]#numElements == 4#. + +a@ +[source] +---- +__swizzled_vec__ RGBA_ACCESS() const +---- + a@ Available only when: [code]#numElements == 4#. + +Returns an instance of the implementation-defined intermediate class template [code]#+__swizzled_vec__+# representing an index sequence which can be used to apply the swizzle in a valid expression as described in <>. + +Where [code]#RGBA_ACCESS# is: [code]#r, g, b, a#. + +a@ +[source] +---- +__swizzled_vec__ INDEX_ACCESS() const +---- + a@ Returns an instance of the implementation-defined intermediate class template [code]#+__swizzled_vec__+# representing an index sequence which can be used to apply the swizzle in a valid expression as described in <>. + +Where [code]#INDEX_ACCESS# is: [code]#s0# for [code]#numElements == 1#, +[code]#s0, s1# for +[code]#numElements == 2#, +[code]#s0, s1, s2# for +[code]#numElements == 3#, +[code]#s0, s1, s2, s3# for +[code]#numElements == 4#, +[code]#s0, s1, s2, s3, s4, s5, s6, s7, s8# for +[code]#numElements == 8# and +[code]#s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, sE, sF# for +[code]#numElements == 16#. + +a@ +[source] +---- +__swizzled_vec__ XYZW_SWIZZLE() const +---- + a@ Available only when: [code]#+numElements <= 4+#, and when the macro [code]#SYCL_SIMPLE_SWIZZLES# is defined before including [code]##. + +Returns an instance of the implementation-defined intermediate class template [code]#+__swizzled_vec__+# representing an index sequence which can be used to apply the swizzle in a valid expression as described in <>. + +Where XYZW_SWIZZLE is all permutations with repetition, of any subset with length greater than [code]#1#, of [code]#x, y# for +[code]#numElements == 2#, +[code]#x, y, z# for +[code]#numElements == 3# and +[code]#x, y, z, w# for +[code]#numElements == 4#. For example a four element [code]#vec# provides permutations including [code]#xzyw#, [code]#xyyy# and [code]#xz#. + +a@ +[source] +---- +__swizzled_vec__ RGBA_SWIZZLE() const +---- + a@ Available only when: [code]#numElements == 4#, and when the macro [code]#SYCL_SIMPLE_SWIZZLES# is defined before including [code]##. + +Returns an instance of the implementation-defined intermediate class template [code]#+__swizzled_vec__+# representing an index sequence which can be used to apply the swizzle in a valid expression as described in <>. + +Where RGBA_SWIZZLE is all permutations with repetition, of any subset with length greater than [code]#1#, of [code]#r, g, b, a#. +For example a four element [code]#vec# provides permutations including [code]#rbga#, [code]#rggg# and [code]#rb#. + +a@ +[source] +---- +__swizzled_vec__ lo() const +---- + a@ Available only when: [code]#numElements > 1#. + +Return an instance of the implementation-defined intermediate class template [code]#+__swizzled_vec__+# representing an index sequence made up of the lower half of this SYCL vec which can be used to apply the swizzle in a valid expression as described in <>. When [code]#numElements == 3#, this SYCL [code]#vec# is treated as though +[code]#numElements == 4# with the fourth element undefined. + +a@ +[source] +---- +__swizzled_vec__ hi() const +---- + a@ Available only when: [code]#numElements > 1#. + +Return an instance of the implementation-defined intermediate class template [code]#+__swizzled_vec__+# representing an index sequence made up of the upper half of this SYCL vec which can be used to apply the swizzle in a valid expression as described in <>. When [code]#numElements == 3#, this SYCL [code]#vec# is treated as though +[code]#numElements == 4# with the fourth element undefined. + +a@ +[source] +---- +__swizzled_vec__ odd() const +---- + a@ Available only when: [code]#numElements > 1#. + +Return an instance of the implementation-defined intermediate class template [code]#+__swizzled_vec__+# representing an index sequence made up of the odd indexes of this SYCL vec which can be used to apply the swizzle in a valid expression as described in <>. When [code]#numElements == 3#, this SYCL [code]#vec# is treated as though +[code]#numElements == 4# with the fourth element undefined. + + +a@ +[source] +---- +__swizzled_vec__ even() const +---- + a@ Available only when: [code]#numElements > 1#. + +Return an instance of the implementation-defined intermediate class template [code]#+__swizzled_vec__+# representing an index sequence made up of the even indexes of this SYCL vec which can be used to apply the swizzle in a valid expression as described in <>. When [code]#numElements == 3#, this SYCL [code]#vec# is treated as though +[code]#numElements == 4# with the fourth element undefined. + +a@ +[source] +---- +template + void load(size_t offset, multi_ptr ptr) +---- + a@ Loads the values at the address of [code]#ptr# offset in elements of type [code]#dataT# by [code]#numElements * offset#, into the components of this SYCL [code]#vec#. + +a@ +[source] +---- +template + void store(size_t offset, multi_ptr ptr) const +---- + a@ Stores the components of this SYCL [code]#vec# into the values at the address of [code]#ptr# offset in elements of type [code]#dataT# by [code]#numElements * offset#. + +a@ +[source] +---- +dataT &operator[](int index) +---- + a@ Returns a reference to the element stored within this SYCL [code]#vec# at the index specified by [code]#index#. + +a@ +[source] +---- +const dataT &operator[](int index) const +---- + a@ Returns a const reference to the element stored within this SYCL [code]#vec# at the index specified by [code]#index#. + +a@ +[source] +---- +vec &operator=(const vec &rhs) +---- + a@ Assign each element of the [code]#rhs# SYCL [code]#vec# to each element of this SYCL [code]#vec# and return a reference to this SYCL [code]#vec#. + +a@ +[source] +---- +vec &operator=(const dataT &rhs) +---- + a@ Assign each element of the [code]#rhs# scalar to each element of this SYCL [code]#vec# and return a reference to this SYCL [code]#vec#. + +|==== + + + +[[table.functions.vec]] +.Hidden friend functions of the [code]#vec# class template +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Hidden friend function @ Description +a@ +[source] +---- +vec operatorOP(const vec &lhs, const vec &rhs) +---- + a@ If [code]#OP# is [code]#%#, available only when: [code]#dataT != float && dataT != double && dataT != half#. + +Construct a new instance of the SYCL [code]#vec# class template with the same template parameters as [code]#lhs# [code]#vec# with each element of the new SYCL [code]#vec# instance the result of an element-wise [code]#OP# arithmetic operation between each element of [code]#lhs# [code]#vec# and each element of the [code]#rhs# SYCL [code]#vec#. + +Where [code]#OP# is: [code]#pass:[+]#, [code]#-#, [code]#*#, [code]#/#, [code]#%#. + +a@ +[source] +---- +vec operatorOP(const vec &lhs, const dataT &rhs) +---- + a@ If [code]#OP# is [code]#%#, available only when: [code]#dataT != float && dataT != double && dataT != half#. + +Construct a new instance of the SYCL [code]#vec# class template with the same template parameters as [code]#lhs# [code]#vec# with each element of the new SYCL [code]#vec# instance the result of an element-wise [code]#OP# arithmetic operation between each element of [code]#lhs# [code]#vec# and the [code]#rhs# scalar. + +Where [code]#OP# is: [code]#pass:[+]#, [code]#-#, [code]#*#, [code]#/#, [code]#%#. + +a@ +[source] +---- +vec &operatorOP(vec &lhs, const vec &rhs) +---- + a@ If [code]#OP# is [code]#%=#, available only when: [code]#dataT != float && dataT != double && dataT != half#. + +Perform an in-place element-wise [code]#OP# arithmetic operation between each element of [code]#lhs# [code]#vec# and each element of the [code]#rhs# SYCL [code]#vec# and return [code]#lhs# [code]#vec#. + +Where [code]#OP# is: [code]#pass:[+=]#, [code]#-=#, [code]#*=#, [code]#/=#, [code]#%=#. + +a@ +[source] +---- +vec &operatorOP(vec &lhs, const dataT &rhs) +---- + a@ If [code]#OP# is [code]#%=#, available only when: [code]#dataT != float && dataT != double && dataT != half#. + +Perform an in-place element-wise [code]#OP# arithmetic operation between each element of [code]#lhs# [code]#vec# and [code]#rhs# scalar and return [code]#lhs# [code]#vec#. + +Where [code]#OP# is: [code]#pass:[+=]#, [code]#-=#, [code]#*=#, [code]#/=#, [code]#%=#. + +a@ +[source] +---- +vec &operatorOP(vec &v) +---- + a@ Perform an in-place element-wise [code]#OP# prefix arithmetic operation on each element of [code]#lhs# [code]#vec#, assigning the result of each element to the corresponding element of [code]#lhs# [code]#vec# and return [code]#lhs# [code]#vec#. + +Where [code]#OP# is: [code]#pass:[++]#, [code]#--#. + +a@ +[source] +---- +vec operatorOP(vec &v, int) +---- + a@ Perform an in-place element-wise [code]#OP# postfix arithmetic operation on each element of [code]#lhs# [code]#vec#, assigning the result of each element to the corresponding element of [code]#lhs# [code]#vec# and returns a copy of [code]#lhs# [code]#vec# before the operation is performed. + +Where [code]#OP# is: [code]#pass:[++]#, [code]#--#. + +a@ +[source] +---- +vec operatorOP(vec &v) +---- + a@ Construct a new instance of the SYCL [code]#vec# class template with the same template parameters as this SYCL [code]#vec# with each element of the new SYCL [code]#vec# instance the result of an element-wise [code]#OP# unary arithmetic operation on each element of this SYCL [code]#vec#. + +Where [code]#OP# is: [code]#pass:[+]#, [code]#-#. + +a@ +[source] +---- +vec operatorOP(const vec &lhs, const vec &rhs) +---- + a@ Available only when: [code]#dataT != float && dataT != double && dataT != half#. + +Construct a new instance of the SYCL [code]#vec# class template with the same template parameters as [code]#lhs# [code]#vec# with each element of the new SYCL [code]#vec# instance the result of an element-wise [code]#OP# bitwise operation between each element of [code]#lhs# [code]#vec# and each element of the [code]#rhs# SYCL [code]#vec#. + +Where [code]#OP# is: [code]#&#, [code]#|#, [code]#^#. + +a@ +[source] +---- +vec operatorOP(const vec &lhs, const dataT &rhs) +---- + a@ Available only when: [code]#dataT != float && dataT != double && dataT != half#. + +Construct a new instance of the SYCL [code]#vec# class template with the same template parameters as [code]#lhs# [code]#vec# with each element of the new SYCL [code]#vec# instance the result of an element-wise [code]#OP# bitwise operation between each element of [code]#lhs# [code]#vec# and the [code]#rhs# scalar. + +Where [code]#OP# is: [code]#&#, [code]#|#, [code]#^#. + +a@ +[source] +---- +vec &operatorOP(vec &lhs, const vec &rhs) +---- + a@ Available only when: [code]#dataT != float && dataT != double && dataT != half#. + +Perform an in-place element-wise [code]#OP# bitwise operation between each element of [code]#lhs# [code]#vec# and the [code]#rhs# SYCL [code]#vec# and return [code]#lhs# [code]#vec#. + +Where [code]#OP# is: [code]#&=#, [code]#|=#, [code]#^=#. + +a@ +[source] +---- +vec &operatorOP(vec &lhs, const dataT &rhs) +---- + a@ Available only when: [code]#dataT != float && dataT != double && dataT != half#. + +Perform an in-place element-wise [code]#OP# bitwise operation between each element of [code]#lhs# [code]#vec# and the [code]#rhs# scalar and return a [code]#lhs# [code]#vec#. + +Where [code]#OP# is: [code]#&=#, [code]#|=#, [code]#^=#. + +a@ +[source] +---- +vec operatorOP(const vec &lhs, const vec &rhs) +---- + a@ Construct a new instance of the SYCL [code]#vec# class template with the same template parameters as [code]#lhs# [code]#vec# with each element of the new SYCL [code]#vec# instance the result of an element-wise [code]#OP# logical operation between each element of [code]#lhs# [code]#vec# and each element of the [code]#rhs# SYCL [code]#vec#. + +The [code]#dataT# template parameter of the constructed SYCL [code]#vec#, [code]#RET#, varies depending on the [code]#dataT# template parameter of this SYCL [code]#vec#. For a SYCL [code]#vec# with [code]#dataT# of type [code]#int8_t# or [code]#uint8_t# [code]#RET# must be [code]#int8_t#. For a SYCL [code]#vec# with [code]#dataT# of type [code]#int16_t#, [code]#uint16_t# or [code]#half# [code]#RET# must be [code]#int16_t#. For a SYCL [code]#vec# with [code]#dataT# of type [code]#int32_t#, [code]#uint32_t# or [code]#float# [code]#RET# must be [code]#int32_t#. For a SYCL [code]#vec# with [code]#dataT# of type [code]#int64_t#, [code]#uint64_t# or [code]#double# [code]#RET# must be [code]#int64_t#. + +Where [code]#OP# is: [code]#&&#, [code]#||#. + +a@ +[source] +---- +vec operatorOP(const vec &lhs, const dataT &rhs) +---- + a@ Construct a new instance of the SYCL [code]#vec# class template with the same template parameters as this SYCL [code]#vec# with each element of the new SYCL [code]#vec# instance the result of an element-wise [code]#OP# logical operation between each element of [code]#lhs# [code]#vec# and the [code]#rhs# scalar. + +The [code]#dataT# template parameter of the constructed SYCL [code]#vec#, [code]#RET#, varies depending on the [code]#dataT# template parameter of this SYCL [code]#vec#. For a SYCL [code]#vec# with [code]#dataT# of type [code]#int8_t# or [code]#uint8_t# [code]#RET# must be [code]#int8_t#. For a SYCL [code]#vec# with [code]#dataT# of type [code]#int16_t#, [code]#uint16_t# or [code]#half# [code]#RET# must be [code]#int16_t#. For a SYCL [code]#vec# with [code]#dataT# of type [code]#int32_t#, [code]#uint32_t# or [code]#float# [code]#RET# must be [code]#int32_t#. For a SYCL [code]#vec# with [code]#dataT# of type [code]#int64_t#, [code]#uint64_t# or [code]#double# [code]#RET# must be [code]#uint64_t#. + +Where [code]#OP# is: [code]#&&#, [code]#||#. + +a@ +[source] +---- +vec operatorOP(const vec &lhs, const vec &rhs) +---- + a@ Available only when: [code]#dataT != float && dataT != double && dataT != half#. + +Construct a new instance of the SYCL [code]#vec# class template with the same template parameters as [code]#lhs# [code]#vec# with each element of the new SYCL [code]#vec# instance the result of an element-wise [code]#OP# bitshift operation between each element of [code]#lhs# [code]#vec# and each element of the [code]#rhs# SYCL [code]#vec#. If [code]#OP# is [code]#>>#, [code]#dataT# is a signed type and [code]#lhs# [code]#vec# has a negative value any vacated bits viewed as an unsigned integer must be assigned the value [code]#1#, otherwise any vacated bits viewed as an unsigned integer must be assigned the value [code]#0#. + +Where [code]#OP# is: [code]#<<#, [code]#>>#. + +a@ +[source] +---- +vec operatorOP(const vec &lhs, const dataT &rhs) +---- + a@ Available only when: [code]#dataT != float && dataT != double && dataT != half#. + +Construct a new instance of the SYCL [code]#vec# class template with the same template parameters as [code]#lhs# [code]#vec# with each element of the new SYCL [code]#vec# instance the result of an element-wise [code]#OP# bitshift operation between each element of [code]#lhs# [code]#vec# and the [code]#rhs# scalar. If [code]#OP# is [code]#>>#, [code]#dataT# is a signed type and [code]#lhs# [code]#vec# has a negative value any vacated bits viewed as an unsigned integer must be assigned the value [code]#1#, otherwise any vacated bits viewed as an unsigned integer must be assigned the value [code]#0#. + +Where [code]#OP# is: [code]#<<#, [code]#>>#. + +a@ +[source] +---- +vec &operatorOP(vec &lhs, const vec &rhs) +---- + a@ Available only when: [code]#dataT != float && dataT != double && dataT != half#. + +Perform an in-place element-wise [code]#OP# bitshift operation between each element of [code]#lhs# [code]#vec# and the [code]#rhs# SYCL [code]#vec# and returns [code]#lhs# [code]#vec#. If [code]#OP# is [code]#>>=#, [code]#dataT# is a signed type and [code]#lhs# [code]#vec# has a negative value any vacated bits viewed as an unsigned integer must be assigned the value [code]#1#, otherwise any vacated bits viewed as an unsigned integer must be assigned the value [code]#0#. + +Where [code]#OP# is: [code]#+<<=+#, [code]#>>=#. + +a@ +[source] +---- +vec &operatorOP(vec &lhs, const dataT &rhs) +---- + a@ Available only when: [code]#dataT != float && dataT != double && dataT != half#. + +Perform an in-place element-wise [code]#OP# bitshift operation between each element of [code]#lhs# [code]#vec# and the [code]#rhs# scalar and returns a reference to this SYCL [code]#vec#. If [code]#OP# is [code]#>>=#, [code]#dataT# is a signed type and [code]#lhs# [code]#vec# has a negative value any vacated bits viewed as an unsigned integer must be assigned the value [code]#1#, otherwise any vacated bits viewed as an unsigned integer must be assigned the value [code]#0#. + +Where [code]#OP# is: [code]#+<<=+#, [code]#>>=#. + +a@ +[source] +---- +vec operatorOP(const vec& lhs, const vec &rhs) +---- + a@ Construct a new instance of the SYCL [code]#vec# class template with the element type [code]#RET# with each element of the new SYCL [code]#vec# instance the result of an element-wise [code]#OP# relational operation between each element of [code]#lhs# [code]#vec# and each element of the [code]#rhs# SYCL [code]#vec#. Each element of the SYCL [code]#vec# that is returned must be [code]#-1# if the operation results in [code]#true# and [code]#0# if the operation results in [code]#false# or either this SYCL [code]#vec# or the [code]#rhs# SYCL [code]#vec# is a NaN. + +The [code]#dataT# template parameter of the constructed SYCL [code]#vec#, [code]#RET#, varies depending on the [code]#dataT# template parameter of this SYCL [code]#vec#. For a SYCL [code]#vec# with [code]#dataT# of type [code]#int8_t# or [code]#uint8_t# [code]#RET# must be [code]#int8_t#. For a SYCL [code]#vec# with [code]#dataT# of type [code]#int16_t#, [code]#uint16_t# or [code]#half# [code]#RET# must be [code]#int16_t#. For a SYCL [code]#vec# with [code]#dataT# of type [code]#int32_t#, [code]#uint32_t# or [code]#float# [code]#RET# must be [code]#int32_t#. For a SYCL [code]#vec# with [code]#dataT# of type [code]#int64_t#, [code]#uint64_t# or [code]#double# [code]#RET# must be [code]#uint64_t#. + +Where [code]#OP# is: [code]#==#, [code]#!=#, [code]#<#, [code]#>#, [code]#+<=+#, [code]#>=#. + +a@ +[source] +---- +vec operatorOP(const vec &lhs, const dataT &rhs) +---- + a@ Construct a new instance of the SYCL [code]#vec# class template with the [code]#dataT# parameter of [code]#RET# with each element of the new SYCL [code]#vec# instance the result of an element-wise [code]#OP# relational operation between each element of [code]#lhs# [code]#vec# and the [code]#rhs# scalar. Each element of the SYCL [code]#vec# that is returned must be [code]#-1# if the operation results in [code]#true# and [code]#0# if the operation results in [code]#false# or either [code]#lhs# [code]#vec# or the [code]#rhs# SYCL [code]#vec# is a NaN. + +The [code]#dataT# template parameter of the constructed SYCL [code]#vec#, [code]#RET#, varies depending on the [code]#dataT# template parameter of this SYCL [code]#vec#. For a SYCL [code]#vec# with [code]#dataT# of type [code]#int8_t# or [code]#uint8_t# [code]#RET# must be [code]#int8_t#. For a SYCL [code]#vec# with [code]#dataT# of type [code]#int16_t#, [code]#uint16_t# or [code]#half# [code]#RET# must be [code]#int16_t#. For a SYCL [code]#vec# with [code]#dataT# of type [code]#int32_t#, [code]#uint32_t# or [code]#float# [code]#RET# must be [code]#int32_t#. For a SYCL [code]#vec# with [code]#dataT# of type [code]#int64_t#, [code]#uint64_t# or [code]#double# [code]#RET# must be [code]#uint64_t#. + +Where [code]#OP# is: [code]#==#, [code]#!=#, [code]#<#, [code]#>#, [code]#+<=+#, [code]#>=#. + +a@ +[source] +---- +vec operatorOP(const dataT &lhs, const vec &rhs) +---- + a@ If [code]#OP# is [code]#%#, available only when: [code]#dataT != float && dataT != double && dataT != half#. + +Construct a new instance of the SYCL [code]#vec# class template with +the same template parameters as the [code]#rhs# SYCL [code]#vec# +with each element of the new SYCL [code]#vec# instance the result of +an element-wise [code]#OP# arithmetic operation between the +[code]#lhs# scalar and each element of the [code]#rhs# SYCL +[code]#vec#. + +Where [code]#OP# is: [code]#pass:[+]#, [code]#-#, [code]#*#, +[code]#/#, [code]#%#. + +a@ +[source] +---- +vec operatorOP(const dataT &lhs, const vec &rhs) +---- + a@ Available only when: [code]#dataT != float && dataT != double && dataT != half#. + +Construct a new instance of the SYCL [code]#vec# class template with +the same template parameters as the [code]#rhs# SYCL [code]#vec# +with each element of the new SYCL [code]#vec# instance the result of +an element-wise [code]#OP# bitwise operation between the [code]#lhs# scalar and each element of the [code]#rhs# SYCL [code]#vec#. + +Where [code]#OP# is: [code]#&#, [code]#|#, [code]#^#. + +a@ +[source] +---- +vec operatorOP(const dataT &lhs, const vec &rhs) +---- + a@ Available only when: [code]#dataT != float && dataT != double && dataT != half#. + +Construct a new instance of the SYCL [code]#vec# class template with +the same template parameters as the [code]#rhs# SYCL [code]#vec# +with each element of the new SYCL [code]#vec# instance the result of +an element-wise [code]#OP# logical operation between the [code]#lhs# scalar and each element of the [code]#rhs# SYCL [code]#vec#. + +The [code]#dataT# template parameter of the constructed SYCL [code]#vec#, [code]#RET#, varies depending on the [code]#dataT# template parameter of this SYCL [code]#vec#. For a SYCL [code]#vec# with [code]#dataT# of type [code]#int8_t# or [code]#uint8_t# [code]#RET# must be [code]#int8_t#. For a SYCL [code]#vec# with [code]#dataT# of type [code]#int16_t#, [code]#uint16_t# or [code]#half# [code]#RET# must be [code]#int16_t#. For a SYCL [code]#vec# with [code]#dataT# of type [code]#int32_t#, [code]#uint32_t# or [code]#float# [code]#RET# must be [code]#int32_t#. For a SYCL [code]#vec# with [code]#dataT# of type [code]#int64_t#, [code]#uint64_t# or [code]#double# [code]#RET# must be [code]#int64_t#. + +Where [code]#OP# is: [code]#&&#, [code]#||#. + +a@ +[source] +---- +vec operatorOP(const dataT &lhs, const vec &rhs) +---- + a@ Construct a new instance of the SYCL [code]#vec# class template with + the same template parameters as the [code]#rhs# SYCL [code]#vec# + with each element of the new SYCL [code]#vec# instance the result of + an element-wise [code]#OP# bitshift operation between the [code]#lhs# scalar and each element of the [code]#rhs# SYCL [code]#vec#. + If [code]#OP# is [code]#>>#, [code]#dataT# is a signed type + and this SYCL [code]#vec# has a negative value any vacated bits viewed + as an unsigned integer must be assigned the value [code]#1#, otherwise + any vacated bits viewed as an unsigned integer must be assigned the value + [code]#0#. + +Where [code]#OP# is: [code]#<<#, [code]#>>#. + +a@ +[source] +---- +vec operatorOP(const dataT &lhs, const vec &rhs) +---- + a@ Available only when: [code]#dataT != float && dataT != double && dataT != half#. + +Construct a new instance of the SYCL [code]#vec# class template with +the element type [code]#RET# with each element of the new SYCL +[code]#vec# instance the result of an element-wise [code]#OP# +relational operation between the [code]#lhs# scalar and each element +of the [code]#rhs# SYCL [code]#vec#. Each element of the SYCL +[code]#vec# that is returned must be [code]#-1# if the operation +results in [code]#true# and [code]#0# if the operation results +in [code]#false# or either this SYCL [code]#vec# or the +[code]#rhs# SYCL [code]#vec# is a NaN. + +The [code]#dataT# template parameter of the constructed SYCL +[code]#vec#, [code]#RET#, varies depending on the [code]#dataT# template parameter of this SYCL [code]#vec#. For a SYCL +[code]#vec# with [code]#dataT# of type [code]#int8_t# or +[code]#uint8_t# [code]#RET# must be [code]#int8_t#. For a +SYCL [code]#vec# with [code]#dataT# of type [code]#int16_t#, [code]#uint16_t# or [code]#half# [code]#RET# +must be [code]#int16_t#. For a SYCL [code]#vec# with +[code]#dataT# of type [code]#int32_t#, [code]#uint32_t# or +[code]#float# [code]#RET# must be [code]#int32_t#. For a +SYCL [code]#vec# with [code]#dataT# of type [code]#int64_t#, [code]#uint64_t# or [code]#double# [code]#RET# +must be [code]#int64_t#. + +Where [code]#OP# is: [code]#==#, [code]#!=#, [code]#<#, [code]#>#, [code]#+<=+#, [code]#>=#. + +a@ +[source] +---- +vec &operator~(const vec &v) +---- + a@ Available only when: [code]#dataT != float && dataT != double && dataT != half#. + +Construct a new instance of the SYCL [code]#vec# class template with the same template parameters as [code]#v# [code]#vec# with each element of the new SYCL [code]#vec# instance the result of an element-wise [code]#OP# bitwise operation on each element of [code]#v# [code]#vec#. + +a@ +[source] +---- +vec operator!(const vec &v) +---- + a@ Construct a new instance of the SYCL [code]#vec# class template with the same template parameters as [code]#v# [code]#vec# with each element of the new SYCL [code]#vec# instance the result of an element-wise [code]#OP# logical operation on each element of [code]#v# [code]#vec#. Each element of the SYCL [code]#vec# that is returned must be [code]#-1# if the operation results in [code]#true# and [code]#0# if the operation results in [code]#false# or this SYCL [code]#vec# is a NaN. + +The [code]#dataT# template parameter of the constructed SYCL [code]#vec#, [code]#RET#, varies depending on the [code]#dataT# template parameter of this SYCL [code]#vec#. For a SYCL [code]#vec# with [code]#dataT# of type [code]#int8_t# or [code]#uint8_t# [code]#RET# must be [code]#int8_t#. For a SYCL [code]#vec# with [code]#dataT# of type [code]#int16_t#, [code]#uint16_t# or [code]#half# [code]#RET# must be [code]#int16_t#. For a SYCL [code]#vec# with [code]#dataT# of type [code]#int32_t#, [code]#uint32_t# or [code]#float# [code]#RET# must be [code]#int32_t#. For a SYCL [code]#vec# with [code]#dataT# of type [code]#int64_t#, [code]#uint64_t# or [code]#double# [code]#RET# must be [code]#int64_t#. + +|==== + + +==== Aliases + +The SYCL programming API provides all permutations of the type alias: + +[code]#+using = vec<, >+# + +where [code]## is [code]#2#, [code]#3#, [code]#4#, +[code]#8# and [code]#16#, and pairings of [code]## and +[code]## for integral types are [code]#char# and +[code]#int8_t#, [code]#uchar# and [code]#uint8_t#, +[code]#short# and [code]#int16_t#, [code]#ushort# and +[code]#uint16_t#, [code]#int# and [code]#int32_t#, +[code]#uint# and [code]#uint32_t#, [code]#long# and +[code]#int64_t#, [code]#ulong# and [code]#uint64_t#, and for +floating point types are both [code]#half#, [code]#float# and +[code]#double#. + +For example [code]#uint4# is the alias to [code]#vec# +and [code]#float16# is the alias to [code]#vec#. + +==== Swizzles + +Swizzle operations can be performed in two ways. Firstly by calling the +[code]#swizzle# member function template, which takes a variadic number +of integer template arguments between [code]#0# and +[code]#numElements-1#, specifying swizzle indexes. Secondly by calling +one of the simple swizzle member functions defined in +<> as [code]#XYZW_SWIZZLE# and +[code]#RGBA_SWIZZLE#. Note that the simple swizzle functions are only +available for up to 4 element vectors and are only available when the macro +[code]#SYCL_SIMPLE_SWIZZLES# is defined before including +[code]##. + +In both cases the return type is always an instance of +[code]#+__swizzled_vec__+#, an implementation-defined temporary class +representing a swizzle of the original SYCL [code]#vec# instance. Both +kinds of swizzle member functions must not perform the swizzle operation +themselves, instead the swizzle operation must be performed by the returned +instance of [code]#+__swizzled_vec__+# when used within an expression, +meaning if the returned [code]#+__swizzled_vec__+# is never used in an +expression no swizzle operation is performed. + +Both the [code]#swizzle# member function template and the simple +swizzle member functions allow swizzle indexes to be repeated. + +A series of static constexpr values are provided within the +[code]#elem# struct to allow specifying named swizzle indexes when +calling the [code]#swizzle# member function template. + + +[[swizzled-vec-class]] +==== Swizzled [code]#vec# class + +The [code]#+__swizzled_vec__+# class must define an unspecified +temporary which provides the entire interface of the SYCL [code]#vec# +class template, including swizzled member functions, with the additions and +alterations described below: + + * The [code]#+__swizzled_vec__+# class template must be readable as an + r-value reference on the RHS of an expression. In this case the swizzle + operation is performed on the RHS of the expression and then the result + is applied to the LHS of the expression. + * The [code]#+__swizzled_vec__+# class template must be assignable as + an l-value reference on the LHS of an expression. In this case the RHS + of the expression is applied to the original SYCL [code]#vec# which + the [code]#+__swizzled_vec__+# represents via the swizzle operation. + Note that a [code]#+__swizzled_vec__+# that is used in an l-value + expression may not contain any repeated element indexes. ++ +For example: [code]#f4.xxxx() = fx.wzyx()# would not be valid. + * The [code]#+__swizzled_vec__+# class template must be convertible to + an instance of SYCL [code]#vec# with the type [code]#dataT# + and number of elements specified by the swizzle member function, if + [code]#numElements > 1#, and must be convertible to an instance of + type [code]#dataT#, if [code]#numElements == 1#. + * The [code]#+__swizzled_vec__+# class template must be non-copyable, + non-moveable, non-user constructible and may not be bound to a l-value + or escape the expression it was constructed in. For example + [code]#auto x = f4.x()# would not be valid. + * The [code]#+__swizzled_vec__+# class template should return + [code]#+__swizzled_vec__ &+# for each operator inherited from the + [code]#vec# class template interface which would return + [code]#vec &#. + + +==== Rounding modes + +The various rounding modes that can be used in the [code]#as# member +function template are described in <>. + + +[[table.vec.roundingmodes]] +.Rounding modes for the SYCL [code]#vec# class template +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Rounding mode @ Description +a@ +[source] +---- +automatic +---- + a@ Default rounding mode for the SYCL [code]#vec# class element type. [code]#rtz# (round toward zero) for integer types and [code]#rte# (round to nearest even) for floating-point types. + +a@ +[source] +---- +rte +---- + a@ Round to nearest even. + +a@ +[source] +---- +rtz +---- + a@ Round toward zero. + +a@ +[source] +---- +rtp +---- + a@ Round toward positive infinity. + +a@ +[source] +---- +rtn +---- + a@ Round toward negative infinity. + +|==== + + + +[[memory-layout-and-alignment]] +==== Memory layout and alignment + +The elements of an instance of the SYCL [code]#vec# class template are +stored in memory sequentially and contiguously and are aligned to the size +of the element type in bytes multiplied by the number of elements: + +[[vec-memory-alignment]] +[latexmath] +++++ +\texttt{sizeof}(\texttt{dataT}) \cdot \texttt{numElements} +++++ + +The exception to this is when the number of element is three in which case +the SYCL [code]#vec# is aligned to the size of the element type in +bytes multiplied by four: + +[[vec3-memory-alignment]] +[latexmath] +++++ +\texttt{sizeof}(\texttt{dataT}) \cdot 4 +++++ + +This is true for both host and device code in order to allow for instances +of the [code]#vec# class template to be passed to SYCL kernel +functions. + + +==== Performance note + +The usage of the subscript [code]#operator[]# may not be efficient on some devices. + +// %%%%%%%%%%%%%%%%%%%%%%%%%%%% end vec_class %%%%%%%%%%%%%%%%%%%%%%%%%%%% + +// \input{marray_class} + +// %%%%%%%%%%%%%%%%%%%%%%%%%%%% begin marray_class %%%%%%%%%%%%%%%%%%%%%%%%%%%% + +[[sec:marray.type]] +=== Math array types + +SYCL provides an [code]#marray# class +template to represent a contiguous fixed-size container. This type allows +sharing of containers between the host and its SYCL devices. + +The [code]#marray# class is templated on its element type and number of +elements. The number of elements parameter, [code]#numElements#, is a positive +value of the [code]#std::size_t# type. The element type parameter, [code]#dataT#, +must be a _numeric type_ as it is defined by {cpp} standard. + +An instance of the [code]#marray# class template can also be +implicitly converted to an instance of the data type when the number of +elements is [code]#1# in order to allow single element arrays and +scalars to be convertible with each other. + +Logical and comparison operators for [code]#marray# class template +return [code]#marray#. + + +==== Math array interface + +The constructors, member functions and non-member functions of the SYCL +[code]#marray# class template are listed in +<>, <> and +<> respectively. + +// Interface for class: vec +[source,,linenums] +---- +include::{header_dir}/marray.h[lines=4..-1] +---- + + +[[table.constructors.marray]] +.Constructors of the SYCL [code]#marray# class template +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Constructor @ Description +a@ +[source] +---- +marray() +---- + a@ Default construct an array with element type [code]#dataT# and + with [code]#numElements# dimensions by default construction of + each of its elements. + +a@ +[source] +---- +explicit marray(const dataT &arg) +---- + a@ Construct an array of element type [code]#dataT# and + [code]#numElements# dimensions by setting each value to [code]#arg# by + assignment. + +a@ +[source] +---- +template + marray(const argTN&... args) +---- + a@ Construct a SYCL [code]#marray# instance from any combination of scalar and SYCL [code]#marray# parameters of the same element type, providing the total number of elements for all parameters sum to [code]#numElements# of this [code]#marray# specialization. + +a@ +[source] +---- +marray(const marray &rhs) +---- + a@ Construct an array of element type [code]#dataT# and number of elements [code]#numElements# by copy from another similar vector. + +|==== + + + +[[table.members.marray]] +.Member functions for the SYCL [code]#marray# class template +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +operator dataT() const +---- + a@ Available only when: [code]#numElements == 1#. + +Converts this SYCL [code]#marray# instance to an instance of [code]#dataT# with +the value of the single element in this SYCL [code]#marray# instance. + +The SYCL [code]#marray# instance shall be implicitly convertible to the same data types, +to which [code]#dataT# is implicitly convertible. +Note that conversion operator shall not be templated +to allow standard conversion sequence for implicit conversion. + +a@ +[source] +---- +static constexpr std::size_t size() noexcept +---- + a@ Returns the size of this SYCL [code]#marray# in bytes. + +a@ +[source] +---- +dataT &operator[](std::size_t index) +---- + a@ Returns a reference to the element stored within this SYCL [code]#marray# at the index specified by [code]#index#. + +a@ +[source] +---- +const dataT &operator[](std::size_t index) const +---- + a@ Returns a const reference to the element stored within this SYCL [code]#marray# at the index specified by [code]#index#. + +a@ +[source] +---- +marray &operator=(const marray &rhs) +---- + a@ Assign each element of the [code]#rhs# SYCL [code]#marray# to each element of this SYCL [code]#marray# and return a reference to this SYCL [code]#marray#. + +a@ +[source] +---- +marray &operator=(const dataT &rhs) +---- + a@ Assign each element of the [code]#rhs# scalar to each element of this SYCL [code]#marray# and return a reference to this SYCL [code]#marray#. + +a@ +[source] +---- +iterator begin() +---- + a@ Returns an iterator referring to the first element stored within the [code]#v# [code]#marray#. + +a@ +[source] +---- +const_iterator begin() const +---- + a@ Returns a const iterator referring to the first element stored within the [code]#v# [code]#marray#. + +a@ +[source] +---- +iterator end() +---- + a@ Returns an iterator referring to the one past the last element stored within the [code]#v# [code]#marray#. + +a@ +[source] +---- +const_iterator end() const +---- + a@ Returns a const iterator referring to the one past the last + element stored within the [code]#v# [code]#marray#. + +|==== + + + +[[table.functions.marray]] +.Hidden friend functions of the [code]#marray# class template +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Hidden friend function @ Description +a@ +[source] +---- +marray operatorOP(const marray &lhs, const marray &rhs) +---- + a@ If [code]#OP# is [code]#%#, available only when: [code]#dataT != float && dataT != double && dataT != half#. + +Construct a new instance of the SYCL [code]#marray# class template with the same template parameters as [code]#lhs# [code]#marray# with each element of the new SYCL [code]#marray# instance the result of an element-wise [code]#OP# arithmetic operation between each element of [code]#lhs# [code]#marray# and each element of the [code]#rhs# SYCL [code]#marray#. + +Where [code]#OP# is: [code]#pass:[+]#, [code]#-#, [code]#*#, [code]#/#, [code]#%#. + +a@ +[source] +---- +marray operatorOP(const marray &lhs, const dataT &rhs) +---- + a@ If [code]#OP# is [code]#%#, available only when: [code]#dataT != float && dataT != double && dataT != half#. + +Construct a new instance of the SYCL [code]#marray# class template with the same template parameters as [code]#lhs# [code]#marray# with each element of the new SYCL [code]#marray# instance the result of an element-wise [code]#OP# arithmetic operation between each element of [code]#lhs# [code]#marray# and the [code]#rhs# scalar. + +Where [code]#OP# is: [code]#pass:[+]#, [code]#-#, [code]#*#, [code]#/#, [code]#%#. + +a@ +[source] +---- +marray &operatorOP(marray &lhs, const marray &rhs) +---- + a@ If [code]#OP# is [code]#%=#, available only when: [code]#dataT != float && dataT != double && dataT != half#. + +Perform an in-place element-wise [code]#OP# arithmetic operation between each element of [code]#lhs# [code]#marray# and each element of the [code]#rhs# SYCL [code]#marray# and return [code]#lhs# [code]#marray#. + +Where [code]#OP# is: [code]#pass:[+=]#, [code]#-=#, [code]#*=#, [code]#/=#, [code]#%=#. + +a@ +[source] +---- +marray &operatorOP(marray &lhs, const dataT &rhs) +---- + a@ If [code]#OP# is [code]#%=#, available only when: [code]#dataT != float && dataT != double && dataT != half#. + +Perform an in-place element-wise [code]#OP# arithmetic operation between each element of [code]#lhs# [code]#marray# and [code]#rhs# scalar and return [code]#lhs# [code]#marray#. + +Where [code]#OP# is: [code]#pass:[+=]#, [code]#-=#, [code]#*=#, [code]#/=#, [code]#%=#. + +a@ +[source] +---- +marray &operatorOP(marray &v) +---- + a@ Perform an in-place element-wise [code]#OP# prefix arithmetic operation on each element of [code]#lhs# [code]#marray#, assigning the result of each element to the corresponding element of [code]#lhs# [code]#marray# and return [code]#lhs# [code]#marray#. + +Where [code]#OP# is: [code]#pass:[++]#, [code]#--#. + +a@ +[source] +---- +marray operatorOP(marray &v, int) +---- + a@ Perform an in-place element-wise [code]#OP# postfix arithmetic operation on each element of [code]#lhs# [code]#marray#, assigning the result of each element to the corresponding element of [code]#lhs# [code]#marray# and returns a copy of [code]#lhs# [code]#marray# before the operation is performed. + +Where [code]#OP# is: [code]#pass:[++]#, [code]#--#. + +a@ +[source] +---- +marray operatorOP(marray &v) +---- + a@ Construct a new instance of the SYCL [code]#marray# class template with the same template parameters as this SYCL [code]#marray# with each element of the new SYCL [code]#marray# instance the result of an element-wise [code]#OP# unary arithmetic operation on each element of this SYCL [code]#marray#. + +Where [code]#OP# is: [code]#pass:[+]#, [code]#-#. + +a@ +[source] +---- +marray operatorOP(const marray &lhs, const marray &rhs) +---- + a@ Available only when: [code]#dataT != float && dataT != double && dataT != half#. + +Construct a new instance of the SYCL [code]#marray# class template with the same template parameters as [code]#lhs# [code]#marray# with each element of the new SYCL [code]#marray# instance the result of an element-wise [code]#OP# bitwise operation between each element of [code]#lhs# [code]#marray# and each element of the [code]#rhs# SYCL [code]#marray#. + +Where [code]#OP# is: [code]#&#, [code]#|#, [code]#^#. + +a@ +[source] +---- +marray operatorOP(const marray &lhs, const dataT &rhs) +---- + a@ Available only when: [code]#dataT != float && dataT != double && dataT != half#. + +Construct a new instance of the SYCL [code]#marray# class template with the same template parameters as [code]#lhs# [code]#marray# with each element of the new SYCL [code]#marray# instance the result of an element-wise [code]#OP# bitwise operation between each element of [code]#lhs# [code]#marray# and the [code]#rhs# scalar. + +Where [code]#OP# is: [code]#&#, [code]#|#, [code]#^#. + +a@ +[source] +---- +marray &operatorOP(marray &lhs, const marray &rhs) +---- + a@ Available only when: [code]#dataT != float && dataT != double && dataT != half#. + +Perform an in-place element-wise [code]#OP# bitwise operation between each element of [code]#lhs# [code]#marray# and the [code]#rhs# SYCL [code]#marray# and return [code]#lhs# [code]#marray#. + +Where [code]#OP# is: [code]#&=#, [code]#|=#, [code]#^=#. + +a@ +[source] +---- +marray &operatorOP(marray &lhs, const dataT &rhs) +---- + a@ Available only when: [code]#dataT != float && dataT != double && dataT != half#. + +Perform an in-place element-wise [code]#OP# bitwise operation between each element of [code]#lhs# [code]#marray# and the [code]#rhs# scalar and return a [code]#lhs# [code]#marray#. + +Where [code]#OP# is: [code]#&=#, [code]#|=#, [code]#^=#. + +a@ +[source] +---- +marray operatorOP(const marray &lhs, const marray &rhs) +---- + a@ Construct a new instance of the [code]#marray# class template with [code]#dataT = bool# and same numElements as [code]#lhs# [code]#marray# with each element of the new [code]#marray# instance the result of an element-wise [code]#OP# logical operation between each element of [code]#lhs# [code]#marray# and each element of the [code]#rhs# [code]#marray#. + +Where [code]#OP# is: [code]#&&#, [code]#||#. + +a@ +[source] +---- +marray operatorOP(const marray &lhs, const dataT &rhs) +---- + a@ Construct a new instance of the [code]#marray# class template with [code]#dataT = bool# and same numElements as [code]#lhs# [code]#marray# with each element of the new [code]#marray# instance the result of an element-wise [code]#OP# logical operation between each element of [code]#lhs# [code]#marray# and the [code]#rhs# scalar. + +Where [code]#OP# is: [code]#&&#, [code]#||#. + +a@ +[source] +---- +marray operatorOP(const marray &lhs, const marray &rhs) +---- + a@ Available only when: [code]#dataT != float && dataT != double && dataT != half#. + +Construct a new instance of the SYCL [code]#marray# class template with the same template parameters as [code]#lhs# [code]#marray# with each element of the new SYCL [code]#marray# instance the result of an element-wise [code]#OP# bitshift operation between each element of [code]#lhs# [code]#marray# and each element of the [code]#rhs# SYCL [code]#marray#. If [code]#OP# is [code]#>>#, [code]#dataT# is a signed type and [code]#lhs# [code]#marray# has a negative value any vacated bits viewed as an unsigned integer must be assigned the value [code]#1#, otherwise any vacated bits viewed as an unsigned integer must be assigned the value [code]#0#. + +Where [code]#OP# is: [code]#<<#, [code]#>>#. + +a@ +[source] +---- +marray operatorOP(const marray &lhs, const dataT &rhs) +---- + a@ Available only when: [code]#dataT != float && dataT != double && dataT != half#. + +Construct a new instance of the SYCL [code]#marray# class template with the same template parameters as [code]#lhs# [code]#marray# with each element of the new SYCL [code]#marray# instance the result of an element-wise [code]#OP# bitshift operation between each element of [code]#lhs# [code]#marray# and the [code]#rhs# scalar. If [code]#OP# is [code]#>>#, [code]#dataT# is a signed type and [code]#lhs# [code]#marray# has a negative value any vacated bits viewed as an unsigned integer must be assigned the value [code]#1#, otherwise any vacated bits viewed as an unsigned integer must be assigned the value [code]#0#. + +Where [code]#OP# is: [code]#<<#, [code]#>>#. + +a@ +[source] +---- +marray &operatorOP(marray &lhs, const marray &rhs) +---- + a@ Available only when: [code]#dataT != float && dataT != double && dataT != half#. + +Perform an in-place element-wise [code]#OP# bitshift operation between each element of [code]#lhs# [code]#marray# and the [code]#rhs# SYCL [code]#marray# and returns [code]#lhs# [code]#marray#. If [code]#OP# is [code]#>>=#, [code]#dataT# is a signed type and [code]#lhs# [code]#marray# has a negative value any vacated bits viewed as an unsigned integer must be assigned the value [code]#1#, otherwise any vacated bits viewed as an unsigned integer must be assigned the value [code]#0#. + +Where [code]#OP# is: [code]#+<<=+#, [code]#>>=#. + +a@ +[source] +---- +marray &operatorOP(marray &lhs, const dataT &rhs) +---- + a@ Available only when: [code]#dataT != float && dataT != double && dataT != half#. + +Perform an in-place element-wise [code]#OP# bitshift operation between each element of [code]#lhs# [code]#marray# and the [code]#rhs# scalar and returns a reference to this SYCL [code]#marray#. If [code]#OP# is [code]#>>=#, [code]#dataT# is a signed type and [code]#lhs# [code]#marray# has a negative value any vacated bits viewed as an unsigned integer must be assigned the value [code]#1#, otherwise any vacated bits viewed as an unsigned integer must be assigned the value [code]#0#. + +Where [code]#OP# is: [code]#+<<=+#, [code]#>>=#. + +a@ +[source] +---- +marray operatorOP(const marray& lhs, const marray &rhs) +---- + a@ Construct a new instance of the [code]#marray# class template with [code]#dataT = bool# and same numElements as [code]#lhs# [code]#marray# + with each element of the new [code]#marray# instance the result of an element-wise [code]#OP# relational operation between each element of [code]#lhs# [code]#marray# + and each element of the [code]#rhs# [code]#marray#. + Corresponding element of the [code]#marray# that is returned must be [code]#false# if the operation results is a NaN. + +Where [code]#OP# is: [code]#==#, [code]#!=#, [code]#<#, [code]#>#, [code]#+<=+#, [code]#>=#. + +a@ +[source] +---- +marray operatorOP(const marray &lhs, const dataT &rhs) +---- + a@ Construct a new instance of the [code]#marray# class template with [code]#dataT = bool# and same numElements as [code]#lhs# [code]#marray# + with each element of the new [code]#marray# instance the result of an element-wise [code]#OP# relational operation between each element of [code]#lhs# [code]#marray# + and the [code]#rhs# scalar. + Corresponding element of the [code]#marray# that is returned must be [code]#false# if the operation results is a NaN. + +Where [code]#OP# is: [code]#==#, [code]#!=#, [code]#<#, [code]#>#, [code]#+<=+#, [code]#>=#. + +a@ +[source] +---- +marray operatorOP(const dataT &lhs, const marray &rhs) +---- + a@ If [code]#OP# is [code]#%#, available only when: [code]#dataT != float && dataT != double && dataT != half#. + +Construct a new instance of the SYCL [code]#marray# class template with +the same template parameters as the [code]#rhs# SYCL [code]#marray# +with each element of the new SYCL [code]#marray# instance the result of +an element-wise [code]#OP# arithmetic operation between the +[code]#lhs# scalar and each element of the [code]#rhs# SYCL +[code]#marray#. + +Where [code]#OP# is: [code]#pass:[+]#, [code]#-#, [code]#*#, +[code]#/#, [code]#%#. + +a@ +[source] +---- +marray operatorOP(const dataT &lhs, const marray &rhs) +---- + a@ Available only when: [code]#dataT != float && dataT != double && dataT != half#. + +Construct a new instance of the SYCL [code]#marray# class template with +the same template parameters as the [code]#rhs# SYCL [code]#marray# +with each element of the new SYCL [code]#marray# instance the result of +an element-wise [code]#OP# bitwise operation between the [code]#lhs# scalar and each element of the [code]#rhs# SYCL [code]#marray#. + +Where [code]#OP# is: [code]#&#, [code]#|#, [code]#^#. + +a@ +[source] +---- +marray operatorOP(const dataT &lhs, const marray &rhs) +---- + a@ Available only when: [code]#dataT != float && dataT != double && dataT != half#. + +Construct a new instance of the [code]#marray# class template with [code]#dataT = bool# and +same numElements as [code]#lhs# [code]#marray# with each element of the new [code]#marray# instance +the result of an element-wise [code]#OP# logical operation between the [code]#lhs# +scalar and each element of the [code]#rhs# [code]#marray#. + +Where [code]#OP# is: [code]#&&#, [code]#||#. + +a@ +[source] +---- +marray operatorOP(const dataT &lhs, const marray &rhs) +---- + a@ Construct a new instance of the SYCL [code]#marray# class template with + the same template parameters as the [code]#rhs# SYCL [code]#marray# + with each element of the new SYCL [code]#marray# instance the result of + an element-wise [code]#OP# bitshift operation between the [code]#lhs# scalar and each element of the [code]#rhs# SYCL [code]#marray#. + If [code]#OP# is [code]#>>#, [code]#dataT# is a signed type + and this SYCL [code]#marray# has a negative value any vacated bits viewed + as an unsigned integer must be assigned the value [code]#1#, otherwise + any vacated bits viewed as an unsigned integer must be assigned the value + [code]#0#. + +Where [code]#OP# is: [code]#<<#, [code]#>>#. + +a@ +[source] +---- +marray operatorOP(const dataT &lhs, const marray &rhs) +---- + a@ Available only when: [code]#dataT != float && dataT != double && dataT != half#. + +Construct a new instance of the [code]#marray# class template with [code]#dataT = bool# and same numElements as [code]#lhs# [code]#marray# +with each element of the new SYCL [code]#marray# instance the result of an element-wise [code]#OP# +relational operation between the [code]#lhs# scalar and each element of the [code]#rhs# [code]#marray#. +Corresponding element of the [code]#marray# that is returned must be [code]#false# if the operation results is a NaN. + +Where [code]#OP# is: [code]#==#, [code]#!=#, [code]#<#, [code]#>#, [code]#+<=+#, [code]#>=#. + +a@ +[source] +---- +marray &operator~(const marray &v) +---- + a@ Available only when: [code]#dataT != float && dataT != double && dataT != half#. + +Construct a new instance of the SYCL [code]#marray# class template with the same template parameters as [code]#v# [code]#marray# with each element of the new SYCL [code]#marray# instance the result of an element-wise [code]#OP# bitwise operation on each element of [code]#v# [code]#marray#. + +a@ +[source] +---- +marray operator!(const marray &v) +---- + a@ Construct a new instance of the [code]#marray# class template with [code]#dataT = bool# and same numElements as [code]#v# [code]#marray# + with each element of the new [code]#marray# instance the result of an element-wise logical [code]#!# operation on each element of [code]#v# [code]#marray#. + +The [code]#dataT# template parameter of the constructed SYCL [code]#marray#, [code]#RET#, varies depending on the [code]#dataT# template parameter of this SYCL [code]#marray#. For a SYCL [code]#marray# with [code]#dataT# of type [code]#int8_t# or [code]#uint8_t# [code]#RET# must be [code]#int8_t#. For a SYCL [code]#marray# with [code]#dataT# of type [code]#int16_t#, [code]#uint16_t# or [code]#half# [code]#RET# must be [code]#int16_t#. For a SYCL [code]#marray# with [code]#dataT# of type [code]#int32_t#, [code]#uint32_t# or [code]#float# [code]#RET# must be [code]#int32_t#. For a SYCL [code]#marray# with [code]#dataT# of type [code]#int64_t#, [code]#uint64_t# or [code]#double# [code]#RET# must be [code]#int64_t#. + +|==== + + + +==== Aliases + +The SYCL programming API provides all permutations of the type alias: + +[code]#+using m = marray<, >+# + +where [code]## is [code]#2#, [code]#3#, [code]#4#, +[code]#8# and [code]#16#, and pairings of [code]## and +[code]## for integral types are [code]#char# and +[code]#int8_t#, [code]#uchar# and [code]#uint8_t#, +[code]#short# and [code]#int16_t#, [code]#ushort# and +[code]#uint16_t#, [code]#int# and [code]#int32_t#, +[code]#uint# and [code]#uint32_t#, [code]#long# and +[code]#int64_t#, [code]#ulong# and [code]#uint64_t#, for +floating point types are both [code]#half#, [code]#float# and +[code]#double#, and for boolean type [code]#bool#. + +For example [code]#muint4# is the alias to [code]#marray# +and [code]#mfloat16# is the alias to [code]#marray#. + + +[[memory-layout-and-alignment.marray]] +==== Memory layout and alignment + +The elements of an instance of the [code]#marray# class template as if +stored in [code]#std::array#. + +// %%%%%%%%%%%%%%%%%%%%%%%%%%%% end marray_class %%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +== Synchronization and atomics + +The available features are: + + * Accessor classes: Accessor classes specify acquisition and release of + buffer and image data structures to provide points at which underlying + queue synchronization primitives must be generated. + * Atomic operations: SYCL devices support a restricted subset of {cpp} + atomics and SYCL uses the library syntax from the next {cpp} specification + to make this available. + * Fences: Fence primitives are made available to order loads and stores. + They are exposed through the [code]#atomic_fence# function. Fences + can have acquire semantics, release semantics or both. + * Barriers: Barrier primitives are made available to synchronize sets of + work-items within individual <>. They are exposed through the + [code]#group_barrier# function. + * Hierarchical parallel dispatch: In the hierarchical parallelism model of + describing computations, synchronization within the work-group is made + explicit through multiple instances of the + [code]#parallel_for_work_item# function call, rather than through + the use of explicit <> operations. + * Device event: they are used inside SYCL kernel functions to wait for + asynchronous operations within a SYCL kernel function to complete. + + +[[sec:barriers-fences]] +=== Barriers and fences + +A <> or <> provides memory ordering semantics +over both the local address space and global address space. A +<> provides control over the re-ordering of memory load and +store operations, subject to the associated memory [code]#order# and memory +[code]#scope#, when paired with synchronization through an atomic object. + +[source,,linenums] +---- +include::{header_dir}/synchronization.h[lines=4..-1] +---- + +The effects of a call to [code]#atomic_fence# depend on the value of +the [code]#order# parameter: + + * [code]#memory_order::relaxed:# No effect + * [code]#memory_order::acquire:# Acquire fence + * [code]#memory_order::release:# Release fence + * [code]#memory_order::acq_rel:# Both an acquire fence and a release + fence + * [code]#memory_order::seq_cst:# A sequentially consistent acquire + and release fence + +A <> acts as both an acquire fence and a release fence: all +work-items in the group execute a release fence prior to synchronizing at +the barrier, and all work-items in the group execute an acquire fence +afterwards. A <> provides implicit atomic synchronization +as if through an internal atomic object, such that the acquire and release fences +associated with the barrier synchronize with each other, without an explicit +atomic operation being required on an atomic object to synchronize the fences. + + +[[device-event-class]] +=== [code]#device_event# class + +The SYCL [code]#device_event# class encapsulates a single SYCL device event +which is available only within SYCL kernel functions and can be used to wait for +asynchronous operations within a SYCL kernel function to complete. + +All member functions of the [code]#device_event# class must not throw a +SYCL exception. + +A synopsis of the SYCL [code]#device_event# class is provided below. The +constructors and member functions of the SYCL [code]#device_event# class +are listed in <> and +<> respectively. + +// Interface of device event class +[source,,linenums] +---- +include::{header_dir}/deviceEvent.h[lines=4..-1] +---- + +[[table.members.device-event]] +.Member functions of the SYCL [code]#device_event# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +void wait() noexcept +---- + a@ Waits for the asynchronous operation associated with this SYCL + [code]#device_event# to complete. + +|==== + +[[table.constructors.device-event]] +.Constructors of the [code]#device_event# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Constructor @ Description +a@ +[source] +---- +device_event(___unspecified___) +---- + a@ Unspecified implementation-defined constructor. + +|==== + + +[[sec:atomic-references]] +=== Atomic references + +The SYCL specification provides atomic operations based on the library +syntax from the next {cpp} specification. The set of supported orderings is +specific to a device, but every device is guaranteed to support at least +[code]#memory_order::relaxed#. Since different devices have different +capabilities, there is no default ordering in SYCL and the default order +used by each instance of [code]#sycl::atomic_ref# is set by a template +argument. If the default order is set to [code]#memory_order::relaxed#, +all memory order arguments default to [code]#memory_order::relaxed#. If +the default order is set to [code]#memory_order::acq_rel#, memory order +arguments default to [code]#memory_order::acquire# for load operations, +[code]#memory_order::release# for store operations and +[code]#memory_order::acq_rel# for read-modify-write operations. If the +default order is set to [code]#memory_order::seq_cst#, all memory order +arguments default to [code]#memory_order::seq_cst#. + +The SYCL atomic library may map directly to the underlying {cpp} library in +<> code, and must interact safely with the host {cpp} +atomic library when used in host code. The SYCL library must be used in +device code to ensure that only the limited subset of functionality is +available. SYCL device compilers should give a compilation error on use of +the [code]#std::atomic# and [code]#std::atomic_ref# classes and +functions in device code. + +The template parameter [code]#Space# is permitted to be +[code]#access::address_space::generic_space#, +[code]#access::address_space::global_space# or [code]#access::address_space::local_space#. + +The data type [code]#T# is permitted to be [code]#int#, [code]#unsigned int#, [code]#long#, +[code]#unsigned long#, +[code]#long long#, +[code]#unsigned long long#, [code]#float# or +[code]#double#. For floating-point types, the member functions of the +[code]#atomic_ref# class may be emulated, and may use a different +floating-point environment to those defined by +[code]#info::device::single_fp_config# and +[code]#info::device::double_fp_config# (i.e. floating-point atomics may +use different rounding modes and may have different exception behavior). + +The atomic types are defined as follows. + +[source,,linenums] +---- +include::{header_dir}/atomicref.h[lines=4..-1] +---- + +The constructors and member functions for instances of the SYCL +[code]#atomic_ref# class using any compatible type are listed in +<> +and <> respectively. Additional member +functions for integral, floating-point and pointer types are listed in +<>, +<> +and <> respectively. + +The static member [code]#required_alignment# describes the minimum +required alignment in bytes of an object that can be referenced by an +[code]#atomic_ref#, which must be at least [code]#alignof(T)#. + +The static member [code]#is_always_lock_free# is true if all atomic +operations for type [code]#T# are always lock-free. A SYCL +implementation is not guaranteed to support atomic operations that are not +lock-free. + +The static members [code]#default_read_order#, [code]#default_write_order# and +[code]#default_read_modify_write_order# reflect the default memory order values for +each type of atomic operation, consistent with the [code]#DefaultOrder# template. + +The atomic operations and member functions behave as described in the {cpp} +specification, barring the restrictions discussed above. Note that care +must be taken when using atomics to implement synchronization routines due +to the lack of forward progress guarantees between work-items in SYCL. No +work-item may be dependent on another work-item to make progress if the code +is to be portable. + + +[[table.atomic-refs.constructors]] +.Constructors of the SYCL [code]#atomic_ref# class template +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Constructor @ Description +a@ +[source] +---- +atomic_ref(T& ref) +---- + a@ Constructs an instance of SYCL [code]#atomic_ref# which is associated + with the reference [code]#ref#. + +|==== + + + +[[table.atomic-refs.members.common]] +.Member functions available on any object of type [code]#atomic_ref# +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +bool is_lock_free() const +---- + a@ Return [code]#true# if the atomic operations provided by this + [code]#atomic_ref# are lock-free. + +a@ +[source] +---- +void store(T operand, + memory_order order = default_write_order, + memory_scope scope = default_scope) const +---- + a@ Atomically stores [code]#operand# to the object referenced by + this [code]#atomic_ref#. The memory order of this atomic operation + must be [code]#memory_order::relaxed#, + [code]#memory_order::release# or [code]#memory_order::seq_cst#. + This function is only supported for 64-bit data types on devices that have + [code]#aspect::atomic64#. + +a@ +[source] +---- +T operator=(T desired) const +---- + a@ Equivalent to [code]#store(desired)#. Returns [code]#desired#. + +a@ +[source] +---- +T load( + memory_order order = default_read_order + memory_scope scope = default_scope) const +---- + a@ Atomically loads the value of the object referenced by this + [code]#atomic_ref#. The memory order of this atomic operation must be + [code]#memory_order::relaxed#, [code]#memory_order::acquire#, + or [code]#memory_order::seq_cst#. This function is only supported for + 64-bit data types on devices that have [code]#aspect::atomic64#. + +a@ +[source] +---- +operator T() const +---- + a@ Equivalent to [code]#load()#. + +a@ +[source] +---- +T exchange(T operand, + memory_order order = default_read_modify_write_order, + memory_scope scope = default_scope) const +---- + a@ Atomically replaces the value of the object referenced by this + [code]#atomic_ref# with value [code]#operand# and + returns the original value of the referenced object. + This function is only supported for 64-bit data types on devices that have + [code]#aspect::atomic64#. + +a@ +[source] +---- +bool compare_exchange_weak(T &expected, T desired, + memory_order success, + memory_order failure, + memory_scope scope = default_scope) const +---- + a@ Atomically compares the value of the object referenced by this [code]#atomic_ref# + against the value of [code]#expected#. If the values are + equal, attempts to + replace the value of the referenced object with the value of + [code]#desired#; + otherwise assigns the original value of the referenced object to [code]#expected#. + +Returns [code]#true# if the comparison operation and replacement operation were +successful. The [code]#failure# memory order of this atomic operation must be +[code]#memory_order::relaxed#, [code]#memory_order::acquire# or +[code]#memory_order::seq_cst#. + +This function is only supported for 64-bit data types on devices that have +[code]#aspect::atomic64#. + +a@ +[source] +---- +bool compare_exchange_weak(T &expected, T desired, + memory_order order = default_read_modify_write_order, + memory_scope scope = default_scope) const +---- + a@ Equivalent to [code]#compare_exchange_weak(expected, desired, order, order, scope)#. + +a@ +[source] +---- +bool compare_exchange_strong(T &expected, T desired, + memory_order success, + memory_order failure, + memory_scope scope = default_scope) const +---- + a@ Atomically compares the value of the object referenced by this [code]#atomic_ref# + against the value of [code]#expected#. If the values are equal, + replaces the value of the referenced object with the value of + [code]#desired#; + otherwise assigns the original value of the referenced object to [code]#expected#. + +Returns [code]#true# if the comparison operation was +successful. The [code]#failure# memory order of this atomic operation must be +[code]#memory_order::relaxed#, [code]#memory_order::acquire# or +[code]#memory_order::seq_cst#. + +This function is only supported for 64-bit data types on devices that have +[code]#aspect::atomic64#. + +a@ +[source] +---- +bool compare_exchange_strong(T &expected, T desired, + memory_order order = + default_read_modify_write_order) const +---- + a@ Equivalent to [code]#compare_exchange_strong(expected, desired, order, order, scope)#. + +|==== + + + +[[table.atomic-refs.members.integral]] +.Additional member functions available on an object of type [code]#atomic_ref# for integral [code]#T# +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +T fetch_add(T operand, + memory_order order = default_read_modify_write_order, + memory_scope scope = default_scope) const +---- + a@ Atomically adds [code]#operand# to the value + of the object referenced by this [code]#atomic_ref# and assigns + the result to the value of the referenced object. Returns the original + value of the referenced object. This function is only supported for 64-bit + data types on devices that have [code]#aspect::atomic64#. + +a@ +[source] +---- +T operator+=(T operand) const +---- + a@ Equivalent to [code]#fetch_add(operand)#. + +a@ +[source] +---- +T operator++(int) const +---- + a@ Equivalent to [code]#fetch_add(1)#. + +a@ +[source] +---- +T operator++() const +---- + a@ Equivalent to [code]#fetch_add(1) pass:[+] 1#. + +a@ +[source] +---- +T fetch_sub(T operand, + memory_order order = default_read_modify_write_order, + memory_scope scope = default_scope) const +---- + a@ Atomically subtracts [code]#operand# from the value + of the object referenced by this [code]#atomic_ref# and assigns + the result to the value of the referenced object. Returns the original + value of the referenced object. This function is only supported for 64-bit + data types on devices that have [code]#aspect::atomic64#. + +a@ +[source] +---- +T operator-=(T operand) const +---- + a@ Equivalent to [code]#fetch_sub(operand)#. + +a@ +[source] +---- +T operator--(int) const +---- + a@ Equivalent to [code]#fetch_sub(1)#. + +a@ +[source] +---- +T operator--() const +---- + a@ Equivalent to [code]#fetch_sub(1) - 1#. + +a@ +[source] +---- +T fetch_and(T operand, + memory_order order = default_read_modify_write_order, + memory_scope scope = default_scope) const +---- + a@ Atomically performs a bitwise AND between [code]#operand# + and the value of the object referenced by this [code]#atomic_ref#, + and assigns the result to the value of the referenced object. Returns the + original value of the referenced object. This function is only supported + for 64-bit data types on devices that have + [code]#aspect::atomic64#. + +a@ +[source] +---- +T operator&=(T operand) const +---- + a@ Equivalent to [code]#fetch_and(operand)#. + +a@ +[source] +---- +T fetch_or(T operand, + memory_order order = default_read_modify_write_order, + memory_scope scope = default_scope) const +---- + a@ Atomically performs a bitwise OR between [code]#operand# + and the value of the object referenced by this [code]#atomic_ref#, + and assigns the result to the value of the referenced object. Returns the + original value of the referenced object. This function is only supported + for 64-bit data types on devices that have + [code]#aspect::atomic64#. + +a@ +[source] +---- +T operator|=(T operand) const +---- + a@ Equivalent to [code]#fetch_or(operand)#. + +a@ +[source] +---- +T fetch_xor(T operand, + memory_order order = default_read_modify_write_order, + memory_scope scope = default_scope) const +---- + a@ Atomically performs a bitwise XOR between [code]#operand# + and the value of the object referenced by this [code]#atomic_ref#, + and assigns the result to the value of the referenced object. Returns the + original value of the referenced object. This function is only supported + for 64-bit data types on devices that have + [code]#aspect::atomic64#. + +a@ +[source] +---- +T operator^=(T operand) const +---- + a@ Equivalent to [code]#fetch_xor(operand)#. + +a@ +[source] +---- +T fetch_min(T operand, + memory_order order = default_read_modify_write_order, + memory_scope scope = default_scope) const +---- + a@ Atomically computes the minimum of [code]#operand# + and the value of the object referenced by this [code]#atomic_ref#, + and assigns the result to the value of the referenced object. Returns the + original value of the referenced object. This function is only supported + for 64-bit data types on devices that have + [code]#aspect::atomic64#. + +a@ +[source] +---- +T fetch_max(T operand, + memory_order order = default_read_modify_write_order, + memory_scope scope = default_scope) const +---- + a@ Atomically computes the maximum of [code]#operand# + and the value of the object referenced by this [code]#atomic_ref#, + and assigns the result to the value of the referenced object. Returns the + original value of the referenced object. This function is only supported + for 64-bit data types on devices that have + [code]#aspect::atomic64#. + +|==== + + + +[[table.atomic-refs.members.floating]] +.Additional member functions available on an object of type [code]#atomic_ref# for floating-point [code]#T# +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +T fetch_add(T operand, + memory_order order = default_read_modify_write_order, + memory_scope scope = default_scope) const +---- + a@ Atomically adds [code]#operand# to the value + of the object referenced by this [code]#atomic_ref# and assigns + the result to the value of the referenced object. Returns the original + value of the referenced object. This function is only supported for 64-bit + data types on devices that have [code]#aspect::atomic64#. + +a@ +[source] +---- +T operator+=(T operand) const +---- + a@ Equivalent to [code]#fetch_add(operand)#. + +a@ +[source] +---- +T fetch_sub(T operand, + memory_order order = default_read_modify_write_order, + memory_scope scope = default_scope) const +---- + a@ Atomically subtracts [code]#operand# from the value + of the object referenced by this [code]#atomic_ref# and assigns + the result to the value of the referenced object. Returns the original + value of the referenced object. This function is only supported for 64-bit + data types on devices that have [code]#aspect::atomic64#. + +a@ +[source] +---- +T operator-=(T operand) const +---- + a@ Equivalent to [code]#fetch_sub(operand)#. + +a@ +[source] +---- +T fetch_min(T operand, + memory_order order = default_read_modify_write_order, + memory_scope scope = default_scope) const +---- + a@ Atomically computes the minimum of [code]#operand# + and the value of the object referenced by this [code]#atomic_ref#, + and assigns the result to the value of the referenced object. Returns the + original value of the referenced object. This function is only supported for + 64-bit data types on devices that have [code]#aspect::atomic64#. + +a@ +[source] +---- +T fetch_max(T operand, + memory_order order = default_read_modify_write_order, + memory_scope scope = default_scope) const +---- + a@ Atomically computes the maximum of [code]#operand# + and the value of the object referenced by this [code]#atomic_ref#, + and assigns the result to the value of the referenced object. Returns the + original value of the referenced object. This function is only supported for + 64-bit data types on devices that have [code]#aspect::atomic64#. + +|==== + + + +[[table.atomic-refs.members.pointer]] +.Additional member functions available on an object of type [code]#atomic_ref# +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +T* fetch_add(ptrdiff_t operand, + memory_order order = default_read_modify_write_order, + memory_scope scope = default_scope) const +---- + a@ Atomically adds [code]#operand# to the value + of the object referenced by this [code]#atomic_ref# and assigns + the result to the value of the referenced object. Returns the original + value of the referenced object. This function is only supported for 64-bit + pointers on devices that have [code]#aspect::atomic64#. + +a@ +[source] +---- +T* operator+=(ptrdiff_t operand) const +---- + a@ Equivalent to [code]#fetch_add(operand)#. + +a@ +[source] +---- +T* operator++(int) const +---- + a@ Equivalent to [code]#fetch_add(1)#. + +a@ +[source] +---- +T* operator++() const +---- + a@ Equivalent to [code]#fetch_add(1) pass:[+] 1#. + +a@ +[source] +---- +T* fetch_sub(ptrdiff_t operand, + memory_order order = default_read_modify_write_order, + memory_scope scope = default_scope) const +---- + a@ Atomically subtracts [code]#operand# from the value + of the object referenced by this [code]#atomic_ref# and assigns + the result to the value of the referenced object. Returns the original + value of the referenced object. This function is only supported for 64-bit + pointers on devices that have [code]#aspect::atomic64#. + +a@ +[source] +---- +T* operator-=(ptrdiff_t operand) const +---- + a@ Equivalent to [code]#fetch_sub(operand)#. + +a@ +[source] +---- +T* operator--(int) const +---- + a@ Equivalent to [code]#fetch_sub(1)#. + +a@ +[source] +---- +T* operator--() const +---- + a@ Equivalent to [code]#fetch_sub(1) - 1#. + +|==== + + + +[[sec:atom-types-depr]] +=== Atomic types (deprecated) + +// Deprecated atomics from SYCL 1.2.1 + +The atomic types and operations on atomic types provided by SYCL 1.2.1 are +deprecated in SYCL 2020, and will be removed in a future version of SYCL. The +types and operations are made available in the [code]#cl::sycl::# +namespace for backwards compatibility. + +The constructors and member functions for the [code]#cl::sycl::atomic# +class are listed in <> +and <> respectively. + +[source,,linenums] +---- +include::{header_dir}/atomic.h[lines=4..-1] +---- + +The global functions are as follows and described in +<>. + +[source,,linenums] +---- +include::{header_dir}/atomicoperations.h[lines=4..-1] +---- + + +[[table.atomics.constructors]] +.Constructors of the [code]#cl::sycl::atomic# class template +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Constructor @ Description +a@ +[source] +---- +template +atomic(multi_ptr ptr) +---- + a@ Deprecated in SYCL 2020. + +Permitted data types for [code]#pointerT# are any valid scalar data +type which is the same size in bytes as [code]#T#. Constructs an +instance of SYCL [code]#atomic# which is associated with the pointer +[code]#ptr#, converted to a pointer of data type [code]#T#. + +|==== + + + +[[table.atomics.members]] +.Member functions available on an object of type [code]#cl::sycl::atomic# +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +void store(T operand, memory_order memoryOrder = + memory_order::relaxed) +---- + a@ Deprecated in SYCL 2020. + +Atomically stores the value [code]#operand# at the address of the +[code]#multi_ptr# associated with this SYCL [code]#atomic#. The +memory order of this atomic operation must be [code]#memory_order::relaxed#. This function is only supported for 64-bit data +types on devices that have [code]#aspect::atomic64#. + +a@ +[source] +---- +T load(memory_order memoryOrder = + memory_order::relaxed) const +---- + a@ Deprecated in SYCL 2020. + +Atomically loads the value at the address of the [code]#multi_ptr# +associated with this SYCL [code]#atomic#. Returns the value at the +address of the [code]#multi_ptr# associated with this SYCL +[code]#atomic# before the call. The memory order of this atomic +operation must be [code]#memory_order::relaxed#. This function is +only supported for 64-bit data types on devices that have +[code]#aspect::atomic64#. + +a@ +[source] +---- +T exchange(T operand, memory_order memoryOrder = + memory_order::relaxed) +---- + a@ Deprecated in SYCL 2020. + +Atomically replaces the value at the address of the [code]#multi_ptr# +associated with this SYCL [code]#atomic# with value [code]#operand# and returns the value at the address of the [code]#multi_ptr# associated with this SYCL [code]#atomic# before the call. +The memory order of this atomic operation must be [code]#memory_order::relaxed#. This function is only supported for 64-bit data +types on devices that have [code]#aspect::atomic64#. + +a@ +[source] +---- +bool compare_exchange_strong(T &expected, T desired, + memory_order successMemoryOrder = + memory_order::relaxed, + memory_order failMemoryOrder = + memory_order::relaxed) +---- + a@ Deprecated in SYCL 2020. + +Available only when: [code]#T != float#. + +Atomically compares the value at the address of the [code]#multi_ptr# +associated with this SYCL [code]#atomic# against the value of +[code]#expected#. If the values are equal, replaces value at address +of the [code]#multi_ptr# associated with this SYCL +[code]#atomic# with the value of [code]#desired#; otherwise assigns the +original value at the address of the [code]#multi_ptr# associated +with this SYCL [code]#atomic# to [code]#expected#. Returns +[code]#true# if the comparison operation was successful. The memory +order of this atomic operation must be [code]#memory_order::relaxed# for both success and fail. This function is only +supported for 64-bit data types on devices that have +[code]#aspect::atomic64#. + +a@ +[source] +---- +T fetch_add(T operand, memory_order memoryOrder = + memory_order::relaxed) +---- + a@ Deprecated in SYCL 2020. + +Available only when: [code]#T != float#. + +Atomically adds the value [code]#operand# to the value at the address +of the [code]#multi_ptr# associated with this SYCL [code]#atomic# and assigns the result to the value at the address of the +[code]#multi_ptr# associated with this SYCL [code]#atomic#. +Returns the value at the address of the [code]#multi_ptr# associated +with this SYCL [code]#atomic# before the call. The memory order of +this atomic operation must be [code]#memory_order::relaxed#. This +function is only supported for 64-bit data types on devices that have +[code]#aspect::atomic64#. + +a@ +[source] +---- +T fetch_sub(T operand, memory_order memoryOrder = + memory_order::relaxed) +---- + a@ Deprecated in SYCL 2020. + +Available only when: [code]#T != float#. + +Atomically subtracts the value [code]#operand# to the value at the +address of the [code]#multi_ptr# associated with this SYCL +[code]#atomic# and assigns the result to the value at the address of +the [code]#multi_ptr# associated with this SYCL [code]#atomic#. +Returns the value at the address of the [code]#multi_ptr# associated +with this SYCL [code]#atomic# before the call. The memory order of +this atomic operation must be [code]#memory_order::relaxed#. This +function is only supported for 64-bit data types on devices that have +[code]#aspect::atomic64#. + +a@ +[source] +---- +T fetch_and(T operand, memory_order memoryOrder = + memory_order::relaxed) +---- + a@ Deprecated in SYCL 2020. + +Available only when: [code]#T != float#. + +Atomically performs a bitwise AND between the value [code]#operand# +and the value at the address of the [code]#multi_ptr# associated with +this SYCL [code]#atomic# and assigns the result to the value at the +address of the [code]#multi_ptr# associated with this SYCL +[code]#atomic#. Returns the value at the address of the [code]#multi_ptr# associated with this SYCL [code]#atomic# before the call. +The memory order of this atomic operation must be [code]#memory_order::relaxed#. This function is only supported for 64-bit data +types on devices that have [code]#aspect::atomic64#. + +a@ +[source] +---- +T fetch_or(T operand, memory_order memoryOrder = + memory_order::relaxed) +---- + a@ Deprecated in SYCL 2020. + +Available only when: [code]#T != float#. + +Atomically performs a bitwise OR between the value [code]#operand# +and the value at the address of the [code]#multi_ptr# associated with +this SYCL [code]#atomic# and assigns the result to the value at the +address of the [code]#multi_ptr# associated with this SYCL +[code]#atomic#. Returns the value at the address of the [code]#multi_ptr# associated with this SYCL [code]#atomic# before the call. +The memory order of this atomic operation must be [code]#memory_order::relaxed#. This function is only supported for 64-bit data +types on devices that have [code]#aspect::atomic64#. + +a@ +[source] +---- +T fetch_xor(T operand, memory_order memoryOrder = + memory_order::relaxed) +---- + a@ Deprecated in SYCL 2020. + +Available only when: [code]#T != float#. + +Atomically performs a bitwise XOR between the value [code]#operand# +and the value at the address of the [code]#multi_ptr# associated with +this SYCL [code]#atomic# and assigns the result to the value at the +address of the [code]#multi_ptr# associated with this SYCL +[code]#atomic#. Returns the value at the address of the [code]#multi_ptr# associated with this SYCL [code]#atomic# before the call. +The memory order of this atomic operation must be [code]#memory_order::relaxed#. This function is only supported for 64-bit data +types on devices that have [code]#aspect::atomic64#. + +a@ +[source] +---- +T fetch_min(T operand, memory_order memoryOrder = + memory_order::relaxed) +---- + a@ Deprecated in SYCL 2020. + +Atomically computes the minimum of the value [code]#operand# and the +value at the address of the [code]#multi_ptr# associated with this +SYCL [code]#atomic# and assigns the result to the value at the address +of the [code]#multi_ptr# associated with this SYCL [code]#atomic#. Returns the value at the address of the [code]#multi_ptr# +associated with this SYCL [code]#atomic# before the call. The memory +order of this atomic operation must be [code]#memory_order::relaxed#. +This function is only supported for 64-bit data types on devices that have +[code]#aspect::atomic64#. + +a@ +[source] +---- +T fetch_max(T operand, memory_order memoryOrder = + memory_order::relaxed) +---- + a@ Deprecated in SYCL 2020. + +Available only when: [code]#T != float#. + +Atomically computes the maximum of the value [code]#operand# and the +value at the address of the [code]#multi_ptr# associated with this +SYCL [code]#atomic# and assigns the result to the value at the address +of the [code]#multi_ptr# associated with this SYCL [code]#atomic#. Returns the value at the address of the [code]#multi_ptr# +associated with this SYCL [code]#atomic# before the call. The memory +order of this atomic operation must be [code]#memory_order::relaxed#. +This function is only supported for 64-bit data types on devices that have +[code]#aspect::atomic64#. + +|==== + + + +[[table.atomics.functions]] +.Global functions available on atomic types +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Functions @ Description +a@ +[source] +---- +template +T atomic_load(atomic object, + memory_order memoryOrder = memory_order::relaxed) +---- + a@ Deprecated in SYCL 2020. + +Equivalent to calling [code]#object.load(memoryOrder)#. + +a@ +[source] +---- +template +void atomic_store(atomic object, T operand, + memory_order memoryOrder = memory_order::relaxed) +---- + a@ Deprecated in SYCL 2020. + +Equivalent to calling [code]#object.store(operand, memoryOrder)#. + +a@ +[source] +---- +template +T atomic_exchange(atomic object, T operand, + memory_order memoryOrder = memory_order::relaxed) +---- + a@ Deprecated in SYCL 2020. + +Equivalent to calling [code]#object.exchange(operand, memoryOrder)#. + +a@ +[source] +---- +template +bool atomic_compare_exchange_strong( + atomic object, T &expected, T desired, + memory_order successMemoryOrder = + memory_order::relaxed + memory_order failMemoryOrder = + memory_order::relaxed) +---- + a@ Deprecated in SYCL 2020. + +Equivalent to calling [code]#object.compare_exchange_strong(expected, desired, successMemoryOrder, failMemoryOrders)#. + +a@ +[source] +---- +template +T atomic_fetch_add(atomic object, T operand, + memory_order memoryOrder = memory_order::relaxed) +---- + a@ Deprecated in SYCL 2020. + +Equivalent to calling [code]#object.fetch_add(operand, memoryOrder)#. + +a@ +[source] +---- +template +T atomic_fetch_sub(atomic object, T operand, + memory_order memoryOrder = memory_order::relaxed) +---- + a@ Deprecated in SYCL 2020. + +Equivalent to calling [code]#object.fetch_sub(operand, memoryOrder)#. + +a@ +[source] +---- +template +T atomic_fetch_and(atomic operand, T object, + memory_order memoryOrder = memory_order::relaxed) +---- + a@ Deprecated in SYCL 2020. + +Equivalent to calling [code]#object.fetch_add(operand, memoryOrder)#. + +a@ +[source] +---- +template +T atomic_fetch_or(atomic object, T operand, + memory_order memoryOrder = memory_order::relaxed) +---- + a@ Deprecated in SYCL 2020. + +Equivalent to calling [code]#object.fetch_or(operand, memoryOrder)#. + +a@ +[source] +---- +template +T atomic_fetch_xor(atomic object, T operand, + memory_order memoryOrder = memory_order::relaxed) +---- + a@ Deprecated in SYCL 2020. + +Equivalent to calling [code]#object.fetch_xor(operand, memoryOrder)#. + +a@ +[source] +---- +template +T atomic_fetch_min(atomic object, T operand, + memory_order memoryOrder = memory_order::relaxed) +---- + a@ Deprecated in SYCL 2020. + +Equivalent to calling [code]#object.fetch_min(operand, memoryOrder)#. + +a@ +[source] +---- +template +T atomic_fetch_max(atomic object, T operand, + memory_order memoryOrder = memory_order::relaxed) +---- + a@ Deprecated in SYCL 2020. + +Equivalent to calling [code]#object.fetch_max(operand, memoryOrder)#. + +|==== + + + +[[subsec:stream]] +== Stream class + +The SYCL [code]#stream# class is a buffered output stream that allows +outputting the values of built-in, vector and SYCL types to the console. The +implementation of how values are streamed to the console is left as an +implementation detail. + +The way in which values are output by an instance of the SYCL +[code]#stream# class can also be altered using a range of manipulators. + +There are two limits that are relevant for the [code]#stream# class. The +[code]#totalBufferSize# limit specifies the maximum size of the overall +character stream that can be output during a kernel invocation, and the +[code]#workItemBufferSize# limit specifies the maximum size of the +character stream that can be output within a work item before a flush must be +performed. Both of these limits are specified in bytes. The +[code]#totalBufferSize# limit must be sufficient to contain the characters +output by all stream statements during execution of a kernel invocation (the +aggregate of outputs from all work items), and the +[code]#workItemBufferSize# limit must be sufficient to contain the +characters output within a work item between stream flush operations. + +If the [code]#totalBufferSize# or [code]#workItemBufferSize# +limits are exceeded, it is implementation-defined whether the streamed +characters exceeding the limit are output, or silently ignored/discarded, +and if output it is implementation-defined whether those extra characters +exceeding the [code]#workItemBufferSize# limit count toward the +[code]#totalBufferSize# limit. Regardless of this implementation +defined behavior of output exceeding the limits, no undefined or erroneous +behavior is permitted of an implementation when the limits are exceeded. +Unused characters within [code]#workItemBufferSize# (any portion of the +[code]#workItemBufferSize# capacity that has not been used at the time +of a stream flush) do not count toward the [code]#totalBufferSize# +limit, in that only characters flushed count toward the +[code]#totalBufferSize# limit. + +The SYCL [code]#stream# class provides the common reference semantics +(see <>). + + +=== Stream class interface + +The constructors and member functions of the SYCL [code]#stream# class +are listed in <>, +<>, and <> respectively. The +additional common special member functions and common member functions are +listed in <> and +<>, respectively. + +The operand types that are supported by the SYCL [code]#stream# class +[code]#operator<<()# operator are listed in +<>. + +The manipulators that are supported by the SYCL [code]#stream# class +[code]#operator<<()# operator are listed in +<>. + +// Interface of the device class +[source,,linenums] +---- +include::{header_dir}/stream.h[lines=4..-1] +---- + + +[[table.operands.stream]] +.Operand types supported by the [code]#stream# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Stream operand type @ Description +a@ +[source] +---- +char, signed char, unsigned char, int, unsigned int, short, unsigned short, long int, unsigned long int, long long int, unsigned long long int +---- + a@ Outputs the value as a stream of characters. + +a@ +[source] +---- +float, double, half +---- + a@ Outputs the value according to the precision of the current statement as a stream of characters. + +a@ +[source] +---- +char *, const char * +---- + a@ Outputs the string. + +a@ +[source] +---- +T *, const T *, multi_ptr +---- + a@ Outputs the address of the pointer as a stream of characters. + +a@ +[source] +---- +vec +---- + a@ Outputs the value of each component of the vector as a stream of characters. + +a@ +[source] +---- +id, range, item, nd_item, group, nd_range, h_item +---- + a@ Outputs the value of each component of each id or range as a stream of characters. + +|==== + + + +[[table.manipulators.stream]] +.Manipulators supported by the [code]#stream# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Stream manipulator @ Description +a@ +[source] +---- +flush +---- + a@ Triggers a flush operation, which synchronizes the work item stream buffer + with the global stream buffer, and then empties the work item stream + buffer. After a flush, the full [code]#workItemBufferSize# is + available again for subsequent streaming within the work item. + +a@ +[source] +---- +endl +---- + a@ Outputs a new-line character and then triggers a flush operation. + +a@ +[source] +---- +dec +---- + a@ Outputs any subsequent values in the current statement in decimal base. + +a@ +[source] +---- +hex +---- + a@ Outputs any subsequent values in the current statement in hexadecimal base. + +a@ +[source] +---- +oct +---- + a@ Outputs any subsequent values in the current statement in octal base. + +a@ +[source] +---- +noshowbase +---- + a@ Outputs any subsequent values without the base prefix. + +a@ +[source] +---- +showbase +---- + a@ Outputs any subsequent values with the base prefix. + +a@ +[source] +---- +noshowpos +---- + a@ Outputs any subsequent values without a plus sign if the value is positive. + +a@ +[source] +---- +showpos +---- + a@ Outputs any subsequent values with a plus sign if the value is positive. + +a@ +[source] +---- +setw(int) +---- + a@ Sets the field width of any subsequent values in the current statement. + +a@ +[source] +---- +setprecision(int) +---- + a@ Sets the precision of any subsequent values in the current statement. + +a@ +[source] +---- +fixed +---- + a@ Outputs any subsequent floating-point values in the current statement in fixed notation. + +a@ +[source] +---- +scientific +---- + a@ Outputs any subsequent floating-point values in the current statement in scientific notation. + +a@ +[source] +---- +hexfloat +---- + a@ Outputs any subsequent floating-point values in the current statement in hexadecimal notation. + +a@ +[source] +---- +defaultfloat +---- + a@ Outputs any subsequent floating-point values in the current statement in the default notation. + +|==== + + + +[[table.constructors.stream]] +.Constructors of the [code]#stream# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Constructor @ Description +a@ +[source] +---- +stream(size_t totalBufferSize, + size_t workItemBufferSize, + handler& cgh, + const property_list &propList = {}) +---- + a@ Constructs a SYCL [code]#stream# instance associated with the command group + specified by [code]#cgh#, with a maximum buffer size in bytes per kernel + invocation specified by the parameter [code]#totalBufferSize#, and a maximum + stream size that can be buffered by a work item between stream flushes + specified by the parameter [code]#workItemBufferSize#. + Zero or more properties can be provided to the constructed SYCL + [code]#stream# via an instance of [code]#property_list#. + +|==== + + + +[[table.members.stream]] +.Member functions of the [code]#stream# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +size_t size() const noexcept +---- + a@ Returns the total buffer size, in bytes. +a@ +[source] +---- +size_t get_size() const +---- + a@ Returns the same value as [code]#size()#. Deprecated. +a@ +[source] +---- +size_t get_work_item_buffer_size() const +---- + a@ Returns the buffer size per work item, in bytes. + +a@ +[source] +---- +size_t get_max_statement_size() const +---- + a@ Deprecated query with same functionality as [code]#get_work_item_buffer_size()#. + +|==== + + + +[[table.globals.stream]] +.Global functions of the [code]#stream# class +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Global function @ Description +a@ +[source] +---- +template const stream& operator<<(const stream& os, const T &rhs) +---- + a@ Outputs any valid values (see <>) as a stream of characters and applies any valid manipulator (see <>) to the current stream. + +|==== + + + +=== Synchronization + +An instance of the SYCL [code]#stream# class is required to synchronize with the host, and must output +everything that is streamed to it via the [code]#operator<<()# operator before a flush operation (that +doesn't exceed the [code]#workItemBufferSize# or [code]#totalBufferSize# limits) within a SYCL +kernel function by the time that the event associated with a command group submission enters the completed +state. The point at which this synchronization occurs and the member function by which this synchronization is +performed are implementation-defined. For example it is valid for an implementation to use +[code]#printf()#. + +The SYCL [code]#stream# class is required to output the content of each stream, between flushes (up to +[code]#workItemBufferSize)#, without mixing with content from the same stream in other work items. +There are no other output order guarantees between work items or between streams. The stream flush +operation therefore delimits the unit of output that is guaranteed to be displayed without mixing with +other work items, with respect to a single stream. + + +=== Implicit flush + +There is guaranteed to be an implicit flush of each stream used by a +kernel, at the end of kernel execution, from the perspective of each +work item. There is also an implicit flush when the endl stream +manipulator is executed. No other implicit flushes are permitted in +an implementation. + + +=== Performance note + +The usage of the [code]#stream# class is designed for debugging purposes and is therefore not recommended for performance critical applications. + +// \input{builtin_functions} + +// %%%%%%%%%%%%%%%%%%%%%%%%%%%% begin builtin_functions %%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +[[sycl:builtins]] +== SYCL built-in functions for SYCL host and device + +// Intentional OpenCL reference +SYCL kernels may execute on any SYCL device, which requires the functions +used in the kernels to be compiled and linked for both device and host. In +the SYCL programming model, the built-ins are available for the entire SYCL +application within the [code]#sycl# namespace, although their semantics +may be different. This section follows the OpenCL 1.2 specification document +<> - except that for SYCL, all functions are located +within the [code]#sycl# namespace - and describes the behavior of these +functions for SYCL host and device. The expected precision and any other +semantic requirements are defined in the backend specification. + +The SYCL built-in functions are available throughout the SYCL application, +and depending on where they execute, they are either implemented using their +host implementation or the device implementation. The SYCL system guarantees +that all of the built-in functions fulfill the same requirements for both +host and device. + + +=== Description of the built-in types available for SYCL host and device + +All of the OpenCL built-in types are available in the namespace +[code]#sycl#. For the purposes of this document we use +generic type names for describing sets of valid SYCL types. The +generic type names themselves are not valid SYCL types, but they +represent a set of valid types, as defined in +<>. Each generic type within a section is +comprised of a combination of scalar, SYCL [code]#vec# and/or [code]#marray# class +specializations. The letters [code]#{n}# and [code]#{N}# define valid sizes for +class specializations, where [code]#{n}# means 2,3,4,8,16 and [code]#{N}# means +any positive value of size_t type. Note that any reference to the base type +refers to the type of a scalar or the element type of a SYCL [code]#vec# or +[code]#marray# specialization. + + + +[[table.gentypes]] +.Generic type name description, which serves as a description for all valid types of <>. +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Generic type name @ Description +a@ +[source] +---- +floatn +---- + a@ [code]#float{n}#, [code]#mfloat{n}#, [code]#marray<{N},float># + +a@ +[source] +---- +genfloatf +---- + a@ [code]#float#, [code]#floatn# + +a@ +[source] +---- +doublen +---- + a@ [code]#double{n}#, [code]#mdouble{n}#, [code]#marray<{N},double># + +a@ +[source] +---- +genfloatd +---- + a@ [code]#double#, [code]#doublen# + +a@ +[source] +---- +halfn +---- + a@ [code]#half{n}#, [code]#mhalf{n}#, [code]#marray<{N},half># + +a@ +[source] +---- +genfloath +---- + a@ [code]#half#, [code]#halfn# + +a@ +[source] +---- +genfloat +---- + a@ [code]#genfloatf#, [code]#genfloatd#, [code]#genfloath# + +a@ +[source] +---- +sgenfloat +---- + a@ [code]#float#, [code]#double#, [code]#half# + +a@ +[source] +---- +gengeofloat +---- + a@ [code]#float#, [code]#float2#, [code]#float3#, [code]#float4#, [code]#mfloat2#, + [code]#mfloat3#, [code]#mfloat4# + +a@ +[source] +---- +gengeodouble +---- + a@ [code]#double#, [code]#double2#, [code]#double3#, [code]#double4#, [code]#mdouble2#, + [code]#mdouble3#, [code]#mdouble4# + +a@ +[source] +---- +charn +---- + a@ [code]#char{n}#, [code]#mchar{n}#, [code]#marray<{N},char># + +a@ +[source] +---- +scharn +---- + a@ [code]#schar{n}#, [code]#mschar{n}#, [code]#marray<{N},signed char># + +a@ +[source] +---- +ucharn +---- + a@ [code]#uchar{n}#, [code]#muchar{n}#, [code]#marray<{N},unsigned char># + +a@ +[source] +---- +igenchar +---- + a@ [code]#signed# char, [code]#scharn# + +a@ +[source] +---- +ugenchar +---- + a@ [code]#unsigned# char, [code]#ucharn# + +a@ +[source] +---- +genchar +---- + a@ [code]#char#, [code]#charn#, [code]#igenchar#, [code]#ugenchar# + +a@ +[source] +---- +shortn +---- + a@ [code]#short{n}#, [code]#mshort{n}#, [code]#marray<{N},short># + +a@ +[source] +---- +genshort +---- + a@ [code]#short#, [code]#shortn# + +a@ +[source] +---- +ushortn +---- + a@ [code]#ushort{n}#, [code]#mushort{n}#, [code]#marray<{N},unsigned short># + +a@ +[source] +---- +ugenshort +---- + a@ [code]#unsigned# short, [code]#ushortn# + +a@ +[source] +---- +uintn +---- + a@ [code]#uint{n}#, [code]#muint{n}#, [code]#marray<{N},unsigned int># + +a@ +[source] +---- +ugenint +---- + a@ [code]#unsigned# int, [code]#uintn# + +a@ +[source] +---- +intn +---- + a@ [code]#int{n}#, [code]#mint{n}#, [code]#marray<{N},int># + +a@ +[source] +---- +genint +---- + a@ [code]#int#, [code]#intn# + +a@ +[source] +---- +ulongn +---- + a@ [code]#ulong{n}#, [code]#mulong{n}#, [code]#marray<{N},unsigned long int># + +a@ +[source] +---- +ugenlong +---- + a@ [code]#unsigned# long int, [code]#ulongn# + +a@ +[source] +---- +longn +---- + a@ [code]#long{n}#, [code]#mlong{n}#, [code]#marray<{N},long int># + +a@ +[source] +---- +genlong +---- + a@ [code]#long# int, [code]#longn# + +a@ +[source] +---- +ulonglongn +---- + a@ [code]#ulonglong{n}#, [code]#mulonglong{n}#, [code]#marray<{N},unsigned long long + int># + +a@ +[source] +---- +ugenlonglong +---- + a@ [code]#unsigned# long long int, [code]#ulonglongn# + +a@ +[source] +---- +longlongn +---- + a@ [code]#longlong{n}#, [code]#mlonglong{n}#, [code]#marray<{N},long long int># + +a@ +[source] +---- +genlonglong +---- + a@ [code]#long# long int, [code]#longlongn# + +a@ +[source] +---- +igenlonginteger +---- + a@ [code]#genlong#, [code]#genlonglong# + +a@ +[source] +---- +ugenlonginteger +---- + a@ [code]#ugenlong#, [code]#ugenlonglong# + +a@ +[source] +---- +geninteger +---- + a@ [code]#genchar#, [code]#genshort#, [code]#ugenshort#, [code]#genint#, [code]#ugenint#, + [code]#igenlonginteger#, [code]#ugenlonginteger# + +a@ +[source] +---- +genintegerNbit +---- + a@ [code]#All# types within geninteger whose base type are _N_ bits in size, + where _N_ = 8, 16, 32, 64. + +a@ +[source] +---- +igeninteger +---- + a@ [code]#igenchar#, [code]#genshort#, [code]#genint#, [code]#igenlonginteger# + +a@ +[source] +---- +igenintegerNbit +---- + a@ [code]#All# types within igeninteger whose base type are _N_ bits in size, + where _N_ = 8, 16, 32, 64. + +a@ +[source] +---- +ugeninteger +---- + a@ [code]#ugenchar#, [code]#ugenshort#, [code]#ugenint#, [code]#ugenlonginteger# + +a@ +[source] +---- +ugenintegerNbit +---- + a@ [code]#All# types within ugeninteger whose base type are _N_ bits in size, + where _N_ = 8, 16, 32, 64. + +a@ +[source] +---- +sgeninteger +---- + a@ [code]#char#, [code]#signed# char, [code]#unsigned# char, [code]#short#, [code]#unsigned# + short, [code]#int#, [code]#unsigned# int, [code]#long# int, [code]#unsigned# long int, + [code]#long# long int, [code]#unsigned# long long int + +a@ +[source] +---- +gentype +---- + a@ [code]#genfloat#, [code]#geninteger# + +a@ +[source] +---- +genfloatptr +---- + a@ All permutations of [code]#multi_ptr# where [code]#dataT# is all types within [code]#genfloat#, + [code]#addressSpace# is [code]#access::address_space::global_space#, + [code]#access::address_space::local_space# and + [code]#access::address_space::private_space# and [code]#IsDecorated# is + [code]#access::decorated::yes# and [code]#access::decorated::no#. + +a@ +[source] +---- +genintptr +---- + a@ All permutations of [code]#multi_ptr# where [code]#dataT# is all types within [code]#genint#, + [code]#addressSpace# is [code]#access::address_space::global_space#, + [code]#access::address_space::local_space# and + [code]#access::address_space::private_space# and [code]#IsDecorated# is + [code]#access::decorated::yes# and [code]#access::decorated::no#. + +a@ +[source] +---- +booln +---- + a@ [code]#marray<{N},bool># + +a@ +[source] +---- +genbool +---- + a@ [code]#bool#, [code]#booln# + +|==== + + + +[[sec:function-objects]] +=== Function objects + +SYCL provides a number of function objects in the [code]#sycl# namespace +on host and device. All function objects obey {cpp} conversion and promotion +rules. Each function object is additionally specialized for [code]#void# +as a _transparent_ function object that deduces its parameter types +and return type. + +[source,,linenums] +---- +include::{header_dir}/functional.h[lines=4..-1] +---- + +[[table.function.objects.plus]] +.Member functions for the [code]#plus# function object +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +T operator()(const T& x, const T& y) const +---- + a@ Returns the sum of its arguments, equivalent to [code]#pass:[x + y]#. + +|==== + +[[table.function.objects.multiplies]] +.Member functions for the [code]#multiplies# function object +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +T operator()(const T& x, const T& y) const +---- + a@ Returns the product of its arguments, equivalent to [code]#x * y#. + +|==== + +[[table.function.objects.bit-and]] +.Member functions for the [code]#bit_and# function object +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +T operator()(const T& x, const T& y) const +---- + a@ Returns the bitwise AND of its arguments, equivalent to [code]#x & y#. + +|==== + +[[table.function.objects.bit-or]] +.Member functions for the [code]#bit_or# function object +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +T operator()(const T& x, const T& y) const +---- + a@ Returns the bitwise OR of its arguments, equivalent to [code]#x | y#. + +|==== + +[[table.function.objects.bit-xor]] +.Member functions for the [code]#bit_xor# function object +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +T operator()(const T& x, const T& y) const +---- + a@ Returns the bitwise XOR of its arguments, equivalent to [code]#x ^ y#. + +|==== + +[[table.function.objects.logical-and]] +.Member functions for the [code]#logical_and# function object +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +T operator()(const T& x, const T& y) const +---- + a@ Returns the logical AND of its arguments, equivalent to [code]#x && y#. + +|==== + +[[table.function.objects.logical-or]] +.Member functions for the [code]#logical_or# function object +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +T operator()(const T& x, const T& y) const +---- + a@ Returns the logical OR of its arguments, equivalent to [code]#x || y#. + +|==== + +[[table.function.objects.minimum]] +.Member functions for the [code]#minimum# function object +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +T operator()(const T& x, const T& y) const +---- + a@ Applies [code]#std::less# to its arguments, in the same order, then + returns the lesser argument unchanged. + +|==== + +[[table.function.objects.maximum]] +.Member functions for the [code]#maximum# function object +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Member function @ Description +a@ +[source] +---- +T operator()(const T& x, const T& y) const +---- + a@ Applies [code]#std::greater# to its arguments, in the same order, then + returns the greater argument unchanged. + +|==== + +[[sec:group-functions]] +=== Group functions + +SYCL provides a number of functions that expose functionality tied to groups of +work-items (such as <> and collective operations). +These group functions act as synchronization points and must be encountered in +converged <> by all work-items in the group. If one work-item in +a group calls a group function, then all work-items in that group must call +exactly the same function under the same set of conditions --- calling the same +function under different conditions (e.g. in different iterations of a loop, or +different branches of a conditional statement) results in undefined behavior. +Additionally, restrictions may be placed on the arguments passed to each +function in order to ensure that all work-items in the group agree on the +operation that is being performed. Any such restrictions on the arguments +passed to a function are defined within the descriptions of those functions. +Violating these restrictions results in undefined behavior. + +All group functions are supported for the fundamental scalar types supported by +SYCL (see <>) and instances of the SYCL +[code]#vec# and [code]#marray# classes. + +Using a group function inside of a kernel may introduce additional +limits on the resources available to user code inside the same kernel. The +behavior of these limits is implementation-defined, but must be reflected by +calls to kernel querying functions (such as +[code]#kernel_bundle::get_kernel_info)# as described in <>. + +It is undefined behavior for any group function to be invoked within a +[code]#parallel_for_work_group# or [code]#parallel_for_work_item# +context. + +==== Group type trait + +[source,,linenums] +---- +include::{header_dir}/algorithms/is_group.h[lines=4..-1] +---- + +The [code]#is_group# type trait is used to determine which types of groups are +supported by group functions, and to control when group functions participate +in overload resolution. + +[code]#is_group# is [code]#std::true_type# if [code]#T# is the type of a +standard SYCL group ([code]#group# or [code]#sub_group#) and +[code]#std::false_type# otherwise. A SYCL implementation may introduce +additional specializations of [code]#is_group# for implementation-defined +group types, if the interface of those types supports all member functions and +static members common to the [code]#group# and [code]#sub_group# classes. + +==== [code]#group_broadcast# + +The [code]#group_broadcast# function communicates a value held by one +work-item to all other work-items in the group. + +[source,,linenums] +---- +include::{header_dir}/groups/broadcast.h[lines=4..-1] +---- + + . _Constraints:_ Available only if + [code]#sycl::is_group_v># is true. ++ +-- +_Returns:_ The value of [code]#x# from the work-item with the smallest linear +id within the group. +-- + + . _Constraints:_ Available only if + [code]#sycl::is_group_v># is true. ++ +-- +_Preconditions:_ [code]#local_linear_id# must be the same for all work-items in +the group. + +_Returns:_ The value of [code]#x# from the work-item with the specified linear +id within the group. +-- + + . _Constraints:_ Available only if + [code]#sycl::is_group_v># is true. ++ +-- +_Preconditions:_ [code]#local_id# must be the same for all work-items in the +group, and its dimensionality must match the dimensionality of the group. + +_Returns:_ The value of [code]#x# from the work-item with the specified id +within the group. +-- + +==== [code]#group_barrier# + +The [code]#group_barrier# function synchronizes all work-items in a group, +using a <>. + +[source,,linenums] +---- +include::{header_dir}/groups/barrier.h[lines=4..-1] +---- + + . _Constraints:_ Available only if + [code]#sycl::is_group_v># is true. ++ +-- +_Effects:_ Synchronizes all work-items in the group. The current work-item will +wait at the barrier until all work-items in the group have reached the barrier. +In addition, the barrier performs <> operations ensuring that +memory accesses issued before the barrier are not re-ordered with those issued +after the barrier: all work-items in the group execute a release fence prior to +synchronizing at the barrier, all work-items in the group execute an +acquire fence afterwards, and there is an implicit synchronization of these +fences as if provided by an explicit atomic operation on an atomic object. + +By default, the scope of these fences is set to the narrowest +scope including all work-items in the group (as reported by +[code]#Group::fence_scope#). This scope may be optionally overridden +with a broader scope, specified by the [code]#fence_scope# argument. +-- + +[[sec:algorithms]] +=== Group algorithms library + +SYCL provides an algorithms library based on the functions described +in Section 28 of the {cpp17} specification. The first argument to each function +is a <>, and data ranges can be described using pointers, iterators or +instances of the [code]#multi_ptr# class. The functions defined in this +section are free functions available in the [code]#sycl# namespace. + +Any restrictions from the standard algorithms library apply. Some of the +functions in the SYCL algorithms library introduce additional restrictions +in order to maximize portability across different devices and to minimize +the chances of encountering unexpected behavior. + +All algorithms are supported for the fundamental scalar types supported by SYCL +(see <>) and instances of the SYCL +[code]#vec# and [code]#marray# classes. + +The <> argument to a SYCL algorithm denotes that it should be performed +collaboratively by the work-items in the specified group. All algorithms +act as group functions (as defined in <>), inheriting all +restrictions of group functions. Unless the description of a function says +otherwise, how the elements of a range are processed by the work-items in a +group is undefined. + +SYCL provides separate functions for algorithms which use the work-items in a +group to execute an operation over a range of iterators and algorithms which +are applied to data held directly by the work-items in a group. An example +of the usage of these functions is given below: + +[[listing.group.algorithms]] +.Using the group algorithms library to perform a work-group reduce +[source,,linenums] +---- +include::{code_dir}/algorithms.cpp[lines=4..-1] +---- + +==== [code]#any_of#, [code]#all_of# and [code]#none_of# + +The [code]#any_of#, [code]#all_of# and [code]#none_of# functions from standard +{cpp} test whether Boolean conditions hold for any of, all of or none of the +values in a range, respectively. + +SYCL provides two sets of similar algorithms: + +. [code]#joint_any_of#, [code]#joint_all_of# and [code]#joint_none_of# use the +work-items in a group to execute the corresponding algorithm in parallel. + +. [code]#any_of_group#, [code]#all_of_group# and [code]#none_of_group# test +Boolean conditions applied to data held directly by the work-items in a group. + +[source,,linenums] +---- +include::{header_dir}/algorithms/any_of.h[lines=4..-1] +---- + + . _Constraints:_ Available only if + [code]#sycl::is_group_v># is true. ++ +-- +_Preconditions:_ [code]#first# and [code]#last# must be the same for all +work-items in the group, and [code]#pred# must be an immutable callable with +the same type and state for all work-items in the group. + +_Returns:_ true if [code]#pred# returns true when applied to the result of +dereferencing any iterator in the range [code]#[first, last)#. +-- + + . _Constraints:_ Available only if + [code]#sycl::is_group_v># is true. ++ +-- +_Preconditions:_ [code]#pred# must be an immutable callable with the same type +and state for all work-items in the group. + +_Returns:_ true if [code]#pred(x)# returns true for any work-item in the group. +-- + + . _Constraints:_ Available only if + [code]#sycl::is_group_v># is true. ++ +-- +_Returns:_ true if [code]#pred# is true for any work-item in the group. +-- + +[source,,linenums] +---- +include::{header_dir}/algorithms/all_of.h[lines=4..-1] +---- + + . _Constraints:_ Available only if + [code]#sycl::is_group_v># is true. ++ +-- +_Preconditions:_ [code]#first# and [code]#last# must be the same for all +work-items in the group, and [code]#pred# must be an immutable callable with +the same type and state for all work-items in the group. + +_Returns:_ true if [code]#pred# returns true when applied to the result of +dereferencing all iterators in the range [code]#[first, last)#. +-- + + . _Constraints:_ Available only if + [code]#sycl::is_group_v># is true. ++ +-- +_Preconditions:_ [code]#pred# must be an immutable callable with the same type +and state for all work-items in the group. + +_Returns:_ true if [code]#pred(x)# returns true for all work-items in the group. +-- + + . _Constraints:_ Available only if + [code]#sycl::is_group_v># is true. ++ +-- +_Returns:_ true if [code]#pred# is true for all work-items in the group. +-- + +[source,,linenums] +---- +include::{header_dir}/algorithms/none_of.h[lines=4..-1] +---- + + . _Constraints:_ Available only if + [code]#sycl::is_group_v># is true. ++ +-- +_Preconditions:_ [code]#first# and [code]#last# must be the same for all +work-items in the group, and [code]#pred# must be an immutable callable with +the same type and state for all work-items in the group. + +_Returns:_ true if [code]#pred# returns false when applied to the result of +dereferencing all iterators in the range [code]#[first, last)#. +-- + + . _Constraints:_ Available only if + [code]#sycl::is_group_v># is true. ++ +-- +_Preconditions:_ [code]#pred# must be an immutable callable with the same type +and state for all work-items in the group. + +_Returns:_ true if [code]#pred(x)# returns false for all work-items in the group. +-- + + . _Constraints:_ Available only if + [code]#sycl::is_group_v># is true. ++ +-- +_Returns:_ true if [code]#pred# is false for all work-items in the group. +-- + +==== [code]#shift_left# and [code]#shift_right# + +The [code]#shift_left# and [code]#shift_right# functions from standard {cpp} +move values in a range down (to the left) or up (to the right) respectively. + +SYCL provides similar algorithms compatible with the [code]#sub_group# class: + +. [code]#shift_group_left# and [code]#shift_group_right# move values held by +the work-items in a group directly to another work-item in the group, by +shifting values a fixed number of work-items to the left or right. + +[source,,linenums] +---- +include::{header_dir}/algorithms/shift.h[lines=4..-1] +---- + + . _Constraints:_ Available only if + [code]#std::is_same_v, sub_group># is true. ++ +-- +_Preconditions:_ [code]#delta# must be the same for all work-items in the +group. [code]#T# must be a trivially copyable type. + +_Returns:_ the value of [code]#x# from the work-item whose group local id +([code]#id#) is [code]#delta# larger than that of the calling work-item. +[code]#pass:[id + delta]# may be greater than or equal to the group's linear +size, but the value returned in this case is unspecified. +-- + + . _Constraints:_ Available only if + [code]#std::is_same_v, sub_group># is true. ++ +-- +_Preconditions:_ [code]#delta# must be the same for all work-items in the +group. [code]#T# must be a trivially copyable type. + +_Returns:_ the value of [code]#x# from the work-item whose group local id +([code]#id#) is [code]#delta# smaller than that of the calling work-item. +[code]#id - delta# may be greater than or equal to the group's linear size, but +the value returned in this case is unspecified. +-- + +==== [code]#permute# + +SYCL provides an algorithm to permute the values held by work-items in a +sub-group: + +. [code]#permute_group_by_xor# permutes values by exchanging values held by pairs +of work-items identified by computing the bitwise exclusive OR of the work-item +id and some fixed mask. + +[source,,linenums] +---- +include::{header_dir}/algorithms/permute.h[lines=4..-1] +---- + + . _Constraints:_ Available only if + [code]#std::is_same_v, sub_group># is true. ++ +-- +_Preconditions:_ [code]#mask# must be the same for all work-items in the +group. [code]#T# must be a trivially copyable type. + +_Returns:_ the value of [code]#x# from the work-item whose group local id +is equal to the bitwise exclusive OR of the calling work-item's group local id +and [code]#mask#. The result of the exclusive OR may be greater than or equal to +the group's linear size, but the value returned in this case is unspecified. +-- + +==== [code]#select# + +SYCL provides an algorithm to directly exchange the values held by work-items in +a sub-group: + +. [code]#select_from_group# allows work-items to obtain a copy of a value held +by any other work-item in the group. + +[source,,linenums] +---- +include::{header_dir}/algorithms/select.h[lines=4..-1] +---- + + . _Constraints:_ Available only if + [code]#std::is_same_v, sub_group># is true. ++ +-- +_Preconditions:_ [code]#T# must be a trivially copyable type. + +_Returns:_ the value of [code]#x# from the work-item with the group local id +specified by [code]#remote_local_id#. The value of [code]#remote_local_id# may +be outside of the group, but the value returned in this case is unspecified. +-- + +==== [code]#reduce# + +The [code]#reduce# function from standard {cpp} combines the values in a range in +an unspecified order using a binary operator. + +SYCL provides two similar algorithms that compute the same generalized sum as +defined by standard {cpp}: + +. [code]#joint_reduce# uses the work-items in a group to execute a +[code]#reduce# operation in parallel. + +. [code]#reduce_over_group# combines values held directly by the work-items in +a group. + +The result of a call to these functions is non-deterministic if the binary +operator is not commutative and associative. Only the binary operators defined +in <> are supported by the [code]#reduce# functions in +SYCL 2020, but the standard {cpp} syntax is used for forward compatibility with +future SYCL versions. + +[source,,linenums] +---- +include::{header_dir}/algorithms/reduce.h[lines=4..-1] +---- + + . _Constraints:_ Available only if + [code]#sycl::is_group_v># is true, [code]#Ptr# is a + pointer to a fundamental type, and [code]#BinaryOperation# is a SYCL + function object type. ++ +-- +_Mandates:_ [code]#binary_op(*first, *first)# must return a value of type +[code]#std::iterator_traits::value_type#. + +_Preconditions:_ [code]#first#, [code]#last# and the type of [code]#binary_op# +must be the same for all work-items in the group. [code]#binary_op# must be an +instance of a SYCL function object. + +_Returns:_ The result of combining the values resulting from dereferencing all +iterators in the range [code]#[first, last)# using the operator +[code]#binary_op#, where the values are combined according to the generalized +sum defined in standard {cpp}. +-- + + . _Constraints:_ Available only if + [code]#sycl::is_group_v># is true, [code]#Ptr# is a + pointer to a fundamental type, [code]#T# is a fundamental type, and + [code]#BinaryOperation# is a SYCL function object type. ++ +-- +_Mandates:_ [code]#binary_op(init, *first)# must return a value of type +[code]#T#. + +_Preconditions:_ [code]#first#, [code]#last#, [code]#init# and the type of +[code]#binary_op# must be the same for all work-items in the group. +[code]#binary_op# must be an instance of a SYCL function object. + +_Returns:_ The result of combining the values resulting from dereferencing all +iterators in the range [code]#[first, last)# and the initial value +[code]#init# using the operator [code]#binary_op#, where the values are combined +according to the generalized sum defined in standard {cpp}. +-- + + . _Constraints:_ Available only if + [code]#sycl::is_group_v># is true, [code]#T# is a + fundamental type and [code]#BinaryOperation# is a SYCL function object + type. ++ +-- +_Mandates:_ [code]#binary_op(x, x)# must return a value of type [code]#T#. + +_Preconditions:_ [code]#binary_op# must be an instance of a SYCL function +object. + +_Returns:_ The result of combining all the values of [code]#x# specified by +each work-item in the group using the operator [code]#binary_op#, where the +values are combined according to the generalized sum defined in standard {cpp}. +-- + + . _Constraints:_ Available only if + [code]#sycl::is_group_v># is true, [code]#V# and + [code]#X# are fundamental types, and [code]#BinaryOperation# is a SYCL + function object type. ++ +-- +_Mandates:_ [code]#binary_op(init, x)# must return a value of type [code]#T#. + +_Preconditions:_ [code]#binary_op# must be an instance of a SYCL function +object. + +_Returns:_ The result of combining all the values of [code]#x# specified by +each work-item in the group and the initial value [code]#init# using the +operator [code]#binary_op#, where the values are combined according to the +generalized sum defined in standard {cpp}. +-- + +==== [code]#exclusive_scan# and [code]#inclusive_scan# + +The [code]#exclusive_scan# and [code]#inclusive_scan# functions in standard +{cpp} compute a prefix sum using a binary operator. For a scan of elements +_[x~0~, {ldots}, x~n~]_, the _i_ th result in an exclusive scan is the +generalized noncommutative sum of all elements preceding _x~i~_ (excluding +_x~i~_ itself), whereas the _i_ th result in an inclusive scan is the +generalized noncommutative sum of all elements preceding _x~i~_ (including +_x~i~_ itself). + +SYCL provides two similar sets of algorithms that compute the same prefix sums +using the generalized noncommutative sum as defined by standard {cpp}: + +. [code]#joint_exclusive_scan# and [code]#joint_inclusive_scan# use the +work-items in a group to execute the corresponding algorithm in parallel, and +intermediate partial prefix sums are written to memory as in standard {cpp}. + +. [code]#exclusive_scan_over_group# and [code]#inclusive_scan_over_group# +perform a scan over values held directly by the work-items in a group, and the +result returned to each work-item represents a partial prefix sum. + +The result of a call to a scan is non-deterministic if the binary operator is not +associative. Only the binary operators defined in <> are +supported by the scan functions in SYCL 2020, but the standard {cpp} syntax is +used for forward compatibility with future SYCL versions. + +[source,,linenums] +---- +include::{header_dir}/algorithms/exclusive_scan.h[lines=4..-1] +---- + + . _Constraints:_ Available only if + [code]#sycl::is_group_v># is true, [code]#InPtr# and + [code]#OutPtr# are pointers to fundamental types, and + [code]#BinaryOperation# is a SYCL function object type. ++ +-- +_Mandates:_ [code]#binary_op(*first, *first)# must return a value of type +[code]#std::iterator_traits::value_type#. + +_Preconditions:_ [code]#first#, [code]#last#, [code]#result# and the type of +[code]#binary_op# must be the same for all work-items in the group. +[code]#binary_op# must be an instance of a SYCL function object. + +_Effects:_ The value written to [code]#result# + _i_ is the exclusive scan of +the values resulting from dereferencing the first _i_ values in the range +[code]#[first, last)# and the identity value of [code]#binary_op#, using +the operator [code]#binary_op#. The scan is computed using a generalized +noncommutative sum as defined in standard {cpp}. + +_Returns:_ A pointer to the end of the output range. +-- + + . _Constraints:_ Available only if + [code]#sycl::is_group_v># is true, [code]#InPtr# and + [code]#OutPtr# are pointers to fundamental types, [code]#T# is a + fundamental type, and [code]#BinaryOperation# is a SYCL function object + type. ++ +-- +_Mandates:_ [code]#binary_op(init, *first)# must return a value of type +[code]#T#. + +_Preconditions:_ [code]#first#, [code]#last#, [code]#result#, [code]#init# and the +type of [code]#binary_op# must be the same for all work-items in the group. +[code]#binary_op# must be an instance of a SYCL function object. + +_Effects:_ The value written to [code]#result# + _i_ is the exclusive scan of +the values resulting from dereferencing the first _i_ values in the range +[code]#[first, last)# and an initial value specified by [code]#init#, using +the operator [code]#binary_op#. The scan is computed using a generalized +noncommutative sum as defined in standard {cpp}. + +_Returns:_ A pointer to the end of the output range. +-- + + . _Constraints:_ Available only if + [code]#sycl::is_group_v># is true, [code]#T# is a + fundamental type, and [code]#BinaryOperation# is a SYCL function object + type. ++ +-- +_Mandates:_ [code]#binary_op(x, x)# must return a value of type [code]#T#. + +_Preconditions:_ [code]#binary_op# must be an instance of a SYCL function +object. + +_Returns:_ The value returned on work-item _i_ is the exclusive scan of +the first _i_ values in the group and the identity value of [code]#binary_op#, +using the operator [code]#binary_op#. The scan is computed using a generalized +noncommutative sum as defined in standard {cpp}. For multi-dimensional groups, +the order of work-items in the group is determined by their linear id. +-- + + . _Constraints:_ Available only if + [code]#sycl::is_group_v># is true, [code]#V# and + [code]#T# are fundamental types, and [code]#BinaryOperation# is a SYCL + function object type. ++ +-- +_Mandates:_ [code]#binary_op(init, x)# must return a value of type [code]#T#. + +_Preconditions:_ [code]#binary_op# must be an instance of a SYCL function +object. + +_Returns:_ The value returned on work-item _i_ is the exclusive scan of +the first _i_ values in the group and an initial value specified by +[code]#init#, using the operator [code]#binary_op#. The scan is computed using +a generalized noncommutative sum as defined in standard {cpp}. For +multi-dimensional groups, the order of work-items in the group is determined by +their linear id. +-- + +[source,,linenums] +---- +include::{header_dir}/algorithms/inclusive_scan.h[lines=4..-1] +---- + + . _Constraints:_ Available only if + [code]#sycl::is_group_v># is true, [code]#InPtr# and + [code]#OutPtr# are pointers to fundamental types, and + [code]#BinaryOperation# is a SYCL function object type. ++ +-- +_Mandates:_ [code]#binary_op(*first, *first)# must return a value of type +[code]#std::iterator_traits::value_type#. + +_Preconditions:_ [code]#first#, [code]#last#, [code]#result# and the type of +[code]#binary_op# must be the same for all work-items in the group. +[code]#binary_op# must be an instance of a SYCL function object. + +_Effects:_ The value written to [code]#result# + _i_ is the inclusive scan of +the values resulting from dereferencing the first _i_ values in the range +[code]#[first, last)# and the identity value of [code]#binary_op#, +using the operator [code]#binary_op#. The scan is computed using a generalized +noncommutative sum as defined in standard {cpp}. + +_Returns:_ A pointer to the end of the output range. +-- + + . _Constraints:_ Available only if + [code]#sycl::is_group_v># is true, [code]#InPtr# and + [code]#OutPtr# are pointers to fundamental types, [code]#BinaryOperation# + is a SYCL function object type, and [code]#T# is a fundamental type. ++ +-- +_Mandates:_ [code]#binary_op(init, *first)# must return a value of type +[code]#T#. + +_Preconditions:_ [code]#first#, [code]#last#, [code]#result#, [code]#init# and the +type of [code]#binary_op# must be the same for all work-items in the group. +[code]#binary_op# must be an instance of a SYCL function object. + +_Effects:_ The value written to [code]#result# + _i_ is the inclusive scan of +the values resulting from dereferencing the first _i_ values in the range +[code]#[first, last)# and an initial value specified by +[code]#init#, using the operator [code]#binary_op#. The scan is computed using +a generalized noncommutative sum as defined in standard {cpp}. + +_Returns:_ A pointer to the end of the output range. +-- + + . _Constraints:_ Available only if + [code]#sycl::is_group_v># is true, [code]#T# is a + fundamental type, and [code]#BinaryOperation# is a SYCL function object + type. ++ +-- +_Mandates:_ [code]#binary_op(x, x)# must return a value of type [code]#T#. + +_Preconditions:_ [code]#binary_op# must be an instance of a SYCL function +object. + +_Returns:_ The value returned on work-item _i_ is the inclusive scan of +the first _i_ values in the group and the identity value of [code]#binary_op#, +using the operator [code]#binary_op#. The scan is computed using a generalized +noncommutative sum as defined in standard {cpp}. For multi-dimensional groups, +the order of work-items in the group is determined by their linear id. +-- + + . _Constraints:_ Available only if + [code]#sycl::is_group_v># is true, [code]#V# is a + fundamental type, [code]#BinaryOperation# is a SYCL function object type, + and [code]#T# is a fundamental type. ++ +-- +_Mandates:_ [code]#binary_op(init, x)# must return a value of type [code]#T#. + +_Preconditions:_ [code]#binary_op# must be an instance of a SYCL function +object. + +_Returns:_ The value returned on work-item _i_ is the inclusive scan of +the first _i_ values in the group and an initial value specified by +[code]#init#, using the operator [code]#binary_op#. The scan is computed using +a generalized noncommutative sum as defined in standard {cpp}. For +multi-dimensional groups, the order of work-items in the group is determined by +their linear id. +-- + +=== Math functions + +In SYCL the OpenCL math functions are available in the namespace +[code]#sycl# on host and device with the same precision +guarantees as defined in the OpenCL 1.2 specification document +<> for host and device. For a SYCL platform the +numerical requirements for host need to match the numerical +requirements of the OpenCL math built-in functions. The built-in +functions can take as input float or optionally double and +their [code]#vec# and [code]#marray# counterparts, +for all supported dimensions including dimension 1. + +The built-in functions available for SYCL host and device, with the same +precision requirements for both host and device, are described in +<>. + + +[[table.math.functions]] +.Math functions which work on SYCL host and device. They correspond to <>. +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Math Function @ Description +a@ +[source] +---- +genfloat acos (genfloat x) +---- + a@ Inverse cosine function. + +a@ +[source] +---- +genfloat acosh (genfloat x) +---- + a@ Inverse hyperbolic cosine. + +a@ +[source] +---- +genfloat acospi (genfloat x) +---- + a@ Compute latexmath:[{\arccos(x)} \over \pi] + +a@ +[source] +---- +genfloat asin (genfloat x) +---- + a@ Inverse sine function. + +a@ +[source] +---- +genfloat asinh (genfloat x) +---- + a@ Inverse hyperbolic sine. + +a@ +[source] +---- +genfloat asinpi (genfloat x) +---- + a@ Compute latexmath:[{\arcsin(x)} \over \pi] + +a@ +[source] +---- +genfloat atan (genfloat y_over_x) +---- + a@ Inverse tangent function. + +a@ +[source] +---- +genfloat atan2 (genfloat y, genfloat x) +---- + a@ Compute latexmath:[\arctan({y \over x})]. + +a@ +[source] +---- +genfloat atanh (genfloat x) +---- + a@ Hyperbolic inverse tangent. + +a@ +[source] +---- +genfloat atanpi (genfloat x) +---- + a@ Compute latexmath:[{\arctan(x)} \over \pi]. + +a@ +[source] +---- +genfloat atan2pi (genfloat y, genfloat x) +---- + a@ Compute latexmath:[{\operatorname{atan2}(y,x)} \over \pi]. + +a@ +[source] +---- +genfloat cbrt (genfloat x) +---- + a@ Compute cube-root. + +a@ +[source] +---- +genfloat ceil (genfloat x) +---- + a@ Round to integral value using the round to positive infinity + rounding mode. + +a@ +[source] +---- +genfloat copysign (genfloat x, genfloat y) +---- + a@ Returns x with its sign changed to match + the sign of y. + +a@ +[source] +---- +genfloat cos (genfloat x) +---- + a@ Compute cosine. + +a@ +[source] +---- +genfloat cosh (genfloat x) +---- + a@ Compute hyperbolic cosine. + +a@ +[source] +---- +genfloat cospi (genfloat x) +---- + a@ Compute latexmath:[\cos (\pi x)]. + +a@ +[source] +---- +genfloat erfc (genfloat x) +---- + a@ Complementary error function. + +a@ +[source] +---- +genfloat erf (genfloat x) +---- + a@ Error function encountered in integrating the normal + distribution. + +a@ +[source] +---- +genfloat exp (genfloat x ) +---- + a@ Compute the base-_e_ exponential of x. + +a@ +[source] +---- +genfloat exp2 (genfloat x) +---- + a@ Exponential base 2 function. + +a@ +[source] +---- +genfloat exp10 (genfloat x) +---- + a@ Exponential base 10 function. + +a@ +[source] +---- +genfloat expm1 (genfloat x) +---- + a@ Compute latexmath:[e^x-1.0]. + +a@ +[source] +---- +genfloat fabs (genfloat x) +---- + a@ Compute absolute value of a floating-point number. + +a@ +[source] +---- +genfloat fdim (genfloat x, genfloat y) +---- + a@ latexmath:[x - y] if latexmath:[x > y], +0 if x is less than or + equal to y. + +a@ +[source] +---- +genfloat floor (genfloat x) +---- + a@ Round to integral value using the round to negative infinity + rounding mode. + +a@ +[source] +---- +genfloat fma (genfloat a, genfloat b, genfloat c) +---- + a@ Returns the correctly rounded floating-point + representation of the sum of c with the infinitely + precise product of a and b. Rounding of + intermediate products shall not occur. Edge case + behavior is per the IEEE 754-2008 standard. + +a@ +[source] +---- +genfloat fmax (genfloat x, genfloat y) +genfloat fmax (genfloat x, sgenfloat y) +---- + a@ Returns y if latexmath:[x < y], otherwise it returns x. If one + argument is a NaN, fmax() returns the other + argument. If both arguments are NaNs, fmax() + returns a NaN. + +a@ +[source] +---- +genfloat fmin (genfloat x, genfloat y) +genfloat fmin (genfloat x, sgenfloat y) +---- + a@ Returns y if latexmath:[y < x], otherwise it returns x. If one + argument is a NaN, fmin() returns the other + argument. If both arguments are NaNs, fmin() + returns a NaN. + +a@ +[source] +---- +genfloat fmod (genfloat x, genfloat y) +---- + a@ Modulus. Returns latexmath:[x \bmod y \cdot \mathrm{trunc}(x/y)]. + +a@ +[source] +---- +genfloat fract (genfloat x, genfloatptr iptr) +---- + a@ Returns fmin(x - floor(x), nextafter(genfloat(1.0), genfloat(0.0)) ). + floor(x) is returned in iptr. + +a@ +[source] +---- +genfloat frexp (genfloat x, genintptr exp) +---- + a@ Extract mantissa and exponent from x. For each + component the mantissa returned is a float with + magnitude in the interval [1/2, 1) or 0. Each + component of x equals mantissa returned latexmath:[\times 2^{exp}]. + +a@ +[source] +---- +genfloat hypot (genfloat x, genfloat y) +---- + a@ Compute the value of the square root of x^2^ + y^2^ without undue overflow + or underflow. + +a@ +[source] +---- +genint ilogb (genfloat x) +---- + a@ Return the exponent as an integer value. + +a@ +[source] +---- +genfloat ldexp (genfloat x, genint k) +genfloat ldexp (genfloat x, int k) +---- + a@ Multiply x by 2^k^. + +a@ +[source] +---- +genfloat lgamma (genfloat x) +---- + a@ Log gamma function. Returns the natural + logarithm of the absolute value of the gamma + function. + +a@ +[source] +---- +genfloat lgamma_r (genfloat x, genintptr signp) +---- + a@ Log gamma function. Returns the natural + logarithm of the absolute value of the gamma + function. The sign of the gamma function is + returned in the signp argument of [code]#lgamma_r#. + +a@ +[source] +---- +genfloat log (genfloat x) +---- + a@ Compute natural logarithm. + +a@ +[source] +---- +genfloat log2 (genfloat x) +---- + a@ Compute a base 2 logarithm. + +a@ +[source] +---- +genfloat log10 (genfloat x) +---- + a@ Compute a base 10 logarithm. + +a@ +[source] +---- +genfloat log1p (genfloat x) +---- + a@ Compute latexmath:[\log_e(1.0 + x)]. + +a@ +[source] +---- +genfloat logb (genfloat x) +---- + a@ Compute the exponent of x, which is the integral + part of logr (latexmath:[|x|]). + +a@ +[source] +---- +genfloat mad (genfloat a,genfloat b, genfloat c) +---- + a@ mad approximates a * b + c. Whether or how the + product of a * b is rounded and how supernormal or + subnormal intermediate products are handled is not + defined. mad is intended to be used where speed is + preferred over accuracy. + +a@ +[source] +---- +genfloat maxmag (genfloat x, genfloat y) +---- + a@ Returns x if latexmath:[|x| > |y|], y if latexmath:[|y| > |x|], otherwise + fmax(x, y). + +a@ +[source] +---- +genfloat minmag (genfloat x, genfloat y) +---- + a@ Returns x if latexmath:[|x| < |y|], y if latexmath:[|y| < |x|], otherwise + fmin(x, y). + +a@ +[source] +---- +genfloat modf (genfloat x, genfloatptr iptr) +---- + a@ Decompose a floating-point number. The modf + function breaks the argument x into integral and + fractional parts, each of which has the same sign as + the argument. It stores the integral part in the object + pointed to by iptr. + +a@ +[source] +---- +genfloatf nan (ugenint nancode) +genfloatd nan (ugenlonginteger nancode) +---- + a@ Returns a quiet NaN. The nancode may be placed + in the significand of the resulting NaN. + +a@ +[source] +---- +genfloat nextafter (genfloat x, +genfloat y) +---- + a@ Computes the next representable single-precision + floating-point value following x in the direction of + y. Thus, if y is less than x, nextafter() returns the + largest representable floating-point number less + than x. + +a@ +[source] +---- +genfloat pow (genfloat x, genfloat y) +---- + a@ Compute x to the power y. + +a@ +[source] +---- +genfloat pown (genfloat x, genint y) +---- + a@ Compute x to the power y, where y is an integer. + +a@ +[source] +---- +genfloat powr (genfloat x, genfloat y) +---- + a@ Compute x to the power y, where latexmath:[x \geq 0]. + +a@ +[source] +---- +genfloat remainder (genfloat x, genfloat y) +---- + a@ Compute the value r such that r = x - n*y, where n + is the integer nearest the exact value of x/y. If there + are two integers closest to x/y, n shall be the even + one. If r is zero, it is given the same sign as x. + +a@ +[source] +---- +genfloat remquo (genfloat x, genfloat y, genintptr quo) +---- + a@ The remquo function computes the value r such + that r = x - k*y, where k is the integer nearest the + exact value of x/y. If there are two integers closest + to x/y, k shall be the even one. If r is zero, it is + given the same sign as x. This is the same value + that is returned by the remainder function. + remquo also calculates the lower seven bits of the + integral quotient x/y, and gives that value the same + sign as x/y. It stores this signed value in the object + pointed to by quo. + +a@ +[source] +---- +genfloat rint (genfloat x) +---- + a@ Round to integral value (using round to nearest + even rounding mode) in floating-point format. + Refer to <> for description of rounding + modes. + +a@ +[source] +---- +genfloat rootn (genfloat x, genint y) +---- + a@ Compute x to the power 1/y. + +a@ +[source] +---- +genfloat round (genfloat x) +---- + a@ Return the integral value nearest to x rounding + halfway cases away from zero, regardless of the + current rounding direction. + +a@ +[source] +---- +genfloat rsqrt (genfloat x) +---- + a@ Compute inverse square root. + +a@ +[source] +---- +genfloat sin (genfloat x) +---- + a@ Compute sine. + +a@ +[source] +---- +genfloat sincos (genfloat x, genfloatptr cosval) +---- + a@ Compute sine and cosine of x. The computed sine + is the return value and computed cosine is returned + in [code]#cosval#. + +a@ +[source] +---- +genfloat sinh (genfloat x) +---- + a@ Compute hyperbolic sine. + +a@ +[source] +---- +genfloat sinpi (genfloat x) +---- + a@ Compute _sin({pi} x)_. + +a@ +[source] +---- +genfloat sqrt (genfloat x) +---- + a@ Compute square root. + +a@ +[source] +---- +genfloat tan (genfloat x) +---- + a@ Compute tangent. + +a@ +[source] +---- +genfloat tanh (genfloat x) +---- + a@ Compute hyperbolic tangent. + +a@ +[source] +---- +genfloat tanpi (genfloat x) +---- + a@ Compute _tan({pi} x)_. + +a@ +[source] +---- +genfloat tgamma (genfloat x) +---- + a@ Compute the gamma function. + +a@ +[source] +---- +genfloat trunc (genfloat x) +---- + a@ Round to integral value using the round to zero + rounding mode. + +|==== + + +In SYCL the implementation-defined precision math functions are +defined in the namespace [code]#sycl::native#. The functions +that are available within this namespace are specified in +<>. + + +[[table.native.math.functions]] +.Native math functions +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Native Math Function @ Description +a@ +[source] +---- +genfloatf cos (genfloatf x) +---- + a@ Compute cosine over an implementation-defined range. + The maximum error is implementation-defined. + +a@ +[source] +---- +genfloatf divide (genfloatf x, genfloatf y) +---- + a@ Compute x / y over an implementation-defined range. + The maximum error is implementation-defined. + +a@ +[source] +---- +genfloatf exp (genfloatf x) +---- + a@ Compute the base- e exponential of x over an + implementation-defined range. The maximum error is + implementation-defined. + +a@ +[source] +---- +genfloatf exp2 (genfloatf x) +---- + a@ Compute the base- 2 exponential of x over an + implementation-defined range. The maximum error is + implementation-defined. + +a@ +[source] +---- +genfloatf exp10 (genfloatf x) +---- + a@ Compute the base- 10 exponential of x over an + implementation-defined range. The maximum error is + implementation-defined. + +a@ +[source] +---- +genfloatf log (genfloatf x) +---- + a@ Compute natural logarithm over an implementation-defined range. + The maximum error is implementation-defined. + +a@ +[source] +---- +genfloatf log2 (genfloatf x) +---- + a@ Compute a base 2 logarithm over an implementation-defined + range. The maximum error is implementation-defined. + +a@ +[source] +---- +genfloatf log10 (genfloatf x) +---- + a@ Compute a base 10 logarithm over an implementation-defined + range. The maximum error is implementation-defined. + +a@ +[source] +---- +genfloatf powr (genfloatf x, genfloatf y) +---- + a@ Compute x to the power y, where latexmath:[x \geq 0]. The range of + x and y are implementation-defined. The maximum error + is implementation-defined. + +a@ +[source] +---- +genfloatf recip (genfloatf x) +---- + a@ Compute reciprocal over an implementation-defined + range. The maximum error is implementation-defined. + +a@ +[source] +---- +genfloatf rsqrt (genfloatf x) +---- + a@ Compute inverse square root over an implementation-defined + range. The maximum error is implementation-defined. + +a@ +[source] +---- +genfloatf sin (genfloatf x) +---- + a@ Compute sine over an implementation-defined range. + The maximum error is implementation-defined. + +a@ +[source] +---- +genfloatf sqrt (genfloatf x) +---- + a@ Compute square root over an implementation-defined + range. The maximum error is implementation-defined. + +a@ +[source] +---- +genfloatf tan (genfloatf x) +---- + a@ Compute tangent over an implementation-defined range. + The maximum error is implementation-defined. + +|==== + + +In SYCL the half precision math functions are defined in +[code]#sycl::half_precision#. The functions that are +available within this namespace are specified in +<>. These functions are +implemented with a minimum of 10-bits of accuracy i.e. an ULP value is +less than or equal to 8192 ulp. + + +[[table.half.math.functions]] +.Half precision math functions +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Half Math function @ Description +a@ +[source] +---- +genfloatf cos (genfloatf x) +---- + a@ Compute cosine. x must be in the range -216 to +216. + +a@ +[source] +---- +genfloatf divide (genfloatf x, genfloatf y) +---- + a@ Compute x / y. + +a@ +[source] +---- +genfloatf exp (genfloatf x) +---- + a@ Compute the base- e exponential of x. + +a@ +[source] +---- +genfloatf exp2 (genfloatf x) +---- + a@ Compute the base- 2 exponential of x. + +a@ +[source] +---- +genfloatf exp10 (genfloatf x) +---- + a@ Compute the base- 10 exponential of x. + +a@ +[source] +---- +genfloatf log (genfloatf x) +---- + a@ Compute natural logarithm. + +a@ +[source] +---- +genfloatf log2 (genfloatf x) +---- + a@ Compute a base 2 logarithm. + +a@ +[source] +---- +genfloatf log10 (genfloatf x) +---- + a@ Compute a base 10 logarithm. + +a@ +[source] +---- +genfloatf powr (genfloatf x, genfloatf y) +---- + a@ Compute x to the power y, where latexmath:[x \geq 0]. + +a@ +[source] +---- +genfloatf recip (genfloatf x) +---- + a@ Compute reciprocal. + +a@ +[source] +---- +genfloatf rsqrt (genfloatf x) +---- + a@ Compute inverse square root. + +a@ +[source] +---- +genfloatf sin (genfloatf x) +---- + a@ Compute sine. x must be in the range -216 + to +216. + +a@ +[source] +---- +genfloatf sqrt (genfloatf x) +---- + a@ Compute square root. + +a@ +[source] +---- +genfloatf tan (genfloatf x) +---- + a@ Compute tangent. x must be in the range + -216 to +216. + +|==== + + + +=== Integer functions + +Integer math functions are available in SYCL in the +namespace [code]#sycl# on host and device. The +built-in functions can take as input [code]#char#, +[code]#unsigned char#, [code]#short#, +[code]#unsigned short#, [code]#int#, +[code]#unsigned int#, +[code]#long long int#, +[code]#unsigned long long int# and +their [code]#vec# and [code]#marray# counterparts. The +supported integer math functions are described in +<>. + + +[[table.integer.functions]] +.Integer functions which work on SYCL host and device, are available in the [code]#sycl# namespace +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Integer Function @ Description +a@ +[source] +---- +geninteger abs (geninteger x) +---- + a@ Returns latexmath:[|x|]. + +a@ +[source] +---- +ugeninteger abs_diff (geninteger x, geninteger y) +---- + a@ Returns latexmath:[|x - y|] without modulo overflow. + +a@ +[source] +---- +geninteger add_sat (geninteger x, geninteger y) +---- + a@ Returns latexmath:[x + y] and saturates the result. + +a@ +[source] +---- +geninteger hadd (geninteger x, geninteger y) +---- + a@ Returns latexmath:[(x + y) >> 1]. The intermediate sum does + not modulo overflow. + +a@ +[source] +---- +geninteger rhadd (geninteger x, geninteger y) +---- + a@ Returns latexmath:[(x + y + 1) >> 1]. The intermediate sum + does not modulo overflow. + +a@ +[source] +---- +geninteger clamp (geninteger x, geninteger minval, geninteger maxval) +geninteger clamp (geninteger x, sgeninteger minval, sgeninteger maxval) +---- + a@ Returns min(max(x, minval), maxval). + Results are undefined if latexmath:[\mathrm{minval} > \mathrm{maxval}]. + +a@ +[source] +---- +geninteger clz (geninteger x) +---- + a@ Returns the number of leading 0-bits in x, starting + at the most significant bit position. If x is 0, + returns the size in bits of the type of x or component type of x, + if x is a vector type. + +a@ +[source] +---- +geninteger ctz (geninteger x) +---- + a@ Returns the count of trailing 0-bits in x. If x is 0, + returns the size in bits of the type of x or component type of x, + if x is a vector type. + +a@ +[source] +---- +geninteger mad_hi ( + geninteger a, geninteger b, geninteger c) +---- + a@ Returns [code]#pass:[mul_hi(a, b)+c]#. + +a@ +[source] +---- +geninteger mad_sat (geninteger a, + geninteger b, geninteger c) +---- + a@ Returns [code]#pass:[a * b + c]# and saturates the result. + +a@ +[source] +---- +geninteger max (geninteger x, geninteger y) +geninteger max (geninteger x, sgeninteger y) +---- + a@ Returns y if latexmath:[x < y], otherwise it returns x. + +a@ +[source] +---- +geninteger min (geninteger x, geninteger y) +geninteger min (geninteger x, sgeninteger y) +---- + a@ Returns y if latexmath:[y < x], otherwise it returns x. + +a@ +[source] +---- +geninteger mul_hi (geninteger x, geninteger y) +---- + a@ Computes [code]#x * y# and returns the high half of the + product of x and y. + +a@ +[source] +---- +geninteger rotate (geninteger v, geninteger i) +---- + a@ For each element in v, the bits are shifted left by + the number of bits given by the corresponding + element in i (subject to usual shift modulo rules + described in the OpenCL 1.2 specification + <>). Bits shifted off the left + side of the element are shifted back in from the + right. + +a@ +[source] +---- +geninteger sub_sat (geninteger x, geninteger y) +---- + a@ Returns latexmath:[x - y] and saturates the result. + +a@ +[source] +---- +ugeninteger16bit upsample (ugeninteger8bit hi, ugeninteger8bit lo) +---- + a@ [code]#result[i] = ((ushort)hi[i] << 8) | lo[i]# + +a@ +[source] +---- +igeninteger16bit upsample (igeninteger8bit hi, ugeninteger8bit lo) +---- + a@ [code]#result[i] = ((short)hi[i] << 8) | lo[i]# + +a@ +[source] +---- +ugeninteger32bit upsample (ugeninteger16bit hi, ugeninteger16bit lo) +---- + a@ [code]#result[i] = ((uint)hi[i] << 16) | lo[i]# + +a@ +[source] +---- +igeninteger32bit upsample (igeninteger16bit hi, ugeninteger16bit lo) +---- + a@ [code]#result[i] = ((int)hi[i] << 16) | lo[i]# + +a@ +[source] +---- +ugeninteger64bit upsample (ugeninteger32bit hi, ugeninteger32bit lo) +---- + a@ [code]#result[i] = ((ulonglong)hi[i] << 32) | lo[i]# + +a@ +[source] +---- +igeninteger64bit upsample (igeninteger32bit hi, ugeninteger32bit lo) +---- + a@ [code]#result[i] = ((longlong)hi[i] << 32) | lo[i]# + +a@ +[source] +---- +geninteger popcount (geninteger x) +---- + a@ Returns the number of non-zero bits in x. + +a@ +[source] +---- +geninteger32bit mad24 (geninteger32bit x, geninteger32bit y, geninteger32bit z) +---- + a@ Multiply two 24-bit integer values x and y and add + the 32-bit integer result to the 32-bit integer z. + Refer to definition of mul24 to see how the 24-bit + integer multiplication is performed. + +a@ +[source] +---- +geninteger32bit mul24 (geninteger32bit x, geninteger32bit y) +---- + a@ Multiply two 24-bit integer values x and y. x and y + are 32-bit integers but only the low 24-bits are used + to perform the multiplication. mul24 should only + be used when values in x and y are in the range + latexmath:[[-2^{23}, 2^{23}-1\]] if x and y are signed integers and in the + range latexmath:[[0, 2^{24}-1\]] if x and y are unsigned integers. If + x and y are not in this range, the multiplication + result is implementation-defined. + +|==== + + + +=== Common functions + +In SYCL the OpenCL [keyword]#common functions# are available in the +namespace [code]#sycl# on host and device as defined in the +OpenCL 1.2 specification document <>. They +are described here in <>. The built-in +functions can take as input [code]#float# or optionally +[code]#double# and their [code]#vec# and [code]#marray# counterparts. + + +[[table.common.functions]] +.Common functions which work on SYCL host and device, are available in the [code]#sycl# namespace. They correspond to <>. +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Common Function @ Description +a@ +[source] +---- +genfloat clamp (genfloat x, genfloat minval, genfloat maxval) +genfloatf clamp (genfloatf x, float minval, float maxval) +genfloatd clamp (genfloatd x, double minval, double maxval) +---- + a@ Returns fmin(fmax(x, minval), maxval). + Results are undefined if latexmath:[\mathrm{minval} > \mathrm{maxval}]. + +a@ +[source] +---- +genfloat degrees (genfloat radians) +---- + a@ Converts radians to degrees, + i.e. latexmath:[{180 \over \pi} \times radians]. + +a@ +[source] +---- +genfloat max (genfloat x, genfloat y) +genfloatf max (genfloatf x, float y) +genfloatd max (genfloatd x, double y) +---- + a@ Returns y if latexmath:[x < y], otherwise it returns x. If x or y + are infinite or NaN, the return values are undefined. + +a@ +[source] +---- +genfloat min (genfloat x, genfloat y) +genfloatf min (genfloatf x, float y) +genfloatd min (genfloatd x, double y) +---- + a@ Returns y if latexmath:[y < x], otherwise it returns x. If x or y + are infinite or NaN, the return values are undefined. + +a@ +[source] +---- +genfloat mix (genfloat x, genfloat y, genfloat a) +genfloatf mix (genfloatf x, genfloatf y, float a) +genfloatd mix (genfloatd x, genfloatd y, double a) +---- + a@ Returns the linear blend of x and y implemented as: + latexmath:[x + (y - x) \times a]. + _a_ must be a value in the range 0.0 ... 1.0. If _a_ is not + in the range 0.0 ... 1.0, the return values are + undefined. + +a@ +[source] +---- +genfloat radians (genfloat degrees) +---- + a@ Converts degrees to radians, i.e. latexmath:[(\pi / 180) \times degrees]. + +a@ +[source] +---- +genfloat step (genfloat edge, genfloat x) +genfloatf step (float edge, genfloatf x) +genfloatd step (double edge, genfloatd x) +---- + a@ Returns 0.0 if latexmath:[x < edge], otherwise it returns 1.0. + +a@ +[source] +---- +genfloat smoothstep (genfloat edge0, +genfloat edge1, genfloat x) +genfloatf smoothstep (float edge0, + float edge1, genfloatf x) +genfloatd smoothstep (double edge0, + double edge1, genfloatd x) +---- + a@ Returns 0.0 if latexmath:[x \leq edge0] and 1.0 if latexmath:[x \geq edge1] + and performs smooth Hermite interpolation between 0 + and 1 when latexmath:[edge0 < x < edge1]. This is useful in + cases where you would want a threshold function + with a smooth transition. + +This is equivalent to: + +[source] +---- +gentype t; +t = clamp ((x <= edge0) / (edge1 >= edge0), 0, 1); +return t * t * (3 - 2 * t); +---- + +Results are undefined if latexmath:[edge0 >= edge1] or if x, +edge0 or edge1 is a NaN. + +a@ +[source] +---- +genfloat sign (genfloat x) +---- + a@ Returns 1.0 if latexmath:[x > 0], -0.0 if latexmath:[x = -0.0], +0.0 if latexmath:[x =+0.0], or -1.0 + if latexmath:[x < 0]. Returns 0.0 if x is a NaN. + +|==== + + + +=== Geometric functions + +In SYCL the OpenCL [keyword]#geometric functions# are available in the +namespace [code]#sycl# on host and device as defined in the OpenCL 1.2 +specification document <>. The built-in functions +can take as input float or optionally double and their [code]#vec# and +[code]#marray# counterparts, for dimensions 2, 3 and 4. On the host the +vector types use the [code]#vec# class and on an SYCL device use the +corresponding native <> vector types. All of the geometric functions +use round-to-nearest-even rounding mode. +<> contains the definitions of supported +geometric functions. + + +[[table.geometric.functions]] +.Geometric functions which work on SYCL host and device, are available in the [code]#sycl# namespace. They correspond to <>. +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Geometric Function @ Description +a@ +[source] +---- +float4 cross (float4 p0, float4 p1) +float3 cross (float3 p0, float3 p1) +double4 cross (double4 p0, double4 p1) +double3 cross (double3 p0, double3 p1) +---- + a@ Returns the cross product of p0.xyz and p1.xyz. The + _w_ component of [code]#float4# result returned will be 0.0. + +a@ +[source] +---- +mfloat4 cross (mfloat4 p0, mfloat4 p1) +mfloat3 cross (mfloat3 p0, mfloat3 p1) +mdouble4 cross (mdouble4 p0, mdouble4 p1) +mdouble3 cross (mdouble3 p0, mdouble3 p1) +---- + a@ Returns the cross product of first 3 components of p0 and p1. The 4th component of result returned will be 0.0. + +a@ +[source] +---- +float dot (gengeofloat p0, gengeofloat p1) +double dot (gengeodouble p0, gengeodouble p1) +---- + a@ Compute dot product. + +a@ +[source] +---- +float distance (gengeofloat p0, gengeofloat p1) +double distance (gengeodouble p0, gengeodouble p1) +---- + a@ Returns the distance between p0 and p1. This is + calculated as [code]#length(p0 - p1)#. + +a@ +[source] +---- +float length (gengeofloat p) +double length (gengeodouble p) +---- + a@ Return the length of vector p, i.e., + latexmath:[\sqrt{ p.x^2 + p.y^2 + ...}] + +a@ +[source] +---- +gengeofloat normalize (gengeofloat p) +gengeodouble normalize (gengeodouble p) +---- + a@ Returns a vector in the same direction as p but with a + length of 1. + +a@ +[source] +---- +float fast_distance (gengeofloat p0, gengeofloat p1) +---- + a@ Returns [code]#fast_length(p0 - p1)#. + +a@ +[source] +---- +float fast_length (gengeofloat p) +---- + a@ Returns the length of vector p computed as: + [code]#pass:[sqrt((half)(pow(p.x,2) + pow(p.y,2) + ...))]# + +a@ +[source] +---- +gengeofloat fast_normalize (gengeofloat p) +---- + a@ Returns a vector in the same direction as p but with a + length of 1. fast_normalize is computed as: + +[code]#pass:[p*rsqrt((half)(pow(p.x,2) + pow(p.y,2) + ... ))]# + +The result shall be within 8192 ulps error from the +infinitely precise result of + +[source] +---- +if (all(p == 0.0f)) + result = p; +else + result = p/sqrt (pow(p.x,2) + pow(p.y,2) + ... ); +---- + +with the following exceptions: + +-- + . If the sum of squares is greater than [code]#FLT_MAX# then the + value of the floating-point values in the result vector are undefined. + . If the sum of squares is less than [code]#FLT_MIN# then the + implementation may return back p. + . If the device is in "`denorms are flushed to zero`" mode, individual + operand elements with magnitude less than [code]#sqrt(FLT_MIN)# may + be flushed to zero before proceeding with the calculation. +-- + +|==== + + + +=== Relational functions + +In SYCL the OpenCL [keyword]#relational functions# are available in the +namespace [code]#sycl# on host and device as defined in the +OpenCL 1.2 specification document <>. The +built-in functions can take as input [code]#char#, +[code]#unsigned char#, [code]#short#, +[code]#unsigned short#, [code]#int#, +[code]#unsigned int#, +[code]#long#, [code]#unsigned long#, [code]#float# or +optionally [code]#double# and their [code]#vec# and +[code]#marray# counterparts. The relational functions are +provided in addition to the operators. + +The available built-in functions for [code]#vec# template class are described in +<> + + +[[table.relational.functions.vec]] +.Relational functions for [code]#vec# template class which work on SYCL host and device, are available in the [code]#sycl# namespace. They correspond to <>. +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Relational Function @ Description +a@ +[source] +---- +igeninteger32bit isequal (genfloatf x, genfloatf y) +igeninteger64bit isequal (genfloatd x, genfloatd y) +---- + a@ Returns the component-wise compare of latexmath:[x == y]. + +a@ +[source] +---- +igeninteger32bit isnotequal (genfloatf x, genfloatf y) +igeninteger64bit isnotequal (genfloatd x, genfloatd y) +---- + a@ Returns the component-wise compare of latexmath:[x != y]. + +a@ +[source] +---- +igeninteger32bit isgreater (genfloatf x, genfloatf y) +igeninteger64bit isgreater (genfloatd x, genfloatd y) +---- + a@ Returns the component-wise compare of latexmath:[x > y]. + +a@ +[source] +---- +igeninteger32bit isgreaterequal (genfloatf x, genfloatf y) +igeninteger64bit isgreaterequal (genfloatd x, genfloatd y) +---- + a@ Returns the component-wise compare of latexmath:[x >= y]. + +a@ +[source] +---- +igeninteger32bit isless (genfloatf x, genfloatf y) +igeninteger64bit isless (genfloatd x, genfloatd y) +---- + a@ Returns the component-wise compare of latexmath:[x < y]. + +a@ +[source] +---- +igeninteger32bit islessequal (genfloatf x, genfloatf y) +igeninteger64bit islessequal (genfloatd x, genfloatd y) +---- + a@ Returns the component-wise compare of latexmath:[x <= y]. + +a@ +[source] +---- +igeninteger32bit islessgreater (genfloatf x, genfloatf y) +igeninteger64bit islessgreater (genfloatd x, genfloatd y) +---- + a@ Returns the component-wise compare of + latexmath:[(x < y) || (x > y)]. + +a@ +[source] +---- +igeninteger32bit isfinite (genfloatf x) +igeninteger64bit isfinite (genfloatd x) +---- + a@ Test for finite value. + +a@ +[source] +---- +igeninteger32bit isinf (genfloatf x) +igeninteger64bit isinf (genfloatd x) +---- + a@ Test for infinity value (positive or negative) . + +a@ +[source] +---- +igeninteger32bit isnan (genfloatf x) +igeninteger64bit isnan (genfloatd x) +---- + a@ Test for a NaN. + +a@ +[source] +---- +igeninteger32bit isnormal (genfloatf x) +igeninteger64bit isnormal (genfloatd x) +---- + a@ Test for a normal value. + +a@ +[source] +---- +igeninteger32bit isordered (genfloatf x, genfloatf y) +igeninteger64bit isordered (genfloatd x, genfloatd y) +---- + a@ Test if arguments are ordered. isordered() takes arguments x and y, and + returns the result [code]#isequal(x, x) && isequal(y, y)#. + +a@ +[source] +---- +igeninteger32bit isunordered (genfloatf x, genfloatf y) +igeninteger64bit isunordered (genfloatd x, genfloatd y) +---- + a@ Test if arguments are unordered. isunordered() + takes arguments x and y, returning non-zero if x or + y is NaN, and zero otherwise. + +a@ +[source] +---- +igeninteger32bit signbit (genfloatf x) +igeninteger64bit signbit (genfloatd x) +---- + a@ Test for sign bit. The scalar version of the + function returns a 1 if the sign bit in the float is set + else returns 0. + +The vector version of the function +returns the following for each component in [keyword]#floatn#: + +-1 (i.e all bits set) if the sign bit in the float is set +else returns 0. + +a@ +[source] +---- +int any (igeninteger x) +---- + a@ Returns 1 if the most significant bit in any + component of x is set; otherwise returns 0. + +a@ +[source] +---- +int all (igeninteger x) +---- + a@ Returns 1 if the most significant bit in all + components of x is set; otherwise returns 0. + +a@ +[source] +---- +gentype bitselect (gentype a, gentype b, gentype c) +---- + a@ Each bit of the result is the corresponding bit of a + if the corresponding bit of c is 0. Otherwise it is + the corresponding bit of b. + +a@ +[source] +---- +geninteger select (geninteger a, geninteger b, igeninteger c) +geninteger select (geninteger a, geninteger b, ugeninteger c) +genfloatf select (genfloatf a, genfloatf b, genint c) +genfloatf select (genfloatf a, genfloatf b, ugenint c) +genfloatd select (genfloatd a, genfloatd b, igeninteger64 c) +genfloatd select (genfloatd a, genfloatd b, ugeninteger64 c) +---- + a@ For each component of a vector type: + +[code]#result[i] = (MSB of c[i] is set) ? b[i] : a[i]#. + +For a scalar type: +[code]#result = c ? b : a#. + +[code]#geninteger# must have the same number of elements and bits as +[code]#gentype#. + +|==== + + +The available built-in functions for [code]#marray# template class are described in +<> + + +[[table.relational.functions.marray]] +.Relational functions for scalar data types and [code]#marray# template class template class which work on SYCL host and device, are available in the [code]#sycl# namespace. +[width="100%",options="header",separator="@",cols="65%,35%"] +|==== +@ Relational Function @ Description +a@ +[source] +---- +genbool isequal (genfloatf x, genfloatf y) +genbool isequal (genfloatd x, genfloatd y) +---- + a@ Returns the component-wise compare of latexmath:[x == y]. + +a@ +[source] +---- +genbool isnotequal (genfloatf x, genfloatf y) +genbool isnotequal (genfloatd x, genfloatd y) +---- + a@ Returns the component-wise compare of latexmath:[x != y]. + +a@ +[source] +---- +genbool isgreater (genfloatf x, genfloatf y) +genbool isgreater (genfloatd x, genfloatd y) +---- + a@ Returns the component-wise compare of latexmath:[x > y]. + +a@ +[source] +---- +genbool isgreaterequal (genfloatf x, genfloatf y) +genbool isgreaterequal (genfloatd x, genfloatd y) +---- + a@ Returns the component-wise compare of latexmath:[x >= y]. + +a@ +[source] +---- +genbool isless (genfloatf x, genfloatf y) +genbool isless (genfloatd x, genfloatd y) +---- + a@ Returns the component-wise compare of latexmath:[x < y]. + +a@ +[source] +---- +genbool islessequal (genfloatf x, genfloatf y) +genbool islessequal (genfloatd x, genfloatd y) +---- + a@ Returns the component-wise compare of latexmath:[x <= y]. + +a@ +[source] +---- +genbool islessgreater (genfloatf x, genfloatf y) +genbool islessgreater (genfloatd x, genfloatd y) +---- + a@ Returns the component-wise compare of + latexmath:[(x < y) || (x > y)]. + +a@ +[source] +---- +genbool isfinite (genfloatf x) +genbool isfinite (genfloatd x) +---- + a@ Test for finite value. + +a@ +[source] +---- +genbool isinf (genfloatf x) +genbool isinf (genfloatd x) +---- + a@ Test for infinity value (positive or negative) . + +a@ +[source] +---- +genbool isnan (genfloatf x) +genbool isnan (genfloatd x) +---- + a@ Test for a NaN. + +a@ +[source] +---- +genbool isnormal (genfloatf x) +genbool isnormal (genfloatd x) +---- + a@ Test for a normal value. + +a@ +[source] +---- +genbool isordered (genfloatf x, genfloatf y) +genbool isordered (genfloatd x, genfloatd y) +---- + a@ Test if arguments are ordered. isordered() takes arguments x and y, and + returns the result [code]#isequal(x, x) && isequal(y, y)#. + +a@ +[source] +---- +genbool isunordered (genfloatf x, genfloatf y) +genbool isunordered (genfloatd x, genfloatd y) +---- + a@ Test if arguments are unordered. isunordered() + takes arguments x and y, returning [code]#true# if x or + y is NaN, and [code]#false# otherwise. + +a@ +[source] +---- +genbool signbit (genfloatf x) +genbool signbit (genfloatd x) +---- + a@ Test for sign bit, returning [code]#true# if the sign bit + in the float is set, and [code]#false# otherwise. + +a@ +[source] +---- +bool any (genbool x) +---- + a@ Returns [code]#true# if the most significant bit in any component of x is set; otherwise returns [code]#false#. + +a@ +[source] +---- +int all (igeninteger x) +---- + a@ Returns [code]#true# if the most significant bit in all components of x is set; otherwise returns [code]#false#. + +a@ +[source] +---- +gentype bitselect (gentype a, gentype b, gentype c) +---- + a@ Each bit of the result is the corresponding bit of a + if the corresponding bit of c is 0. Otherwise it is + the corresponding bit of b. + +a@ +[source] +---- +gentype select (gentype a, gentype b, genbool c) +---- + a@ Returns the component-wise [code]#result = c ? b : a#. + +|==== + + +// %%%%%%%%%%%%%%%%%%%%%%%%%%%% end builtin_functions %%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +// %%%%%%%%%%%%%%%%%%%%%%%%%%%% end programming_interface %%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/adoc/chapters/references.adoc b/adoc/chapters/references.adoc new file mode 100644 index 00000000..750c3980 --- /dev/null +++ b/adoc/chapters/references.adoc @@ -0,0 +1,32 @@ +[appendix] +[[references]] += References + +[[cpp17]] International Organization for Standardization (ISO). +"`Programming Languages — {cpp}`". ISO/IEC 14882:2017, 2017. + +[[dr2325]] +International Organization for Standardization (ISO). +Accepted resolution to C++ Standard Core Language Defect Report DR2325. +http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p0593r6.html . + +[[openclext12]] +Khronos OpenCL Working Group. +_The OpenCL Extension Specification_, Version 1.2.25 (2/13/18). +http://www.khronos.org/registry/cl/specs/opencl-1.2-extensions.pdf . + +[[opencl12]] +Khronos OpenCL Working Group. +_The OpenCL Specification, Version 1.2.19_ (11/14/12). +https://www.khronos.org/registry/OpenCL/specs/opencl-1.2.pdf . + +[[opencl20]] +Khronos OpenCL Working Group. +_The OpenCL Specification, Version 2.0.29_ (July 21, 2015). +https://www.khronos.org/registry/OpenCL/specs/opencl-2.0.pdf . + +[[cpp20]] +International Organization for Standardization (ISO). +" Programming Languages — {cpp}, Langages de programmation +— C++ ", International Standard ISO/IEC 14882:2020(E), +Sixth edition 2020-12, 2020. diff --git a/adoc/chapters/what_changed.adoc b/adoc/chapters/what_changed.adoc new file mode 100644 index 00000000..23c3f77a --- /dev/null +++ b/adoc/chapters/what_changed.adoc @@ -0,0 +1,424 @@ +// %%%%%%%%%%%%%%%%%%%%%%%%%%%% begin what_changed %%%%%%%%%%%%%%%%%%%%%%%%%%%% + +[appendix] +[[cha:what-changed-from]] += What has changed from previous versions + + +[[sec:what-changed-between]] +== What has changed from SYCL 1.2.1 to SYCL 2020 + +The SYCL runtime moved from namespace [code]#cl::sycl# provided +by [code]#{hash}include # to namespace [code]#sycl# +provided by [code]#{hash}include # as explained in +<>. The old header file is still +available for compatibility with SYCL 1.2.1 applications. + +The SYCL specification is now based on the core language of {cpp17}, as +described in <>. Features of +{cpp17} are now enabled within the specification, such as deduction guides +for class template argument deduction. + +Naming of lambda functions passed to kernel invocations is now optional. + +Changes to buffers, images and accessors: + + * The [code]#image# class has been removed. There are now new classes + [code]#unsampled_image# and [code]#sampled_image# which represent sampled + and unsampled images. The [code]#sampler# class has been removed and + replaced with the new [code]#image_sampler# structure. + + * Support for image arrays has been removed. + + * The type name [code]#access::target# has been deprecated and replaced with + the type [code]#target#. + + * The type name [code]#access::mode# has been deprecated and replaced with + the type [code]#access_mode#. + + * The name of the [code]#accessor# target [code]#target::global_buffer# + has been deprecated and replaced with [code]#target::device#. + + * Support for the [code]#accessor# target [code]#target::host_buffer# has + been deprecated. There is now a new accessor class [code]#host_accessor# + which provides equivalent functionality. + + * The [code]#buffer# member functions which return an [code]#accessor# of + type [code]#target::host_buffer# have been deprecated. A new member + function [code]#get_host_access()# has been added which returns a + [code]#host_accessor#. + + * The [code]#buffer# class has a new variadic overload of the + [code]#get_access()# member function which allows construction of an + [code]#accessor# with various parameters. + + * Support for the [code]#accessor# target [code]#target::local# has been + deprecated. There is now a new accessor class [code]#local_accessor# which + provides equivalent functionality. + + * Support for the [code]#accessor# targets [code]#target::image# and + [code]#target::host_image# have been removed. There are now new accessor + classes for sampled and unsampled images: [code]#sampled_image_accessor#, + [code]#host_sampled_image_accessor#, [code]#unsampled_image_accessor# and + [code]#host_unsampled_image_accessor#. + + * A new [code]#accessor# target [code]#target::host_task# has been added, + which allows access to a [code]#buffer# from a <>. + + * Support for the [code]#accessor# modes [code]#access_mode::discard_write# + and [code]#access_mode::discard_read_write# has been deprecated. Accessors + can now be constructed with a property list, and the new property + [code]#property::no_init# provides equivalent functionality. + + * Support for the [code]#accessor# mode [code]#access_mode::atomic# and the + member functions that return an instance of the [code]#atomic# class have + been deprecated in favor of using the new [code]#atomic_ref# class instead. + + * Support for the [code]#accessor# template parameter [code]#isPlaceholder# + has been deprecated, and the value of this parameter no longer has any + bearing on whether the accessor is a placeholder. The enumerated type + [code]#access::placeholder# is also deprecated. A placeholder + accessor can now be constructed by calling the appropriate constructor, + without regard to the template parameter. + + * The return type of [code]#accessor::is_placeholder()# is no longer + [code]#constexpr#. + + * The member function [code]#handler::require()# may now be called on any + [code]#accessor# with target [code]#target::device#, + [code]#target::constant_buffer# or [code]#target::host_task#, regardless + of whether it is a placeholder. + + * New [code]#accessor# constructors have been added which take a type tag + parameter, which allows the class template parameters to be inferred via + {cpp} class template argument deduction (CTAD). + + * The [code]#buffer# member function [code]#get_access()# now has a default + value for the [code]#target# template parameter, so it is no longer + necessary to provide any template parameters in order to get a + [code]#access_mode::read_write# accessor. + + * The [code]#accessor# template parameters [code]#dimensions# and + [code]#accessMode# now have default values, so the only required template + parameter is [code]#dataT#. Moreover, the default access mode is either + [code]#access_mode::read_write# or [code]#access_mode::read#, + depending on the constness of the [code]#dataT# type. This makes it + possible to declare a read-only accessor by simply using a [code]#const# + qualified type. + + * Implicit conversions have been added between the two forms of read-only + [code]#accessor# (one form has [code]#const dataT# and + [code]#access_mode::read# and the other has non-const [code]#dataT# and + [code]#access_mode::read#). There is also an implicit conversion from + a read-write [code]#accessor# to either of the read-only forms. + + * Member functions of [code]#accessor# which return a reference to an + element have been changed to return a [code]#const# reference for + read-only accessors. The [code]#get_pointer()# member function has also + been changed to return a [code]#const# pointer for read-only accessors. + + * The [code]#accessor# member function [code]#get_pointer()# now returns + a raw pointer. The [code]#get_multi_ptr()# member function was introduced + which returns the [code]#multi_ptr# class to the appropriate space. + + * The [code]#accessor# class now meets the {cpp} requirement of + [code]#ReversibleContainer#. This includes (but is not limited to) + returning [code]#begin# and [code]#end# iterators, specifying a default + constructible accessor that can be passed to a kernel but not dereferenced, + and making them equality comparable. + + * Many of the [code]#accessor# member functions have been marked + [code]#noexcept#. + + * A <> is no longer allowed to read elements that are + outside of its range; attempting to do so produces undefined behavior. + + * The semantics of the subscript operator have been changed for a + <> which has an offset. Calling [code]#operator[](0)# now + returns a reference to the first element in the range, rather than a + reference to the first element in the underlying buffer. + +Constant memory no longer appears in the SYCL device memory model in SYCL 2020. + +Kernel attributes have been better described and are now applied +to the function type of a kernel function, which allows them to be +applied directly to lambdas. This means that propagation of the +attribute from a function to the calling kernel is no longer required, +and attributes are instead applied directly to the kernel function +that they impact. + +The list of built-in integer math functions was extended with +[code]#ctz()# in <>. +Specification of [code]#clz()# was extended with the case +of argument is 0. + +The classes [code]#vector_class#, [code]#string_class#, +[code]#function_class#, [code]#mutex_class#, +[code]#shared_ptr_class#, [code]#weak_ptr_class#, +[code]#hash_class# and [code]#exception_ptr_class# have been +removed from the API and the standard classes +[code]#std::vector#, [code]#std::string#, +[code]#std::function#, [code]#std::mutex#, +[code]#std::shared_ptr#, [code]#std::weak_ptr#, +[code]#std::hash# and [code]#std::exception_ptr# are used +instead. + +The specific [code]#sycl::buffer# API taking +[code]#std::unique_ptr# has been removed. The behavior is the +same as in SYCL 1.2.1 but with a simplified API. Since there is still +the API taking [code]#std::shared_ptr# and there is an implicit +conversion from a [code]#std::unique_ptr# prvalue to a +[code]#std::shared_ptr#, the API can still be used as before with +a [code]#std::unique_ptr# to give away memory ownership. + +Offsets to [code]#parallel_for#, [code]#nd_range#, [code]#nd_item# and [code]#item# classes have been deprecated. +As such, the parallel iteration spaces all begin at [code]#(0,0,0)# and developers are now required to handle any offset arithmetic themselves. +The behavior of [code]#nd_item.get_global_linear_id()# and [code]#nd_item.get_local_linear_id()# has been clarified accordingly. + +Unified Shared Memory (USM), in <>, has been added as a pointer-based strategy +for data management. It defines several types of allocations with various +accessibility rules for host and devices. USM is meant to complement +buffers, not replace them. + +The [code]#queue# class received a new [code]#property# +that requires in-order semantics for a queue where operations are +executed in the order in which they are submitted. + +The [code]#queue# class received several new member functions to +invoke kernels directly on a queue objects instead of inside a +command group handler in the [code]#submit# member function. + +The [code]#program# class has been removed and replaced with a new class +[code]#kernel_bundle#, which provides similar functionality in a type-safe and +thread-safe way. The [code]#kernel# class has changed, and some member +functions have been removed. + +Support has been added for <>, +which allow a <> to use constant variables whose values +aren't known until the kernel is invoked. A <> can now +take an optional parameter of type [code]#kernel_handler#, which allows the +kernel to read the values of +<>. + +The constructors for SYCL [code]#context# and [code]#queue# +are made [code]#explicit# to prevent ambiguities in the selected +constructor resulting from implicit type conversion. + +The requirement for {cpp} standard layout for data shared between host +and devices has been relaxed. SYCL now requires data shared between +host and devices to be <> as defined <>. + +The concept of a <> of <> was generalized to include +<> and <>. A <> is represented +by the [code]#sycl::group# class as in SYCL 1.2.1, and a <> +is represented by the new [code]#sycl::sub_group# class. + +The [code]#host_task# member function for the [code]#queue# has been +introduced for en-queueing <> on a <> to schedule the +<> to invoke native {cpp} functions, conforming to the SYCL memory +model. <> also support interoperability with the native +<> objects associated at that point in the DAG using +the optional [code]#interop_handle# class. + +A library of algorithms based on the {cpp17} algorithms library +was introduced in <>. These algorithms +provide a simple way for developers to apply common parallel algorithms +using the work-items of a group. + +The definition of the [code]#sycl::group# class was modified to +support the new group functions in <>. +New member types and variables were added to enable generic programming, and +member functions were updated to encapsulate all functionality tied to +<> in the [code]#sycl::group# class. See +<> for details. + +The [code]#barrier# and [code]#mem_fence# member functions of the +[code]#nd_item# class have been removed. The [code]#barrier# member +function has been replaced by the [code]#group_barrier()# function, which +can be used to synchronize either <> or <>. The +[code]#mem_fence# member function has been replaced by the +[code]#atomic_fence# function, which is more closely aligned with +[code]#std::atomic_thread_fence# and offers control over memory ordering +and scope. + +Changes in the SYCL [code]#vec# class described in +<>: + + * [code]#operator[]# was added; + * unary [code]#pass:[operator+()]# and [code]#operator-()# were added; + +The device selection now relies on a simpler API based on ranking +functions used as <> described in +<>. + +A new device selector utility has been added to <>, +the [code]#aspect_selector#, which returns a selector object +that only selects devices that have all the requested aspects. + +A new reduction library consisting of the [code]#reduction# function and +[code]#reducer# class was introduced to simplify the expression of variables +with <> semantics in SYCL kernels. See <>. + +The [code]#atomic# class from SYCL 1.2.1 was deprecated in favor of a new +[code]#atomic_ref# interface. + +The SYCL exception class hierarchy has been condensed into a single exception +type: [code]#exception#. +[code]#exception# now derives from +[code]#std::exception#. The variety of errors are now provided via error +codes, which aligns with the {cpp} error code mechanism. + +The new error code mechanism now also generalizes the previous +[code]#get_cl_code# interface to provide a generic interface way for +querying backend-specific error codes. + +Default asynchronous error handling behavior is now defined, so that asynchronous +errors will cause abnormal program termination even if a user-defined +asynchronous handler function is not defined. This prevents asynchronous errors +from being silently lost during early stages of application development. + +Kernel invocation functions, such as [code]#parallel_for#, now take +kernel functions by [code]#const# reference. Kernel functions must now have +a [code]#const#-qualified [code]#operator()#, and are allowed to be copied zero +or more times by an implementation. These clarifications allow implementations +to have flexibility for specific devices, and define what users should expect +with kernel functors. Specifically, kernel functors can not be marked as +[code]#mutable#, and sharing of data between work-items should not be +attempted through state stored within a kernel functor. + +A new concept called device <> has been added, which tells the set +of optional features a device supports. This new mechanism replaces the +[code]#has_extension()# function and some uses of [code]#get_info()#. + +There is a new <> which describes how extensions +to the SYCL language can be added by vendors and by the Khronos Group. + +A [code]#queue# constructor has been added that takes both a +[code]#device# and [code]#context#, to simplify interfacing +with libraries. + +The [code]#parallel_for# interface has been simplified in some forms +to accept a braced initializer list in place of a [code]#range#, and +to always take [code]#item# arguments. Kernel invocation functions have +also been modified to accept generic lambda expressions. Implicit conversions +from one-dimensional [code]#item# and one-dimensional [code]#id# to scalar types +have been defined. All of these modifications lead to simpler SYCL code in common +use cases. + +Some device-specific queries have been renamed to more clearly be "`device-specific +kernel`" [code]#get_info# queries ([code]#info::kernel_device_specific#) +instead of "`work-group`" ([code]#get_workgroup_info#) and sub-group +([code]#get_sub_group_info#) queries. + +A new math array type [code]#marray# has been defined to begin disambiguation +of the multiple possible interpretations of how [code]#sycl::vec# should be +interpreted and implemented. + +Changes in SYCL address spaces: + + * the address space meaning has been significantly improved; + * the generic address space was introduced; + * the constant address space was deprecated; + * behavior of unannotated pointer/reference (raw pointer/reference) is now + dependent on the compilation mode. The compiler can either interpret + unannotated pointer/reference has addressing the generic address space + or to be deduced; + * some ambiguities in the address space deduction were clarified. Notably + that deduced type does not affect the user-provided type. + +Changes in [code]#multi_ptr# interface: + + * addition of [code]#access::address_space::generic_space# to represent + the generic address space; + * deprecation of [code]#access::address_space::constant_space#; + * an extra template parameter to allow to select a flavor of the + [code]#multi_ptr# interface. There are now 3 different interfaces: + ** interface exposing undecorated types. Returned pointer and reference + are not annotated by an address space; + ** interface exposing decorated types. Returned pointer and reference are + annotated by an address space; + ** legacy 1.2.1 interface (deprecated). + * deprecation of the 1.2.1 interface; + * deprecation of [code]#constant_ptr#; + * [code]#global_ptr#, [code]#local_ptr# and + [code]#private_ptr# alias take the new extra parameter; + * addition of the [code]#address_space_cast# free function to cast + undecorated pointer to [code]#multi_pointer#; + * addition of construction/conversion operator for the generic address + space; + * removal of the constructor and assignment operator taking an unannotated + pointer; + * implicit conversion to a pointer is now deprecated. [code]#get# should + be used instead; + * the return type of the member function [code]#get# now depends on the + selected interface. + * addition of the member function [code]#get_raw# which returns the + underlying pointer as an unannotated pointer; + * addition of the member function [code]#get_decorated# which returns the + underlying pointer as an annotated pointer. + +The [code]#cl::sycl::byte# has been deprecated and now the {cpp17} +[code]#std::byte# should be used instead. + +A SYCL implementation is no longer required to provide a host device. +Instead, an implementation is only required to provide at least one +device. Implementations are still allowed to provide devices that are +implemented on the host, but it is no longer required. The specification +no longer defines any special semantics for a "host device" and APIs +specific to the host device have been removed. + +The default constructors for the [code]#device# and [code]#platform# classes +have been changed to construct a copy of the default device and a copy of the +platform containing the default device. Previously, they returned a copy of +the host device and a copy of the platform containing the host device. The +default constructor for the [code]#event# class has also been changed to +construct an event that comes from a default-constructed [code]#queue#. +Previously, it constructed an event that used the host backend. + +Explicit copy functions of the handler class +have also been introduced to the queue class as shortcuts for the handler ones. +This is enabled by the improved placeholder accessors +to help reduce code verbosity in certain cases +because the shortcut functions implicitly create a command group +and call [code]#handler::require#. + +Information query descriptors have been changed to structures under namespaces +named accordingly. [code]#param_traits# has been removed and the return type of +an information query is now contained in the descriptor. +The [code]#sycl::info::device::max_work_item_sizes# is now a +template that takes a dimension parameter corresponding to the number of +dimensions of the work-item size maxima. + +Changes to retrieving size information: + + * all [code]#get_size()# member functions have been deprecated + and replaced with [code]#byte_size()#, which is marked [code]#noexcept#; + * all [code]#get_count()# member functions have been deprecated + and replaced with [code]#size()#, which is marked [code]#noexcept#; + * in the [code]#vec# class the functions [code]#byte_size()# and [code]#size()# + are now static member functions; + * in the [code]#stream# class [code]#get_size()# has been deprecated + in favor of [code]#size()#, + whereas [code]#stream::byte_size()# is not available; + * accessors for sampled and unsampled images only define [code]#size()# + and not [code]#byte_size()#. + +The device descriptors [code]#info::device::max_constant_buffer_size# and +[code]#info::device::max_constant_args# are deprecated in SYCL 2020. + +The [code]#buffer_allocator# is now templated on the data type +and follows the C++ named requirement [code]#Allocator#. + +// Expose various workarounds showing how to typeset +, ++ and -- The +The SYCL [code]#id# and [code]#range# have now unary +pass:quotes[[code\]#+#] and [code]#-# operations, prefix +[code]#++# and [code]#--# operations, postfix +pass:quotes[[code\]#++#] and pass:quotes[[code\]#--#] operations which +were forgotten in SYCL 1.2.1. + +In SYCL 1.2.1, the [code]#handler::copy()# overload with two [code]#accessor# +parameters did not clearly specify which accessor's size determines the amount +of memory that is copied. The spec now clarifies that the [code]#src# +accessor's size is used. + +// %%%%%%%%%%%%%%%%%%%%%%%%%%%% end what_changed %%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/adoc/code/algorithms.cpp b/adoc/code/algorithms.cpp new file mode 100644 index 00000000..ddedb5a6 --- /dev/null +++ b/adoc/code/algorithms.cpp @@ -0,0 +1,35 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +buffer inputBuf { 1024 }; +buffer outputBuf { 2 }; +{ + // Initialize buffer on the host with 0, 1, 2, 3, ..., 1023 + host_accessor a { inputBuf }; + std::iota(a.begin(), a.end(), 0); +} + +myQueue.submit([&](handler & cgh) { + + accessor inputValues { inputBuf, cgh, read_only }; + accessor outputValues { outputBuf, cgh, write_only, no_init }; + + cgh.parallel_for(nd_range<1>(range<1>(16), range<1>(16)), + [=] (nd_item<1> it) { + + // Apply a group algorithm to any number of values, described by an iterator range + // The work-group reduces all inputValues and each work-item works on part of the range + int* first = inputValues.get_pointer(); + int* last = first + 1024; + int sum = joint_reduce(it.get_group(), first, last, plus<>()); + outputValues[0] = sum; + + // Apply a group algorithm to a set of values held directly by work-items + // The work-group reduces a number of values equal to the size of the group and each work-item provides one value + int partial_sum = reduce_over_group(it.get_group(), inputValues[it.get_linear_id()], plus<>()); + outputValues[1] = partial_sum; + + }); +}); + +assert(outputBuf.get_host_access()[0] == 523776 && outputBuf.get_host_access()[1] == 136); diff --git a/adoc/code/anatomy.cpp b/adoc/code/anatomy.cpp new file mode 100644 index 00000000..b891c382 --- /dev/null +++ b/adoc/code/anatomy.cpp @@ -0,0 +1,39 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +#include +#include +using namespace sycl; // (optional) avoids need for "sycl::" before SYCL names + +int main() { + int data[1024]; // Allocate data to be worked on + + // Create a default queue to enqueue work to the default device + queue myQueue; + + // By wrapping all the SYCL work in a {} block, we ensure + // all SYCL tasks must complete before exiting the block, + // because the destructor of resultBuf will wait + { + // Wrap our data variable in a buffer + buffer resultBuf { data, range<1> { 1024 } }; + + // Create a command group to issue commands to the queue + myQueue.submit([&](handler& cgh) { + // Request write access to the buffer without initialization + accessor writeResult { resultBuf, cgh, write_only, no_init }; + + // Enqueue a parallel_for task with 1024 work-items + cgh.parallel_for(1024, [=](id<1> idx) { + // Initialize each buffer element with its own rank number starting at 0 + writeResult[idx] = idx; + }); // End of the kernel function + }); // End of our commands for this queue + } // End of scope, so we wait for work producing resultBuf to complete + + // Print result + for (int i = 0; i < 1024; i++) + std::cout << "data[" << i << "] = " << data[i] << std::endl; + + return 0; +} diff --git a/adoc/code/aspectTraitExample.cpp b/adoc/code/aspectTraitExample.cpp new file mode 100644 index 00000000..fd3289e0 --- /dev/null +++ b/adoc/code/aspectTraitExample.cpp @@ -0,0 +1,33 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: MIT + +#include +using namespace sycl; // (optional) avoids need for "sycl::" before SYCL names + +constexpr int N = 512; + +template +class MyKernel { + public: + void operator()(id<1> i) { + if constexpr (hasFp16) { + // Algorithm using sycl::half type + } else { + // Fall back code for devices that don't support sycl::half + } + } +}; + +int main() { + queue myQueue; + myQueue.submit([&](handler& cgh) { + device dev = myQueue.get_device(); + if (dev.has(aspect::fp16)) { + cgh.parallel_for(range{N}, MyKernel>{}); + } else { + cgh.parallel_for(range{N}, MyKernel>{}); + } + }); + + myQueue.wait(); +} diff --git a/adoc/code/attributes.cpp b/adoc/code/attributes.cpp new file mode 100644 index 00000000..e25a6f3d --- /dev/null +++ b/adoc/code/attributes.cpp @@ -0,0 +1,19 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +// Kernel defined as a lambda +myQueue.submit([&](handler &h) { + h.parallel_for( range<1>(16), + [=] (item<1> it) [[sycl::reqd_work_group_size(16)]] { + //[kernel code] + }); +}); + +// Kernel defined as a functor to be invoked later +class KernelFunctor { + public: + void operator()(item<1> it) const [[sycl::reqd_work_group_size(16)]] { + //[kernel code] + }; +}; + diff --git a/adoc/code/basicParallelForGeneric.cpp b/adoc/code/basicParallelForGeneric.cpp new file mode 100755 index 00000000..d6d76327 --- /dev/null +++ b/adoc/code/basicParallelForGeneric.cpp @@ -0,0 +1,13 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +myQueue.submit([&](handler & cgh) { + auto acc = myBuffer.get_access(cgh); + + cgh.parallel_for(range<1>(numWorkItems), + [=] (auto item) { + // kernel argument type is auto treated as an item + size_t index = item.get_linear_id(); + acc[index] = index; + }); +}); diff --git a/adoc/code/basicParallelForIntegral.cpp b/adoc/code/basicParallelForIntegral.cpp new file mode 100755 index 00000000..7b638a75 --- /dev/null +++ b/adoc/code/basicParallelForIntegral.cpp @@ -0,0 +1,12 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +myQueue.submit([&](handler & cgh) { + auto acc = myBuffer.get_access(cgh); + + cgh.parallel_for(range<1>(numWorkItems), + [=] (size_t index) { + // kernel argument type is size_t + acc[index] = index; + }); +}); diff --git a/adoc/code/basicParallelForItem.cpp b/adoc/code/basicParallelForItem.cpp new file mode 100644 index 00000000..fb3cd176 --- /dev/null +++ b/adoc/code/basicParallelForItem.cpp @@ -0,0 +1,13 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +myQueue.submit([&](handler & cgh) { + accessor acc { myBuffer, cgh, write_only }; + + cgh.parallel_for(range<1>(numWorkItems), + [=] (item<1> item) { + // kernel argument type is item + size_t index = item.get_linear_id(); + acc[index] = index; + }); +}); diff --git a/adoc/code/basicParallelForNumber.cpp b/adoc/code/basicParallelForNumber.cpp new file mode 100755 index 00000000..ed62c0e5 --- /dev/null +++ b/adoc/code/basicParallelForNumber.cpp @@ -0,0 +1,13 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +myQueue.submit([&](handler & cgh) { + auto acc = myBuffer.get_access(cgh); + + // parallel_for may be called with number (with numWorkItems) + cgh.parallel_for(numWorkItems, + [=] (auto item) { + size_t index = item.get_linear_id(); + acc[index] = index; + }); +}); diff --git a/adoc/code/basicparallelfor.cpp b/adoc/code/basicparallelfor.cpp new file mode 100644 index 00000000..18f74caf --- /dev/null +++ b/adoc/code/basicparallelfor.cpp @@ -0,0 +1,11 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +myQueue.submit([&](handler & cgh) { + accessor acc { myBuffer, cgh, write_only }; + + cgh.parallel_for(range<1>(numWorkItems), + [=] (id<1> index) { + acc[index] = 42.0f; + }); +}); diff --git a/adoc/code/bundle-builtin-kernel.cpp b/adoc/code/bundle-builtin-kernel.cpp new file mode 100644 index 00000000..2faa44c6 --- /dev/null +++ b/adoc/code/bundle-builtin-kernel.cpp @@ -0,0 +1,33 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +#include +using namespace sycl; // (optional) avoids need for "sycl::" before SYCL names + +int main() { + queue myQueue; + auto myContext = myQueue.get_context(); + auto myDevice = myQueue.get_device(); + + const std::vector builtinKernelIds = + myDevice.get_info(); + + // Get an executable kernel_bundle containing all the built-in kernels + // supported by the device. + kernel_bundle myBundle = + get_kernel_bundle(myContext, {myDevice}, builtinKernelIds); + + // Retrieve a kernel object that can be used to query for more information + // about the built-in kernel or to submit it to a command group. We assume + // here that the device supports at least one built-in kernel. + kernel builtinKernel = myBundle.get_kernel(builtinKernelIds[0]); + + // Submit the built-in kernel. + myQueue.submit([&](handler &cgh) { + // Setting the arguments depends on the backend and the exact kernel used. + cgh.set_args(...); + cgh.parallel_for(range{1024}, builtinKernel); + }); + + myQueue.wait(); +} diff --git a/adoc/code/bundle-kernel-introspection.cpp b/adoc/code/bundle-kernel-introspection.cpp new file mode 100644 index 00000000..118e7771 --- /dev/null +++ b/adoc/code/bundle-kernel-introspection.cpp @@ -0,0 +1,41 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +#include +using namespace sycl; // (optional) avoids need for "sycl::" before SYCL names + +class MyKernel; // Forward declare the name of our kernel. + +int main() { + size_t N = 1024; + queue myQueue; + auto myContext = myQueue.get_context(); + auto myDev = myQueue.get_device(); + + // Get an executable kernel bundle containing our kernel. + kernel_id kernelId = get_kernel_id(); + auto myBundle = get_kernel_bundle(myContext, kernelId); + + // Get the kernel's maximum work group size when running on our device. + kernel myKernel = myBundle.get_kernel(kernelId); + size_t maxWgSize = myKernel.get_info(myDev); + + // Compute a good ND-range to use for iteration in the kernel + // based on the maximum work group size. + std::array divisors = {1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1}; + size_t wgSize = *std::find_if(divisors.begin(), divisors.end(), [=](auto d) { + return (d <= maxWgSize); + }); + nd_range myRange {range{N}, range{wgSize}}; + + myQueue.submit([&](handler& cgh) { + // Use the kernel bundle we queried, so we are sure the queried work-group + // size matches the kernel we run. + cgh.use_kernel_bundle(myBundle); + cgh.parallel_for(myRange, ([=](nd_item<1> index) { + // kernel code + })); + }); + + myQueue.wait(); +} diff --git a/adoc/code/bundle-pre-compile.cpp b/adoc/code/bundle-pre-compile.cpp new file mode 100644 index 00000000..651d09d3 --- /dev/null +++ b/adoc/code/bundle-pre-compile.cpp @@ -0,0 +1,27 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +#include +using namespace sycl; // (optional) avoids need for "sycl::" before SYCL names + +int main() { + queue myQueue; + auto myContext = myQueue.get_context(); + + // This call to get_kernel_bundle() forces an online compilation of all the + // application's kernels for the device in "myContext", unless those kernels + // were already compiled for that device by the ahead-of-time compiler. + auto myBundle = get_kernel_bundle(myContext); + + myQueue.submit([&](handler& cgh) { + // Calling use_kernel_bundle() causes the parallel_for() below to use the + // pre-compiled kernel from "myBundle". + cgh.use_kernel_bundle(myBundle); + + cgh.parallel_for(range{1024}, ([=](item index) { + // kernel code + })); + }); + + myQueue.wait(); +} diff --git a/adoc/code/bundle-spec-constants.cpp b/adoc/code/bundle-spec-constants.cpp new file mode 100644 index 00000000..df5b6f88 --- /dev/null +++ b/adoc/code/bundle-spec-constants.cpp @@ -0,0 +1,55 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +#include +using namespace sycl; // (optional) avoids need for "sycl::" before SYCL names + +// Forward declare names for our two kernels. +class MyKernel1; +class MyKernel2; + +extern int get_width(); +extern int get_height(); + +// Declare specialization constants used in our kernels. +specialization_id width; +specialization_id height; + +int main() { + queue myQueue; + auto myContext = myQueue.get_context(); + + // Get the identifiers for our kernels, then get an input kernel bundle that + // contains our two kernels. + auto kernelIds = {get_kernel_id(), get_kernel_id()}; + auto inputBundle = get_kernel_bundle(myContext, kernelIds); + + // Set the values of the specialization constants. + inputBundle.set_specialization_constant(get_width()); + inputBundle.set_specialization_constant(get_height()); + + // Build the kernel bundle into an executable form. The values of the + // specialization constants are compiled in. + auto exeBundle = build(inputBundle); + + myQueue.submit([&](handler& cgh) { + // Use the kernel bundle we built in this command group. + cgh.use_kernel_bundle(exeBundle); + cgh.parallel_for(range{1024}, ([=](item index, kernel_handler kh) { + // Read the value of the specialization constant. + int w = kh.get_specialization_constant(); + // ... + })); + }); + + myQueue.submit([&](handler& cgh) { + // This command group uses the same kernel bundle. + cgh.use_kernel_bundle(exeBundle); + cgh.parallel_for(range{1024}, ([=](item index, kernel_handler kh) { + int h = kh.get_specialization_constant(); + // ... + })); + }); + + myQueue.wait(); +} diff --git a/adoc/code/explicitcopy.cpp b/adoc/code/explicitcopy.cpp new file mode 100644 index 00000000..ffa8e32c --- /dev/null +++ b/adoc/code/explicitcopy.cpp @@ -0,0 +1,23 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +const size_t nElems = 10u; + +// Create a vector and fill it with values 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 +std::vector v { nElems }; +std::iota(std::begin(v), std::end(v), 0); + +// Create a buffer with no associated user storage +sycl::buffer b { range<1>(nElems) }; + +// Create a queue +queue myQueue; + +myQueue.submit([&](handler &cgh) { + // Retrieve a ranged write accessor to a global buffer with access to the + // first half of the buffer + accessor acc { b, cgh, range<1>(nElems / 2), id<1>(0), write_only }; + // Copy the first five elements of the vector into the buffer associated with + // the accessor + cgh.copy(v.data(), acc); +}); diff --git a/adoc/code/handlingBackendErrorCode.cpp b/adoc/code/handlingBackendErrorCode.cpp new file mode 100644 index 00000000..65f8f356 --- /dev/null +++ b/adoc/code/handlingBackendErrorCode.cpp @@ -0,0 +1,28 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +void catch_backend_errors(sycl::context const& ctx) { + try { + do_something_to_invoke_error(ctx); + } + catch(sycl::exception const& e) { + if(e.category() == sycl::error_category_for()) { + switch(e.code().value()) { + case CL_INVALID_PROGRAM: + std::cerr << "OpenCL invalid program error: " << e.what(); + /* ...*/ + } + else { + throw; + } + } + else { + if(e.code() == sycl::errc::invalid) { + std::cerr << "Invalid error: " << e.what(); + } + else { + throw; + } + } + } +} diff --git a/adoc/code/handlingErrorCode.cpp b/adoc/code/handlingErrorCode.cpp new file mode 100644 index 00000000..e21ebf29 --- /dev/null +++ b/adoc/code/handlingErrorCode.cpp @@ -0,0 +1,16 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +void catch_invalid_errors(sycl::context const& ctx) { + try { + do_something_to_invoke_error(ctx); + } + catch(sycl::exception const& e) { + if(e.code() == sycl::errc::invalid) { + std::cerr << "Invalid error: " << e.what(); + } + else { + throw; + } + } +} diff --git a/adoc/code/handlingException.cpp b/adoc/code/handlingException.cpp new file mode 100644 index 00000000..484ec6d6 --- /dev/null +++ b/adoc/code/handlingException.cpp @@ -0,0 +1,11 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +void catch_any_errors(sycl::context const& ctx) { + try { + do_something_to_invoke_error(ctx); + } + catch(sycl::exception const& e) { + std::cerr << e.what(); + } +} diff --git a/adoc/code/lambdaNameExamples.cpp b/adoc/code/lambdaNameExamples.cpp new file mode 100644 index 00000000..16f16988 --- /dev/null +++ b/adoc/code/lambdaNameExamples.cpp @@ -0,0 +1,57 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +// Explicit kernel names can be optionally forward declared at namespace scope +class MyForwardDeclName; + +template +class MyTemplatedKernelName; + +// Define and launch templated kernel +template +void templatedFunction() { + queue myQueue; + + // Launch A: No explicit kernel name + myQueue.submit([&](handler& h) { + h.single_task([=]{ + // [kernel code that depends on type T] + }); + }); + + // Launch B: Name the kernel when invoking (this is optional) + myQueue.submit([&](handler& h) { + h.single_task>([=]{ + // The provided kernel name (MyTemplatedKernelName) depends on T + // because the kernel does. T must also be forward declarable at + // namespace scope. + + // [kernel code that depends on type T] + }); + }); +} + +int main() { + queue myQueue; + + myQueue.submit([&](handler& h) { + // Declare MyKernel within this kernel invocation. Legal because + // forward declaration at namespace scope is optional + h.single_task([=]{ + // [kernel code] + }); + }); + + myQueue.submit([&](handler& h) { + // Use kernel name that was forward declared at namespace scope + h.single_task([=]{ + // [kernel code] + }); + }); + + templatedFunction(); // OK + + templatedFunction>(); // Launch A is OK, Launch B illegal + // because std::complex is not forward declarable according to C++, and was + // used in an explicit kernel name which must be forward declarable. +} diff --git a/adoc/code/largesample.cpp b/adoc/code/largesample.cpp new file mode 100644 index 00000000..d5a58507 --- /dev/null +++ b/adoc/code/largesample.cpp @@ -0,0 +1,80 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +#include +#include +using namespace sycl; // (optional) avoids need for "sycl::" before SYCL names + +// Size of the matrices +constexpr size_t N = 2000; +constexpr size_t M = 3000; + +int main() { + // Create a queue to work on + queue myQueue; + + // Create some 2D buffers of float for our matrices + buffer a { range<2>{N, M} }; + buffer b { range<2>{N, M} }; + buffer c { range<2>{N, M} }; + + // Launch an asynchronous kernel to initialize a + myQueue.submit([&](handler& cgh) { + // The kernel writes a, so get a write accessor on it + accessor A { a, cgh, write_only }; + + // Enqueue a parallel kernel iterating on a N*M 2D iteration space + cgh.parallel_for(range<2> {N, M}, [=](id<2> index) { + A[index] = index[0] * 2 + index[1]; + }); + }); + + // Launch an asynchronous kernel to initialize b + myQueue.submit([&](handler& cgh) { + // The kernel writes b, so get a write accessor on it + accessor B { b, cgh, write_only }; + + // From the access pattern above, the SYCL runtime detects that this + // command_group is independent from the first one and can be + // scheduled independently + + // Enqueue a parallel kernel iterating on a N*M 2D iteration space + cgh.parallel_for(range<2> {N, M}, [=](id<2> index) { + B[index] = index[0] * 2014 + index[1] * 42; + }); + }); + + // Launch an asynchronous kernel to compute matrix addition c = a + b + myQueue.submit([&](handler& cgh) { + // In the kernel a and b are read, but c is written + accessor A { a, cgh, read_only }; + accessor B { b, cgh, read_only }; + accessor C { c, cgh, write_only }; + + // From these accessors, the SYCL runtime will ensure that when + // this kernel is run, the kernels computing a and b have completed + + // Enqueue a parallel kernel iterating on a N*M 2D iteration space + cgh.parallel_for(range<2> {N, M}, [=](id<2> index) { + C[index] = A[index] + B[index]; + }); + }); + + // Ask for an accessor to read c from application scope. The SYCL runtime + // waits for c to be ready before returning from the constructor + host_accessor C { c, read_only }; + std::cout << std::endl << "Result:" << std::endl; + for (size_t i = 0; i < N; i++) { + for (size_t j = 0; j < M; j++) { + // Compare the result to the analytic value + if (C[i][j] != i * (2 + 2014) + j * (1 + 42)) { + std::cout << "Wrong value " << C[i][j] << " on element " << i << " " + << j << std::endl; + exit(-1); + } + } + } + + std::cout << "Good computation!" << std::endl; + return 0; +} diff --git a/adoc/code/myfunctor.cpp b/adoc/code/myfunctor.cpp new file mode 100644 index 00000000..c89dcf22 --- /dev/null +++ b/adoc/code/myfunctor.cpp @@ -0,0 +1,27 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +class RandomFiller { + public: + RandomFiller(accessor ptr) + : ptr_ { ptr } { + std::random_device hwRand; + std::uniform_int_distribution<> r { 1, 100 }; + randomNum_ = r(hwRand); + } + void operator()(item<1> item) const { ptr_[item.get_id()] = get_random(); } + int get_random() { return randomNum_; } + + private: + accessor ptr_; + int randomNum_; +}; + +void workFunction(buffer& b, queue& q, const range<1> r) { + myQueue.submit([&](handler& cgh) { + accessor ptr { buf, cgh }; + RandomFiller filler { ptr }; + + cgh.parallel_for(r, filler); + }); +} diff --git a/adoc/code/mykernel.cpp b/adoc/code/mykernel.cpp new file mode 100644 index 00000000..7c003bcf --- /dev/null +++ b/adoc/code/mykernel.cpp @@ -0,0 +1,20 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +// Explicit kernel names can be optionally forward declared at namespace scope +class MyKernel; + +myQueue.submit([&](handler& h) { + + // Explicitly name kernel with previously forward declared type + h.single_task([=]{ + // [kernel code] + }); + + // Explicitly name kernel without forward declaring type at + // namespace scope. Must still be forward declarable at + // namespace scope, even if not declared at that scope + h.single_task([=]{ + // [kernel code] + }); +}); diff --git a/adoc/code/parallelForWithKernelHandler.cpp b/adoc/code/parallelForWithKernelHandler.cpp new file mode 100644 index 00000000..ad410830 --- /dev/null +++ b/adoc/code/parallelForWithKernelHandler.cpp @@ -0,0 +1,20 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +myQueue.submit([&](handler & cgh) { + cgh.parallel_for( + range<3>(3,3,3), // global range + [=] (item<3> it, kernel_handler kh) { + //[kernel code] + }); +}); + +// This form of parallel_for with the "offset" parameter is deprecated in SYCL 2020 +myQueue.submit([&](handler & cgh) { + cgh.parallel_for( + range<3>(3,3,3), // global range + id<3>(1,1,1), // offset + [=] (item<3> it, kernel_handler kh) { + //[kernel code] + }); +}); diff --git a/adoc/code/parallelForWorkGroupWithKernelHandler.cpp b/adoc/code/parallelForWorkGroupWithKernelHandler.cpp new file mode 100644 index 00000000..d3af99c9 --- /dev/null +++ b/adoc/code/parallelForWorkGroupWithKernelHandler.cpp @@ -0,0 +1,33 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +myQueue.submit([&](handler & cgh) { + // Issue 8 work-groups of 8 work-items each + cgh.parallel_for_work_group( + range<3>(2, 2, 2), range<3>(2, 2, 2), [=](group<3> myGroup, + kernel_handler kh) { + + //[workgroup code] + int myLocal; // this variable is shared between workitems + // this variable will be instantiated for each work-item separately + private_memory myPrivate(myGroup); + + // Issue parallel work-items. The number issued per work-group is determined + // by the work-group size range of parallel_for_work_group. In this case, + // 8 work-items will execute the parallel_for_work_item body for each of the + // 8 work-groups, resulting in 64 executions globally/total. + myGroup.parallel_for_work_item([&](h_item<3> myItem) { + //[work-item code] + myPrivate(myItem) = 0; + }); + + // Implicit work-group barrier + + // Carry private value across loops + myGroup.parallel_for_work_item([&](h_item<3> myItem) { + //[work-item code] + output[myItem.get_global_id()] = myPrivate(myItem); + }); + //[workgroup code] + }); +}); diff --git a/adoc/code/parallelfor.cpp b/adoc/code/parallelfor.cpp new file mode 100644 index 00000000..5b547382 --- /dev/null +++ b/adoc/code/parallelfor.cpp @@ -0,0 +1,20 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +myQueue.submit([&](handler & cgh) { + cgh.parallel_for( + range<3>(3,3,3), // global range + [=] (item<3> it) { + //[kernel code] + }); +}); + +// This form of parallel_for with the "offset" parameter is deprecated in SYCL 2020 +myQueue.submit([&](handler & cgh) { + cgh.parallel_for( + range<3>(3,3,3), // global range + id<3>(1,1,1), // offset + [=] (item<3> it) { + //[kernel code] + }); +}); diff --git a/adoc/code/parallelforbarrier.cpp b/adoc/code/parallelforbarrier.cpp new file mode 100644 index 00000000..0ad33fa5 --- /dev/null +++ b/adoc/code/parallelforbarrier.cpp @@ -0,0 +1,12 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +myQueue.submit([&](handler & cgh) { + cgh.parallel_for( + nd_range<3>(range<3>(4, 4, 4), range<3>(2, 2, 2)), [=](nd_item<3> item) { + //[kernel code] + // Internal synchronization + group_barrier(item.get_group()); + //[kernel code] + }); +}); diff --git a/adoc/code/parallelforworkgroup.cpp b/adoc/code/parallelforworkgroup.cpp new file mode 100644 index 00000000..a3a27f9f --- /dev/null +++ b/adoc/code/parallelforworkgroup.cpp @@ -0,0 +1,32 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +myQueue.submit([&](handler & cgh) { + // Issue 8 work-groups of 8 work-items each + cgh.parallel_for_work_group( + range<3>(2, 2, 2), range<3>(2, 2, 2), [=](group<3> myGroup) { + + //[workgroup code] + int myLocal; // this variable is shared between workitems + // this variable will be instantiated for each work-item separately + private_memory myPrivate(myGroup); + + // Issue parallel work-items. The number issued per work-group is determined + // by the work-group size range of parallel_for_work_group. In this case, + // 8 work-items will execute the parallel_for_work_item body for each of the + // 8 work-groups, resulting in 64 executions globally/total. + myGroup.parallel_for_work_item([&](h_item<3> myItem) { + //[work-item code] + myPrivate(myItem) = 0; + }); + + // Implicit work-group barrier + + // Carry private value across loops + myGroup.parallel_for_work_item([&](h_item<3> myItem) { + //[work-item code] + output[myItem.get_global_id()] = myPrivate(myItem); + }); + //[workgroup code] + }); +}); diff --git a/adoc/code/parallelforworkgroup2.cpp b/adoc/code/parallelforworkgroup2.cpp new file mode 100644 index 00000000..6a512549 --- /dev/null +++ b/adoc/code/parallelforworkgroup2.cpp @@ -0,0 +1,27 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +myQueue.submit([&](handler & cgh) { + // Issue 8 work-groups. The work-group size is chosen by the runtime because unspecified + cgh.parallel_for_work_group( + range<3>(2, 2, 2), [=](group<3> myGroup) { + + // Launch a set of work-items for each work-group. The number of work-items is chosen + // by the runtime because the work-group size was not specified to parallel_for_work_group + // and a logical range is not specified to parallel_for_work_item. + myGroup.parallel_for_work_item([=](h_item<3> myItem) { + //[work-item code] + }); + + // Implicit work-group barrier + + // Launch 512 logical work-items that will be executed by the underlying work-group size + // chosen by the runtime. myItem allows the logical and physical work-item IDs to be + // queried. 512 logical work-items will execute for each work-group, and the parallel_for + // body will therefore be executed 8*512 = 4096 times globally/total. + myGroup.parallel_for_work_item(range<3>(8, 8, 8), [=](h_item<3> myItem) { + //[work-item code] + }); + //[workgroup code] + }); +}); diff --git a/adoc/code/propertyExample.cpp b/adoc/code/propertyExample.cpp new file mode 100644 index 00000000..6c8070b5 --- /dev/null +++ b/adoc/code/propertyExample.cpp @@ -0,0 +1,19 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +{ + context myContext; + + std::vector> bufferList { + buffer{ptr, rng}, + buffer{ptr, rng, property::use_host_ptr{}}, + buffer{ptr, rng, property::context_bound{myContext}} + }; + + for(auto& buf : bufferList) { + if (buf.has_property()) { + auto prop = buf.get_property(); + assert(myContext == prop.get_context()); + } + } +} diff --git a/adoc/code/queueShortcuts.cpp b/adoc/code/queueShortcuts.cpp new file mode 100644 index 00000000..b167d111 --- /dev/null +++ b/adoc/code/queueShortcuts.cpp @@ -0,0 +1,20 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +class MyKernel; + +auto usmPtr = malloc_device(1024); // USM pointer + +int* data = /* pointer to some data */; +buffer buf{data, 1024}; +accessor acc{buf}; // Placeholder accessor + +// Queue shortcut for a kernel invocation +myQueue.single_task([=] { + // Allowed to use USM pointers, + // not allowed to use accessors + usmPtr[0] = 0; +}); + +// Placeholder accessor will automatically be registered +myQueue.copy(data, acc); diff --git a/adoc/code/reduction.cpp b/adoc/code/reduction.cpp new file mode 100644 index 00000000..f30c50d7 --- /dev/null +++ b/adoc/code/reduction.cpp @@ -0,0 +1,42 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +buffer valuesBuf { 1024 }; +{ + // Initialize buffer on the host with 0, 1, 2, 3, ..., 1023 + host_accessor a { valuesBuf }; + std::iota(a.begin(), a.end(), 0); +} + +// Buffers with just 1 element to get the reduction results +int sumResult = 0; +buffer sumBuf { &sumResult, 1 }; +int maxResult = 0; +buffer maxBuf { &maxResult, 1 }; + +myQueue.submit([&](handler& cgh) { + + // Input values to reductions are standard accessors + auto inputValues = valuesBuf.get_access(cgh); + + // Create temporary objects describing variables with reduction semantics + auto sumReduction = reduction(sumBuf, cgh, plus<>()); + auto maxReduction = reduction(maxBuf, cgh, maximum<>()); + + // parallel_for performs two reduction operations + // For each reduction variable, the implementation: + // - Creates a corresponding reducer + // - Passes a reference to the reducer to the lambda as a parameter + cgh.parallel_for(range<1>{1024}, + sumReduction, maxReduction, + [=](id<1> idx, auto& sum, auto& max) { + // plus<>() corresponds to += operator, so sum can be updated via += or combine() + sum += inputValues[idx]; + + // maximum<>() has no shorthand operator, so max can only be updated via combine() + max.combine(inputValues[idx]); + }); +}); + +// sumBuf and maxBuf contain the reduction results once the kernel completes +assert(maxBuf.get_host_access()[0] == 1023 && sumBuf.get_host_access()[0] == 523776); diff --git a/adoc/code/requires.cpp b/adoc/code/requires.cpp new file mode 100644 index 00000000..8d3b4c2d --- /dev/null +++ b/adoc/code/requires.cpp @@ -0,0 +1,30 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +class KernelFunctor { + public: + void operator()(item<1> it) const [[sycl::requires(has(aspect::fp16))]] { + foo(); + bar(); + }; + + private: + void foo() const { + half fp = 1.0; // No compiler diagnostic here + } + + void bar() const { + sycl::atomic_ref longAtomic(longValue); + longAtomic.fetchAdd(1); // ERROR: Compiler issues diagnostic because + // "aspect::atomic64" missing from "has()" + } +}; + +// Using "sycl::requires()" does not provide any guarantee that the device +// actually supports the required features. Therefore, the host code should +// still check the devices aspects before submitting the kernel. +if (myQueue.get_device().has(aspect::fp16)) { + myQueue.submit([&](handler &h) { + h.parallel_for(range{16}, KernelFunctor{}); + }); +} diff --git a/adoc/code/singleTaskWithKernelHandler.cpp b/adoc/code/singleTaskWithKernelHandler.cpp new file mode 100644 index 00000000..c1ea772c --- /dev/null +++ b/adoc/code/singleTaskWithKernelHandler.cpp @@ -0,0 +1,9 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +myQueue.submit([&](handler & cgh) { +cgh.single_task( + [=] (kernel_handler kh) { + // [kernel code] + })); +}); diff --git a/adoc/code/singletask.cpp b/adoc/code/singletask.cpp new file mode 100644 index 00000000..f007ba44 --- /dev/null +++ b/adoc/code/singletask.cpp @@ -0,0 +1,9 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +myQueue.submit([&](handler & cgh) { +cgh.single_task( + [=] () { + // [kernel code] + })); +}); diff --git a/adoc/code/subbuffer.cpp b/adoc/code/subbuffer.cpp new file mode 100644 index 00000000..08752c4a --- /dev/null +++ b/adoc/code/subbuffer.cpp @@ -0,0 +1,16 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +buffer parent_buffer { range<2>{ 8,8 } }; // Create 2-d buffer with 8x8 ints + +// OK: Contiguous region from middle of buffer +buffer sub_buf1 { parent_buffer, /*offset*/ range<2>{ 2,0 }, /*size*/ range<2>{ 2,8 } }; + +// invalid exception: Non-contiguous regions of 2-d buffer +buffer sub_buf2 { parent_buffer, /*offset*/ range<2>{ 2,0 }, /*size*/ range<2>{ 2,2 } }; +buffer sub_buf3 { parent_buffer, /*offset*/ range<2>{ 2,2 }, /*size*/ range<2>{ 2,6 } }; + +// invalid exception: Out-of-bounds size +buffer sub_buf4 { parent_buffer, /*offset*/ range<2>{ 2,2 }, /*size*/ range<2>{ 2,8 } }; + + diff --git a/adoc/code/twoOptionalFeatures.cpp b/adoc/code/twoOptionalFeatures.cpp new file mode 100644 index 00000000..bb2df277 --- /dev/null +++ b/adoc/code/twoOptionalFeatures.cpp @@ -0,0 +1,23 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +queue q1(dev1); +if (dev1.has(aspect::fp16)) { + q1.submit([&](handler &cgh) { + cgh.parallel_for(range{N}, [=](id i) { + half fpShort = 1.0; + /* ... */ + }); + }); +} + +queue q2(dev2); +if (dev2.has(aspect::atomic64)) { + q2.submit([&](handler &cgh) { + cgh.parallel_for(range{N}, [=](id i) { + /* ... */ + sycl::atomic_ref longAtomic(longValue); + longAtomic.fetch_add(1); + }); + }); +} diff --git a/adoc/code/usingSpecConstants.cpp b/adoc/code/usingSpecConstants.cpp new file mode 100644 index 00000000..ec3247d3 --- /dev/null +++ b/adoc/code/usingSpecConstants.cpp @@ -0,0 +1,47 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +#include +using namespace sycl; // (optional) avoids need for "sycl::" before SYCL names + +using coeff_t = std::array, 3>; + +// Read coefficients from somewhere. +coeff_t get_coefficients(); + +// Identify the specialization constant. +specialization_id coeff_id; + +void do_conv(buffer in, buffer out) { + queue myQueue; + + myQueue.submit([&](handler &cgh) { + accessor in_acc { in, cgh, read_only }; + accessor out_acc { out, cgh, write_only }; + + // Set the coefficient of the convolution as constant. + // This will build a specific kernel the coefficient available as literals. + cgh.set_specialization_constant(get_coefficients()); + + cgh.parallel_for( + in.get_range(), [=](item<2> item_id, kernel_handler h) { + float acc = 0; + coeff_t coeff = h.get_specialization_constant(); + for (int i = -1; i <= 1; i++) { + if (item_id[0] + i < 0 || item_id[0] + i >= in_acc.get_range()[0]) + continue; + for (int j = -1; j <= 1; j++) { + if (item_id[1] + j < 0 || item_id[1] + j >= in_acc.get_range()[1]) + continue; + // The underlying JIT can see all the values of the array returned + // by coeff.get(). + acc += coeff[i + 1][j + 1] * + in_acc[item_id[0] + i][item_id[1] + j]; + } + } + out_acc[item_id] = acc; + }); + }); + + myQueue.wait(); +} diff --git a/adoc/code/usm_device.cpp b/adoc/code/usm_device.cpp new file mode 100644 index 00000000..c7fae9c4 --- /dev/null +++ b/adoc/code/usm_device.cpp @@ -0,0 +1,35 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +#include +#include +using namespace sycl; // (optional) avoids need for "sycl::" before SYCL names + +int main() { + // Create a default queue to enqueue work to the default device + queue myQueue; + + // Allocate shared memory bound to the device and context associated to the queue + int *data = sycl::malloc_device(1024, myQueue); + + myQueue.parallel_for(1024, [=](id<1> idx) { + // Initialize each buffer element with its own rank number starting at 0 + data[idx] = idx; + }); // End of the kernel function + + // Explicitly wait for kernel execution since there is no accessor involved + myQueue.wait(); + + // Create an array to receive the device content + int hostData[1024]; + // Receive the content from the device + myQueue.memcpy(hostData, data, 1024*sizeof(int)); + // Wait for the copy to complete + myQueue.wait(); + + // Print result + for (int i = 0; i < 1024; i++) + std::cout <<"hostData["<< i << "] = " << hostData[i] << std::endl; + + return 0; +} diff --git a/adoc/code/usm_shared.cpp b/adoc/code/usm_shared.cpp new file mode 100644 index 00000000..9d9928e9 --- /dev/null +++ b/adoc/code/usm_shared.cpp @@ -0,0 +1,30 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +#include +#include +using namespace sycl; // (optional) avoids need for "sycl::" before SYCL names + +int main() { + // Create a default queue to enqueue work to the default device + queue myQueue; + + // Allocate shared memory bound to the device and context associated to the queue + // Replacing malloc_shared with malloc_host would yield a correct program that + // allocated device-visible memory on the host. + int *data = sycl::malloc_shared(1024, myQueue); + + myQueue.parallel_for(1024, [=](id<1> idx) { + // Initialize each buffer element with its own rank number starting at 0 + data[idx] = idx; + }); // End of the kernel function + + // Explicitly wait for kernel execution since there is no accessor involved + myQueue.wait(); + + // Print result + for (int i = 0; i < 1024; i++) + std::cout <<"data["<< i << "] = " << data[i] << std::endl; + + return 0; +} diff --git a/adoc/config/README.md b/adoc/config/README.md new file mode 100644 index 00000000..073bad06 --- /dev/null +++ b/adoc/config/README.md @@ -0,0 +1,30 @@ +# Vulkan Asciidoc Configuration Files + +## Macros + +The macros in `spec-macros.rb` and `spec-macros/extension.rb` are +described in the "Vulkan Documentation and Extensions: Procedures and +Conventions" document (see the [styleguide](../styleguide.txt)). + +## Support for Math + +Asciidoctor is customized to insert KaTeX ` +' + + output.sub! /(?=<\/head>)/, loaded_script + output.sub! /(
$ERRFILE + +status=$? +if test $status -ne 0 ; then + echo "$0: $GS return status = $status, aborting" +elif grep -q Error $ERRFILE ; then + echo "$0: $GS succeeded but found Error in $ERRFILE (follows), aborting" + echo '---------- Errors from $GS ----------' + grep Error $ERRFILE + echo '-------------------------------------' + status=1 +else + rm -f $ERRFILE +fi + +exit $status diff --git a/adoc/config/rouge/lib/rouge/lexers/sycl.rb b/adoc/config/rouge/lib/rouge/lexers/sycl.rb new file mode 100644 index 00000000..3cc365a3 --- /dev/null +++ b/adoc/config/rouge/lib/rouge/lexers/sycl.rb @@ -0,0 +1,464 @@ +# -*- coding: utf-8 -*- # +# frozen_string_literal: true + +module Rouge + module Lexers + load_lexer 'cpp.rb' + + class Sycl < Cpp + title "SYCL" + desc "The standard SYCL C++ for heterogeneous computing from Khronos Group" + + tag 'sycl' + + sycl_data_types = %w( + char2 char3 char4 char8 char16 + double2 double3 double4 double8 double16 + float2 float3 float4 float8 float16 + half half2 half3 half4 half8 half16 + int2 int3 int4 int8 int16 + long2 long3 long4 long8 long16 + longlong2 longlong3 longlong4 longlong8 longlong16 + schar2 schar3 schar4 schar8 schar16 + short2 short3 short4 short8 short16 + uchar2 uchar3 uchar4 uchar8 uchar16 + uint2 uint3 uint4 uint8 uint16 + ulong2 ulong3 ulong4 ulong8 ulong16 + ulonglong2 ulonglong3 ulonglong4 ulonglong8 ulonglong16 + ushort2 ushort3 ushort4 ushort8 ushort16 + ) + + # Split member functions from free functions? + sycl_functions = %w( + aligned_alloc + aligned_alloc_device + aligned_alloc_host + aligned_alloc_shared + all_of + any_of + aspect_selector + barrier + byte_size + copy + create_sub_devices + depends_on + exclusive_scan + fill + free + get + get_access + get_allocator + get_backend + get_backend_info + get_context + get_count + get_device + get_devices + get_host_access + get_info + get_native + get_native_context + get_native_device + get_native_mem + get_native_queue + get_platform + get_platforms + get_pointer_device + get_pointer_type + get_profiling_info + get_property + get_size + get_wait_list + group_all_of + group_any_of + group_barrier + group_broadcast + group_exclusive_scan + group_inclusive_scan + group_none_of + group_reduce + has + has_extension + has_property + host_task + inclusive_scan + is_cpu + is_gpu + is_accelerator + is_in_order + is_sub_buffer + make_buffer + make_context + make_device + make_event + make_image_sampler + make_kernel + make_kernel_bundle + make_platform + make_queue + make_sampled_image + make_sampler + make_stream + make_unsampled_image + malloc + malloc_device + malloc_host + malloc_shared + mem_advise + memcpy + memset + none_of + parallel_for + parallel_for_work_group + parallel_for_work_item + param_traits + prefetch + reduce + reinterpret + set_final_data + set_write_back + single_task + submit + throw_asynchronous + update_host + wait + wait_and_throw + ) + + # Generic types used in SYCL pseudo code descriptions like Gen, + # SGen, GenVec... + sycl_generic_types = %w( + charn + doublen + floatn + genchar + genfloat + genfloatd + genfloatf + genfloath + genfloatptr + gengeodouble + gengeofloat + genhalf + genint + geninteger + geninteger16bit + geninteger32bit + geninteger64bit + geninteger8bit + genintegerNbit + genintptr + genlong + genlonglong + genshort + gentype + genvector + halfn + igenchar + igeninteger + igeninteger16bit + igeninteger32bit + igeninteger64bit + igeninteger8bit + igenintegerNbit + igenlonginteger + intn + longlongn + longn + scharn + sgenfloat + sgeninteger + shortn + ucharn + ugenchar + ugenint + ugeninteger + ugeninteger16bit + ugeninteger32bit + ugeninteger64bit + ugeninteger8bit + ugenintegerNbit + ugenlong + ugenlonginteger + ugenlonglong + ugenshort + uintn + ulonglongn + ulongn + ushortn + ) + + sycl_macros = %w( + SYCL_EXTERNAL + ) + + sycl_namespaces = %w( + info + event_profiling + kernel_device_specific + property + sycl + ) + + # Types, namespace and attributes used by the SYCL OpenCL backend + sycl_opencl_keywords = %w( + __kernel + __read_only + __read_write + __write_only + cl + cl_bool + cl_char + cl_char16 + cl_char2 + cl_char3 + cl_char4 + cl_char8 + cl_command_queue + cl_context + cl_device_id + cl_double + cl_double16 + cl_double2 + cl_double3 + cl_double4 + cl_double8 + cl_event + cl_exception + cl_float + cl_float16 + cl_float2 + cl_float3 + cl_float4 + cl_float8 + cl_half + cl_half16 + cl_half2 + cl_half3 + cl_half4 + cl_half8 + cl_int + cl_int16 + cl_int2 + cl_int3 + cl_int4 + cl_int8 + cl_kernel + cl_long + cl_long16 + cl_long2 + cl_long3 + cl_long4 + cl_long8 + cl_mem + cl_pipe + cl_platform_id + cl_program + cl_sampler + cl_short + cl_short16 + cl_short2 + cl_short3 + cl_short4 + cl_short8 + cl_uchar + cl_uchar16 + cl_uchar2 + cl_uchar3 + cl_uchar4 + cl_uchar8 + cl_uint + cl_uint16 + cl_uint2 + cl_uint3 + cl_uint4 + cl_uint8 + cl_ulong + cl_ulong16 + cl_ulong2 + cl_ulong4 + cl_ulong8 + cl_ushort + cl_ushort16 + cl_ushort2 + cl_ushort3 + cl_ushort4 + cl_ushort8 + event_t + ) + + sycl_types = %w( + accelerator_selector + access + access_mode + accessor + all_devices_have + any_device_has + aspect + async_exception + async_handler + atomic_ref + backend + backend_input_t + backend_return_t + backend_traits + bit_and + bit_or + bit_xor + buffer + buffer_allocator + constant_ptr + context + context_bound + cpu_selector + decorated_constant_ptr + decorated_global_ptr + decorated_local_ptr + decorated_private_ptr + default_selector + device + device_event + device_type + event + event_command_status + exception + exception_list + executable + generic_ptr + global_ptr + gpu_selector + group + h_item + handler + host_accessor + host_selector + id + image_allocator + image_sampler + input + interop_handle + is_property + is_property_of + item + kernel + kernel_bundle + local_mem_type + local_ptr + logical_and + logical_or + marray + maximum + memory_order + memory_scope + minimum + mode + multi_ptr + multiplies + nd_item + nd_range + object + partition_affinity_domain + partition_property + platform + plus + private_memory + private_ptr + property_list + queue + range + raw_constant_ptr + raw_generic_ptr + raw_global_ptr + raw_local_ptr + raw_private_ptr + reducer + reduction + sampled_image + specialization_id + stream + sub_group + target + unsampled_image + use_host_ptr + use_mutex + usm_allocator + vec + ) + + # SYCL pre-defined variables and tags + sycl_variables = %w( + accelerator_selector_v + all_devices_have_v + any_device_has_v + cpu_selector_v + default_selector_v + gpu_selector_v + host_selector_v + is_property_of_v + is_property_v + memory_order_acq_rel + memory_order_acquire + memory_order_relaxed + memory_order_release + memory_order_seq_cst + memory_scope_device + memory_scope_sub_group + memory_scope_system + memory_scope_work_group + memory_scope_work_item + no_init + read_only + write_only + ) + + # Here are some interesting tokens + # https://pygments.org/docs/tokens/ unused in C++ we can reuse + # in SYCL mode: + # Comment::Preproc + # Keyword.Pseudo + # Keyword.Reserved + # Literal::String::Regex + # Literal::String::Symbol + # Name::Attribute + # Name.Builtin.Pseudo + # Name.Function.Magic + # Name.Other + # Name.Variable.Magic + # Operator.Word + # Generic + # Generic.Deleted + # Generic.Emph + # Generic.Error + # Generic.Heading + # Generic.Inserted + # Generic.Output + # Generic.Prompt + # Generic.Strong + # Generic.Subheading + # Generic.Traceback + + + # Insert some specific rules at the beginning of the statement + # rule of the C++ lexer + prepend :statements do + rule %r/(?:#{sycl_data_types.join('|')})\b/, + Keyword::Pseudo + rule %r/(?:#{sycl_functions.join('|')})\b/, + Name::Function::Magic + rule %r/(?:#{sycl_generic_types.join('|')})\b/, + Name::Builtin::Pseudo + rule %r/(?:#{sycl_macros.join('|')})\b/, + Generic::Output + rule %r/(?:#{sycl_namespaces.join('|')})\b/, + Generic::Heading + rule %r/(?:#{sycl_opencl_keywords.join('|')})\b/, + Name::Other + rule %r/(?:#{sycl_types.join('|')})\b/, + Keyword::Reserved + rule %r/(?:#{sycl_variables.join('|')})\b/, + Name::Variable::Magic + end + + end + end +end diff --git a/adoc/config/rouge/lib/rouge/themes/sycl_spec.rb b/adoc/config/rouge/lib/rouge/themes/sycl_spec.rb new file mode 100644 index 00000000..7e4862e4 --- /dev/null +++ b/adoc/config/rouge/lib/rouge/themes/sycl_spec.rb @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- # +# frozen_string_literal: true + +# The SYCL theme used by Khronos in the SYCL specification + +module Rouge + module Themes + class SYCLspec < Github + name 'sycl.spec' + + # Use mostly :bold versions to be clearer and because :italic + # does not work with asciidoctor-pdf + + # sycl_data_types DarkOrchid3 #9a32cd + style Keyword::Pseudo, :fg => '#9a32cd', :italic => true + # sycl_functions #00c5cd Turquoise 3 + style Name::Function::Magic, :fg => '#00c5cd', :bold => true + # sycl_generic_types magenta #ff00ff + style Name::Builtin::Pseudo, :fg => '#ff00ff', :italic => true + # sycl_macros OliveDrab2 #b3ee3a + style Generic::Output, :fg => '#b3ee3a', :bold => true + # sycl_namespaces use official SYCL orange defined by Khronos #f35a1c + style Generic::Heading, :fg => '#f35a1c', :bold => true + # sycl_opencl_keywords + style Name::Other, :fg => '#ff4500', :italic => true + # sycl_types VioletRed1 #ff3e96 + style Keyword::Reserved, :fg => '#ff3e96', :bold => true + # sycl_variables orange1 #ffa500 + style Name::Variable::Magic, :fg => '#ffa500', :bold => true + # Fix the gray comment which is not as visible as YellowGreen #9acd32 + style Comment, :fg => '#9acd32' + style Comment::Multiline, :fg => '#9acd32' + style Comment::Single, :fg => '#9acd32' + # Use a clearer white background + style Text, :bg => '#ffffff' + + end + end +end diff --git a/adoc/config/rouge_sycl.rb b/adoc/config/rouge_sycl.rb new file mode 100644 index 00000000..b83cbf70 --- /dev/null +++ b/adoc/config/rouge_sycl.rb @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- # +# frozen_string_literal: true +# Copyright (c) 2011-2021 The Khronos Group, Inc. +# SPDX-License-Identifier: Apache-2.0 + +puts "Loading rouge_sycl extensions for source code highlighting" + +require 'rouge' + +RUBY_ENGINE == 'opal' ? (require 'rouge/lib/rouge/lexers/sycl' ; + require 'rouge/lib/rouge/themes/sycl_spec') \ + : (require_relative 'rouge/lib/rouge/lexers/sycl' ; + require_relative 'rouge/lib/rouge/themes/sycl_spec') diff --git a/adoc/config/spec-macros.rb b/adoc/config/spec-macros.rb new file mode 100644 index 00000000..83e35643 --- /dev/null +++ b/adoc/config/spec-macros.rb @@ -0,0 +1,13 @@ +# Copyright (c) 2011-2021 The Khronos Group, Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +#require 'asciidoctor/extensions' unless RUBY_ENGINE == 'opal' +RUBY_ENGINE == 'opal' ? (require 'spec-macros/extension') : (require_relative 'spec-macros/extension') + +# All the inline macros we need +Asciidoctor::Extensions.register do + inline_macro MustInlineMacro + inline_macro ReflinkInlineMacro + inline_macro CodeInlineMacro +end diff --git a/adoc/config/spec-macros/extension.rb b/adoc/config/spec-macros/extension.rb new file mode 100644 index 00000000..dea8d2d6 --- /dev/null +++ b/adoc/config/spec-macros/extension.rb @@ -0,0 +1,73 @@ +# Copyright (c) 2011-2021 The Khronos Group, Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +require 'asciidoctor/extensions' unless RUBY_ENGINE == 'opal' + +include ::Asciidoctor + +class SpecInlineMacroBase < Extensions::InlineMacroProcessor + use_dsl + using_format :short +end + +class NormativeInlineMacroBase < SpecInlineMacroBase + def text + 'normative' + end + + def process parent, target, attributes + create_inline parent, :quoted, '' + text + '' + end +end + +class LinkInlineMacroBase < SpecInlineMacroBase + def process parent, target, attributes + if parent.document.attributes['cross-file-links'] + return Inline.new(parent, :anchor, target, :type => :link, :target => (target + '.html')) + else + return Inline.new(parent, :anchor, target, :type => :xref, :target => ('#' + target), :attributes => {'fragment' => target, 'refid' => target}) + end + end +end + +class CodeInlineMacroBase < SpecInlineMacroBase + def process parent, target, attributes + create_inline parent, :quoted, '' + target.gsub('→', '->') + '' + end +end + +class StrongInlineMacroBase < SpecInlineMacroBase + def process parent, target, attributes + create_inline parent, :quoted, '' + target.gsub('→', '->') + '' + end +end + +class ParamInlineMacroBase < SpecInlineMacroBase + def process parent, target, attributes + create_inline parent, :quoted, '' + target.gsub('→', '->') + '' + end +end + +class MustInlineMacro < NormativeInlineMacroBase + named :must + match /must:(\w*)/ + + def text + 'must' + end +end + +# Generic reference page link to any entity with an anchor/refpage +class ReflinkInlineMacro < LinkInlineMacroBase + named :reflink + match /reflink:(\w+)/ +end + +# This doesn't include the full range of code: use +# match /code:(\w+(\.\w+)*)/ +# match /code:([-A-Za-z0-9_()<>!=?:"&%|/*^+"]+ +class CodeInlineMacro < CodeInlineMacroBase + named :code + match /code:([-A-Za-z0-9_()<>!=?:"&%|*^+"\/]+)/ +end diff --git a/adoc/config/themes/pdf-theme.yml b/adoc/config/themes/pdf-theme.yml new file mode 100644 index 00000000..cb72e70d --- /dev/null +++ b/adoc/config/themes/pdf-theme.yml @@ -0,0 +1,340 @@ +# http://gist.asciidoctor.org/?github-asciidoctor%2Fasciidoctor-pdf%2F%2Fdocs%2Ftheming-guide.adoc + +# Modified from asciidoctor-pdf 1.5.3 (gems/asciidoctor-pdf-1.5.3/data/themes/default-theme.yml) +# by adding chapter names to the page footer and some custom roles + +# Number the pages starting at the title +page-numbering-start-at: title +# but only start the headers and footers on the next page, the table-of-content +running-content-start-at: toc + +font: + catalog: + # Noto Serif supports Latin, Latin-1 Supplement, Latin Extended-A, Greek, Cyrillic, Vietnamese & an assortment of symbols + Noto Serif: + normal: notoserif-regular-subset.ttf + bold: notoserif-bold-subset.ttf + italic: notoserif-italic-subset.ttf + bold_italic: notoserif-bold_italic-subset.ttf + # M+ 1mn supports ASCII and the circled numbers used for conums + M+ 1mn: + normal: mplus1mn-regular-subset.ttf + bold: mplus1mn-bold-subset.ttf + italic: mplus1mn-italic-subset.ttf + bold_italic: mplus1mn-bold_italic-subset.ttf +page: + background_color: FFFFFF + layout: portrait + # When opening the file, display all the page + initial_zoom: Fit + margin: [0.5in, 0.67in, 0.67in, 0.67in] + # margin_inner and margin_outer keys are used for recto/verso print margins when media=prepress + margin_inner: 0.75in + margin_outer: 0.59in + size: A4 +base: + align: justify + # color as hex string (leading # is optional) + font_color: 333333 + # color as RGB array + #font_color: [51, 51, 51] + # color as CMYK array (approximated) + #font_color: [0, 0, 0, 0.92] + #font_color: [0, 0, 0, 92%] + font_family: Noto Serif + # choose one of these font_size/line_height_length combinations + #font_size: 14 + #line_height_length: 20 + #font_size: 11.25 + #line_height_length: 18 + #font_size: 11.2 + #line_height_length: 16 + ##font_size: 10.5 + # Do not forget to adapt accordingly line_height_length + font_size: 10 + #line_height_length: 15 + # correct line height for Noto Serif metrics + #line_height_length: 12 + line_height_length: 10 + #font_size: 11.25 + #line_height_length: 18 + line_height: $base_line_height_length / $base_font_size + font_size_large: round($base_font_size * 1.25) + font_size_small: round($base_font_size * 0.85) + font_size_min: $base_font_size * 0.75 + font_style: normal + border_color: EEEEEE + border_radius: 4 + border_width: 0.5 +role: + line-through: + text_decoration: line-through + underline: + text_decoration: underline + big: + font_size: $base_font_size_large + small: + font_size: $base_font_size_small + subtitle: + font_size: 0.8em + font_color: 999999 + # Asciidoctor custom [code] role + code: + font_size: 1em + font_family: M+ 1mn + font_color: FF0000 +# From khronos.css code CSS style: +# code, .code { font-family: Consolas, "Liberation Mono", Courier, monospace; font-weight: normal; color: #264357; } +# font_color: $base_font_color +# font_family: $literal_font_family +# font_size: ceil($base_font_size) +# padding: $code_font_size +# line_height: 1.25 +# # line_gap is an experimental property to control how a background color is applied to an inline block element +# line_gap: 3.8 +# background_color: F5F5F5 +# border_color: CCCCCC +# border_radius: $base_border_radius +# border_width: 0.75 + +# FIXME vertical_rhythm is weird; we should think in terms of ems +#vertical_rhythm: $base_line_height_length * 2 / 3 +# correct line height for Noto Serif metrics (comes with built-in line height) +vertical_rhythm: $base_line_height_length +horizontal_rhythm: $base_line_height_length +# QUESTION should vertical_spacing be block_spacing instead? +vertical_spacing: $vertical_rhythm +link: + font_color: 428BCA +# literal is currently used for inline monospaced in prose and table cells +literal: + font_color: B12146 + font_family: M+ 1mn +button: + content: "[\u2009%s\u2009]" + font_style: bold +key: + background_color: F5F5F5 + border_color: CCCCCC + border_offset: 2 + border_radius: 2 + border_width: 0.5 + font_family: $literal_font_family + separator: "\u202f+\u202f" +mark: + background_color: FFFF00 + border_offset: 1 +menu: + caret_content: " \u203a " +heading: + align: left + font_color: $base_font_color + font_style: bold + # h1 is used for part titles (book doctype) or the doctitle (article doctype) + h1_font_size: floor($base_font_size * 2.6) + # h2 is used for chapter titles (book doctype only) + h2_font_size: floor($base_font_size * 2.15) + h3_font_size: round($base_font_size * 1.7) + h4_font_size: $base_font_size_large + h5_font_size: $base_font_size + h6_font_size: $base_font_size_small + #line_height: 1.4 + # correct line height for Noto Serif metrics (comes with built-in line height) + line_height: 1 + margin_top: $vertical_rhythm * 0.4 + margin_bottom: $vertical_rhythm * 0.9 + min_height_after: $base_line_height_length * 1.5 +title_page: + align: right + logo: + top: 10% + title: + top: 55% + font_size: $heading_h1_font_size + font_color: 999999 + line_height: 0.9 + subtitle: + font_size: $heading_h3_font_size + font_style: bold_italic + line_height: 1 + authors: + margin_top: $base_font_size * 1.25 + font_size: $base_font_size_large + font_color: 181818 + revision: + margin_top: $base_font_size * 1.25 +block: + margin_top: 0 + margin_bottom: $vertical_rhythm +caption: + align: left + font_size: $base_font_size * 0.95 + font_style: italic + # FIXME perhaps set line_height instead of / in addition to margins? + margin_inside: $vertical_rhythm / 3 + #margin_inside: $vertical_rhythm / 4 + margin_outside: 0 +lead: + font_size: $base_font_size_large + line_height: 1.4 +abstract: + font_color: 5C6266 + font_size: $lead_font_size + line_height: $lead_line_height + font_style: italic + first_line_font_style: bold + title: + align: center + font_color: $heading_font_color + font_size: $heading_h4_font_size + font_style: $heading_font_style +admonition: + column_rule_color: $base_border_color + column_rule_width: $base_border_width + padding: [0, $horizontal_rhythm, 0, $horizontal_rhythm] + #icon: + # tip: + # name: far-lightbulb + # stroke_color: 111111 + # size: 24 + label: + text_transform: uppercase + font_style: bold +blockquote: + font_size: $base_font_size_large + border_color: $base_border_color + border_width: 0 + border_left_width: 5 + # FIXME disable negative padding bottom once margin collapsing is implemented + padding: [0, $horizontal_rhythm, $block_margin_bottom * -0.75, $horizontal_rhythm + $blockquote_border_left_width / 2] + cite_font_size: $base_font_size_small + cite_font_color: 999999 +verse: + font_size: $blockquote_font_size + border_color: $blockquote_border_color + border_width: $blockquote_border_width + border_left_width: $blockquote_border_left_width + padding: $blockquote_padding + cite_font_size: $blockquote_cite_font_size + cite_font_color: $blockquote_cite_font_color +# code is used for source blocks (perhaps change to source or listing?) +code: + font_color: $base_font_color + font_family: $literal_font_family + font_size: ceil($base_font_size) + padding: $code_font_size + line_height: 1.25 + # line_gap is an experimental property to control how a background color is applied to an inline block element + line_gap: 3.8 + background_color: F5F5F5 + border_color: CCCCCC + border_radius: $base_border_radius + border_width: 0.75 +conum: + font_family: $literal_font_family + font_color: $literal_font_color + font_size: $base_font_size + line_height: 4 / 3 + glyphs: circled +example: + border_color: $base_border_color + border_radius: $base_border_radius + border_width: 0.75 + background_color: $page_background_color + # FIXME reenable padding bottom once margin collapsing is implemented + padding: [$vertical_rhythm, $horizontal_rhythm, 0, $horizontal_rhythm] +image: + align: left +prose: + margin_top: $block_margin_top + margin_bottom: $block_margin_bottom +sidebar: + background_color: EEEEEE + border_color: E1E1E1 + border_radius: $base_border_radius + border_width: $base_border_width + # FIXME reenable padding bottom once margin collapsing is implemented + padding: [$vertical_rhythm, $vertical_rhythm * 1.25, 0, $vertical_rhythm * 1.25] + title: + align: center + font_color: $heading_font_color + font_size: $heading_h4_font_size + font_style: $heading_font_style +thematic_break: + border_color: $base_border_color + border_style: solid + border_width: $base_border_width + margin_top: $vertical_rhythm * 0.5 + margin_bottom: $vertical_rhythm * 1.5 +description_list: + term_font_style: bold + term_spacing: $vertical_rhythm / 4 + description_indent: $horizontal_rhythm * 1.25 +outline_list: + indent: $horizontal_rhythm * 1.5 + #marker_font_color: 404040 + # NOTE outline_list_item_spacing applies to list items that do not have complex content + item_spacing: $vertical_rhythm / 2 +table: + background_color: $page_background_color + border_color: DDDDDD + border_width: $base_border_width + cell_padding: 3 + head: + font_style: bold + border_bottom_width: $base_border_width * 2.5 + body: + stripe_background_color: F9F9F9 + foot: + background_color: F0F0F0 +toc: + indent: $horizontal_rhythm + line_height: 1.4 + dot_leader: + #content: ". " + font_color: A9A9A9 + #levels: 2 3 +footnotes: + font_size: round($base_font_size * 0.75) + item_spacing: $outline_list_item_spacing / 2 + +header: + font_size: $base_font_size_small + border_color: DDDDDD + border_width: 0.25 + height: $base_line_height_length * 2.5 + line_height: 1 + vertical_align: middle + # Put the spec name and the deep section title in the header + sectlevels: 10 + recto: + left: + content: '{SYCL_NAME} {SYCL_VERSION} rev {SYCL_REVISION}' + right: + content: '{section-title}' + verso: + left: + content: '{section-title}' + right: + content: '{SYCL_NAME} {SYCL_VERSION} rev {SYCL_REVISION}' + +footer: + font_size: $base_font_size_small + # NOTE if background_color is set, background and border will span width of page + border_color: DDDDDD + border_width: 0.25 + height: $base_line_height_length * 2.5 + line_height: 1 + padding: [$base_line_height_length / 2, 1, 0, 1] + vertical_align: top + # Put the page number and the chapter title + recto: + #columns: "<50% =0% >50%" + right: + # content: '{page-number}' + content: '{chapter-title} | {page-number}' + verso: + #columns: $footer_recto_columns + left: + # content: $footer_recto_right_content + content: '{page-number} | {chapter-title}' diff --git a/adoc/headers/Readme.txt b/adoc/headers/Readme.txt new file mode 100644 index 00000000..7316360e --- /dev/null +++ b/adoc/headers/Readme.txt @@ -0,0 +1,12 @@ +SYCL headers +------------- + +These headers are provided as part of the specification document, for the purpose of providing +a common interface for the SYCL system. + +The original authors are: + + * Gordon Brown, Codeplay Software Ltd. + * Ronan Keryell, AMD + * Ruyman Reyes, Codeplay Software Ltd. + * Maria Rovatsou, Codeplay Software Ltd. diff --git a/adoc/headers/accessMode.h b/adoc/headers/accessMode.h new file mode 100644 index 00000000..7fc7e248 --- /dev/null +++ b/adoc/headers/accessMode.h @@ -0,0 +1,18 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { +enum class access_mode { + read, + write, + read_write, + discard_write, // Deprecated in SYCL 2020 + discard_read_write, // Deprecated in SYCL 2020 + atomic // Deprecated in SYCL 2020 +}; + +namespace access { + // The legacy type "access::mode" is deprecated. + using mode = sycl::access_mode; +} // namespace access +} // namespace sycl diff --git a/adoc/headers/accessProperties.h b/adoc/headers/accessProperties.h new file mode 100755 index 00000000..69ea56d1 --- /dev/null +++ b/adoc/headers/accessProperties.h @@ -0,0 +1,10 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { +namespace property { + struct no_init {}; +} // namespace property + +inline constexpr property::no_init no_init; +} // namespace sycl diff --git a/adoc/headers/accessTags.h b/adoc/headers/accessTags.h new file mode 100755 index 00000000..0427cdeb --- /dev/null +++ b/adoc/headers/accessTags.h @@ -0,0 +1,13 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { + +inline constexpr __unspecified__ read_only; +inline constexpr __unspecified__ read_write; +inline constexpr __unspecified__ write_only; +inline constexpr __unspecified__ read_only_host_task; +inline constexpr __unspecified__ read_write_host_task; +inline constexpr __unspecified__ write_only_host_task; + +} // namespace sycl diff --git a/adoc/headers/accessorBuffer.h b/adoc/headers/accessorBuffer.h new file mode 100644 index 00000000..8236765a --- /dev/null +++ b/adoc/headers/accessorBuffer.h @@ -0,0 +1,200 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { + +enum class target { + device, + host_task, + global_buffer = device, // Deprecated + constant_buffer, // Deprecated + local, // Deprecated + host_buffer // Deprecated +}; + +namespace access { + // The legacy type "access::target" is deprecated. + using sycl::target; + +enum class placeholder { // Deprecated + false_t, + true_t +}; + +} // namespace access + + +template ? access_mode::read + : access_mode::read_write), + target accessTarget = target::device, + access::placeholder isPlaceholder = access::placeholder::false_t> +class accessor { + public: + using value_type = // const dataT for read-only accessors, dataT otherwise + __value_type__; + using reference = value_type &; + using const_reference = const dataT &; + template + using accessor_ptr = // multi_ptr to value_type with target address space, + __pointer_class__; // unspecified for access_mode::host_task + using iterator = __unspecified_iterator__; + using const_iterator = __unspecified_iterator__; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using difference_type = typename std::iterator_traits::difference_type; + using size_type = size_t; + + accessor(); + + /* Available only when: (dimensions == 0) */ + template + accessor(buffer &bufferRef, + const property_list &propList = {}); + + /* Available only when: (dimensions == 0) */ + template + accessor(buffer &bufferRef, + handler &commandGroupHandlerRef, const property_list &propList = {}); + + /* Available only when: (dimensions > 0) */ + template + accessor(buffer &bufferRef, + const property_list &propList = {}); + + /* Available only when: (dimensions > 0) */ + template + accessor(buffer &bufferRef, TagT tag, + const property_list &propList = {}); + + /* Available only when: (dimensions > 0) */ + template + accessor(buffer &bufferRef, + handler &commandGroupHandlerRef, const property_list &propList = {}); + + /* Available only when: (dimensions > 0) */ + template + accessor(buffer &bufferRef, + handler &commandGroupHandlerRef, TagT tag, + const property_list &propList = {}); + + /* Available only when: (dimensions > 0) */ + template + accessor(buffer &bufferRef, + range accessRange, const property_list &propList = {}); + + /* Available only when: (dimensions > 0) */ + template + accessor(buffer &bufferRef, + range accessRange, TagT tag, + const property_list &propList = {}); + + /* Available only when: (dimensions > 0) */ + template + accessor(buffer &bufferRef, + range accessRange, id accessOffset, + const property_list &propList = {}); + + /* Available only when: (dimensions > 0) */ + template + accessor(buffer &bufferRef, + range accessRange, id accessOffset, + TagT tag, const property_list &propList = {}); + + /* Available only when: (dimensions > 0) */ + template + accessor(buffer &bufferRef, + handler &commandGroupHandlerRef, range accessRange, + const property_list &propList = {}); + + /* Available only when: (dimensions > 0) */ + template + accessor(buffer &bufferRef, + handler &commandGroupHandlerRef, range accessRange, + TagT tag, const property_list &propList = {}); + + /* Available only when: (dimensions > 0) */ + template + accessor(buffer &bufferRef, + handler &commandGroupHandlerRef, range accessRange, + id accessOffset, const property_list &propList = {}); + + /* Available only when: (dimensions > 0) */ + template + accessor(buffer &bufferRef, + handler &commandGroupHandlerRef, range accessRange, + id accessOffset, TagT tag, + const property_list &propList = {}); + + /* -- common interface members -- */ + + void swap(accessor &other); + + bool is_placeholder() const; + + size_type byte_size() const noexcept; + + size_type size() const noexcept; + + size_type max_size() const noexcept; + + // Deprecated + size_t get_size() const; + + // Deprecated + size_t get_count() const; + + bool empty() const noexcept; + + /* Available only when: (dimensions > 0) */ + range get_range() const; + + /* Available only when: (dimensions > 0) */ + id get_offset() const; + + /* Available only when: (dimensions == 0) */ + operator reference() const; + + /* Available only when: (dimensions > 0) */ + reference operator[](id index) const; + + /* Available only when: (dimensions > 1) */ + __unspecified__ &operator[](size_t index) const; + + /* Available only when: (accessMode != access_mode::atomic && dimensions == 1) */ + reference operator[](size_t index) const; + + /* Deprecated + Available only when: (accessMode == access_mode::atomic && dimensions == 0) */ + operator cl::sycl::atomic () const; + + /* Deprecated + Available only when: (accessMode == access_mode::atomic && dimensions == 1) */ + cl::sycl::atomic operator[]( + id index) const; + + std::add_pointer_t get_pointer() const noexcept; + + template + accessor_ptr get_multi_ptr() const noexcept; + + iterator begin() const noexcept; + + iterator end() const noexcept; + + const_iterator cbegin() const noexcept; + + const_iterator cend() const noexcept; + + reverse_iterator rbegin() const noexcept; + + reverse_iterator rend() const noexcept; + + const_reverse_iterator crbegin() const noexcept; + + const_reverse_iterator crend() const noexcept; +}; + +} // namespace sycl diff --git a/adoc/headers/accessorDeprecatedConstant.h b/adoc/headers/accessorDeprecatedConstant.h new file mode 100644 index 00000000..7ee17af3 --- /dev/null +++ b/adoc/headers/accessorDeprecatedConstant.h @@ -0,0 +1,89 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { + +template +class accessor { + public: + using value_type = const dataT; + using reference = const dataT &; + using const_reference = const dataT &; + + /* Available only when: (dimensions == 0) */ + template + accessor(buffer &bufferRef, + const property_list &propList = {}); + + /* Available only when: (dimensions == 0) */ + template + accessor(buffer &bufferRef, + handler &commandGroupHandlerRef, const property_list &propList = {}); + + /* Available only when: (dimensions > 0) */ + template + accessor(buffer &bufferRef, + const property_list &propList = {}); + + /* Available only when: (dimensions > 0) */ + template + accessor(buffer &bufferRef, + handler &commandGroupHandlerRef, const property_list &propList = {}); + + /* Available only when: (dimensions > 0) */ + template + accessor(buffer &bufferRef, + range accessRange, const property_list &propList = {}); + + /* Available only when: (dimensions > 0) */ + template + accessor(buffer &bufferRef, + range accessRange, id accessOffset, + const property_list &propList = {}); + + /* Available only when: (dimensions > 0) */ + template + accessor(buffer &bufferRef, + handler &commandGroupHandlerRef, range accessRange, + const property_list &propList = {}); + + /* Available only when: (dimensions > 0) */ + template + accessor(buffer &bufferRef, + handler &commandGroupHandlerRef, range accessRange, + id accessOffset, const property_list &propList = {}); + + /* -- common interface members -- */ + + bool is_placeholder() const; + + size_t get_size() const noexcept; + + size_t get_count() const noexcept; + + /* Available only when: (dimensions > 0) */ + range get_range() const; + + /* Available only when: (dimensions > 0) */ + id get_offset() const; + + /* Available only when: (dimensions == 0) */ + operator reference() const; + + /* Available only when: (dimensions > 0) */ + reference operator[](id index) const; + + /* Available only when: (dimensions > 1) */ + __unspecified__ &operator[](size_t index) const; + + /* Available only when: (dimensions == 1) */ + reference operator[](size_t index) const; + + constant_ptr get_pointer() const noexcept; +}; + +} // namespace sycl diff --git a/adoc/headers/accessorDeprecatedHost.h b/adoc/headers/accessorDeprecatedHost.h new file mode 100644 index 00000000..853a1e7a --- /dev/null +++ b/adoc/headers/accessorDeprecatedHost.h @@ -0,0 +1,68 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { + +template +class accessor { + public: + using value_type = // const dataT for access_mode::read, dataT otherwise + __value_type__; + using reference = value_type &; + using const_reference = const dataT &; + + /* Available only when: (dimensions == 0) */ + template + accessor(buffer &bufferRef, + const property_list &propList = {}); + + /* Available only when: (dimensions > 0) */ + template + accessor(buffer &bufferRef, + const property_list &propList = {}); + + /* Available only when: (dimensions > 0) */ + template + accessor(buffer &bufferRef, + range accessRange, const property_list &propList = {}); + + /* Available only when: (dimensions > 0) */ + template + accessor(buffer &bufferRef, + range accessRange, id accessOffset, + const property_list &propList = {}); + + /* -- common interface members -- */ + + bool is_placeholder() const; + + size_t get_size() const; + + size_t get_count() const; + + /* Available only when: (dimensions > 0) */ + range get_range() const; + + /* Available only when: (dimensions > 0) */ + id get_offset() const; + + /* Available only when: (dimensions == 0) */ + operator reference() const; + + /* Available only when: (dimensions > 0) */ + reference operator[](id index) const; + + /* Available only when: (dimensions > 1) */ + __unspecified__ &operator[](size_t index) const; + + /* Available only when: (dimensions == 1) */ + reference operator[](size_t index) const; + + std::add_pointer_t get_pointer() const noexcept; +}; + +} // namespace sycl diff --git a/adoc/headers/accessorDeprecatedLocal.h b/adoc/headers/accessorDeprecatedLocal.h new file mode 100644 index 00000000..e3219205 --- /dev/null +++ b/adoc/headers/accessorDeprecatedLocal.h @@ -0,0 +1,60 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { + +template +class accessor { + public: + using value_type = dataT; + using reference = dataT &; + using const_reference = const dataT &; + + /* Available only when: (dimensions == 0) */ + accessor(handler &commandGroupHandlerRef, + const property_list &propList = {}); + + /* Available only when: (dimensions > 0) */ + accessor(range allocationSize, handler &commandGroupHandlerRef, + const property_list &propList = {}); + + /* -- common interface members -- */ + + bool is_placeholder() const; + + size_t get_size() const; + + size_t get_count() const; + + /* Available only when: (dimensions > 0) */ + range get_range() const; + + /* Available only when: (accessMode == access_mode::read_write && dimensions == 0) */ + operator reference() const; + + /* Available only when: (accessMode == access_mode::read_write && dimensions > 0) */ + reference operator[](id index) const; + + /* Available only when: (dimensions > 1) */ + __unspecified__ &operator[](size_t index) const; + + /* Available only when: (accessMode == access_mode::read_write && dimensions == 1) */ + reference operator[](size_t index) const; + + /* Available only when: (accessMode == access_mode::atomic && dimensions == 0) */ + operator atomic () const; + + /* Available only when: (accessMode == access_mode::atomic && dimensions > 0) */ + atomic operator[](id index) const; + + /* Available only when: (accessMode == access_mode::atomic && dimensions == 1) */ + atomic operator[](size_t index) const; + + local_ptr get_pointer() const noexcept; +}; + +} // namespace sycl diff --git a/adoc/headers/accessorHost.h b/adoc/headers/accessorHost.h new file mode 100755 index 00000000..fd365412 --- /dev/null +++ b/adoc/headers/accessorHost.h @@ -0,0 +1,111 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { +template ? access_mode::read + : access_mode::read_write), +class host_accessor { + public: + using value_type = // const dataT for read-only accessors, dataT otherwise + __value_type__; + using reference = value_type &; + using const_reference = const dataT &; + using iterator = __unspecified_iterator__; + using const_iterator = __unspecified_iterator__; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using difference_type = typename std::iterator_traits::difference_type; + using size_type = size_t; + + host_accessor(); + + /* Available only when: (dimensions == 0) */ + template + host_accessor(buffer &bufferRef, + const property_list &propList = {}); + + /* Available only when: (dimensions > 0) */ + template + host_accessor(buffer &bufferRef, + const property_list &propList = {}); + + /* Available only when: (dimensions > 0) */ + template + host_accessor(buffer &bufferRef, TagT tag, + const property_list &propList = {}); + + /* Available only when: (dimensions > 0) */ + template + host_accessor(buffer &bufferRef, + range accessRange, const property_list &propList = {}); + + /* Available only when: (dimensions > 0) */ + template + host_accessor(buffer &bufferRef, + range accessRange, TagT tag, + const property_list &propList = {}); + + /* Available only when: (dimensions > 0) */ + template + host_accessor(buffer &bufferRef, + range accessRange, id accessOffset, + const property_list &propList = {}); + + /* Available only when: (dimensions > 0) */ + template + host_accessor(buffer &bufferRef, + range accessRange, id accessOffset, + TagT tag, const property_list &propList = {}); + + /* -- common interface members -- */ + + void swap(host_accessor &other); + + size_type byte_size() const noexcept; + + size_type size() const noexcept; + + size_type max_size() const noexcept; + + bool empty() const noexcept; + + /* Available only when: (dimensions > 0) */ + range get_range() const; + + /* Available only when: (dimensions > 0) */ + id get_offset() const; + + /* Available only when: (dimensions == 0) */ + operator reference() const; + + /* Available only when: (dimensions > 0) */ + reference operator[](id index) const; + + /* Available only when: (dimensions > 1) */ + __unspecified__ &operator[](size_t index) const; + + /* Available only when: (dimensions == 1) */ + reference operator[](size_t index) const; + + std::add_pointer_t get_pointer() const noexcept; + + iterator begin() const noexcept; + + iterator end() const noexcept; + + const_iterator cbegin() const noexcept; + + const_iterator cend() const noexcept; + + reverse_iterator rbegin() const noexcept; + + reverse_iterator rend() const noexcept; + + const_reverse_iterator crbegin() const noexcept; + + const_reverse_iterator crend() const noexcept; +}; +} // namespace sycl diff --git a/adoc/headers/accessorLocal.h b/adoc/headers/accessorLocal.h new file mode 100644 index 00000000..0d3341b0 --- /dev/null +++ b/adoc/headers/accessorLocal.h @@ -0,0 +1,79 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { +template +class local_accessor { + public: + using value_type = // const dataT for read-only accessors, dataT otherwise + __value_type__; + using reference = value_type &; + using const_reference = const dataT &; + template + using accessor_ptr = + multi_ptr; + using iterator = __unspecified_iterator__; + using const_iterator = __unspecified_iterator__; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using difference_type = typename std::iterator_traits::difference_type; + using size_type = size_t; + + local_accessor(); + + /* Available only when: (dimensions == 0) */ + local_accessor(handler &commandGroupHandlerRef, + const property_list &propList = {}); + + /* Available only when: (dimensions > 0) */ + local_accessor(range allocationSize, handler &commandGroupHandlerRef, + const property_list &propList = {}); + + /* -- common interface members -- */ + + void swap(accessor &other); + + size_type byte_size() const noexcept; + + size_type size() const noexcept; + + size_type max_size() const noexcept; + + bool empty() const noexcept; + + range get_range() const; + + /* Available only when: (dimensions == 0) */ + operator reference() const; + + /* Available only when: (dimensions > 0) */ + reference operator[](id index) const; + + /* Available only when: (dimensions > 1) */ + __unspecified__ &operator[](size_t index) const; + + /* Available only when: (dimensions == 1) */ + reference operator[](size_t index) const; + + std::add_pointer_t get_pointer() const noexcept; + + template + accessor_ptr get_multi_ptr() const noexcept; + + iterator begin() const noexcept; + + iterator end() const noexcept; + + const_iterator cbegin() const noexcept; + + const_iterator cend() const noexcept; + + reverse_iterator rbegin() const noexcept; + + reverse_iterator rend() const noexcept; + + const_reverse_iterator crbegin() const noexcept; + + const_reverse_iterator crend() const noexcept; +}; +} // namespace sycl diff --git a/adoc/headers/accessorSampledImage.h b/adoc/headers/accessorSampledImage.h new file mode 100644 index 00000000..6e02598c --- /dev/null +++ b/adoc/headers/accessorSampledImage.h @@ -0,0 +1,67 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { + +enum class image_target { + device, + host_task +}; + +template +class sampled_image_accessor { + public: + using value_type = const dataT; + using reference = const dataT &; + using const_reference = const dataT &; + + template + sampled_image_accessor(sampled_image &imageRef, + handler &commandGroupHandlerRef, + const property_list &propList = {}); + + template + sampled_image_accessor(sampled_image &imageRef, + handler &commandGroupHandlerRef, TagT tag, + const property_list &propList = {}); + + /* -- common interface members -- */ + + /* -- property interface members -- */ + + size_t size() const noexcept; + + /* if dimensions == 1, coordT = float + if dimensions == 2, coordT = float2 + if dimensions == 3, coordT = float4 */ + template + dataT read(const coordT &coords) const noexcept; +}; + +template +class host_sampled_image_accessor { + public: + using value_type = const dataT; + using reference = const dataT &; + using const_reference = const dataT &; + + template + host_sampled_image_accessor(sampled_image &imageRef, + const property_list &propList = {}); + + /* -- common interface members -- */ + + /* -- property interface members -- */ + + size_t size() const noexcept; + + /* if dimensions == 1, coordT = float + if dimensions == 2, coordT = float2 + if dimensions == 3, coordT = float4 */ + template + dataT read(const coordT &coords) const noexcept; +}; + +} // namespace sycl diff --git a/adoc/headers/accessorUnsampledImage.h b/adoc/headers/accessorUnsampledImage.h new file mode 100644 index 00000000..06e4aaa4 --- /dev/null +++ b/adoc/headers/accessorUnsampledImage.h @@ -0,0 +1,92 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { + +enum class image_target { + device, + host_task +}; + +template +class unsampled_image_accessor { + public: + using value_type = // const dataT for read-only accessors, dataT otherwise + __value_type__; + using reference = value_type &; + using const_reference = const dataT &; + + template + unsampled_image_accessor(unsampled_image &imageRef, + handler &commandGroupHandlerRef, + const property_list &propList = {}); + + template + unsampled_image_accessor(unsampled_image &imageRef, + handler &commandGroupHandlerRef, TagT tag, + const property_list &propList = {}); + + /* -- common interface members -- */ + + /* -- property interface members -- */ + + size_t size() const noexcept; + + /* Available only when: accessMode == access_mode::read + if dimensions == 1, coordT = int + if dimensions == 2, coordT = int2 + if dimensions == 4, coordT = int4 */ + template + dataT read(const coordT &coords) const noexcept; + + /* Available only when: accessMode == access_mode::write + if dimensions == 1, coordT = int + if dimensions == 2, coordT = int2 + if dimensions == 3, coordT = int4 */ + template + void write(const coordT &coords, const dataT &color) const; +}; + +template +class host_unsampled_image_accessor { + public: + using value_type = // const dataT for read-only accessors, dataT otherwise + __value_type__; + using reference = value_type &; + using const_reference = const dataT &; + + template + host_unsampled_image_accessor(unsampled_image &imageRef, + const property_list &propList = {}); + + template + host_unsampled_image_accessor(unsampled_image &imageRef, + TagT tag, const property_list &propList = {}); + + /* -- common interface members -- */ + + /* -- property interface members -- */ + + size_t size() const noexcept; + + /* Available only when: accessMode == access_mode::read + if dimensions == 1, coordT = int + if dimensions == 2, coordT = int2 + if dimensions == 4, coordT = int4 */ + template + dataT read(const coordT &coords) const noexcept; + + /* Available only when: accessMode == access_mode::write + if dimensions == 1, coordT = int + if dimensions == 2, coordT = int2 + if dimensions == 3, coordT = int4 */ + template + void write(const coordT &coords, const dataT &color) const; +}; + +} // namespace sycl diff --git a/adoc/headers/algorithms/all_of.h b/adoc/headers/algorithms/all_of.h new file mode 100644 index 00000000..31477e69 --- /dev/null +++ b/adoc/headers/algorithms/all_of.h @@ -0,0 +1,11 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: MIT + +template +bool joint_all_of(Group g, Ptr first, Ptr last, Predicate pred); // (1) + +template +bool all_of_group(Group g, T x, Predicate pred); // (2) + +template +bool all_of_group(Group g, bool pred); // (3) diff --git a/adoc/headers/algorithms/any_of.h b/adoc/headers/algorithms/any_of.h new file mode 100644 index 00000000..74b0b99d --- /dev/null +++ b/adoc/headers/algorithms/any_of.h @@ -0,0 +1,11 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: MIT + +template +bool joint_any_of(Group g, Ptr first, Ptr last, Predicate pred); // (1) + +template +bool any_of_group(Group g, T x, Predicate pred); // (2) + +template +bool any_of_group(Group g, bool pred); // (3) diff --git a/adoc/headers/algorithms/exclusive_scan.h b/adoc/headers/algorithms/exclusive_scan.h new file mode 100644 index 00000000..73c4e2eb --- /dev/null +++ b/adoc/headers/algorithms/exclusive_scan.h @@ -0,0 +1,14 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: MIT + +template +OutPtr joint_exclusive_scan(Group g, InPtr first, InPtr last, OutPtr result, BinaryOperation binary_op); // (1) + +template +T joint_exclusive_scan(Group g, InPtr first, InPtr last, OutPtr result, T init, BinaryOperation binary_op); // (2) + +template +T exclusive_scan_over_group(Group g, T x, BinaryOperation binary_op); // (3) + +template +T exclusive_scan_over_group(Group g, V x, T init, BinaryOperation binary_op); // (4) diff --git a/adoc/headers/algorithms/inclusive_scan.h b/adoc/headers/algorithms/inclusive_scan.h new file mode 100644 index 00000000..4387d466 --- /dev/null +++ b/adoc/headers/algorithms/inclusive_scan.h @@ -0,0 +1,14 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: MIT + +template +OutPtr joint_inclusive_scan(Group g, InPtr first, InPtr last, OutPtr result, BinaryOperation binary_op); // (1) + +template +T joint_inclusive_scan(Group g, InPtr first, InPtr last, OutPtr result, BinaryOperation binary_op, T init); // (2) + +template +T inclusive_scan_over_group(Group g, T x, BinaryOperation binary_op); // (3) + +template +T inclusive_scan_over_group(Group g, V x, BinaryOperation binary_op, T init); // (4) diff --git a/adoc/headers/algorithms/is_group.h b/adoc/headers/algorithms/is_group.h new file mode 100644 index 00000000..effd0cc0 --- /dev/null +++ b/adoc/headers/algorithms/is_group.h @@ -0,0 +1,10 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: MIT + +namespace sycl { + template + struct is_group; + + template + inline constexpr bool is_group_v = is_group::value; +} diff --git a/adoc/headers/algorithms/none_of.h b/adoc/headers/algorithms/none_of.h new file mode 100644 index 00000000..3bb1cf71 --- /dev/null +++ b/adoc/headers/algorithms/none_of.h @@ -0,0 +1,11 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: MIT + +template +bool joint_none_of(Group g, Ptr first, Ptr last, Predicate pred); // (1) + +template +bool none_of_group(Group g, T x, Predicate pred); // (2) + +template +bool none_of_group(Group g, bool pred); // (3) diff --git a/adoc/headers/algorithms/permute.h b/adoc/headers/algorithms/permute.h new file mode 100644 index 00000000..a356b41a --- /dev/null +++ b/adoc/headers/algorithms/permute.h @@ -0,0 +1,5 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: MIT + +template +T permute_group_by_xor(Group g, T x, Group::linear_id_type mask); // (1) diff --git a/adoc/headers/algorithms/reduce.h b/adoc/headers/algorithms/reduce.h new file mode 100644 index 00000000..4ff4e72b --- /dev/null +++ b/adoc/headers/algorithms/reduce.h @@ -0,0 +1,14 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: MIT + +template +std::iterator_traits::value_type joint_reduce(Group g, Ptr first, Ptr last, BinaryOperation binary_op); // (1) + +template +T joint_reduce(Group g, Ptr first, Ptr last, T init, BinaryOperation binary_op); // (2) + +template +T reduce_over_group(Group g, T x, BinaryOperation binary_op); // (3) + +template +T reduce_over_group(Group g, V x, T init, BinaryOperation binary_op); // (4) diff --git a/adoc/headers/algorithms/select.h b/adoc/headers/algorithms/select.h new file mode 100644 index 00000000..1631ab3b --- /dev/null +++ b/adoc/headers/algorithms/select.h @@ -0,0 +1,5 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: MIT + +template +T select_from_group(Group g, T x, Group::id_type remote_local_id); // (1) diff --git a/adoc/headers/algorithms/shift.h b/adoc/headers/algorithms/shift.h new file mode 100644 index 00000000..c08ac1d6 --- /dev/null +++ b/adoc/headers/algorithms/shift.h @@ -0,0 +1,8 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: MIT + +template +T shift_group_left(Group g, T x, Group::linear_id_type delta = 1); // (1) + +template +T shift_group_right(Group g, T x, Group::linear_id_type delta = 1); // (2) diff --git a/adoc/headers/aspectTraits.h b/adoc/headers/aspectTraits.h new file mode 100644 index 00000000..372be7a0 --- /dev/null +++ b/adoc/headers/aspectTraits.h @@ -0,0 +1,12 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: MIT + +namespace sycl { + +template struct any_device_has; +template struct all_devices_have; + +template inline constexpr bool any_device_has_v = any_device_has::value; +template inline constexpr bool all_devices_have_v = all_devices_have::value; + +} diff --git a/adoc/headers/atomic.h b/adoc/headers/atomic.h new file mode 100644 index 00000000..0d0e5e1f --- /dev/null +++ b/adoc/headers/atomic.h @@ -0,0 +1,61 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace cl { +namespace sycl { +/* Deprecated in SYCL 2020 */ +enum class memory_order : int { + relaxed +}; + +/* Deprecated in SYCL 2020 */ +template +class atomic { + public: + template + atomic(multi_ptr ptr); + + void store(T operand, memory_order memoryOrder = + memory_order::relaxed); + + T load(memory_order memoryOrder = memory_order::relaxed) const; + + T exchange(T operand, memory_order memoryOrder = + memory_order::relaxed); + + /* Available only when: T != float */ + bool compare_exchange_strong(T &expected, T desired, + memory_order successMemoryOrder = memory_order::relaxed, + memory_order failMemoryOrder = memory_order::relaxed); + + /* Available only when: T != float */ + T fetch_add(T operand, memory_order memoryOrder = + memory_order::relaxed); + + /* Available only when: T != float */ + T fetch_sub(T operand, memory_order memoryOrder = + memory_order::relaxed); + + /* Available only when: T != float */ + T fetch_and(T operand, memory_order memoryOrder = + memory_order::relaxed); + + /* Available only when: T != float */ + T fetch_or(T operand, memory_order memoryOrder = + memory_order::relaxed); + + /* Available only when: T != float */ + T fetch_xor(T operand, memory_order memoryOrder = + memory_order::relaxed); + + /* Available only when: T != float */ + T fetch_min(T operand, memory_order memoryOrder = + memory_order::relaxed); + + /* Available only when: T != float */ + T fetch_max(T operand, memory_order memoryOrder = + memory_order::relaxed); +}; +} // namespace sycl +} // namespace cl diff --git a/adoc/headers/atomicoperations.h b/adoc/headers/atomicoperations.h new file mode 100644 index 00000000..ee91bf97 --- /dev/null +++ b/adoc/headers/atomicoperations.h @@ -0,0 +1,62 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace cl { +namespace sycl { +/* Deprecated in SYCL 2020 */ +template +void atomic_store(atomic object, T operand, memory_order memoryOrder = + memory_order::relaxed); + +/* Deprecated in SYCL 2020 */ +template +T atomic_load(atomic object, memory_order memoryOrder = + memory_order::relaxed); + +/* Deprecated in SYCL 2020 */ +template +T atomic_exchange(atomic object, T operand, memory_order memoryOrder = + memory_order::relaxed); + +/* Deprecated in SYCL 2020 */ +template +bool atomic_compare_exchange_strong(atomic object, T &expected, T desired, + memory_order successMemoryOrder = memory_order::relaxed, + memory_order failMemoryOrder = memory_order::relaxed); + +/* Deprecated in SYCL 2020 */ +template +T atomic_fetch_add(atomic object, T operand, memory_order memoryOrder = + memory_order::relaxed); + +/* Deprecated in SYCL 2020 */ +template +T atomic_fetch_sub(atomic object, T operand, memory_order memoryOrder = + memory_order::relaxed); + +/* Deprecated in SYCL 2020 */ +template +T atomic_fetch_and(atomic object, T operand, memory_order memoryOrder = + memory_order::relaxed); + +/* Deprecated in SYCL 2020 */ +template +T atomic_fetch_or(atomic object, T operand, memory_order memoryOrder = + memory_order::relaxed); + +/* Deprecated in SYCL 2020 */ +template +T atomic_fetch_xor(atomic object, T operand, memory_order memoryOrder = + memory_order::relaxed); + +/* Deprecated in SYCL 2020 */ +template +T atomic_fetch_min(atomic object, T operand, memory_order memoryOrder = + memory_order::relaxed); + +/* Deprecated in SYCL 2020 */ +template +T atomic_fetch_max(atomic object, T operand, memory_order memoryOrder = + memory_order::relaxed); +} // namespace sycl +} // namespace cl diff --git a/adoc/headers/atomicref.h b/adoc/headers/atomicref.h new file mode 100644 index 00000000..7c53d1fa --- /dev/null +++ b/adoc/headers/atomicref.h @@ -0,0 +1,222 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: MIT + +namespace sycl { + +// Exposition only +template +struct memory_order_traits; + +template <> +struct memory_order_traits { + static constexpr memory_order read_order = memory_order::relaxed; + static constexpr memory_order write_order = memory_order::relaxed; +}; + +template <> +struct memory_order_traits { + static constexpr memory_order read_order = memory_order::acquire; + static constexpr memory_order write_order = memory_order::release; +}; + +template <> +struct memory_order_traits { + static constexpr memory_order read_order = memory_order::seq_cst; + static constexpr memory_order write_order = memory_order::seq_cst; +}; + +template +class atomic_ref { + public: + + using value_type = T; + static constexpr size_t required_alignment = /* implementation-defined */; + static constexpr bool is_always_lock_free = /* implementation-defined */; + static constexpr memory_order default_read_order = memory_order_traits::read_order; + static constexpr memory_order default_write_order = memory_order_traits::write_order; + static constexpr memory_order default_read_modify_write_order = DefaultOrder; + static constexpr memory_scope default_scope = DefaultScope; + + bool is_lock_free() const noexcept; + + explicit atomic_ref(T&); + atomic_ref(const atomic_ref&) noexcept; + atomic_ref& operator=(const atomic_ref&) = delete; + + void store(T operand, + memory_order order = default_write_order, + memory_scope scope = default_scope) const noexcept; + + T operator=(T desired) const noexcept; + + T load(memory_order order = default_read_order, + memory_scope scope = default_scope) const noexcept; + + operator T() const noexcept; + + T exchange(T operand, + memory_order order = default_read_modify_write_order, + memory_scope scope = default_scope) const noexcept; + + bool compare_exchange_weak(T &expected, T desired, + memory_order success, + memory_order failure, + memory_scope scope = default_scope) const noexcept; + + bool compare_exchange_weak(T &expected, T desired, + memory_order order = default_read_modify_write_order, + memory_scope scope = default_scope) const noexcept; + + bool compare_exchange_strong(T &expected, T desired, + memory_order success, + memory_order failure, + memory_scope scope = default_scope) const noexcept; + + bool compare_exchange_strong(T &expected, T desired, + memory_order order = default_read_modify_write_order, + memory_scope scope = default_scope) const noexcept; +}; + +// Partial specialization for integral types +template +class atomic_ref { + + /* All other members from atomic_ref are available */ + + using difference_type = value_type; + + Integral fetch_add(Integral operand, + memory_order order = default_read_modify_write_order, + memory_scope scope = default_scope) const noexcept; + + Integral fetch_sub(Integral operand, + memory_order order = default_read_modify_write_order, + memory_scope scope = default_scope) const noexcept; + + Integral fetch_and(Integral operand, + memory_order order = default_read_modify_write_order, + memory_scope scope = default_scope) const noexcept; + + Integral fetch_or(Integral operand, + memory_order order = default_read_modify_write_order, + memory_scope scope = default_scope) const noexcept; + + Integral fetch_min(Integral operand, + memory_order order = default_read_modify_write_order, + memory_scope scope = default_scope) const noexcept; + + Integral fetch_max(Integral operand, + memory_order order = default_read_modify_write_order, + memory_scope scope = default_scope) const noexcept; + + Integral operator++(int) const noexcept; + Integral operator--(int) const noexcept; + Integral operator++() const noexcept; + Integral operator--() const noexcept; + Integral operator+=(Integral) const noexcept; + Integral operator-=(Integral) const noexcept; + Integral operator&=(Integral) const noexcept; + Integral operator|=(Integral) const noexcept; + Integral operator^=(Integral) const noexcept; + +}; + +// Partial specialization for floating-point types +template +class atomic_ref { + + /* All other members from atomic_ref are available */ + + using difference_type = value_type; + + Floating fetch_add(Floating operand, + memory_order order = default_read_modify_write_order, + memory_scope scope = default_scope) const noexcept; + + Floating fetch_sub(Floating operand, + memory_order order = default_read_modify_write_order, + memory_scope scope = default_scope) const noexcept; + + Floating fetch_min(Floating operand, + memory_order order = default_read_modify_write_order, + memory_scope scope = default_scope) const noexcept; + + Floating fetch_max(Floating operand, + memory_order order = default_read_modify_write_order, + memory_scope scope = default_scope) const noexcept; + + Floating operator+=(Floating) const noexcept; + Floating operator-=(Floating) const noexcept; + +}; + +// Partial specialization for pointers +template +class atomic_ref { + + using value_type = T*; + using difference_type = ptrdiff_t; + static constexpr size_t required_alignment = /* implementation-defined */; + static constexpr bool is_always_lock_free = /* implementation-defined */; + static constexpr memory_order default_read_order = memory_order_traits::read_order; + static constexpr memory_order default_write_order = memory_order_traits::write_order; + static constexpr memory_order default_read_modify_write_order = DefaultOrder; + static constexpr memory_scope default_scope = DefaultScope; + + bool is_lock_free() const noexcept; + + explicit atomic_ref(T*&); + atomic_ref(const atomic_ref&) noexcept; + atomic_ref& operator=(const atomic_ref&) = delete; + + void store(T* operand, + memory_order order = default_write_order, + memory_scope scope = default_scope) const noexcept; + + T* operator=(T* desired) const noexcept; + + T* load(memory_order order = default_read_order, + memory_scope scope = default_scope) const noexcept; + + operator T*() const noexcept; + + T* exchange(T* operand, + memory_order order = default_read_modify_write_order, + memory_scope scope = default_scope) const noexcept; + + bool compare_exchange_weak(T* &expected, T* desired, + memory_order success, + memory_order failure, + memory_scope scope = default_scope) const noexcept; + + bool compare_exchange_weak(T* &expected, T* desired, + memory_order order = default_read_modify_write_order, + memory_scope scope = default_scope) const noexcept; + + bool compare_exchange_strong(T* &expected, T* desired, + memory_order success, + memory_order failure, + memory_scope scope = default_scope) const noexcept; + + bool compare_exchange_strong(T* &expected, T* desired, + memory_order order = default_read_modify_write_order, + memory_scope scope = default_scope) const noexcept; + + T* fetch_add(difference_type, + memory_order order = default_read_modify_write_order, + memory_scope scope = default_scope) const noexcept; + + T* fetch_sub(difference_type, + memory_order order = default_read_modify_write_order, + memory_scope scope = default_scope) const noexcept; + + T* operator++(int) const noexcept; + T* operator--(int) const noexcept; + T* operator++() const noexcept; + T* operator--() const noexcept; + T* operator+=(difference_type) const noexcept; + T* operator-=(difference_type) const noexcept; + +}; + +} // namespace sycl diff --git a/adoc/headers/backends.h b/adoc/headers/backends.h new file mode 100644 index 00000000..403f3341 --- /dev/null +++ b/adoc/headers/backends.h @@ -0,0 +1,8 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: MIT + +namespace sycl { +enum class backend { + +}; +} // namespace sycl diff --git a/adoc/headers/buffer.h b/adoc/headers/buffer.h new file mode 100644 index 00000000..6cf19e7e --- /dev/null +++ b/adoc/headers/buffer.h @@ -0,0 +1,189 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { +namespace property { +namespace buffer { +class use_host_ptr { + public: + use_host_ptr() = default; +}; + +class use_mutex { + public: + use_mutex(std::mutex &mutexRef); + + std::mutex *get_mutex_ptr() const; +}; + +class context_bound { + public: + context_bound(context boundContext); + + context get_context() const; +}; +} // namespace buffer +} // namespace property + +template >> +class buffer { + public: + using value_type = T; + using reference = value_type &; + using const_reference = const value_type &; + using allocator_type = AllocatorT; + + buffer(const range &bufferRange, + const property_list &propList = {}); + + buffer(const range &bufferRange, AllocatorT allocator, + const property_list &propList = {}); + + buffer(T *hostData, const range &bufferRange, + const property_list &propList = {}); + + buffer(T *hostData, const range &bufferRange, + AllocatorT allocator, const property_list &propList = {}); + + buffer(const T *hostData, const range &bufferRange, + const property_list &propList = {}); + + buffer(const T *hostData, const range &bufferRange, + AllocatorT allocator, const property_list &propList = {}); + + /* Available only if Container is a contiguous container: + - std::data(container) and std::size(container) are well formed + - return type of std::data(container) is convertible to T* + and dimensions == 1 */ + template + buffer(Container &container, AllocatorT allocator, + const property_list &propList = {}); + + /* Available only if Container is a contiguous container: + - std::data(container) and std::size(container) are well formed + - return type of std::data(container) is convertible to T* + and dimensions == 1 */ + template + buffer(Container &container, const property_list &propList = {}); + + buffer(const std::shared_ptr &hostData, + const range &bufferRange, AllocatorT allocator, + const property_list &propList = {}); + + buffer(const std::shared_ptr &hostData, + const range &bufferRange, + const property_list &propList = {}); + + buffer(const std::shared_ptr &hostData, + const range &bufferRange, AllocatorT allocator, + const property_list &propList = {}); + + buffer(const std::shared_ptr &hostData, + const range &bufferRange, + const property_list &propList = {}); + + template + buffer(InputIterator first, InputIterator last, AllocatorT allocator, + const property_list &propList = {}); + + template + buffer(InputIterator first, InputIterator last, + const property_list &propList = {}); + + buffer(buffer &b, const id &baseIndex, + const range &subRange); + + /* -- common interface members -- */ + + /* -- property interface members -- */ + + range get_range() const; + + size_t byte_size() const noexcept; + + size_t size() const noexcept; + + // Deprecated + size_t get_count() const; + + // Deprecated + size_t get_size() const; + + AllocatorT get_allocator() const; + + template + accessor get_access( + handler &commandGroupHandler); + + // Deprecated + template + accessor get_access(); + + template + accessor get_access( + handler &commandGroupHandler, range accessRange, + id accessOffset = {}); + + // Deprecated + template + accessor get_access( + range accessRange, id accessOffset = {}); + + template + auto get_access(Ts...); + + template + auto get_host_access(Ts...); + + template + void set_final_data(Destination finalData = nullptr); + + void set_write_back(bool flag = true); + + bool is_sub_buffer() const; + + template + buffer::template rebind_alloc< + ReinterpretT>> + reinterpret(range reinterpretRange) const; + + // Only available when ReinterpretDim == 1 + // or when (ReinterpretDim == dimensions) && + // (sizeof(ReinterpretT) == sizeof(T)) + template + buffer::template rebind_alloc< + ReinterpretT>> + reinterpret() const; +}; + +// Deduction guides +template +buffer(InputIterator, InputIterator, AllocatorT, const property_list & = {}) + -> buffer::value_type, 1, + AllocatorT>; + +template +buffer(InputIterator, InputIterator, const property_list & = {}) + -> buffer::value_type, 1>; + +template +buffer(const T *, const range &, AllocatorT, + const property_list & = {}) + -> buffer; + +template +buffer(const T *, const range &, const property_list & = {}) + -> buffer; + +template +buffer(Container &, AllocatorT, const property_list & = {}) + ->buffer; + +template +buffer(Container &, const property_list & = {}) + ->buffer; + +} // namespace sycl diff --git a/adoc/headers/bundle/deviceImageClass.h b/adoc/headers/bundle/deviceImageClass.h new file mode 100644 index 00000000..bcf62d84 --- /dev/null +++ b/adoc/headers/bundle/deviceImageClass.h @@ -0,0 +1,16 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: MIT + +namespace sycl { + +template +class device_image { + public: + device_image() = delete; + + bool has_kernel(const kernel_id &kernelId) const noexcept; + + bool has_kernel(const kernel_id &kernelId, const device &dev) const noexcept; +}; + +} // namespace sycl diff --git a/adoc/headers/bundle/freeFunctions.h b/adoc/headers/bundle/freeFunctions.h new file mode 100644 index 00000000..65708a5e --- /dev/null +++ b/adoc/headers/bundle/freeFunctions.h @@ -0,0 +1,119 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: MIT + +namespace sycl { + +enum class bundle_state { + input, + object, + executable +}; + + +class kernel_id { /* ... */ }; + +template +class kernel_bundle { /* ... */ }; + + +template +kernel_id get_kernel_id(); + +std::vector get_kernel_ids(); + + +template +kernel_bundle get_kernel_bundle(const context &ctxt); + +template +kernel_bundle get_kernel_bundle(const context &ctxt, + const std::vector &kernelIds); + +template +kernel_bundle get_kernel_bundle(const context &ctxt); + +template +kernel_bundle get_kernel_bundle(const context &ctxt, const std::vector &devs); + +template +kernel_bundle get_kernel_bundle(const context &ctxt, const std::vector &devs, + const std::vector &kernelIds); + +template +kernel_bundle get_kernel_bundle(const context &ctxt, const std::vector &devs); + +template +kernel_bundle get_kernel_bundle(const context &ctxt, Selector selector); + +template +kernel_bundle get_kernel_bundle(const context &ctxt, const std::vector &devs, + Selector selector); + + +template +bool has_kernel_bundle(const context &ctxt); + +template +bool has_kernel_bundle(const context &ctxt, const std::vector &kernelIds); + +template +bool has_kernel_bundle(const context &ctxt); + +template +bool has_kernel_bundle(const context &ctxt, const std::vector &devs); + +template +bool has_kernel_bundle(const context &ctxt, const std::vector &devs, + const std::vector &kernelIds); + +template +bool has_kernel_bundle(const context &ctxt, const std::vector &devs); + + +bool is_compatible(const std::vector &kernelIds, const device &dev); + +template +bool is_compatible(const device &dev); + + +template +kernel_bundle join(const std::vector> &bundles); + + +kernel_bundle +compile(const kernel_bundle &inputBundle, + const property_list &propList = {}); + +kernel_bundle +compile(const kernel_bundle &inputBundle, + const std::vector &devs, + const property_list &propList = {}); + +kernel_bundle +link(const kernel_bundle &objectBundle, + const property_list &propList = {}); + +kernel_bundle +link(const std::vector> &objectBundles, + const property_list &propList = {}); + +kernel_bundle +link(const kernel_bundle &objectBundle, + const std::vector &devs, + const property_list &propList = {}); + +kernel_bundle +link(const std::vector> &objectBundles, + const std::vector &devs, + const property_list &propList = {}); + +kernel_bundle +build(const kernel_bundle &inputBundle, + const property_list &propList = {}); + +kernel_bundle +build(const kernel_bundle &inputBundle, + const std::vector &devs, + const property_list &propList = {}); + +} // namespace sycl diff --git a/adoc/headers/bundle/kernelBundleClass.h b/adoc/headers/bundle/kernelBundleClass.h new file mode 100644 index 00000000..dd58dd19 --- /dev/null +++ b/adoc/headers/bundle/kernelBundleClass.h @@ -0,0 +1,52 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: MIT + +namespace sycl { + +class kernel { /* ... */ }; + +template +class kernel_bundle { + public: + using device_image_iterator = __unspecified__; + + kernel_bundle() = delete; + + bool empty() const noexcept; + + backend get_backend() const noexcept; + + context get_context() const noexcept; + + std::vector get_devices() const noexcept; + + bool has_kernel(const kernel_id &kernelId) const noexcept; + + bool has_kernel(const kernel_id &kernelId, const device &dev) const noexcept; + + std::vector get_kernel_ids() const; + + /* Available only when: (State == bundle_state::executable) */ + kernel get_kernel(const kernel_id &kernelId) const; + + bool contains_specialization_constants() const noexcept; + + bool native_specialization_constant() const noexcept; + + template + bool has_specialization_constant() const noexcept; + + /* Available only when: (State == bundle_state::input) */ + template + void set_specialization_constant( + typename std::remove_reference_t::type value); + + template + typename std::remove_reference_t::type get_specialization_constant() const; + + device_image_iterator begin() const; + + device_image_iterator end() const; +}; + +} // namespace sycl diff --git a/adoc/headers/bundle/kernelClass.h b/adoc/headers/bundle/kernelClass.h new file mode 100644 index 00000000..981969b0 --- /dev/null +++ b/adoc/headers/bundle/kernelClass.h @@ -0,0 +1,26 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: MIT + +namespace sycl { + +class kernel { + public: + kernel() = delete; + + backend get_backend() const noexcept; + + context get_context() const; + + kernel_bundle get_kernel_bundle() const; + + template + typename param::return_type get_info() const; + + template + typename param::return_type get_info(const device &dev) const; + + template + typename param::return_type get_backend_info() const; +}; + +} // namespace sycl diff --git a/adoc/headers/bundle/kernelIdClass.h b/adoc/headers/bundle/kernelIdClass.h new file mode 100644 index 00000000..cb87dfa3 --- /dev/null +++ b/adoc/headers/bundle/kernelIdClass.h @@ -0,0 +1,13 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: MIT + +namespace sycl { + +class kernel_id { + public: + kernel_id() = delete; + + const char *get_name() const noexcept; +}; + +} // namespace sycl diff --git a/adoc/headers/commandGroup.h b/adoc/headers/commandGroup.h new file mode 100644 index 00000000..d7691670 --- /dev/null +++ b/adoc/headers/commandGroup.h @@ -0,0 +1,22 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { +class command_group { + public: + template + command_group(queue &primaryQueue, const functorT &lambda); + + template + command_group(queue &primaryQueue, queue &secondaryQueue, + const functorT &lambda); + + ~command_group(); + + event start_event(); + + event kernel_event(); + + event complete_event(); +}; +} // namespace sycl diff --git a/adoc/headers/commandGroupHandler.h b/adoc/headers/commandGroupHandler.h new file mode 100644 index 00000000..7b6bc28e --- /dev/null +++ b/adoc/headers/commandGroupHandler.h @@ -0,0 +1,130 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { + +class handler { + private: + + // implementation defined constructor + handler(___unspecified___); + + public: + + template + void require(accessor acc); + + void depends_on(event depEvent); + + void depends_on(const std::vector &depEvents); + + //----- Backend interoperability interface + // + template + void set_arg(int argIndex, T && arg); + + template + void set_args(Ts &&... args); + + //------ Kernel dispatch API + // + // Note: In all kernel dispatch functions, the template parameter + // "typename KernelName" is optional. + // + template + void single_task(const KernelType &kernelFunc); + + // Parameter pack acts as-if: Reductions&&... reductions, const KernelType &kernelFunc + template + void parallel_for(range numWorkItems, + Rest&&... rest); + + // Deprecated in SYCL 2020. + template + void parallel_for(range numWorkItems, + id workItemOffset, + const KernelType& kernelFunc); + + // Parameter pack acts as-if: Reductions&&... reductions, const KernelType &kernelFunc + template + void parallel_for(nd_range executionRange, + Rest&&... rest); + + template + void parallel_for_work_group(range numWorkGroups, + const WorkgroupFunctionType &kernelFunc); + + template + void parallel_for_work_group(range numWorkGroups, + range workGroupSize, + const WorkgroupFunctionType &kernelFunc); + + void single_task(const kernel &kernelObject); + + template + void parallel_for(range numWorkItems, const kernel &kernelObject); + + template + void parallel_for(nd_range ndRange, const kernel &kernelObject); + + + //------ USM functions + // + + void memcpy(void *dest, const void *src, size_t numBytes); + + template + void copy(T *dest, const T *src, size_t count); + + void memset(void *ptr, int value, size_t numBytes); + + template + void fill(void *ptr, const T &pattern, size_t count); + + void prefetch(void *ptr, size_t numBytes); + + void mem_advise(void *ptr, size_t numBytes, int advice); + + + //------ Explicit memory operation APIs + // + template + void copy(accessor src, + std::shared_ptr dest); + + template + void copy(std::shared_ptr src, + accessor dest); + + template + void copy(accessor src, + T_dest *dest); + + template + void copy(const T_src *src, + accessor dest); + + template + void copy(accessor src, + accessor dest); + + template + void update_host(accessor acc); + + template + void fill(accessor dest, const T& src); + + void use_kernel_bundle(const kernel_bundle &execBundle); + + template + typename std::remove_reference_t::type get_specialization_constant(); + +}; +} // namespace sycl diff --git a/adoc/headers/common-byval.h b/adoc/headers/common-byval.h new file mode 100644 index 00000000..7797502a --- /dev/null +++ b/adoc/headers/common-byval.h @@ -0,0 +1,34 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { + +class T { + ... + + public: + // If any of the following five special member functions are not + // public, inline or defaulted, then all five of them should be + // explicitly declared (see rule of five). + // Otherwise, none of them should be explicitly declared + // (see rule of zero). + + // T(const T &rhs); + + // T(T &&rhs); + + // T &operator=(const T &rhs); + + // T &operator=(T &&rhs); + + // ~T(); + + ... + + friend bool operator==(const T &lhs, const T &rhs) { /* ... */ } + + friend bool operator!=(const T &lhs, const T &rhs) { /* ... */ } + + ... +}; +} // namespace sycl diff --git a/adoc/headers/common-reference.h b/adoc/headers/common-reference.h new file mode 100644 index 00000000..f859327f --- /dev/null +++ b/adoc/headers/common-reference.h @@ -0,0 +1,28 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { + +class T { + ... + + public: + T(const T &rhs); + + T(T &&rhs); + + T &operator=(const T &rhs); + + T &operator=(T &&rhs); + + ~T(); + + ... + + friend bool operator==(const T &lhs, const T &rhs) { /* ... */ } + + friend bool operator!=(const T &lhs, const T &rhs) { /* ... */ } + + ... +}; +} // namespace sycl diff --git a/adoc/headers/context.h b/adoc/headers/context.h new file mode 100644 index 00000000..678f74ca --- /dev/null +++ b/adoc/headers/context.h @@ -0,0 +1,39 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { +class context { + public: + explicit context(const property_list &propList = {}); + + explicit context(async_handler asyncHandler, + const property_list &propList = {}); + + explicit context(const device &dev, const property_list &propList = {}); + + explicit context(const device &dev, async_handler asyncHandler, + const property_list &propList = {}); + + explicit context(const std::vector &deviceList, + const property_list &propList = {}); + + explicit context(const std::vector &deviceList, + async_handler asyncHandler, + const property_list &propList = {}); + + /* -- property interface members -- */ + + /* -- common interface members -- */ + + backend get_backend() const noexcept; + + platform get_platform() const; + + std::vector get_devices() const; + + template typename param::return_type get_info() const; + + template + typename param::return_type get_backend_info() const; +}; +} // namespace sycl diff --git a/adoc/headers/contextInfo.h b/adoc/headers/contextInfo.h new file mode 100644 index 00000000..ef6a937f --- /dev/null +++ b/adoc/headers/contextInfo.h @@ -0,0 +1,17 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { +namespace info { +namespace context { + +struct platform; +struct devices; +struct atomic_memory_order_capabilities; +struct atomic_fence_order_capabilities; +struct atomic_memory_scope_capabilities; +struct atomic_fence_scope_capabilities; + +} // namespace context +} // info +} // sycl diff --git a/adoc/headers/device.h b/adoc/headers/device.h new file mode 100644 index 00000000..69fed091 --- /dev/null +++ b/adoc/headers/device.h @@ -0,0 +1,49 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { + +class device { + public: + device(); + + template + explicit device(const DeviceSelector &deviceSelector); + + /* -- common interface members -- */ + + backend get_backend() const noexcept; + + bool is_cpu() const; + + bool is_gpu() const; + + bool is_accelerator() const; + + platform get_platform() const; + + template typename param::return_type get_info() const; + + template + typename param::return_type get_backend_info() const; + + bool has(aspect asp) const; + + bool has_extension(const std::string &extension) const; // Deprecated + + // Available only when prop == info::partition_property::partition_equally + template + std::vector create_sub_devices(size_t count) const; + + // Available only when prop == info::partition_property::partition_by_counts + template + std::vector create_sub_devices(const std::vector &counts) const; + + // Available only when prop == info::partition_property::partition_by_affinity_domain + template + std::vector create_sub_devices(info::partition_affinity_domain affinityDomain) const; + + static std::vector get_devices( + info::device_type deviceType = info::device_type::all); +}; +} // namespace sycl diff --git a/adoc/headers/deviceEnumClassAspect.h b/adoc/headers/deviceEnumClassAspect.h new file mode 100644 index 00000000..75dc2a9a --- /dev/null +++ b/adoc/headers/deviceEnumClassAspect.h @@ -0,0 +1,28 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: MIT + +namespace sycl { + +enum class aspect { + cpu, + gpu, + accelerator, + custom, + emulated, + host_debuggable, + fp16, + fp64, + atomic64, + image, + online_compiler, + online_linker, + queue_profiling, + usm_device_allocations, + usm_host_allocations, + usm_atomic_host_allocations, + usm_shared_allocations, + usm_atomic_shared_allocations, + usm_system_allocations +}; + +} // namespace sycl diff --git a/adoc/headers/deviceEvent.h b/adoc/headers/deviceEvent.h new file mode 100644 index 00000000..bdf4052c --- /dev/null +++ b/adoc/headers/deviceEvent.h @@ -0,0 +1,12 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { +class device_event { + + device_event(__unspecified__); + + public: + void wait() noexcept; +}; +} // namespace sycl diff --git a/adoc/headers/deviceInfo.h b/adoc/headers/deviceInfo.h new file mode 100644 index 00000000..0fdd8ba8 --- /dev/null +++ b/adoc/headers/deviceInfo.h @@ -0,0 +1,137 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { +namespace info { +namespace device { + +struct device_type; +struct vendor_id; +struct max_compute_units; +struct max_work_item_dimensions; +template struct max_work_item_sizes; +struct max_work_group_size; +struct preferred_vector_width_char; +struct preferred_vector_width_short; +struct preferred_vector_width_int; +struct preferred_vector_width_long; +struct preferred_vector_width_float; +struct preferred_vector_width_double; +struct preferred_vector_width_half; +struct native_vector_width_char; +struct native_vector_width_short; +struct native_vector_width_int; +struct native_vector_width_long; +struct native_vector_width_float; +struct native_vector_width_double; +struct native_vector_width_half; +struct max_clock_frequency; +struct address_bits; +struct max_mem_alloc_size; +struct image_support; // Deprecated +struct max_read_image_args; +struct max_write_image_args; +struct image2d_max_height; +struct image2d_max_width; +struct image3d_max_height; +struct image3d_max_width; +struct image3d_max_depth; +struct image_max_buffer_size; +struct max_samplers; +struct max_parameter_size; +struct mem_base_addr_align; +struct half_fp_config; +struct single_fp_config; +struct double_fp_config; +struct global_mem_cache_type; +struct global_mem_cache_line_size; +struct global_mem_cache_size; +struct global_mem_size; +struct max_constant_buffer_size; // Deprecated +struct max_constant_args; // Deprecated +struct local_mem_type; +struct local_mem_size; +struct error_correction_support; +struct host_unified_memory; +struct atomic_memory_order_capabilities; +struct atomic_fence_order_capabilities; +struct atomic_memory_scope_capabilities; +struct atomic_fence_scope_capabilities; +struct profiling_timer_resolution; +struct is_endian_little; +struct is_available; +struct is_compiler_available; // Deprecated +struct is_linker_available; // Deprecated +struct execution_capabilities; +struct queue_profiling; // Deprecated +struct built_in_kernels; // Deprecated +struct built_in_kernel_ids; +struct platform; +struct name; +struct vendor; +struct driver_version; +struct profile; +struct version; +struct backend_version; +struct aspects; +struct extensions; // Deprecated +struct printf_buffer_size; +struct preferred_interop_user_sync; +struct parent_device; +struct partition_max_sub_devices; +struct partition_properties; +struct partition_affinity_domains; +struct partition_type_property; +struct partition_type_affinity_domain; + +} // namespace device + +enum class device_type : unsigned int { + cpu, // Maps to OpenCL CL_DEVICE_TYPE_CPU + gpu, // Maps to OpenCL CL_DEVICE_TYPE_GPU + accelerator, // Maps to OpenCL CL_DEVICE_TYPE_ACCELERATOR + custom, // Maps to OpenCL CL_DEVICE_TYPE_CUSTOM + automatic, // Maps to OpenCL CL_DEVICE_TYPE_DEFAULT + host, + all // Maps to OpenCL CL_DEVICE_TYPE_ALL +}; + +enum class partition_property : int { + no_partition, + partition_equally, + partition_by_counts, + partition_by_affinity_domain +}; + +enum class partition_affinity_domain : int { + not_applicable, + numa, + L4_cache, + L3_cache, + L2_cache, + L1_cache, + next_partitionable +}; + +enum class local_mem_type : int { none, local, global }; + +enum class fp_config : int { + denorm, + inf_nan, + round_to_nearest, + round_to_zero, + round_to_inf, + fma, + correctly_rounded_divide_sqrt, + soft_float +}; + +enum class global_mem_cache_type : int { none, read_only, read_write }; + +enum class execution_capability : unsigned int { + exec_kernel, + exec_native_kernel +}; + +} // namespace info +} // namespace sycl diff --git a/adoc/headers/deviceSelector.h b/adoc/headers/deviceSelector.h new file mode 100644 index 00000000..52c92097 --- /dev/null +++ b/adoc/headers/deviceSelector.h @@ -0,0 +1,27 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { + +// Predefined device selectors +__unspecified__ default_selector_v; +__unspecified__ cpu_selector_v; +__unspecified__ gpu_selector_v; +__unspecified__ accelerator_selector_v; + +// Predefined types for compatibility with old SYCL 1.2.1 device selectors +using default_selector = __unspecified__; +using cpu_selector = __unspecified__; +using gpu_selector = __unspecified__; +using accelerator_selector = __unspecified__; + +// Returns a selector that selects a device based on desired aspects +__unspecified_callable__ aspect_selector( + const std::vector &aspectList, + const std::vector &denyList = {}); +template +__unspecified_callable__ aspect_selector(aspectListTN... aspectList); +template +__unspecified_callable__ aspect_selector(); + +} // namespace sycl diff --git a/adoc/headers/event.h b/adoc/headers/event.h new file mode 100644 index 00000000..7cc3609a --- /dev/null +++ b/adoc/headers/event.h @@ -0,0 +1,33 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { + +class event { + public: + event(); + + /* -- common interface members -- */ + + backend get_backend() const noexcept; + + std::vector get_wait_list(); + + void wait(); + + static void wait(const std::vector &eventList); + + void wait_and_throw(); + + static void wait_and_throw(const std::vector &eventList); + + template typename param::return_type get_info() const; + + template + typename param::return_type get_backend_info() const; + + template + typename param::return_type get_profiling_info() const; +}; + +} // namespace sycl diff --git a/adoc/headers/eventInfo.h b/adoc/headers/eventInfo.h new file mode 100644 index 00000000..33847332 --- /dev/null +++ b/adoc/headers/eventInfo.h @@ -0,0 +1,26 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { +namespace info { +namespace event { + +struct command_execution_status; + +} // namespace event + +enum class event_command_status : int { + submitted, + running, + complete +}; + +namespace event_profiling { + +struct command_submit; +struct command_start; +struct command_end; + +} // namespace event_profiling +} // namespace info +} // namespace sycl diff --git a/adoc/headers/exception.h b/adoc/headers/exception.h new file mode 100644 index 00000000..118f2578 --- /dev/null +++ b/adoc/headers/exception.h @@ -0,0 +1,84 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { + +using async_handler = std::function; + +class exception : public virtual std::exception { + public: + exception(std::error_code ec, const std::string& what_arg); + exception(std::error_code ec, const char * what_arg); + exception(std::error_code ec); + exception(int ev, const std::error_category& ecat, const std::string& what_arg); + exception(int ev, const std::error_category& ecat, const char* what_arg); + exception(int ev, const std::error_category& ecat); + + exception(context ctx, std::error_code ec, const std::string& what_arg); + exception(context ctx, std::error_code ec, const char* what_arg); + exception(context ctx, std::error_code ec); + exception(context ctx, int ev, const std::error_category& ecat, const std::string& what_arg); + exception(context ctx, int ev, const std::error_category& ecat, const char* what_arg); + exception(context ctx, int ev, const std::error_category& ecat); + + const std::error_code& code() const noexcept; + const std::error_category& category() const noexcept; + + bool has_context() const noexcept; + context get_context() const; +}; + +class exception_list { + // Used as a container for a list of asynchronous exceptions + public: + using value_type = std::exception_ptr; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = std::size_t; + using iterator = /*unspecified*/; + using const_iterator = /*unspecified*/; + + size_type size() const; + iterator begin() const; // first asynchronous exception + iterator end() const; // refer to past-the-end last asynchronous exception +}; + +enum class errc { + runtime = /* implementation-defined */, + kernel = /* implementation-defined */, + accessor = /* implementation-defined */, + nd_range = /* implementation-defined */, + event = /* implementation-defined */, + kernel_argument = /* implementation-defined */, + build = /* implementation-defined */, + invalid = /* implementation-defined */, + memory_allocation = /* implementation-defined */, + platform = /* implementation-defined */, + profiling = /* implementation-defined */, + feature_not_supported = /* implementation-defined */, + kernel_not_supported = /* implementation-defined */, + backend_mismatch = /* implementation-defined */ +}; + +template +using errc_for = typename backend_traits::errc; + +std::error_condition make_error_condition(errc e) noexcept; +std::error_code make_error_code(errc e) noexcept; + +const std::error_category& sycl_category() noexcept; + +template +const std::error_category& error_category_for() noexcept; + +} // namespace sycl + +namespace std { + + template <> + struct is_error_condition_enum : true_type {}; + + template <> + struct is_error_code_enum : true_type {}; + +} // namespace std diff --git a/adoc/headers/expressingParallelism/classKernelHandler.h b/adoc/headers/expressingParallelism/classKernelHandler.h new file mode 100644 index 00000000..96237dbf --- /dev/null +++ b/adoc/headers/expressingParallelism/classKernelHandler.h @@ -0,0 +1,12 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: MIT + +namespace sycl { + +class kernel_handler { + public: + template + typename std::remove_reference_t::type get_specialization_constant(); +}; + +} // namespace sycl diff --git a/adoc/headers/expressingParallelism/classSpecializationId.h b/adoc/headers/expressingParallelism/classSpecializationId.h new file mode 100644 index 00000000..9665b216 --- /dev/null +++ b/adoc/headers/expressingParallelism/classSpecializationId.h @@ -0,0 +1,20 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: MIT + +namespace sycl { + +template +class specialization_id { + public: + using value_type = T; + + template + explicit constexpr specialization_id(Args&&... args); + + specialization_id(const specialization_id& rhs) = delete; + specialization_id(specialization_id&& rhs) = delete; + specialization_id &operator=(const specialization_id& rhs) = delete; + specialization_id &operator=(specialization_id&& rhs) = delete; +}; + +} // namespace sycl diff --git a/adoc/headers/expressingParallelism/kernelHandlerSynopsis.h b/adoc/headers/expressingParallelism/kernelHandlerSynopsis.h new file mode 100644 index 00000000..667ab451 --- /dev/null +++ b/adoc/headers/expressingParallelism/kernelHandlerSynopsis.h @@ -0,0 +1,21 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: MIT + +namespace sycl { + +class kernel_handler { + private: + + kernel_handler(__unspecified__); + + public: + + template + bool has_specialization_constant() const noexcept; + + template + typename std::remove_reference_t::type get_specialization_constant(); + +}; + +} // namespace sycl diff --git a/adoc/headers/functional.h b/adoc/headers/functional.h new file mode 100644 index 00000000..d0af2bff --- /dev/null +++ b/adoc/headers/functional.h @@ -0,0 +1,51 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: MIT + +namespace sycl { + +template +struct plus { + T operator()(const T& x, const T& y) const; +}; + +template +struct multiplies { + T operator()(const T& x, const T& y) const; +}; + +template +struct bit_and { + T operator()(const T& x, const T& y) const; +}; + +template +struct bit_or { + T operator()(const T& x, const T& y) const; +}; + +template +struct bit_xor { + T operator()(const T& x, const T& y) const; +}; + +template +struct logical_and { + T operator()(const T& x, const T& y) const; +}; + +template +struct logical_or { + T operator()(const T& x, const T& y) const; +}; + +template +struct minimum { + T operator()(const T& x, const T& y) const; +}; + +template +struct maximum { + T operator()(const T& x, const T& y) const; +}; + +} // namespace sycl diff --git a/adoc/headers/group.h b/adoc/headers/group.h new file mode 100644 index 00000000..65776783 --- /dev/null +++ b/adoc/headers/group.h @@ -0,0 +1,73 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { +template +class group { +public: + + using id_type = id; + using range_type = range; + using linear_id_type = size_t; + static constexpr int dimensions = Dimensions; + static constexpr memory_scope fence_scope = memory_scope::work_group; + + /* -- common interface members -- */ + + id get_group_id() const; + + size_t get_group_id(int dimension) const; + + id get_local_id() const; + + size_t get_local_id(int dimension) const; + + range get_local_range() const; + + size_t get_local_range(int dimension) const; + + range get_group_range() const; + + size_t get_group_range(int dimension) const; + + range get_max_local_range() const; + + size_t operator[](int dimension) const; + + size_t get_group_linear_id() const; + + size_t get_local_linear_id() const; + + size_t get_group_linear_range() const; + + size_t get_local_linear_range() const; + + bool leader() const; + + template + void parallel_for_work_item(const workItemFunctionT &func) const; + + template + void parallel_for_work_item(range logicalRange, + const workItemFunctionT &func) const; + + template + device_event async_work_group_copy(decorated_local_ptr dest, + decorated_global_ptr src, size_t numElements) const; + + template + device_event async_work_group_copy(decorated_global_ptr dest, + decorated_local_ptr src, size_t numElements) const; + + template + device_event async_work_group_copy(decorated_local_ptr dest, + decorated_global_ptr src, size_t numElements, size_t srcStride) const; + + template + device_event async_work_group_copy(decorated_global_ptr dest, + decorated_local_ptr src, size_t numElements, size_t destStride) const; + + template + void wait_for(eventTN... events) const; +}; +} // sycl diff --git a/adoc/headers/groups/barrier.h b/adoc/headers/groups/barrier.h new file mode 100644 index 00000000..7e4967ab --- /dev/null +++ b/adoc/headers/groups/barrier.h @@ -0,0 +1,5 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: MIT + +template +void group_barrier(Group g, memory_scope fence_scope = Group::fence_scope); // (1) diff --git a/adoc/headers/groups/broadcast.h b/adoc/headers/groups/broadcast.h new file mode 100644 index 00000000..6a6d9715 --- /dev/null +++ b/adoc/headers/groups/broadcast.h @@ -0,0 +1,11 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: MIT + +template +bool group_broadcast(Group g, T x); // (1) + +template +T group_broadcast(Group g, T x, Group::linear_id_type local_linear_id); // (2) + +template +T group_broadcast(Group g, T x, Group::id_type local_id); // (3) diff --git a/adoc/headers/handler/useKernelBundle.h b/adoc/headers/handler/useKernelBundle.h new file mode 100644 index 00000000..220ca7b6 --- /dev/null +++ b/adoc/headers/handler/useKernelBundle.h @@ -0,0 +1,4 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: MIT + +void use_kernel_bundle(const kernel_bundle &execBundle); diff --git a/adoc/headers/hitem.h b/adoc/headers/hitem.h new file mode 100644 index 00000000..1f51b6f6 --- /dev/null +++ b/adoc/headers/hitem.h @@ -0,0 +1,53 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { +template +class h_item { +public: + h_item() = delete; + + /* -- common interface members -- */ + + item get_global() const; + + item get_local() const; + + item get_logical_local() const; + + item get_physical_local() const; + + range get_global_range() const; + + size_t get_global_range(int dimension) const; + + id get_global_id() const; + + size_t get_global_id(int dimension) const; + + range get_local_range() const; + + size_t get_local_range(int dimension) const; + + id get_local_id() const; + + size_t get_local_id(int dimension) const; + + range get_logical_local_range() const; + + size_t get_logical_local_range(int dimension) const; + + id get_logical_local_id() const; + + size_t get_logical_local_id(int dimension) const; + + range get_physical_local_range() const; + + size_t get_physical_local_range(int dimension) const; + + id get_physical_local_id() const; + + size_t get_physical_local_id(int dimension) const; + +}; +} // namespace sycl diff --git a/adoc/headers/hostTask/classHandler/hostTask.h b/adoc/headers/hostTask/classHandler/hostTask.h new file mode 100644 index 00000000..2ba03cf4 --- /dev/null +++ b/adoc/headers/hostTask/classHandler/hostTask.h @@ -0,0 +1,12 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: MIT + +class handler { + ... + + public: + template + void host_task(T &&hostTaskCallable); // (1) + + ... +}; diff --git a/adoc/headers/hostTask/classInteropHandle.h b/adoc/headers/hostTask/classInteropHandle.h new file mode 100644 index 00000000..3024faf4 --- /dev/null +++ b/adoc/headers/hostTask/classInteropHandle.h @@ -0,0 +1,4 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: MIT + +class interop_handle; diff --git a/adoc/headers/hostTask/classInteropHandle/constructors.h b/adoc/headers/hostTask/classInteropHandle/constructors.h new file mode 100644 index 00000000..9ee22d03 --- /dev/null +++ b/adoc/headers/hostTask/classInteropHandle/constructors.h @@ -0,0 +1,10 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: MIT + +private: + + interop_handle(__unspecified__); // (1) + +public: + + interop_handle() = delete; // (2) diff --git a/adoc/headers/hostTask/classInteropHandle/getbackend.h b/adoc/headers/hostTask/classInteropHandle/getbackend.h new file mode 100644 index 00000000..895b9730 --- /dev/null +++ b/adoc/headers/hostTask/classInteropHandle/getbackend.h @@ -0,0 +1,4 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: MIT + +backend get_backend() const noexcept; diff --git a/adoc/headers/hostTask/classInteropHandle/getnativeX.h b/adoc/headers/hostTask/classInteropHandle/getnativeX.h new file mode 100644 index 00000000..1e07b6dc --- /dev/null +++ b/adoc/headers/hostTask/classInteropHandle/getnativeX.h @@ -0,0 +1,28 @@ +headers/hostTask/classInteropHandle/getnativeX.h +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: MIT + +template +backend_return_t> +get_native_mem(const accessor &bufferAcc) const; + +template +backend_return_t> +get_native_mem( // (2) + const unsampled_image_accessor &imageAcc) const; + +template +backend_return_t> +get_native_mem( // (3) + const sampled_image_accessor &imageAcc) const; + +template +backend_return_t get_native_queue() const; // (4) + +template +backend_return_t get_native_device() const; // (5) + +template +backend_return_t get_native_context() const; // (6) diff --git a/adoc/headers/hostTask/hostTaskSynopsis.h b/adoc/headers/hostTask/hostTaskSynopsis.h new file mode 100644 index 00000000..ff99bf4b --- /dev/null +++ b/adoc/headers/hostTask/hostTaskSynopsis.h @@ -0,0 +1,57 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: MIT + +namespace sycl { + +class interop_handle { + private: + + interop_handle(__unspecified__); + + public: + + interop_handle() = delete; + + backend get_backend() const noexcept; + + template + backend_return_t> + get_native_mem(const accessor &bufferAccessor) const; + + template + backend_return_t> + get_native_mem( + const unsampled_image_accessor + &imageAcc) const; + + template + backend_return_t> + get_native_mem( + const sampled_image_accessor &imageAcc) + const; + + template + backend_return_t get_native_queue() const; + + template + backend_return_t get_native_device() const; + + template + backend_return_t get_native_context() const; + +}; + +class handler { + ... + + public: + + template + void host_task(T &&hostTaskCallable); + + ... +}; + +} // namespace sycl diff --git a/adoc/headers/id.h b/adoc/headers/id.h new file mode 100644 index 00000000..ca16deee --- /dev/null +++ b/adoc/headers/id.h @@ -0,0 +1,59 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { +template +class id { +public: + id(); + + /* The following constructor is only available in the id class + * specialization where: dimensions==1 */ + id(size_t dim0); + /* The following constructor is only available in the id class + * specialization where: dimensions==2 */ + id(size_t dim0, size_t dim1); + /* The following constructor is only available in the id class + * specialization where: dimensions==3 */ + id(size_t dim0, size_t dim1, size_t dim2); + + /* -- common interface members -- */ + + id(const range &range); + id(const item &item); + + size_t get(int dimension) const; + size_t &operator[](int dimension); + size_t operator[](int dimension) const; + + // only available if dimensions == 1 + operator size_t() const; + + // OP is: +, -, *, /, %, <<, >>, &, |, ^, &&, ||, <, >, <=, >= + friend id operatorOP(const id &lhs, const id &rhs) { /* ... */ } + friend id operatorOP(const id &lhs, const size_t &rhs) { /* ... */ } + + // OP is: +=, -=, *=, /=, %=, <<=, >>=, &=, |=, ^= + friend id &operatorOP(id &lhs, const id &rhs) { /* ... */ } + friend id &operatorOP(id &lhs, const size_t &rhs) { /* ... */ } + + // OP is: +, -, *, /, %, <<, >>, &, |, ^, &&, ||, <, >, <=, >= + friend id operatorOP(const size_t &lhs, const id &rhs) { /* ... */ } + + // OP is unary +, - + friend id operatorOP(const id &rhs) { /* ... */ } + + // OP is prefix ++, -- + friend id & operatorOP(id &rhs) { /* ... */ } + + // OP is postfix ++, -- + friend id operatorOP(id &lhs, int) { /* ... */ } + +}; + +// Deduction guides +id(size_t) -> id<1>; +id(size_t, size_t) -> id<2>; +id(size_t, size_t, size_t) -> id<3>; + +} // namespace sycl diff --git a/adoc/headers/identity.h b/adoc/headers/identity.h new file mode 100644 index 00000000..f83239a5 --- /dev/null +++ b/adoc/headers/identity.h @@ -0,0 +1,18 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +template +struct known_identity { + static constexpr AccumulatorT value; +}; + +template +inline constexpr AccumulatorT known_identity_v = known_identity::value; + +template +struct has_known_identity { + static constexpr bool value; +}; + +template +inline constexpr bool has_known_identity_v = has_known_identity::value; diff --git a/adoc/headers/imageProperties.h b/adoc/headers/imageProperties.h new file mode 100644 index 00000000..f94de125 --- /dev/null +++ b/adoc/headers/imageProperties.h @@ -0,0 +1,27 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { +namespace property { +namespace image { +class use_host_ptr { + public: + use_host_ptr() = default; +}; + +class use_mutex { + public: + use_mutex(std::mutex &mutexRef); + + std::mutex *get_mutex_ptr() const; +}; + +class context_bound { + public: + context_bound(context boundContext); + + context get_context() const; +}; +} // namespace image +} // namespace property +} // namespace sycl diff --git a/adoc/headers/imageSampler.h b/adoc/headers/imageSampler.h new file mode 100644 index 00000000..1238ba29 --- /dev/null +++ b/adoc/headers/imageSampler.h @@ -0,0 +1,28 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { +enum class addressing_mode: unsigned int { + mirrored_repeat, + repeat, + clamp_to_edge, + clamp, + none +}; + +enum class filtering_mode: unsigned int { + nearest, + linear +}; + +enum class coordinate_normalization_mode : unsigned int { + normalized, + unnormalized +}; + +struct image_sampler { + addressing_mode addressing; + coordinate_mode coordinate; + filtering_mode filtering; +}; +} // namespace sycl diff --git a/adoc/headers/interop/templateFunctionGetNative.h b/adoc/headers/interop/templateFunctionGetNative.h new file mode 100644 index 00000000..6be9a2c4 --- /dev/null +++ b/adoc/headers/interop/templateFunctionGetNative.h @@ -0,0 +1,9 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: MIT + +namespace sycl { + +template +backend_return_t get_native(const T &syclObject); + +} // namespace sycl diff --git a/adoc/headers/interop/templateFunctionMakeX.h b/adoc/headers/interop/templateFunctionMakeX.h new file mode 100644 index 00000000..baaaf5d4 --- /dev/null +++ b/adoc/headers/interop/templateFunctionMakeX.h @@ -0,0 +1,77 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: MIT + +namespace sycl { + +template +platform make_platform(const backend_input_t &backendObject); + +template +device make_device(const backend_input_t &backendObject); + +template +context make_context(const backend_input_t &backendObject, + const async_handler asyncHandler = {}); + +template +queue make_queue(const backend_input_t &backendObject, + const context &targetContext, + const async_handler asyncHandler = {}); + +template +event make_event(const backend_input_t &backendObject, + const context &targetContext); + +template >> +buffer +make_buffer(const backend_input_t> + &backendObject, + const context &targetContext, event availableEvent); + +template >> +buffer +make_buffer(const backend_input_t> + &backendObject, + const context &targetContext); + +template +sampled_image make_sampled_image( + const backend_input_t> + &backendObject, + const context &targetContext, image_sampler imageSampler, + event availableEvent); + +template +sampled_image make_sampled_image( + const backend_input_t> + &backendObject, + const context &targetContext, image_sampler imageSampler); + +template +unsampled_image make_unsampled_image( + const backend_input_t> + &backendObject, + const context &targetContext, event availableEvent); + +template +unsampled_image make_unsampled_image( + const backend_input_t> + &backendObject, + const context &targetContext); + +template +kernel_bundle make_kernel_bundle( + const backend_input_t> &backendObject, + const context &targetContext); + +template +kernel make_kernel(const backend_input_t &backendObject, + const context &targetContext); + +} // namespace sycl diff --git a/adoc/headers/interop/typeTraitsBackendTraits.h b/adoc/headers/interop/typeTraitsBackendTraits.h new file mode 100644 index 00000000..964d5bd6 --- /dev/null +++ b/adoc/headers/interop/typeTraitsBackendTraits.h @@ -0,0 +1,26 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: MIT + +namespace sycl { + +template +class backend_traits { + public: + template + using input_type = see-below; + + template + using return_type = see-below; + + using errc = see-below; +}; + +template +using backend_input_t = + typename backend_traits::template input_type; + +template +using backend_return_t = + typename backend_traits::template return_type; + +} // namespace sycl diff --git a/adoc/headers/item.h b/adoc/headers/item.h new file mode 100644 index 00000000..8cb063fa --- /dev/null +++ b/adoc/headers/item.h @@ -0,0 +1,34 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { +template +class item { +public: + item() = delete; + + /* -- common interface members -- */ + + id get_id() const; + + size_t get_id(int dimension) const; + + size_t operator[](int dimension) const; + + range get_range() const; + + size_t get_range(int dimension) const; + + // Deprecated in SYCL 2020. + // only available if with_offset is true + id get_offset() const; + + // only available if with_offset is false + operator item() const; + + // only available if dimensions == 1 + operator size_t() const; + + size_t get_linear_id() const; +}; +} // namespace sycl diff --git a/adoc/headers/kernelInfo.h b/adoc/headers/kernelInfo.h new file mode 100644 index 00000000..f2214047 --- /dev/null +++ b/adoc/headers/kernelInfo.h @@ -0,0 +1,28 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { +namespace info { +namespace kernel { + +struct num_args; +struct attributes; + +} // namespace kernel + +namespace kernel_device_specific { + +struct global_work_size; +struct work_group_size; +struct compile_work_group_size; +struct preferred_work_group_size_multiple; +struct private_mem_size; +struct max_num_sub_groups; +struct compile_num_sub_groups; +struct max_sub_group_size; +struct compile_sub_group_size; + +} // namespace kernel_device_specific + +} // namespace info +} // namespace sycl diff --git a/adoc/headers/marray.h b/adoc/headers/marray.h new file mode 100755 index 00000000..6fc4da0e --- /dev/null +++ b/adoc/headers/marray.h @@ -0,0 +1,124 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { + +template +class marray { + public: + using value_type = dataT; + using reference = dataT&; + using const_reference = const dataT&; + using iterator = dataT*; + using const_iterator = const dataT*; + + marray(); + + explicit marray(const dataT &arg); + + template + marray(const argTN&... args); + + marray(const marray &rhs); + marray(marray &&rhs); + + // Available only when: numElements == 1 + operator dataT() const; + + static constexpr std::size_t size() noexcept; + + // subscript operator + reference operator[](std::size_t index); + const_reference operator[](std::size_t index) const; + + marray &operator=(const marray &rhs); + marray &operator=(const dataT &rhs); + + // iterator functions + iterator begin(); + const_iterator begin() const; + + iterator end(); + const_iterator end() const; + + + // OP is: +, -, *, /, % + /* If OP is %, available only when: dataT != float && dataT != double && dataT != half. */ + friend marray operatorOP(const marray &lhs, const marray &rhs) { /* ... */ } + friend marray operatorOP(const marray &lhs, const dataT &rhs) { /* ... */ } + + // OP is: +=, -=, *=, /=, %= + /* If OP is %=, available only when: dataT != float && dataT != double && dataT != half. */ + friend marray &operatorOP(marray &lhs, const marray &rhs) { /* ... */ } + friend marray &operatorOP(marray &lhs, const dataT &rhs) { /* ... */ } + + // OP is prefix ++, -- + friend marray &operatorOP(marray &rhs) { /* ... */ } + + // OP is postfix ++, -- + friend marray operatorOP(marray& lhs, int) { /* ... */ } + + // OP is unary +, - + friend marray operatorOP(marray &rhs) { /* ... */ } + + // OP is: &, |, ^ + /* Available only when: dataT != float && dataT != double && dataT != half. */ + friend marray operatorOP(const marray &lhs, const marray &rhs) { /* ... */ } + friend marray operatorOP(const marray &lhs, const dataT &rhs) { /* ... */ } + + // OP is: &=, |=, ^= + /* Available only when: dataT != float && dataT != double && dataT != half. */ + friend marray &operatorOP(marray &lhs, const marray &rhs) { /* ... */ } + friend marray &operatorOP(marray &lhs, const dataT &rhs) { /* ... */ } + + // OP is: &&, || + friend marray operatorOP(const marray &lhs, const marray &rhs) { + /* ... */ } + friend marray operatorOP(const marray& lhs, const dataT &rhs) { + /* ... */ } + + // OP is: <<, >> + /* Available only when: dataT != float && dataT != double && dataT != half. */ + friend marray operatorOP(const marray &lhs, const marray &rhs) { /* ... */ } + friend marray operatorOP(const marray &lhs, const dataT &rhs) { /* ... */ } + + // OP is: <<=, >>= + /* Available only when: dataT != float && dataT != double && dataT != half. */ + friend marray &operatorOP(marray &lhs, const marray &rhs) { /* ... */ } + friend marray &operatorOP(marray &lhs, const dataT &rhs) { /* ... */ } + + // OP is: ==, !=, <, >, <=, >= + friend marray operatorOP(const marray &lhs, const marray &rhs) { + /* ... */ } + friend marray operatorOP(const marray &lhs, const dataT &rhs) { + /* ... */ } + + /* Available only when: dataT != float && dataT != double && dataT != half. */ + friend marray operator~(const marray &v) { /* ... */ } + + // OP is: +, -, *, /, % + /* operator% is only available when: dataT != float && dataT != double && dataT != half. */ + friend marray operatorOP(const dataT &lhs, const marray &rhs) { /* ... */ } + + // OP is: &, |, ^ + /* Available only when: dataT != float && dataT != double + && dataT != half. */ + friend marray operatorOP(const dataT &lhs, const marray &rhs) { /* ... */ } + + // OP is: &&, || + friend marray operatorOP(const dataT &lhs, const marray &rhs) { + /* ... */ } + + // OP is: <<, >> + /* Available only when: dataT != float && dataT != double && dataT != half. */ + friend marray operatorOP(const dataT &lhs, const marray &rhs) { /* ... */ } + + // OP is: ==, !=, <, >, <=, >= + friend marray operatorOP(const dataT &lhs, const marray &rhs) { + /* ... */ } + + friend marray operator!(const marray &v) { /* ... */ } + +}; + +} // namespace sycl diff --git a/adoc/headers/memoryOrder.h b/adoc/headers/memoryOrder.h new file mode 100644 index 00000000..f6be4fd1 --- /dev/null +++ b/adoc/headers/memoryOrder.h @@ -0,0 +1,15 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: MIT + +namespace sycl { + +enum class memory_order : /* unspecified */ { + relaxed, acquire, release, acq_rel, seq_cst +}; +inline constexpr auto memory_order_relaxed = memory_order::relaxed; +inline constexpr auto memory_order_acquire = memory_order::acquire; +inline constexpr auto memory_order_release = memory_order::release; +inline constexpr auto memory_order_acq_rel = memory_order::acq_rel; +inline constexpr auto memory_order_seq_cst = memory_order::seq_cst; + +} // namespace sycl diff --git a/adoc/headers/memoryScope.h b/adoc/headers/memoryScope.h new file mode 100644 index 00000000..e9e476b7 --- /dev/null +++ b/adoc/headers/memoryScope.h @@ -0,0 +1,15 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: MIT + +namespace sycl { + +enum class memory_scope : /* unspecified */ { + work_item, sub_group, work_group, device, system +}; +inline constexpr auto memory_scope_work_item = memory_scope::work_item; +inline constexpr auto memory_scope_sub_group = memory_scope::sub_group; +inline constexpr auto memory_scope_work_group = memory_scope::work_group; +inline constexpr auto memory_scope_device = memory_scope::device; +inline constexpr auto memory_scope_system = memory_scope::system; + +} // namespace sycl diff --git a/adoc/headers/multipointer.h b/adoc/headers/multipointer.h new file mode 100644 index 00000000..ad306a0a --- /dev/null +++ b/adoc/headers/multipointer.h @@ -0,0 +1,288 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { +namespace access { +enum class address_space : int { + global_space, + local_space, + constant_space, // Deprecated in SYCL 2020 + private_space, + generic_space, +}; + +enum class decorated : int { + no, + yes, + legacy, +}; + +} // namespace access + +template struct remove_decoration { + using type = /* ... */; +}; + +template +using remove_decoration_t = remove_decoration::type; + +template +class multi_ptr { + public: + static constexpr bool is_decorated = DecorateAddress == access::decorated::yes; + static constexpr access::address_space address_space = Space; + + using value_type = ElementType; + using pointer = std::conditional>; + using reference = std::conditional>; + using iterator_category = std::random_access_iterator_tag; + using difference_type = std::ptrdiff_t; + + static_assert(std::is_same_v, std::add_pointer_t>); + static_assert(std::is_same_v, std::add_lvalue_reference_t>); + // Legacy has a different interface. + static_assert(DecorateAddress != access::decorated::legacy); + + // Constructors + multi_ptr(); + multi_ptr(const multi_ptr&); + multi_ptr(multi_ptr&&); + explicit multi_ptr(multi_ptr::pointer); + multi_ptr(std::nullptr_t); + + // Only if Space == global_space or generic_space + template + multi_ptr(accessor); + + // Only if Space == local_space or generic_space + template + multi_ptr(local_accessor) + + // Deprecated + // Only if Space == local_space or generic_space + template + multi_ptr(accessor); + + // Assignment and access operators + multi_ptr &operator=(const multi_ptr&); + multi_ptr &operator=(multi_ptr&&); + multi_ptr &operator=(std::nullptr_t); + + // Only if Space == address_space::generic_space + // and ASP != access::address_space::constant_space + template + multi_ptr &operator=(const multi_ptr&); + // Only if Space == address_space::generic_space + // and ASP != access::address_space::constant_space + template + multi_ptr &operator=(multi_ptr&&); + + reference operator*() const; + pointer operator->() const; + + pointer get() const; + std::add_pointer_t get_raw() const; + __unspecified__ * get_decorated() const; + + // Conversion to the underlying pointer type + // Deprecated, get() should be used instead. + operator pointer() const; + + // Only if Space == address_space::generic_space + // Cast to private_ptr + explicit operator multi_ptr(); + // Only if Space == address_space::generic_space + // Cast to private_ptr + explicit + operator multi_ptr() const; + // Only if Space == address_space::generic_space + // Cast to global_ptr + explicit operator multi_ptr(); + // Only if Space == address_space::generic_space + // Cast to global_ptr + explicit + operator multi_ptr() const; + // Only if Space == address_space::generic_space + // Cast to local_ptr + explicit operator multi_ptr(); + // Only if Space == address_space::generic_space + // Cast to local_ptr + explicit + operator multi_ptr() const; + + // Implicit conversion to a multi_ptr. + // Only available when value_type is not const-qualified. + template + operator multi_ptr() const; + + // Implicit conversion to a multi_ptr. + // Only available when value_type is const-qualified. + template + operator multi_ptr() const; + + // Implicit conversion to multi_ptr. + template + operator multi_ptr() const; + + // Implicit conversion to the non-decorated version of multi_ptr. + // Only available when is_decorated is true. + operator multi_ptr() const; + + // Implicit conversion to the decorated version of multi_ptr. + // Only available when is_decorated is false. + operator multi_ptr() const; + + void prefetch(size_t numElements) const; + + // Arithmetic operators + friend multi_ptr& operator++(multi_ptr& mp) { /* ... */ } + friend multi_ptr operator++(multi_ptr& mp, int) { /* ... */ } + friend multi_ptr& operator--(multi_ptr& mp) { /* ... */ } + friend multi_ptr operator--(multi_ptr& mp, int) { /* ... */ } + friend multi_ptr& operator+=(multi_ptr& lhs, difference_type r) { /* ... */ } + friend multi_ptr& operator-=(multi_ptr& lhs, difference_type r) { /* ... */ } + friend multi_ptr operator+(const multi_ptr& lhs, difference_type r) { /* ... */ } + friend multi_ptr operator-(const multi_ptr& lhs, difference_type r) { /* ... */ } + friend reference operator*(const multi_ptr& lhs) { /* ... */ } + + friend bool operator==(const multi_ptr& lhs, const multi_ptr& rhs) { /* ... */ } + friend bool operator!=(const multi_ptr& lhs, const multi_ptr& rhs) { /* ... */ } + friend bool operator<(const multi_ptr& lhs, const multi_ptr& rhs) { /* ... */ } + friend bool operator>(const multi_ptr& lhs, const multi_ptr& rhs) { /* ... */ } + friend bool operator<=(const multi_ptr& lhs, const multi_ptr& rhs) { /* ... */ } + friend bool operator>=(const multi_ptr& lhs, const multi_ptr& rhs) { /* ... */ } + + friend bool operator==(const multi_ptr& lhs, std::nullptr_t) { /* ... */ } + friend bool operator!=(const multi_ptr& lhs, std::nullptr_t) { /* ... */ } + friend bool operator<(const multi_ptr& lhs, std::nullptr_t) { /* ... */ } + friend bool operator>(const multi_ptr& lhs, std::nullptr_t) { /* ... */ } + friend bool operator<=(const multi_ptr& lhs, std::nullptr_t) { /* ... */ } + friend bool operator>=(const multi_ptr& lhs, std::nullptr_t) { /* ... */ } + + friend bool operator==(std::nullptr_t, const multi_ptr& rhs) { /* ... */ } + friend bool operator!=(std::nullptr_t, const multi_ptr& rhs) { /* ... */ } + friend bool operator<(std::nullptr_t, const multi_ptr& rhs) { /* ... */ } + friend bool operator>(std::nullptr_t, const multi_ptr& rhs) { /* ... */ } + friend bool operator<=(std::nullptr_t, const multi_ptr& rhs) { /* ... */ } + friend bool operator>=(std::nullptr_t, const multi_ptr& rhs) { /* ... */ } + +}; + +// Specialization of multi_ptr for void and const void +// VoidType can be either void or const void +template +class multi_ptr { + public: + static constexpr bool is_decorated = DecorateAddress == access::decorated::yes; + static constexpr access::address_space address_space = Space; + + using value_type = VoidType; + using pointer = std::conditional>; + using difference_type = std::ptrdiff_t; + + static_assert(std::is_same_v, std::add_pointer_t>); + // Legacy has a different interface. + static_assert(DecorateAddress != access::decorated::legacy); + + // Constructors + multi_ptr(); + multi_ptr(const multi_ptr&); + multi_ptr(multi_ptr&&); + explicit multi_ptr(multi_ptr::pointer); + multi_ptr(std::nullptr_t); + + // Only if Space == global_space + template + multi_ptr(accessor); + + // Only if Space == local_space + template + multi_ptr(local_accessor); + + // Deprecated + // Only if Space == local_space + template + multi_ptr(accessor); + + // Assignment operators + multi_ptr &operator=(const multi_ptr&); + multi_ptr &operator=(multi_ptr&&); + multi_ptr &operator=(std::nullptr_t); + + pointer get() const; + + // Conversion to the underlying pointer type + explicit operator pointer() const; + + // Explicit conversion to a multi_ptr + // If VoidType is const, ElementType must be as well + template + explicit operator multi_ptr() const; + + // Implicit conversion to the non-decorated version of multi_ptr. + // Only available when is_decorated is true. + operator multi_ptr() const; + + // Implicit conversion to the decorated version of multi_ptr. + // Only available when is_decorated is false. + operator multi_ptr() const; + + // Implicit conversion to multi_ptr + operator multi_ptr() const; + + friend bool operator==(const multi_ptr& lhs, const multi_ptr& rhs) { /* ... */ } + friend bool operator!=(const multi_ptr& lhs, const multi_ptr& rhs) { /* ... */ } + friend bool operator<(const multi_ptr& lhs, const multi_ptr& rhs) { /* ... */ } + friend bool operator>(const multi_ptr& lhs, const multi_ptr& rhs) { /* ... */ } + friend bool operator<=(const multi_ptr& lhs, const multi_ptr& rhs) { /* ... */ } + friend bool operator>=(const multi_ptr& lhs, const multi_ptr& rhs) { /* ... */ } + + friend bool operator==(const multi_ptr& lhs, std::nullptr_t) { /* ... */ } + friend bool operator!=(const multi_ptr& lhs, std::nullptr_t) { /* ... */ } + friend bool operator<(const multi_ptr& lhs, std::nullptr_t) { /* ... */ } + friend bool operator>(const multi_ptr& lhs, std::nullptr_t) { /* ... */ } + friend bool operator<=(const multi_ptr& lhs, std::nullptr_t) { /* ... */ } + friend bool operator>=(const multi_ptr& lhs, std::nullptr_t) { /* ... */ } + + friend bool operator==(std::nullptr_t, const multi_ptr& rhs) { /* ... */ } + friend bool operator!=(std::nullptr_t, const multi_ptr& rhs) { /* ... */ } + friend bool operator<(std::nullptr_t, const multi_ptr& rhs) { /* ... */ } + friend bool operator>(std::nullptr_t, const multi_ptr& rhs) { /* ... */ } + friend bool operator<=(std::nullptr_t, const multi_ptr& rhs) { /* ... */ } + friend bool operator>=(std::nullptr_t, const multi_ptr& rhs) { /* ... */ } + +}; + +// Deprecated, address_space_cast should be used instead. +template +multi_ptr make_ptr(ElementType *); + +template +multi_ptr address_space_cast(ElementType *); + +// Deduction guides +template +multi_ptr( + accessor) + -> multi_ptr; +template +multi_ptr(local_accessor) + -> multi_ptr; + +} // namespace sycl diff --git a/adoc/headers/multipointerlegacy.h b/adoc/headers/multipointerlegacy.h new file mode 100644 index 00000000..3787ce75 --- /dev/null +++ b/adoc/headers/multipointerlegacy.h @@ -0,0 +1,187 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { + +// Legacy interface, inherited from 1.2.1. +// Deprecated. +template +class [[deprecated]] multi_ptr { + public: + using element_type = ElementType; + using difference_type = std::ptrdiff_t; + + // Implementation defined pointer and reference types that correspond to + // SYCL/OpenCL interoperability types for OpenCL C functions. + using pointer_t = multi_ptr::pointer; + using const_pointer_t = multi_ptr::pointer; + using reference_t = multi_ptr::reference; + using const_reference_t = multi_ptr::reference; + + static constexpr access::address_space address_space = Space; + + // Constructors + multi_ptr(); + multi_ptr(const multi_ptr&); + multi_ptr(multi_ptr&&); + multi_ptr(pointer_t); + multi_ptr(ElementType*); + multi_ptr(std::nullptr_t); + ~multi_ptr(); + + // Assignment and access operators + multi_ptr &operator=(const multi_ptr&); + multi_ptr &operator=(multi_ptr&&); + multi_ptr &operator=(pointer_t); + multi_ptr &operator=(ElementType*); + multi_ptr &operator=(std::nullptr_t); + friend ElementType& operator*(const multi_ptr& mp) { /* ... */ } + ElementType* operator->() const; + + // Only if Space == global_space + template + multi_ptr(accessor); + + // Only if Space == local_space + template + multi_ptr(accessor); + + // Only if Space == constant_space + template + multi_ptr(accessor); + + // Returns the underlying OpenCL C pointer + pointer_t get() const; + + // Implicit conversion to the underlying pointer type + operator ElementType*() const; + + // Implicit conversion to a multi_ptr + // Only available when ElementType is not const-qualified + operator multi_ptr() const; + + // Implicit conversion to a multi_ptr + // Only available when ElementType is const-qualified + operator multi_ptr() const; + + // Implicit conversion to multi_ptr + operator multi_ptr() const; + + // Arithmetic operators + friend multi_ptr& operator++(multi_ptr& mp) { /* ... */ } + friend multi_ptr operator++(multi_ptr& mp, int) { /* ... */ } + friend multi_ptr& operator--(multi_ptr& mp) { /* ... */ } + friend multi_ptr operator--(multi_ptr& mp, int) { /* ... */ } + friend multi_ptr& operator+=(multi_ptr& lhs, difference_type r) { /* ... */ } + friend multi_ptr& operator-=(multi_ptr& lhs, difference_type r) { /* ... */ } + friend multi_ptr operator+(const multi_ptr& lhs, difference_type r) { /* ... */ } + friend multi_ptr operator-(const multi_ptr& lhs, difference_type r) { /* ... */ } + + void prefetch(size_t numElements) const; + + friend bool operator==(const multi_ptr& lhs, const multi_ptr& rhs) { /* ... */ } + friend bool operator!=(const multi_ptr& lhs, const multi_ptr& rhs) { /* ... */ } + friend bool operator<(const multi_ptr& lhs, const multi_ptr& rhs) { /* ... */ } + friend bool operator>(const multi_ptr& lhs, const multi_ptr& rhs) { /* ... */ } + friend bool operator<=(const multi_ptr& lhs, const multi_ptr& rhs) { /* ... */ } + friend bool operator>=(const multi_ptr& lhs, const multi_ptr& rhs) { /* ... */ } + + friend bool operator==(const multi_ptr& lhs, std::nullptr_t) { /* ... */ } + friend bool operator!=(const multi_ptr& lhs, std::nullptr_t) { /* ... */ } + friend bool operator<(const multi_ptr& lhs, std::nullptr_t) { /* ... */ } + friend bool operator>(const multi_ptr& lhs, std::nullptr_t) { /* ... */ } + friend bool operator<=(const multi_ptr& lhs, std::nullptr_t) { /* ... */ } + friend bool operator>=(const multi_ptr& lhs, std::nullptr_t) { /* ... */ } + + friend bool operator==(std::nullptr_t, const multi_ptr& rhs) { /* ... */ } + friend bool operator!=(std::nullptr_t, const multi_ptr& rhs) { /* ... */ } + friend bool operator<(std::nullptr_t, const multi_ptr& rhs) { /* ... */ } + friend bool operator>(std::nullptr_t, const multi_ptr& rhs) { /* ... */ } + friend bool operator<=(std::nullptr_t, const multi_ptr& rhs) { /* ... */ } + friend bool operator>=(std::nullptr_t, const multi_ptr& rhs) { /* ... */ } + +}; + +// Legacy interface, inherited from 1.2.1. +// Deprecated. +// Specialization of multi_ptr for void and const void +// VoidType can be either void or const void +template +class [[deprecated]] multi_ptr { + public: + using element_type = VoidType; + using difference_type = std::ptrdiff_t; + + // Implementation defined pointer types that correspond to + // SYCL/OpenCL interoperability types for OpenCL C functions + using pointer_t = multi_ptr::pointer; + using const_pointer_t = multi_ptr::pointer; + + static constexpr access::address_space address_space = Space; + + // Constructors + multi_ptr(); + multi_ptr(const multi_ptr&); + multi_ptr(multi_ptr&&); + multi_ptr(pointer_t); + multi_ptr(VoidType*); + multi_ptr(std::nullptr_t); + ~multi_ptr(); + + // Assignment operators + multi_ptr &operator=(const multi_ptr&); + multi_ptr &operator=(multi_ptr&&); + multi_ptr &operator=(pointer_t); + multi_ptr &operator=(VoidType*); + multi_ptr &operator=(std::nullptr_t); + + // Only if Space == global_space + template + multi_ptr(accessor); + + // Only if Space == local_space + template + multi_ptr(accessor); + + // Only if Space == constant_space + template + multi_ptr(accessor); + + // Returns the underlying OpenCL C pointer + pointer_t get() const; + + // Implicit conversion to the underlying pointer type + operator VoidType*() const; + + // Explicit conversion to a multi_ptr + // If VoidType is const, ElementType must be as well + template + explicit operator multi_ptr() const; + + // Implicit conversion to multi_ptr + operator multi_ptr() const; + + friend bool operator==(const multi_ptr& lhs, const multi_ptr& rhs) { /* ... */ } + friend bool operator!=(const multi_ptr& lhs, const multi_ptr& rhs) { /* ... */ } + friend bool operator<(const multi_ptr& lhs, const multi_ptr& rhs) { /* ... */ } + friend bool operator>(const multi_ptr& lhs, const multi_ptr& rhs) { /* ... */ } + friend bool operator<=(const multi_ptr& lhs, const multi_ptr& rhs) { /* ... */ } + friend bool operator>=(const multi_ptr& lhs, const multi_ptr& rhs) { /* ... */ } + + friend bool operator==(const multi_ptr& lhs, std::nullptr_t) { /* ... */ } + friend bool operator!=(const multi_ptr& lhs, std::nullptr_t) { /* ... */ } + friend bool operator<(const multi_ptr& lhs, std::nullptr_t) { /* ... */ } + friend bool operator>(const multi_ptr& lhs, std::nullptr_t) { /* ... */ } + friend bool operator<=(const multi_ptr& lhs, std::nullptr_t) { /* ... */ } + friend bool operator>=(const multi_ptr& lhs, std::nullptr_t) { /* ... */ } + + friend bool operator==(std::nullptr_t, const multi_ptr& rhs) { /* ... */ } + friend bool operator!=(std::nullptr_t, const multi_ptr& rhs) { /* ... */ } + friend bool operator<(std::nullptr_t, const multi_ptr& rhs) { /* ... */ } + friend bool operator>(std::nullptr_t, const multi_ptr& rhs) { /* ... */ } + friend bool operator<=(std::nullptr_t, const multi_ptr& rhs) { /* ... */ } + friend bool operator>=(std::nullptr_t, const multi_ptr& rhs) { /* ... */ } + +}; + +} // namespace sycl diff --git a/adoc/headers/ndRange.h b/adoc/headers/ndRange.h new file mode 100644 index 00000000..57efb8c0 --- /dev/null +++ b/adoc/headers/ndRange.h @@ -0,0 +1,20 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { +template +class nd_range { +public: + + /* -- common interface members -- */ + + // The offset is deprecated in SYCL 2020. + nd_range(range globalSize, range localSize, + id offset = id()); + + range get_global_range() const; + range get_local_range() const; + range get_group_range() const; + id get_offset() const; // Deprecated in SYCL 2020. +}; +} // namespace sycl diff --git a/adoc/headers/nditem.h b/adoc/headers/nditem.h new file mode 100644 index 00000000..afb64785 --- /dev/null +++ b/adoc/headers/nditem.h @@ -0,0 +1,66 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { +template +class nd_item { +public: + nd_item() = delete; + + /* -- common interface members -- */ + + id get_global_id() const; + + size_t get_global_id(int dimension) const; + + size_t get_global_linear_id() const; + + id get_local_id() const; + + size_t get_local_id(int dimension) const; + + size_t get_local_linear_id() const; + + group get_group() const; + + size_t get_group(int dimension) const; + + size_t get_group_linear_id() const; + + range get_group_range() const; + + size_t get_group_range(int dimension) const; + + range get_global_range() const; + + size_t get_global_range(int dimension) const; + + range get_local_range() const; + + size_t get_local_range(int dimension) const; + + // Deprecated in SYCL 2020. + id get_offset() const; + + nd_range get_nd_range() const; + + template + device_event async_work_group_copy(decorated_local_ptr dest, + decorated_global_ptr src, size_t numElements) const; + + template + device_event async_work_group_copy(decorated_global_ptr dest, + decorated_local_ptr src, size_t numElements) const; + + template + device_event async_work_group_copy(decorated_local_ptr dest, + decorated_global_ptr src, size_t numElements, size_t srcStride) const; + + template + device_event async_work_group_copy(decorated_global_ptr dest, + decorated_local_ptr src, size_t numElements, size_t destStride) const; + + template + void wait_for(eventTN... events) const; +}; +} // namespace sycl diff --git a/adoc/headers/openclBackend/createBundle.h b/adoc/headers/openclBackend/createBundle.h new file mode 100644 index 00000000..59f5c738 --- /dev/null +++ b/adoc/headers/openclBackend/createBundle.h @@ -0,0 +1,15 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: MIT + +namespace sycl::opencl { + +template +kernel_bundle create_bundle(const context &ctxt, + const std::vector &devs, + const std::vector &clPrograms); + +kernel_bundle +create_bundle(const context &ctxt, const std::vector &devs, + const std::vector &clKernels); + +} // namespace sycl::opencl diff --git a/adoc/headers/openclBackend/samplerImagePair.h b/adoc/headers/openclBackend/samplerImagePair.h new file mode 100644 index 00000000..354bcbc4 --- /dev/null +++ b/adoc/headers/openclBackend/samplerImagePair.h @@ -0,0 +1,17 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: MIT + +struct sampler_1dimage_pair_t { + sampler_t sampler; + image1d_t image; +} + +struct sampler_2dimage_pair_t { + sampler_t sampler; + image2d_t image; +} + +struct sampler_3dimage_pair_t { + sampler_t sampler; + image3d_t image; +} diff --git a/adoc/headers/openclcInterop.h b/adoc/headers/openclcInterop.h new file mode 100644 index 00000000..3fc05df0 --- /dev/null +++ b/adoc/headers/openclcInterop.h @@ -0,0 +1,5 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +extern "C" typename sycl::decorated_global_ptr::pointer my_func( + sycl::float4::vector_t x, double y); diff --git a/adoc/headers/parallelFor.h b/adoc/headers/parallelFor.h new file mode 100644 index 00000000..87df3320 --- /dev/null +++ b/adoc/headers/parallelFor.h @@ -0,0 +1,61 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +void single_task(kernel *syclKernel); + +void parallel_for(nd_range ndRange, kernel *k); + +void parallel_for(range range kernel *syclKernel); + + +template +void single_task(KernelType); + +template +void parallel_for(range num_work_items, KernelType); + +// Deprecated in SYCL 2020. +template +void parallel_for(range numWorkItems, + id workItemOffset, KernelType); + +template +void parallel_for(nd_range ndRange, KernelType); + +template +void parallel_for_work_group(range numWorkGroups, + WorkgroupFunctionType); + +template +void parallel_for_work_group(range numWorkGroups, + range workGroupSize, + WorkgroupFunctionType); + +template +void single_task(KernelType); + +template +void parallel_for(range numWorkItems, KernelType); + +// Deprecated in SYCL 2020. +template +void parallel_for(range numWorkItems, + id workItemOffset, KernelType); + +template +void parallel_for(nd_range ndRange, KernelType); + +// Deprecated in SYCL 2020. +template +void parallel_for(nd_range numWorkItems, + id workItemOffset, KernelType); + + +template +void parallel_for_work_group(range numWorkGroups, + WorkgroupFunctionType); + +template +void parallel_for_work_group(range numWorkGroups, + range workGroupSize, + WorkgroupFunctionType); diff --git a/adoc/headers/platform.h b/adoc/headers/platform.h new file mode 100644 index 00000000..c9a073dd --- /dev/null +++ b/adoc/headers/platform.h @@ -0,0 +1,30 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { +class platform { + public: + platform(); + + template + explicit platform(const DeviceSelector &deviceSelector); + + /* -- common interface members -- */ + + backend get_backend() const noexcept; + + std::vector get_devices( + info::device_type = info::device_type::all) const; + + template typename param::return_type get_info() const; + + template + typename param::return_type get_backend_info() const; + + bool has(aspect asp) const; + + bool has_extension(const std::string &extension) const; // Deprecated + + static std::vector get_platforms(); +}; +} // namespace sycl diff --git a/adoc/headers/platformInfo.h b/adoc/headers/platformInfo.h new file mode 100644 index 00000000..f377c79b --- /dev/null +++ b/adoc/headers/platformInfo.h @@ -0,0 +1,16 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { +namespace info { +namespace platform { + +struct profile; +struct version; +struct name; +struct vendor; +struct extensions; // Deprecated + +} // namespace platform +} // namespace info +} // namespace sycl diff --git a/adoc/headers/pointer.h b/adoc/headers/pointer.h new file mode 100644 index 00000000..9af44eb5 --- /dev/null +++ b/adoc/headers/pointer.h @@ -0,0 +1,59 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { + +template +class multi_ptr; + +// Template specialization aliases for different pointer address spaces + +template +using global_ptr = multi_ptr; + +template +using local_ptr = multi_ptr; + +// Deprecated in SYCL 2020 +template +using constant_ptr = multi_ptr; + +template +using private_ptr = multi_ptr; + +// Template specialization aliases for different pointer address spaces. +// The interface exposes non-decorated pointer while keeping the +// address space information internally. + +template +using raw_global_ptr = multi_ptr; + +template +using raw_local_ptr = multi_ptr; + +template +using raw_private_ptr = multi_ptr; + +// Template specialization aliases for different pointer address spaces. +// The interface exposes decorated pointer. + +template +using decorated_global_ptr = multi_ptr; + +template +using decorated_local_ptr = multi_ptr; + +template +using decorated_private_ptr = multi_ptr; + +} // namespace sycl diff --git a/adoc/headers/priv.h b/adoc/headers/priv.h new file mode 100644 index 00000000..a639b72a --- /dev/null +++ b/adoc/headers/priv.h @@ -0,0 +1,14 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { +template +class private_memory { + public: + // Construct based directly off the number of work-items + private_memory(const group &); + + // Access the instance for the current work-item + T &operator()(const h_item &id); +}; +} diff --git a/adoc/headers/properties.h b/adoc/headers/properties.h new file mode 100644 index 00000000..38be1809 --- /dev/null +++ b/adoc/headers/properties.h @@ -0,0 +1,35 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { + +template +struct is_property; + +template +inline constexpr bool is_property_v = is_property::value; + +template +struct is_property_of; + +template +inline constexpr bool is_property_of_v = is_property_of::value; + +class T { + ... + + template + bool has_property() const noexcept; + + template + propertyT get_property() const; + + ... +}; + +class property_list { + public: + template + property_list(propertyTN... props); +}; +} // namespace sycl diff --git a/adoc/headers/queue.h b/adoc/headers/queue.h new file mode 100644 index 00000000..90334c0e --- /dev/null +++ b/adoc/headers/queue.h @@ -0,0 +1,206 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { +class queue { + public: + explicit queue(const property_list &propList = {}); + + explicit queue(const async_handler &asyncHandler, + const property_list &propList = {}); + + template + explicit queue(const DeviceSelector &deviceSelector, + const property_list &propList = {}); + + template + explicit queue(const DeviceSelector &deviceSelector, + const async_handler &asyncHandler, + const property_list &propList = {}); + + explicit queue(const device &syclDevice, const property_list &propList = {}); + + explicit queue(const device &syclDevice, const async_handler &asyncHandler, + const property_list &propList = {}); + + template + explicit queue(const context &syclContext, + const DeviceSelector &deviceSelector, + const property_list &propList = {}); + + template + explicit queue(const context &syclContext, + const DeviceSelector &deviceSelector, + const async_handler &asyncHandler, + const property_list &propList = {}); + + explicit queue(const context &syclContext, const device &syclDevice, + const property_list &propList = {}); + + explicit queue(const context &syclContext, const device &syclDevice, + const async_handler &asyncHandler, + const property_list &propList = {}); + + /* -- common interface members -- */ + + /* -- property interface members -- */ + + backend get_backend() const noexcept; + + context get_context() const; + + device get_device() const; + + bool is_in_order() const; + + template typename param::return_type get_info() const; + + template + typename param::return_type get_backend_info() const; + + template + event submit(T cgf); + + template + event submit(T cgf, const queue &secondaryQueue); + + void wait(); + + void wait_and_throw(); + + void throw_asynchronous(); + + /* -- convenience shortcuts -- */ + + template + event single_task(const KernelType &kernelFunc); + + template + event single_task(event depEvent, const KernelType &kernelFunc); + + template + event single_task(const std::vector &depEvents, + const KernelType &kernelFunc); + + // Parameter pack acts as-if: Reductions&&... reductions, const KernelType &kernelFunc + template + event parallel_for(range numWorkItems, + Rest&&... rest); + + // Parameter pack acts as-if: Reductions&&... reductions, const KernelType &kernelFunc + template + event parallel_for(range numWorkItems, event depEvent, + Rest&&... rest); + + // Parameter pack acts as-if: Reductions&&... reductions, const KernelType &kernelFunc + template + event parallel_for(range numWorkItems, + const std::vector &depEvents, + Rest&&... rest); + + // Parameter pack acts as-if: Reductions&&... reductions, const KernelType &kernelFunc + template + event parallel_for(nd_range executionRange, + Rest&&... rest); + + // Parameter pack acts as-if: Reductions&&... reductions, const KernelType &kernelFunc + template + event parallel_for(nd_range executionRange, + event depEvent, + Rest&&... rest); + + // Parameter pack acts as-if: Reductions&&... reductions, const KernelType &kernelFunc + template + event parallel_for(nd_range executionRange, + const std::vector &depEvents, + Rest&&... rest); + + /* -- USM functions -- */ + + event memcpy(void* dest, const void* src, size_t numBytes); + event memcpy(void* dest, const void* src, size_t numBytes, + event depEvent); + event memcpy(void* dest, const void* src, size_t numBytes, + const std::vector &depEvents); + + template + event copy(T* dest, const T *src, size_t count); + template + event copy(T* dest, const T *src, size_t count, + event depEvent); + template + event copy(T* dest, const T *src, size_t count, + const std::vector &depEvents); + + event memset(void* ptr, int value, size_t numBytes); + event memset(void* ptr, int value, size_t numBytes, + event depEvent); + event memset(void* ptr, int value, size_t numBytes, + const std::vector &depEvents); + + template + event fill(void* ptr, const T& pattern, size_t count); + template + event fill(void* ptr, const T& pattern, size_t count, + event depEvent); + template + event fill(void* ptr, const T& pattern, size_t count, + const std::vector &depEvents); + + event prefetch(void* ptr, size_t numBytes); + event prefetch(void* ptr, size_t numBytes, + event depEvent); + event prefetch(void* ptr, size_t numBytes, + const std::vector &depEvents); + + event mem_advise(void *ptr, size_t numBytes, int advice); + event mem_advise(void *ptr, size_t numBytes, int advice, + event depEvent); + event mem_advise(void *ptr, size_t numBytes, int advice, + const std::vector &depEvents); + + /// Placeholder accessor shortcuts + + // Explicit copy functions + + template + event copy(accessor src, + std::shared_ptr dest); + + template + event + copy(std::shared_ptr src, + accessor dest); + + template + event copy(accessor src, + T_dest *dest); + + template + event + copy(const T_src *src, + accessor dest); + + template + event copy( + accessor src, + accessor dest); + + template + event update_host(accessor acc); + + template + event fill(accessor dest, const T &src); +}; +} // namespace sycl diff --git a/adoc/headers/queueInfo.h b/adoc/headers/queueInfo.h new file mode 100644 index 00000000..e893ca10 --- /dev/null +++ b/adoc/headers/queueInfo.h @@ -0,0 +1,13 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { +namespace info { +namespace queue { + +struct context; +struct device; + +} // namespace queue +} // namespace info +} // namespace sycl diff --git a/adoc/headers/range.h b/adoc/headers/range.h new file mode 100644 index 00000000..8c814e9f --- /dev/null +++ b/adoc/headers/range.h @@ -0,0 +1,50 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { +template +class range { +public: + /* The following constructor is only available in the range class specialization where: dimensions==1 */ + range(size_t dim0); + /* The following constructor is only available in the range class specialization where: dimensions==2 */ + range(size_t dim0, size_t dim1); + /* The following constructor is only available in the range class specialization where: dimensions==3 */ + range(size_t dim0, size_t dim1, size_t dim2); + + /* -- common interface members -- */ + + size_t get(int dimension) const; + size_t &operator[](int dimension); + size_t operator[](int dimension) const; + + size_t size() const; + + // OP is: +, -, *, /, %, <<, >>, &, |, ^, &&, ||, <, >, <=, >= + friend range operatorOP(const range &lhs, const range &rhs) { /* ... */ } + friend range operatorOP(const range &lhs, const size_t &rhs) { /* ... */ } + + // OP is: +=, -=, *=, /=, %=, <<=, >>=, &=, |=, ^= + friend range & operatorOP(range &lhs, const range &rhs) { /* ... */ } + friend range & operatorOP(range &lhs, const size_t &rhs) { /* ... */ } + + // OP is: +, -, *, /, %, <<, >>, &, |, ^, &&, ||, <, >, <=, >= + friend range operatorOP(const size_t &lhs, const range &rhs) { /* ... */ } + + // OP is unary +, - + friend range operatorOP(const range &rhs) { /* ... */ } + + // OP is prefix ++, -- + friend range & operatorOP(range &rhs) { /* ... */ } + + // OP is postfix ++, -- + friend range operatorOP(range &lhs, int) { /* ... */ } + +}; + +// Deduction guides +range(size_t) -> range<1>; +range(size_t, size_t) -> range<2>; +range(size_t, size_t, size_t) -> range<3>; + +} // sycl diff --git a/adoc/headers/reducer.h b/adoc/headers/reducer.h new file mode 100644 index 00000000..c0198f77 --- /dev/null +++ b/adoc/headers/reducer.h @@ -0,0 +1,42 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: MIT + +// Exposition only +template +class reducer { + + reducer(const reducer&) = delete; + reducer& operator(const reducer&) = delete; + + /* Only available if Dimensions == 0 */ + void combine(const T& partial); + + /* Only available if Dimensions > 0 */ + __unspecified__ &operator[](size_t index) const; + + /* Only available if identity value is known */ + T identity() const; + +}; + +template +void operator+=(reducer,0>&, const T&); + +template +void operator*=(reducer,0>&, const T&); + +/* Only available for integral types */ +template +void operator&=(reducer,0>&, const T&); + +/* Only available for integral types */ +template +void operator|=(reducer,0>&, const T&); + +/* Only available for integral types */ +template +void operator^=(reducer,0>&, const T&); + +/* Only available for integral types */ +template +void operator++(reducer,0>&); diff --git a/adoc/headers/reduction.h b/adoc/headers/reduction.h new file mode 100644 index 00000000..c9af6763 --- /dev/null +++ b/adoc/headers/reduction.h @@ -0,0 +1,23 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: MIT + +template +__unspecified__ reduction(BufferT vars, handler& cgh, BinaryOperation combiner, const property_list &propList = {}); + +template +__unspecified__ reduction(T* var, BinaryOperation combiner, const property_list &propList = {}); + +template +__unspecified__ reduction(span vars, BinaryOperation combiner, const property_list &propList = {}); + +/* Available only if has_known_identity::value is false */ +template +__unspecified__ reduction(BufferT vars, handler& cgh, const BufferT::value_type& identity, BinaryOperation combiner, const property_list &propList = {}); + +/* Available only if has_known_identity::value is false */ +template +__unspecified__ reduction(T* var, const T& identity, BinaryOperation combiner, const property_list &propList = {}); + +/* Available only if has_known_identity::value is false */ +template +__unspecified__ reduction(span vars, const T& identity, BinaryOperation combiner); diff --git a/adoc/headers/sampledImage.h b/adoc/headers/sampledImage.h new file mode 100644 index 00000000..77c33db9 --- /dev/null +++ b/adoc/headers/sampledImage.h @@ -0,0 +1,61 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { +enum class image_format : unsigned int { + r8g8b8a8_unorm, + r16g16b16a16_unorm, + r8g8b8a8_sint, + r16g16b16a16_sint, + r32b32g32a32_sint, + r8g8b8a8_uint, + r16g16b16a16_uint, + r32b32g32a32_uint, + r16b16g16a16_sfloat, + r32g32b32a32_sfloat, + b8g8r8a8_unorm, +}; + +template +class sampled_image { + public: + sampled_image(const void *hostPointer, image_format format, + image_sampler sampler, const range &rangeRef, + const property_list &propList = {}); + + /* Available only when: dimensions > 1 */ + sampled_image(const void *hostPointer, image_format format, + image_sampler sampler, const range &rangeRef, + const range &pitch, + const property_list &propList = {}); + + sampled_image(std::shared_ptr &hostPointer, image_format format, + image_sampler sampler, const range &rangeRef, + const property_list &propList = {}); + + /* Available only when: dimensions > 1 */ + sampled_image(std::shared_ptr &hostPointer, image_format format, + image_sampler sampler, const range &rangeRef, + const range &pitch, + const property_list &propList = {}); + + /* -- common interface members -- */ + + /* -- property interface members -- */ + + range get_range() const; + + /* Available only when: dimensions > 1 */ + range get_pitch() const; + + size_t byte_size() const; + + size_t size() const; + + template + auto get_access(Ts... args); + + template + auto get_host_access(Ts... args); +}; +} // namespace sycl diff --git a/adoc/headers/stream.h b/adoc/headers/stream.h new file mode 100644 index 00000000..7c62da63 --- /dev/null +++ b/adoc/headers/stream.h @@ -0,0 +1,79 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { + +enum class stream_manipulator { + flush, + dec, + hex, + oct, + noshowbase, + showbase, + noshowpos, + showpos, + endl, + fixed, + scientific, + hexfloat, + defaultfloat +}; + + +const stream_manipulator flush = stream_manipulator::flush; + +const stream_manipulator dec = stream_manipulator::dec; + +const stream_manipulator hex = stream_manipulator::hex; + +const stream_manipulator oct = stream_manipulator::oct; + +const stream_manipulator noshowbase = stream_manipulator::noshowbase; + +const stream_manipulator showbase = stream_manipulator::showbase; + +const stream_manipulator noshowpos = stream_manipulator::noshowpos; + +const stream_manipulator showpos = stream_manipulator::showpos; + +const stream_manipulator endl = stream_manipulator::endl; + +const stream_manipulator fixed = stream_manipulator::fixed; + +const stream_manipulator scientific = stream_manipulator::scientific; + +const stream_manipulator hexfloat = stream_manipulator::hexfloat; + +const stream_manipulator defaultfloat = stream_manipulator::defaultfloat; + +__precision_manipulator__ setprecision(int precision); + +__width_manipulator__ setw(int width); + +class stream { + public: + + stream(size_t totalBufferSize, size_t workItemBufferSize, handler& cgh + const property_list &propList = {}); + + /* -- common interface members -- */ + + /* -- property interface members -- */ + + size_t size() const noexcept; + + // Deprecated + size_t get_size() const; + + size_t get_work_item_buffer_size() const; + + /* get_max_statement_size() has the same functionality as get_work_item_buffer_size(), + and is provided for backward compatibility. get_max_statement_size() is a deprecated + query. */ + size_t get_max_statement_size() const; +}; + +template +const stream& operator<<(const stream& os, const T &rhs); + +} // namespace sycl diff --git a/adoc/headers/subgroup.h b/adoc/headers/subgroup.h new file mode 100644 index 00000000..2376e283 --- /dev/null +++ b/adoc/headers/subgroup.h @@ -0,0 +1,38 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { +class sub_group { +public: + + using id_type = id<1>; + using range_type = range<1>; + using linear_id_type = uint32_t; + static constexpr int dimensions = 1; + static constexpr memory_scope fence_scope = memory_scope::sub_group; + + /* -- common interface members -- */ + + id<1> get_group_id() const; + + id<1> get_local_id() const; + + range<1> get_local_range() const; + + range<1> get_group_range() const; + + range<1> get_max_local_range() const; + + uint32_t get_group_linear_id() const; + + uint32_t get_local_linear_id() const; + + uint32_t get_group_linear_range() const; + + uint32_t get_local_linear_range() const; + + bool leader() const; + +}; +} // sycl + diff --git a/adoc/headers/synchronization.h b/adoc/headers/synchronization.h new file mode 100644 index 00000000..8c96b4d3 --- /dev/null +++ b/adoc/headers/synchronization.h @@ -0,0 +1,8 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { + +void atomic_fence(memory_order order, memory_scope scope); + +} // namespace sycl diff --git a/adoc/headers/unsampledImage.h b/adoc/headers/unsampledImage.h new file mode 100644 index 00000000..5a784e19 --- /dev/null +++ b/adoc/headers/unsampledImage.h @@ -0,0 +1,104 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { +enum class image_format : unsigned int { + r8g8b8a8_unorm, + r16g16b16a16_unorm, + r8g8b8a8_sint, + r16g16b16a16_sint, + r32b32g32a32_sint, + r8g8b8a8_uint, + r16g16b16a16_uint, + r32b32g32a32_uint, + r16b16g16a16_sfloat, + r32g32b32a32_sfloat, + b8g8r8a8_unorm, +}; + +template +class unsampled_image { + public: + unsampled_image(image_format format, const range &rangeRef, + const property_list &propList = {}); + + unsampled_image(image_format format, const range &rangeRef, + AllocatorT allocator, const property_list &propList = {}); + + /* Available only when: dimensions > 1 */ + unsampled_image(image_format format, const range &rangeRef, + const range &pitch, + const property_list &propList = {}); + + /* Available only when: dimensions > 1 */ + unsampled_image(image_format format, const range &rangeRef, + const range &pitch, AllocatorT allocator, + const property_list &propList = {}); + + unsampled_image(void *hostPointer, image_format format, + const range &rangeRef, + const property_list &propList = {}); + + unsampled_image(void *hostPointer, image_format format, + const range &rangeRef, AllocatorT allocator, + const property_list &propList = {}); + + /* Available only when: dimensions > 1 */ + unsampled_image(void *hostPointer, image_format format, + const range &rangeRef, + const range &pitch, + const property_list &propList = {}); + + /* Available only when: dimensions > 1 */ + unsampled_image(void *hostPointer, image_format format, + const range &rangeRef, + const range &pitch, AllocatorT allocator, + const property_list &propList = {}); + + unsampled_image(std::shared_ptr &hostPointer, image_format format, + const range &rangeRef, + const property_list &propList = {}); + + unsampled_image(std::shared_ptr &hostPointer, image_format format, + const range &rangeRef, AllocatorT allocator, + const property_list &propList = {}); + + /* Available only when: dimensions > 1 */ + unsampled_image(std::shared_ptr &hostPointer, image_format format, + const range &rangeRef, + const range &pitch, + const property_list &propList = {}); + + /* Available only when: dimensions > 1 */ + unsampled_image(std::shared_ptr &hostPointer, image_format format, + const range &rangeRef, + const range &pitch, AllocatorT allocator, + const property_list &propList = {}); + + /* -- common interface members -- */ + + /* -- property interface members -- */ + + range get_range() const; + + /* Available only when: dimensions > 1 */ + range get_pitch() const; + + size_t byte_size() const noexcept; + + size_t size() const noexcept; + + AllocatorT get_allocator() const; + + template + auto get_access(Ts... args); + + template + auto get_host_access(Ts... args); + + template + void set_final_data(Destination finalData = std::nullptr); + + void set_write_back(bool flag = true); +}; +} // namespace sycl diff --git a/adoc/headers/vec.h b/adoc/headers/vec.h new file mode 100644 index 00000000..c76ebc19 --- /dev/null +++ b/adoc/headers/vec.h @@ -0,0 +1,222 @@ +// Copyright (c) 2011-2021 The Khronos Group, Inc. +// SPDX-License-Identifier: Apache-2.0 + +namespace sycl { + +enum class rounding_mode { + automatic, + rte, + rtz, + rtp, + rtn +}; + +struct elem { + static constexpr int x = 0; + static constexpr int y = 1; + static constexpr int z = 2; + static constexpr int w = 3; + static constexpr int r = 0; + static constexpr int g = 1; + static constexpr int b = 2; + static constexpr int a = 3; + static constexpr int s0 = 0; + static constexpr int s1 = 1; + static constexpr int s2 = 2; + static constexpr int s3 = 3; + static constexpr int s4 = 4; + static constexpr int s5 = 5; + static constexpr int s6 = 6; + static constexpr int s7 = 7; + static constexpr int s8 = 8; + static constexpr int s9 = 9; + static constexpr int sA = 10; + static constexpr int sB = 11; + static constexpr int sC = 12; + static constexpr int sD = 13; + static constexpr int sE = 14; + static constexpr int sF = 15; +}; + +template +class vec { + public: + using element_type = dataT; + +#ifdef __SYCL_DEVICE_ONLY__ + using vector_t = __unspecified__; +#endif + + vec(); + + explicit vec(const dataT &arg); + + template + vec(const argTN&... args); + + vec(const vec &rhs); + +#ifdef __SYCL_DEVICE_ONLY__ + vec(vector_t nativeVector); + + operator vector_t() const; +#endif + + // Available only when: numElements == 1 + operator dataT() const; + + static constexpr size_t byte_size() noexcept; + + static constexpr size_t size() noexcept; + + // Deprecated + size_t get_size() const; + + // Deprecated + size_t get_count() const; + + template + vec convert() const; + + template + asT as() const; + + template + __swizzled_vec__ swizzle() const; + + // Available only when numElements <= 4. + // XYZW_ACCESS is: x, y, z, w, subject to numElements. + __swizzled_vec__ XYZW_ACCESS() const; + + // Available only numElements == 4. + // RGBA_ACCESS is: r, g, b, a. + __swizzled_vec__ RGBA_ACCESS() const; + + // INDEX_ACCESS is: s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, + // sE, sF, subject to numElements. + __swizzled_vec__ INDEX_ACCESS() const; + +#ifdef SYCL_SIMPLE_SWIZZLES + // Available only when numElements <= 4. + // XYZW_SWIZZLE is all permutations with repetition of: x, y, z, w, subject to + // numElements. + __swizzled_vec__ XYZW_SWIZZLE() const; + + // Available only when numElements == 4. + // RGBA_SWIZZLE is all permutations with repetition of: r, g, b, a. + __swizzled_vec__ RGBA_SWIZZLE() const; + +#endif // #ifdef SYCL_SIMPLE_SWIZZLES + + // Available only when: numElements > 1. + __swizzled_vec__ lo() const; + __swizzled_vec__ hi() const; + __swizzled_vec__ odd() const; + __swizzled_vec__ even() const; + + // load and store member functions + template + void load(size_t offset, multi_ptr ptr); + template + void store(size_t offset, multi_ptr ptr) const; + + // subscript operator + dataT &operator[](int index); + const dataT &operator[](int index) const; + + // OP is: +, -, *, /, % + /* If OP is %, available only when: dataT != float && dataT != double + && dataT != half. */ + friend vec operatorOP(const vec &lhs, const vec &rhs) { /* ... */ } + friend vec operatorOP(const vec &lhs, const dataT &rhs) { /* ... */ } + + // OP is: +=, -=, *=, /=, %= + /* If OP is %=, available only when: dataT != float && dataT != double + && dataT != half. */ + friend vec &operatorOP(vec &lhs, const vec &rhs) { /* ... */ } + friend vec &operatorOP(vec &lhs, const dataT &rhs) { /* ... */ } + + // OP is prefix ++, -- + friend vec &operatorOP(vec &rhs) { /* ... */ } + + // OP is postfix ++, -- + friend vec operatorOP(vec& lhs, int) { /* ... */ } + + // OP is unary +, - + friend vec operatorOP(vec &rhs) const { /* ... */ } + + // OP is: &, |, ^ + /* Available only when: dataT != float && dataT != double + && dataT != half. */ + friend vec operatorOP(const vec &lhs, const vec &rhs) { /* ... */ } + friend vec operatorOP(const vec &lhs, const dataT &rhs) { /* ... */ } + + // OP is: &=, |=, ^= + /* Available only when: dataT != float && dataT != double + && dataT != half. */ + friend vec &operatorOP(vec &lhs, const vec &rhs) { /* ... */ } + friend vec &operatorOP(vec &lhs, const dataT &rhs) { /* ... */ } + + // OP is: &&, || + friend vec operatorOP(const vec &lhs, const vec &rhs) { + /* ... */ } + friend vec operatorOP(const vec& lhs, const dataT &rhs) { + /* ... */ } + + // OP is: <<, >> + /* Available only when: dataT != float && dataT != double + && dataT != half. */ + friend vec operatorOP(const vec &lhs, const vec &rhs) { /* ... */ } + friend vec operatorOP(const vec &lhs, const dataT &rhs) { /* ... */ } + + // OP is: <<=, >>= + /* Available only when: dataT != float && dataT != double + && dataT != half. */ + friend vec &operatorOP(vec &lhs, const vec &rhs) { /* ... */ } + friend vec &operatorOP(vec &lhs, const dataT &rhs) { /* ... */ } + + // OP is: ==, !=, <, >, <=, >= + friend vec operatorOP(const vec &lhs, const vec &rhs) { + /* ... */ } + friend vec operatorOP(const vec &lhs, const dataT &rhs) { + /* ... */ } + + vec &operator=(const vec &rhs); + vec &operator=(const dataT &rhs); + + /* Available only when: dataT != float && dataT != double + && dataT != half. */ + friend vec operator~(const vec &v) { /* ... */ } + friend vec operator!(const vec &v) { /* ... */ } + + // OP is: +, -, *, /, % + /* operator% is only available when: dataT != float && dataT != double && + dataT != half. */ + friend vec operatorOP(const dataT &lhs, const vec &rhs) { /* ... */ } + + // OP is: &, |, ^ + /* Available only when: dataT != float && dataT != double + && dataT != half. */ + friend vec operatorOP(const dataT &lhs, const vec &rhs) { /* ... */ } + + // OP is: &&, || + friend vec operatorOP(const dataT &lhs, const vec &rhs) { + /* ... */ } + + // OP is: <<, >> + /* Available only when: dataT != float && dataT != double + && dataT != half. */ + friend vec operatorOP(const dataT &lhs, const vec &rhs) { /* ... */ } + + // OP is: ==, !=, <, >, <=, >= + friend vec operatorOP(const dataT &lhs, const vec &rhs) { + /* ... */ } + +}; + +// Deduction guides +// Available only when: (std::is_same_v && ...) +template +vec(T, U...) -> vec; + +} // namespace sycl diff --git a/adoc/images/Makefile b/adoc/images/Makefile new file mode 100644 index 00000000..5211fd14 --- /dev/null +++ b/adoc/images/Makefile @@ -0,0 +1,26 @@ +# This only needs to be run if changing the .tikz files. +# Generated SVG are checked into the repository and need only be +# rebuilt if the TikZ markup changes. +# Building requires asciidoctor, asciidoctor-diagram, pdf2svg, +# and a LaTeX installation including pdflatex, tikz, +# and the 'arrows' tikzlibrary. + +TIKZ = \ + fig:three-cg-one-queue.tikz \ + fig:three-cg-three-queue.tikz \ + fig:device_to_device1.tikz \ + fig:device_to_device2.tikz \ + fig:overlap.tikz \ + fig:host-acc.tikz + +all: makesvg.html + +# The actual Makefile target is irrelevant. +# The side effect of running it is generating SVG files to be checked in. +makesvg.html: makesvg.adoc + asciidoctor --backend html5 --require asciidoctor-diagram \ + --out-file makesvg.html makesvg.adoc + -rm $@ + +clean: + -rm -f makesvg.html *.svg diff --git a/adoc/images/device_to_device1.svg b/adoc/images/device_to_device1.svg new file mode 100644 index 00000000..b8e889c5 --- /dev/null +++ b/adoc/images/device_to_device1.svg @@ -0,0 +1,329 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/adoc/images/device_to_device1.tikz b/adoc/images/device_to_device1.tikz new file mode 100644 index 00000000..4e858a54 --- /dev/null +++ b/adoc/images/device_to_device1.tikz @@ -0,0 +1,34 @@ +[tikz,"device_to_device1"] +---- +\usetikzlibrary{arrows} +\begin{tikzpicture}[auto] \small +\tikzset{Base/.style={align=center}, %, minimum height=2ex}, + Line/.style={draw, very thick, >=latex', black}, + LineHost/.style={draw, dashed, >=latex', black}, + MemoryObject/.style={draw, Base, black}, + CommandGroup/.style={draw, Base, rounded corners, black}, + Notice/.style = {draw, above, rounded corners, rectangle callout, text width=6cm, + callout absolute pointer={#1} }, + Action/.style = {very thick, solid, draw, rectangle callout, rounded corners, black, Base} + } + +\matrix (binmat) [ampersand replacement=\&, column sep=0.5em, row sep=2em] + {\node (empty) {}; \& + \node (empty) {}; \& + \node [MemoryObject] (Host) {Host memory}; \& + \node (empty) {}; \\ + \node (empty) {}; \& + \node [CommandGroup] (CGA) {$CG_a(b1_{RW})$}; \& + \node (empty) {}; \& + \node [CommandGroup, style=dotted] (CGB) {$CG_b(b2_{RW})$}; \\ + \node (empty) {}; \& + \& \node [CommandGroup] (CGC) {$CG_c(b1_{RW},b2_{RW})$}; \\ + \node (empty) {}; \& + \& \node (empty) {}; \\ +}; + \path [LineHost, ->] (Host) -- node[blue, left=0.2, near start] {$A(b1_{RW})$} (CGA); + \path [LineHost, ->] (Host) -- node[blue, right=0.2, near start] {$A(b2_{RW})$} (CGB); + \path [Line, ->] (CGA) -- node[blue, left=0.2, near end] {$A'(b1_{RW})$} (CGC); + \path [Line, ->] (CGB) -- node[blue, right=0.2, near end] {$A'(b2_{RW})$} (CGC); +\end{tikzpicture} +---- diff --git a/adoc/images/device_to_device2.svg b/adoc/images/device_to_device2.svg new file mode 100644 index 00000000..508fbd7e --- /dev/null +++ b/adoc/images/device_to_device2.svg @@ -0,0 +1,440 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/adoc/images/device_to_device2.tikz b/adoc/images/device_to_device2.tikz new file mode 100644 index 00000000..6290aee0 --- /dev/null +++ b/adoc/images/device_to_device2.tikz @@ -0,0 +1,34 @@ +[tikz,"device_to_device2"] +---- +\usetikzlibrary{arrows} +\begin{tikzpicture}[auto] \small +\tikzset{Base/.style={align=center}, %, minimum height=2ex}, + Line/.style={draw, very thick, >=latex', black}, + LineHost/.style={draw, dashed, >=latex', black}, + MemoryObject/.style={draw, Base, black}, + CommandGroup/.style={draw, Base, rounded corners, black}, + Notice/.style = {draw, above, rounded corners, rectangle callout, text width=6cm, + callout absolute pointer={#1} }, + Action/.style = {very thick, solid, draw, rectangle callout, rounded corners, black, Base} + } + +\matrix (binmat) [ampersand replacement=\&, column sep=0.5em, row sep=2em] + {\node (empty) {}; \& + \node (empty) {}; \& + \node [MemoryObject] (Host) {Host memory (ptr)}; \& + \node (empty) {}; \\ + \node (empty) {}; \& + \node [CommandGroup] (CGA) {$CG_a(b1_{RW})$}; \& + \node (empty) {}; \& + \node [CommandGroup, style=dotted] (CGB) {$CG_b(b2_{RW})$}; \\ + \node (empty) {}; \& + \& \node [CommandGroup] (CGC) {$CG_c(b1_{RW},b2_{RW})$}; \\ + \node (empty) {}; \& + \& \node (empty) {}; \\ +}; + \path [LineHost, ->] (Host) -- node[blue, left=0.3, near start] {clEnqueueWriteBuffer(q1, ptr, b1\_c1)} (CGA); + \path [LineHost, ->] (Host) -- node[blue, right=0.3, near start] {clEnqueueWriteBuffer(q2, ptr, b2\_c2)} (CGB); + \path [Line, ->] (CGA) -- node[blue, left=0.2, near end] {} (CGC); + \path [Line, ->] (CGB) -- node[blue, right=0.5, near end, align=left] {clEnqueueReadBuffer(q2, b2\_c2, ptr);\\ clEnqueueReadBuffer(q1, b2\_c1, ptr)} (CGC); +\end{tikzpicture} +---- diff --git a/adoc/images/host-acc.svg b/adoc/images/host-acc.svg new file mode 100644 index 00000000..c9bf0bf2 --- /dev/null +++ b/adoc/images/host-acc.svg @@ -0,0 +1,192 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/adoc/images/host-acc.tikz b/adoc/images/host-acc.tikz new file mode 100644 index 00000000..c71a2322 --- /dev/null +++ b/adoc/images/host-acc.tikz @@ -0,0 +1,31 @@ +[tikz,"host-acc"] +---- +\usetikzlibrary{arrows} +\begin{tikzpicture}[auto] \small +\tikzset{Base/.style={align=center}, %, minimum height=2ex}, + Line/.style={draw, very thick, >=latex', black}, + LineHost/.style={draw, dashed, >=latex', black}, + MemoryObject/.style={draw, Base, black}, + HostAcc/.style={draw, Base, black, cylinder}, + CommandGroup/.style={draw, Base, rounded corners, black}, + Notice/.style = {draw, above, rounded corners, rectangle callout, text width=6cm, + callout absolute pointer={#1} }, + } + +\matrix (binmat) [ampersand replacement=\&, column sep=0.5em, row sep=2em] +{ + \node [CommandGroup] (CGA) {$CG_a(b1_{RW})$}; \& + \node (empty) {}; \& + \node (empty) {}; \\ + \node [CommandGroup] (CGB) {$CG_b(b2_{RW})$}; \& + \node [MemoryObject] (HA) {$H(b1_{RW})$}; \\ + \& \node [CommandGroup] (CGC) {$CG_c(b1_{RW}, b2_{RW})$}; \\ + \node (empty) {}; \& + + \& \node (empty) {}; \\ +}; +\path [Line, ->] (CGA) -- (HA); +\path [Line, ->] (CGB) -- (CGC); +\path [Line, ->] (HA) -- (CGC); +\end{tikzpicture} +---- diff --git a/adoc/images/makesvg.adoc b/adoc/images/makesvg.adoc new file mode 100644 index 00000000..0bae5027 --- /dev/null +++ b/adoc/images/makesvg.adoc @@ -0,0 +1,12 @@ +// Shell used to convert TikZ images into SVG + +:tikz-format: svg + += Images + +include::three-cg-one-queue.tikz[] +include::three-cg-three-queue.tikz[] +include::device_to_device1.tikz[] +include::device_to_device2.tikz[] +include::overlap.tikz[] +include::host-acc.tikz[] diff --git a/adoc/images/overlap.svg b/adoc/images/overlap.svg new file mode 100644 index 00000000..6dbb55ec --- /dev/null +++ b/adoc/images/overlap.svg @@ -0,0 +1,214 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/adoc/images/overlap.tikz b/adoc/images/overlap.tikz new file mode 100644 index 00000000..3454411a --- /dev/null +++ b/adoc/images/overlap.tikz @@ -0,0 +1,28 @@ +[tikz,"overlap"] +---- +\usetikzlibrary{arrows} +\begin{tikzpicture}[auto] \small +\tikzset{Base/.style={align=center}, %, minimum height=2ex}, + Line/.style={draw, very thick, >=latex', black}, + LineHost/.style={draw, dashed, >=latex', black}, + MemoryObject/.style={draw, Base, black}, + CommandGroup/.style={draw, Base, rounded corners, black}, + Notice/.style = {draw, above, rounded corners, rectangle callout, text width=6cm, + callout absolute pointer={#1} }, + } + +\matrix (binmat) [ampersand replacement=\&, column sep=0.5em, row sep=2em] +{ + \node [CommandGroup] (CGA) {$CG_a(b1_{RW, [0,10)})$}; \& + \node (empty) {}; \& + \node [CommandGroup] (CGB) {$CG_b(b1_{RW, [10, 20)})$}; \\ + \node (empty) {}; \& + \& \node [CommandGroup] (CGC) {$CG_c(b1_{RW, [5, 15)})$}; \\ + \node (empty) {}; \& + + \& \node (empty) {}; \\ +}; +\path [Line, ->] (CGA) -- (CGC); +\path [Line, ->] (CGB) -- (CGC); +\end{tikzpicture} +---- diff --git a/adoc/images/three-cg-one-queue.svg b/adoc/images/three-cg-one-queue.svg new file mode 100644 index 00000000..eaf1911b --- /dev/null +++ b/adoc/images/three-cg-one-queue.svg @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/adoc/images/three-cg-one-queue.tikz b/adoc/images/three-cg-one-queue.tikz new file mode 100644 index 00000000..3ac2aefc --- /dev/null +++ b/adoc/images/three-cg-one-queue.tikz @@ -0,0 +1,26 @@ +[tikz,"three-cg-one-queue"] +---- +\usetikzlibrary{arrows} +\begin{tikzpicture}[auto] \small +\tikzset{ + Base/.style={align=center}, %, minimum height=2ex}, + Line/.style={draw, very thick, >=latex', black}, + CommandGroup/.style={draw, Base, rounded corners, black}, + Notice/.style = { draw, above, rounded corners, rectangle callout, text width=6cm, + callout absolute pointer={#1} }, + } + +\matrix (binmat) [ampersand replacement=\&, column sep=0.5em, row sep=2em] +{ + \node [CommandGroup] (CGA) {$CG_a(r_1)$}; \& + \node (empty) {}; \& + \node [CommandGroup] (CGB) {$CG_b(r_2)$}; \\ + + \& \node [CommandGroup] (CGC) {$CG_c(r_1,r_2)$}; \\ + \& \node (empty) {}; \\ +}; + +\path [Line, ->] (CGA) -- (CGC); +\path [Line, ->] (CGB) -- (CGC); +\end{tikzpicture} +---- diff --git a/adoc/images/three-cg-three-queue.svg b/adoc/images/three-cg-three-queue.svg new file mode 100644 index 00000000..eaf1911b --- /dev/null +++ b/adoc/images/three-cg-three-queue.svg @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/adoc/images/three-cg-three-queue.tikz b/adoc/images/three-cg-three-queue.tikz new file mode 100644 index 00000000..98c09bd7 --- /dev/null +++ b/adoc/images/three-cg-three-queue.tikz @@ -0,0 +1,26 @@ +[tikz,"three-cg-three-queue"] +---- +\usetikzlibrary{arrows} +\begin{tikzpicture}[auto] \small +\tikzset{ + Base/.style={align=center}, %, minimum height=2ex}, + Line/.style={draw, very thick, >=latex', black}, + CommandGroup/.style={draw, Base, rounded corners, black}, + Notice/.style = { draw, above, rounded corners, rectangle callout, text width=6cm, + callout absolute pointer={#1} }, + } + +\matrix (binmat) [ampersand replacement=\&, column sep=0.5em, row sep=2em] +{ + \node [CommandGroup] (CGA) {$CG_a(r_1)$}; \& + \node (empty) {}; \& + \node [CommandGroup] (CGB) {$CG_b(r_2)$}; \\ + + \& \node [CommandGroup] (CGC) {$CG_c(r_1,r_2)$}; \\ + \& \node (empty) {}; \\ +}; + +\path [Line, ->] (CGA) -- (CGC); +\path [Line, ->] (CGB) -- (CGC); +\end{tikzpicture} +---- diff --git a/adoc/katex/README.md b/adoc/katex/README.md new file mode 100644 index 00000000..5868416e --- /dev/null +++ b/adoc/katex/README.md @@ -0,0 +1,91 @@ +# [KaTeX](https://katex.org/) +[![npm](https://img.shields.io/npm/v/katex.svg)](https://www.npmjs.com/package/katex) +[![CircleCI](https://circleci.com/gh/KaTeX/KaTeX.svg?style=shield)](https://circleci.com/gh/KaTeX/KaTeX) +[![codecov](https://codecov.io/gh/KaTeX/KaTeX/branch/master/graph/badge.svg)](https://codecov.io/gh/KaTeX/KaTeX) +[![Join the chat at https://gitter.im/KaTeX/KaTeX](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/KaTeX/KaTeX?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![Dependabot Status](https://api.dependabot.com/badges/status?host=github&repo=KaTeX/KaTeX)](https://dependabot.com) +[![jsDelivr](https://data.jsdelivr.com/v1/package/npm/katex/badge?style=rounded)](https://www.jsdelivr.com/package/npm/katex) +![](https://img.badgesize.io/KaTeX/KaTeX/v0.11.1/dist/katex.min.js?compression=gzip) + +KaTeX is a fast, easy-to-use JavaScript library for TeX math rendering on the web. + + * **Fast:** KaTeX renders its math synchronously and doesn't need to reflow the page. See how it compares to a competitor in [this speed test](http://www.intmath.com/cg5/katex-mathjax-comparison.php). + * **Print quality:** KaTeX's layout is based on Donald Knuth's TeX, the gold standard for math typesetting. + * **Self contained:** KaTeX has no dependencies and can easily be bundled with your website resources. + * **Server side rendering:** KaTeX produces the same output regardless of browser or environment, so you can pre-render expressions using Node.js and send them as plain HTML. + +KaTeX is compatible with all major browsers, including Chrome, Safari, Firefox, Opera, Edge, and IE 9–11. + +KaTeX supports much (but not all) of LaTeX and many LaTeX packages. See the [list of supported functions](https://katex.org/docs/supported.html). + +Try out KaTeX [on the demo page](https://katex.org/#demo)! + +## Getting started + +### Starter template + +```html + + + + + + + + + + + + + ... + +``` + +You can also [download KaTeX](https://github.com/KaTeX/KaTeX/releases) and host it yourself. + +For details on how to configure auto-render extension, refer to [the documentation](https://katex.org/docs/autorender.html). + +### API + +Call `katex.render` to render a TeX expression directly into a DOM element. +For example: + +```js +katex.render("c = \\pm\\sqrt{a^2 + b^2}", element, { + throwOnError: false +}); +``` + +Call `katex.renderToString` to generate an HTML string of the rendered math, +e.g., for server-side rendering. For example: + +```js +var html = katex.renderToString("c = \\pm\\sqrt{a^2 + b^2}", { + throwOnError: false +}); +// '...' +``` + +Make sure to include the CSS and font files in both cases. +If you are doing all rendering on the server, there is no need to include the +JavaScript on the client. + +The examples above use the `throwOnError: false` option, which renders invalid +inputs as the TeX source code in red (by default), with the error message as +hover text. For other available options, see the +[API documentation](https://katex.org/docs/api.html), +[options documentation](https://katex.org/docs/options.html), and +[handling errors documentation](https://katex.org/docs/error.html). + +## Demo and Documentation + +Learn more about using KaTeX [on the website](https://katex.org)! + +## Contributing + +See [CONTRIBUTING.md](CONTRIBUTING.md) + +## License + +KaTeX is licensed under the [MIT License](http://opensource.org/licenses/MIT). diff --git a/adoc/katex/contrib/auto-render.js b/adoc/katex/contrib/auto-render.js new file mode 100644 index 00000000..d31cc7cf --- /dev/null +++ b/adoc/katex/contrib/auto-render.js @@ -0,0 +1,339 @@ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(require("katex")); + else if(typeof define === 'function' && define.amd) + define(["katex"], factory); + else if(typeof exports === 'object') + exports["renderMathInElement"] = factory(require("katex")); + else + root["renderMathInElement"] = factory(root["katex"]); +})((typeof self !== 'undefined' ? self : this), function(__WEBPACK_EXTERNAL_MODULE__0__) { +return /******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); +/******/ } +/******/ }; +/******/ +/******/ // define __esModule on exports +/******/ __webpack_require__.r = function(exports) { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ +/******/ // create a fake namespace object +/******/ // mode & 1: value is a module id, require it +/******/ // mode & 2: merge all properties of value into the ns +/******/ // mode & 4: return value when already ns object +/******/ // mode & 8|1: behave like require +/******/ __webpack_require__.t = function(value, mode) { +/******/ if(mode & 1) value = __webpack_require__(value); +/******/ if(mode & 8) return value; +/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; +/******/ var ns = Object.create(null); +/******/ __webpack_require__.r(ns); +/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); +/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); +/******/ return ns; +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; +/******/ +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = 1); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ (function(module, exports) { + +module.exports = __WEBPACK_EXTERNAL_MODULE__0__; + +/***/ }), +/* 1 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); + +// EXTERNAL MODULE: external "katex" +var external_katex_ = __webpack_require__(0); +var external_katex_default = /*#__PURE__*/__webpack_require__.n(external_katex_); + +// CONCATENATED MODULE: ./contrib/auto-render/splitAtDelimiters.js +/* eslint no-constant-condition:0 */ +var findEndOfMath = function findEndOfMath(delimiter, text, startIndex) { + // Adapted from + // https://github.com/Khan/perseus/blob/master/src/perseus-markdown.jsx + var index = startIndex; + var braceLevel = 0; + var delimLength = delimiter.length; + + while (index < text.length) { + var character = text[index]; + + if (braceLevel <= 0 && text.slice(index, index + delimLength) === delimiter) { + return index; + } else if (character === "\\") { + index++; + } else if (character === "{") { + braceLevel++; + } else if (character === "}") { + braceLevel--; + } + + index++; + } + + return -1; +}; + +var splitAtDelimiters = function splitAtDelimiters(startData, leftDelim, rightDelim, display) { + var finalData = []; + + for (var i = 0; i < startData.length; i++) { + if (startData[i].type === "text") { + var text = startData[i].data; + var lookingForLeft = true; + var currIndex = 0; + var nextIndex = void 0; + nextIndex = text.indexOf(leftDelim); + + if (nextIndex !== -1) { + currIndex = nextIndex; + finalData.push({ + type: "text", + data: text.slice(0, currIndex) + }); + lookingForLeft = false; + } + + while (true) { + if (lookingForLeft) { + nextIndex = text.indexOf(leftDelim, currIndex); + + if (nextIndex === -1) { + break; + } + + finalData.push({ + type: "text", + data: text.slice(currIndex, nextIndex) + }); + currIndex = nextIndex; + } else { + nextIndex = findEndOfMath(rightDelim, text, currIndex + leftDelim.length); + + if (nextIndex === -1) { + break; + } + + finalData.push({ + type: "math", + data: text.slice(currIndex + leftDelim.length, nextIndex), + rawData: text.slice(currIndex, nextIndex + rightDelim.length), + display: display + }); + currIndex = nextIndex + rightDelim.length; + } + + lookingForLeft = !lookingForLeft; + } + + finalData.push({ + type: "text", + data: text.slice(currIndex) + }); + } else { + finalData.push(startData[i]); + } + } + + return finalData; +}; + +/* harmony default export */ var auto_render_splitAtDelimiters = (splitAtDelimiters); +// CONCATENATED MODULE: ./contrib/auto-render/auto-render.js +/* eslint no-console:0 */ + + + +var auto_render_splitWithDelimiters = function splitWithDelimiters(text, delimiters) { + var data = [{ + type: "text", + data: text + }]; + + for (var i = 0; i < delimiters.length; i++) { + var delimiter = delimiters[i]; + data = auto_render_splitAtDelimiters(data, delimiter.left, delimiter.right, delimiter.display || false); + } + + return data; +}; +/* Note: optionsCopy is mutated by this method. If it is ever exposed in the + * API, we should copy it before mutating. + */ + + +var auto_render_renderMathInText = function renderMathInText(text, optionsCopy) { + var data = auto_render_splitWithDelimiters(text, optionsCopy.delimiters); + var fragment = document.createDocumentFragment(); + + for (var i = 0; i < data.length; i++) { + if (data[i].type === "text") { + fragment.appendChild(document.createTextNode(data[i].data)); + } else { + var span = document.createElement("span"); + var math = data[i].data; // Override any display mode defined in the settings with that + // defined by the text itself + + optionsCopy.displayMode = data[i].display; + + try { + if (optionsCopy.preProcess) { + math = optionsCopy.preProcess(math); + } + + external_katex_default.a.render(math, span, optionsCopy); + } catch (e) { + if (!(e instanceof external_katex_default.a.ParseError)) { + throw e; + } + + optionsCopy.errorCallback("KaTeX auto-render: Failed to parse `" + data[i].data + "` with ", e); + fragment.appendChild(document.createTextNode(data[i].rawData)); + continue; + } + + fragment.appendChild(span); + } + } + + return fragment; +}; + +var renderElem = function renderElem(elem, optionsCopy) { + for (var i = 0; i < elem.childNodes.length; i++) { + var childNode = elem.childNodes[i]; + + if (childNode.nodeType === 3) { + // Text node + var frag = auto_render_renderMathInText(childNode.textContent, optionsCopy); + i += frag.childNodes.length - 1; + elem.replaceChild(frag, childNode); + } else if (childNode.nodeType === 1) { + (function () { + // Element node + var className = ' ' + childNode.className + ' '; + var shouldRender = optionsCopy.ignoredTags.indexOf(childNode.nodeName.toLowerCase()) === -1 && optionsCopy.ignoredClasses.every(function (x) { + return className.indexOf(' ' + x + ' ') === -1; + }); + + if (shouldRender) { + renderElem(childNode, optionsCopy); + } + })(); + } // Otherwise, it's something else, and ignore it. + + } +}; + +var renderMathInElement = function renderMathInElement(elem, options) { + if (!elem) { + throw new Error("No element provided to render"); + } + + var optionsCopy = {}; // Object.assign(optionsCopy, option) + + for (var option in options) { + if (options.hasOwnProperty(option)) { + optionsCopy[option] = options[option]; + } + } // default options + + + optionsCopy.delimiters = optionsCopy.delimiters || [{ + left: "$$", + right: "$$", + display: true + }, { + left: "\\(", + right: "\\)", + display: false + }, // LaTeX uses $…$, but it ruins the display of normal `$` in text: + // {left: "$", right: "$", display: false}, + // \[…\] must come last in this array. Otherwise, renderMathInElement + // will search for \[ before it searches for $$ or \( + // That makes it susceptible to finding a \\[0.3em] row delimiter and + // treating it as if it were the start of a KaTeX math zone. + { + left: "\\[", + right: "\\]", + display: true + }]; + optionsCopy.ignoredTags = optionsCopy.ignoredTags || ["script", "noscript", "style", "textarea", "pre", "code"]; + optionsCopy.ignoredClasses = optionsCopy.ignoredClasses || []; + optionsCopy.errorCallback = optionsCopy.errorCallback || console.error; // Enable sharing of global macros defined via `\gdef` between different + // math elements within a single call to `renderMathInElement`. + + optionsCopy.macros = optionsCopy.macros || {}; + renderElem(elem, optionsCopy); +}; + +/* harmony default export */ var auto_render = __webpack_exports__["default"] = (renderMathInElement); + +/***/ }) +/******/ ])["default"]; +}); \ No newline at end of file diff --git a/adoc/katex/contrib/auto-render.min.js b/adoc/katex/contrib/auto-render.min.js new file mode 100644 index 00000000..3a6d6639 --- /dev/null +++ b/adoc/katex/contrib/auto-render.min.js @@ -0,0 +1 @@ +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("katex")):"function"==typeof define&&define.amd?define(["katex"],t):"object"==typeof exports?exports.renderMathInElement=t(require("katex")):e.renderMathInElement=t(e.katex)}("undefined"!=typeof self?self:this,function(e){return function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}return r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=1)}([function(t,r){t.exports=e},function(e,t,r){"use strict";r.r(t);var n=r(0),o=r.n(n),a=function(e,t,r){for(var n=r,o=0,a=e.length;n className.indexOf(' ' + x + ' ') === -1); + + if (shouldRender) { + renderElem(childNode, optionsCopy); + } + } // Otherwise, it's something else, and ignore it. + + } +}; + +const renderMathInElement = function renderMathInElement(elem, options) { + if (!elem) { + throw new Error("No element provided to render"); + } + + const optionsCopy = {}; // Object.assign(optionsCopy, option) + + for (const option in options) { + if (options.hasOwnProperty(option)) { + optionsCopy[option] = options[option]; + } + } // default options + + + optionsCopy.delimiters = optionsCopy.delimiters || [{ + left: "$$", + right: "$$", + display: true + }, { + left: "\\(", + right: "\\)", + display: false + }, // LaTeX uses $…$, but it ruins the display of normal `$` in text: + // {left: "$", right: "$", display: false}, + // \[…\] must come last in this array. Otherwise, renderMathInElement + // will search for \[ before it searches for $$ or \( + // That makes it susceptible to finding a \\[0.3em] row delimiter and + // treating it as if it were the start of a KaTeX math zone. + { + left: "\\[", + right: "\\]", + display: true + }]; + optionsCopy.ignoredTags = optionsCopy.ignoredTags || ["script", "noscript", "style", "textarea", "pre", "code"]; + optionsCopy.ignoredClasses = optionsCopy.ignoredClasses || []; + optionsCopy.errorCallback = optionsCopy.errorCallback || console.error; // Enable sharing of global macros defined via `\gdef` between different + // math elements within a single call to `renderMathInElement`. + + optionsCopy.macros = optionsCopy.macros || {}; + renderElem(elem, optionsCopy); +}; + +export default renderMathInElement; diff --git a/adoc/katex/contrib/copy-tex.css b/adoc/katex/contrib/copy-tex.css new file mode 100644 index 00000000..90801d84 --- /dev/null +++ b/adoc/katex/contrib/copy-tex.css @@ -0,0 +1,14 @@ +/* Force selection of entire .katex/.katex-display blocks, so that we can + * copy/paste the entire source code. If you omit this CSS, partial + * selections of a formula will work, but will copy the ugly HTML + * representation instead of the LaTeX source code. (Full selections will + * still produce the LaTeX source code.) + */ +.katex, +.katex-display { + user-select: all; + -moz-user-select: all; + -webkit-user-select: all; + -ms-user-select: all; +} + diff --git a/adoc/katex/contrib/copy-tex.js b/adoc/katex/contrib/copy-tex.js new file mode 100644 index 00000000..4649f8f7 --- /dev/null +++ b/adoc/katex/contrib/copy-tex.js @@ -0,0 +1,213 @@ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else { + var a = factory(); + for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i]; + } +})((typeof self !== 'undefined' ? self : this), function() { +return /******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); +/******/ } +/******/ }; +/******/ +/******/ // define __esModule on exports +/******/ __webpack_require__.r = function(exports) { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ +/******/ // create a fake namespace object +/******/ // mode & 1: value is a module id, require it +/******/ // mode & 2: merge all properties of value into the ns +/******/ // mode & 4: return value when already ns object +/******/ // mode & 8|1: behave like require +/******/ __webpack_require__.t = function(value, mode) { +/******/ if(mode & 1) value = __webpack_require__(value); +/******/ if(mode & 8) return value; +/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; +/******/ var ns = Object.create(null); +/******/ __webpack_require__.r(ns); +/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); +/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); +/******/ return ns; +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; +/******/ +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = 1); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ (function(module, exports, __webpack_require__) { + +// extracted by mini-css-extract-plugin + +/***/ }), +/* 1 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); + +// EXTERNAL MODULE: ./contrib/copy-tex/copy-tex.css +var copy_tex = __webpack_require__(0); + +// CONCATENATED MODULE: ./contrib/copy-tex/katex2tex.js +// Set these to how you want inline and display math to be delimited. +var defaultCopyDelimiters = { + inline: ['$', '$'], + // alternative: ['\(', '\)'] + display: ['$$', '$$'] // alternative: ['\[', '\]'] + +}; // Replace .katex elements with their TeX source ( element). +// Modifies fragment in-place. Useful for writing your own 'copy' handler, +// as in copy-tex.js. + +var katexReplaceWithTex = function katexReplaceWithTex(fragment, copyDelimiters) { + if (copyDelimiters === void 0) { + copyDelimiters = defaultCopyDelimiters; + } + + // Remove .katex-html blocks that are preceded by .katex-mathml blocks + // (which will get replaced below). + var katexHtml = fragment.querySelectorAll('.katex-mathml + .katex-html'); + + for (var i = 0; i < katexHtml.length; i++) { + var element = katexHtml[i]; + + if (element.remove) { + element.remove(null); + } else { + element.parentNode.removeChild(element); + } + } // Replace .katex-mathml elements with their annotation (TeX source) + // descendant, with inline delimiters. + + + var katexMathml = fragment.querySelectorAll('.katex-mathml'); + + for (var _i = 0; _i < katexMathml.length; _i++) { + var _element = katexMathml[_i]; + + var texSource = _element.querySelector('annotation'); + + if (texSource) { + if (_element.replaceWith) { + _element.replaceWith(texSource); + } else { + _element.parentNode.replaceChild(texSource, _element); + } + + texSource.innerHTML = copyDelimiters.inline[0] + texSource.innerHTML + copyDelimiters.inline[1]; + } + } // Switch display math to display delimiters. + + + var displays = fragment.querySelectorAll('.katex-display annotation'); + + for (var _i2 = 0; _i2 < displays.length; _i2++) { + var _element2 = displays[_i2]; + _element2.innerHTML = copyDelimiters.display[0] + _element2.innerHTML.substr(copyDelimiters.inline[0].length, _element2.innerHTML.length - copyDelimiters.inline[0].length - copyDelimiters.inline[1].length) + copyDelimiters.display[1]; + } + + return fragment; +}; +/* harmony default export */ var katex2tex = (katexReplaceWithTex); +// CONCATENATED MODULE: ./contrib/copy-tex/copy-tex.js + // Global copy handler to modify behavior on .katex elements. + +document.addEventListener('copy', function (event) { + var selection = window.getSelection(); + + if (selection.isCollapsed) { + return; // default action OK if selection is empty + } + + var fragment = selection.getRangeAt(0).cloneContents(); + + if (!fragment.querySelector('.katex-mathml')) { + return; // default action OK if no .katex-mathml elements + } // Preserve usual HTML copy/paste behavior. + + + var html = []; + + for (var i = 0; i < fragment.childNodes.length; i++) { + html.push(fragment.childNodes[i].outerHTML); + } + + event.clipboardData.setData('text/html', html.join('')); // Rewrite plain-text version. + + event.clipboardData.setData('text/plain', katex2tex(fragment).textContent); // Prevent normal copy handling. + + event.preventDefault(); +}); +// CONCATENATED MODULE: ./contrib/copy-tex/copy-tex.webpack.js +/** + * This is the webpack entry point for KaTeX. As ECMAScript doesn't support + * CSS modules natively, a separate entry point is used. + */ + + + +/***/ }) +/******/ ])["default"]; +}); \ No newline at end of file diff --git a/adoc/katex/contrib/copy-tex.min.css b/adoc/katex/contrib/copy-tex.min.css new file mode 100644 index 00000000..555ed115 --- /dev/null +++ b/adoc/katex/contrib/copy-tex.min.css @@ -0,0 +1 @@ +.katex,.katex-display{user-select:all;-moz-user-select:all;-webkit-user-select:all;-ms-user-select:all} diff --git a/adoc/katex/contrib/copy-tex.min.js b/adoc/katex/contrib/copy-tex.min.js new file mode 100644 index 00000000..e0354d6b --- /dev/null +++ b/adoc/katex/contrib/copy-tex.min.js @@ -0,0 +1 @@ +!function(e,t){if("object"==typeof exports&&"object"==typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var n=t();for(var r in n)("object"==typeof exports?exports:e)[r]=n[r]}}("undefined"!=typeof self?self:this,function(){return function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=1)}([function(e,t,n){},function(e,t,n){"use strict";n.r(t);n(0);var r={inline:["$","$"],display:["$$","$$"]},o=function(e,t){void 0===t&&(t=r);for(var n=e.querySelectorAll(".katex-mathml + .katex-html"),o=0;o element). +// Modifies fragment in-place. Useful for writing your own 'copy' handler, +// as in copy-tex.js. + +const katexReplaceWithTex = function katexReplaceWithTex(fragment, copyDelimiters) { + if (copyDelimiters === void 0) { + copyDelimiters = defaultCopyDelimiters; + } + + // Remove .katex-html blocks that are preceded by .katex-mathml blocks + // (which will get replaced below). + const katexHtml = fragment.querySelectorAll('.katex-mathml + .katex-html'); + + for (let i = 0; i < katexHtml.length; i++) { + const element = katexHtml[i]; + + if (element.remove) { + element.remove(null); + } else { + element.parentNode.removeChild(element); + } + } // Replace .katex-mathml elements with their annotation (TeX source) + // descendant, with inline delimiters. + + + const katexMathml = fragment.querySelectorAll('.katex-mathml'); + + for (let i = 0; i < katexMathml.length; i++) { + const element = katexMathml[i]; + const texSource = element.querySelector('annotation'); + + if (texSource) { + if (element.replaceWith) { + element.replaceWith(texSource); + } else { + element.parentNode.replaceChild(texSource, element); + } + + texSource.innerHTML = copyDelimiters.inline[0] + texSource.innerHTML + copyDelimiters.inline[1]; + } + } // Switch display math to display delimiters. + + + const displays = fragment.querySelectorAll('.katex-display annotation'); + + for (let i = 0; i < displays.length; i++) { + const element = displays[i]; + element.innerHTML = copyDelimiters.display[0] + element.innerHTML.substr(copyDelimiters.inline[0].length, element.innerHTML.length - copyDelimiters.inline[0].length - copyDelimiters.inline[1].length) + copyDelimiters.display[1]; + } + + return fragment; +}; + +document.addEventListener('copy', function (event) { + const selection = window.getSelection(); + + if (selection.isCollapsed) { + return; // default action OK if selection is empty + } + + const fragment = selection.getRangeAt(0).cloneContents(); + + if (!fragment.querySelector('.katex-mathml')) { + return; // default action OK if no .katex-mathml elements + } // Preserve usual HTML copy/paste behavior. + + + const html = []; + + for (let i = 0; i < fragment.childNodes.length; i++) { + html.push(fragment.childNodes[i].outerHTML); + } + + event.clipboardData.setData('text/html', html.join('')); // Rewrite plain-text version. + + event.clipboardData.setData('text/plain', katexReplaceWithTex(fragment).textContent); // Prevent normal copy handling. + + event.preventDefault(); +}); diff --git a/adoc/katex/contrib/mathtex-script-type.js b/adoc/katex/contrib/mathtex-script-type.js new file mode 100644 index 00000000..daa01a63 --- /dev/null +++ b/adoc/katex/contrib/mathtex-script-type.js @@ -0,0 +1,137 @@ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(require("katex")); + else if(typeof define === 'function' && define.amd) + define(["katex"], factory); + else { + var a = typeof exports === 'object' ? factory(require("katex")) : factory(root["katex"]); + for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i]; + } +})((typeof self !== 'undefined' ? self : this), function(__WEBPACK_EXTERNAL_MODULE__0__) { +return /******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); +/******/ } +/******/ }; +/******/ +/******/ // define __esModule on exports +/******/ __webpack_require__.r = function(exports) { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ +/******/ // create a fake namespace object +/******/ // mode & 1: value is a module id, require it +/******/ // mode & 2: merge all properties of value into the ns +/******/ // mode & 4: return value when already ns object +/******/ // mode & 8|1: behave like require +/******/ __webpack_require__.t = function(value, mode) { +/******/ if(mode & 1) value = __webpack_require__(value); +/******/ if(mode & 8) return value; +/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; +/******/ var ns = Object.create(null); +/******/ __webpack_require__.r(ns); +/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); +/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); +/******/ return ns; +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; +/******/ +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = 1); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ (function(module, exports) { + +module.exports = __WEBPACK_EXTERNAL_MODULE__0__; + +/***/ }), +/* 1 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var katex__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(0); +/* harmony import */ var katex__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(katex__WEBPACK_IMPORTED_MODULE_0__); + +var scripts = document.body.getElementsByTagName("script"); +scripts = Array.prototype.slice.call(scripts); +scripts.forEach(function (script) { + if (!script.type || !script.type.match(/math\/tex/i)) { + return -1; + } + + var display = script.type.match(/mode\s*=\s*display(;|\s|\n|$)/) != null; + var katexElement = document.createElement(display ? "div" : "span"); + katexElement.setAttribute("class", display ? "equation" : "inline-equation"); + + try { + katex__WEBPACK_IMPORTED_MODULE_0___default.a.render(script.text, katexElement, { + displayMode: display + }); + } catch (err) { + //console.error(err); linter doesn't like this + katexElement.textContent = script.text; + } + + script.parentNode.replaceChild(katexElement, script); +}); + +/***/ }) +/******/ ])["default"]; +}); \ No newline at end of file diff --git a/adoc/katex/contrib/mathtex-script-type.min.js b/adoc/katex/contrib/mathtex-script-type.min.js new file mode 100644 index 00000000..ae9f5286 --- /dev/null +++ b/adoc/katex/contrib/mathtex-script-type.min.js @@ -0,0 +1 @@ +!function(e,t){if("object"==typeof exports&&"object"==typeof module)module.exports=t(require("katex"));else if("function"==typeof define&&define.amd)define(["katex"],t);else{var r="object"==typeof exports?t(require("katex")):t(e.katex);for(var n in r)("object"==typeof exports?exports:e)[n]=r[n]}}("undefined"!=typeof self?self:this,function(e){return function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}return r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=1)}([function(t,r){t.exports=e},function(e,t,r){"use strict";r.r(t);var n=r(0),o=r.n(n),u=document.body.getElementsByTagName("script");(u=Array.prototype.slice.call(u)).forEach(function(e){if(!e.type||!e.type.match(/math\/tex/i))return-1;var t=null!=e.type.match(/mode\s*=\s*display(;|\s|\n|$)/),r=document.createElement(t?"div":"span");r.setAttribute("class",t?"equation":"inline-equation");try{o.a.render(e.text,r,{displayMode:t})}catch(t){r.textContent=e.text}e.parentNode.replaceChild(r,e)})}]).default}); \ No newline at end of file diff --git a/adoc/katex/contrib/mathtex-script-type.mjs b/adoc/katex/contrib/mathtex-script-type.mjs new file mode 100644 index 00000000..7cfb90e9 --- /dev/null +++ b/adoc/katex/contrib/mathtex-script-type.mjs @@ -0,0 +1,24 @@ +import katex from '../katex.mjs'; + +let scripts = document.body.getElementsByTagName("script"); +scripts = Array.prototype.slice.call(scripts); +scripts.forEach(function (script) { + if (!script.type || !script.type.match(/math\/tex/i)) { + return -1; + } + + const display = script.type.match(/mode\s*=\s*display(;|\s|\n|$)/) != null; + const katexElement = document.createElement(display ? "div" : "span"); + katexElement.setAttribute("class", display ? "equation" : "inline-equation"); + + try { + katex.render(script.text, katexElement, { + displayMode: display + }); + } catch (err) { + //console.error(err); linter doesn't like this + katexElement.textContent = script.text; + } + + script.parentNode.replaceChild(katexElement, script); +}); diff --git a/adoc/katex/contrib/mhchem.js b/adoc/katex/contrib/mhchem.js new file mode 100644 index 00000000..f84566ef --- /dev/null +++ b/adoc/katex/contrib/mhchem.js @@ -0,0 +1,3241 @@ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(require("katex")); + else if(typeof define === 'function' && define.amd) + define(["katex"], factory); + else { + var a = typeof exports === 'object' ? factory(require("katex")) : factory(root["katex"]); + for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i]; + } +})((typeof self !== 'undefined' ? self : this), function(__WEBPACK_EXTERNAL_MODULE__0__) { +return /******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); +/******/ } +/******/ }; +/******/ +/******/ // define __esModule on exports +/******/ __webpack_require__.r = function(exports) { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ +/******/ // create a fake namespace object +/******/ // mode & 1: value is a module id, require it +/******/ // mode & 2: merge all properties of value into the ns +/******/ // mode & 4: return value when already ns object +/******/ // mode & 8|1: behave like require +/******/ __webpack_require__.t = function(value, mode) { +/******/ if(mode & 1) value = __webpack_require__(value); +/******/ if(mode & 8) return value; +/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; +/******/ var ns = Object.create(null); +/******/ __webpack_require__.r(ns); +/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); +/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); +/******/ return ns; +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; +/******/ +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = 1); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ (function(module, exports) { + +module.exports = __WEBPACK_EXTERNAL_MODULE__0__; + +/***/ }), +/* 1 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var katex__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(0); +/* harmony import */ var katex__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(katex__WEBPACK_IMPORTED_MODULE_0__); +/* eslint-disable */ + +/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */ + +/* vim: set ts=2 et sw=2 tw=80: */ + +/************************************************************* + * + * KaTeX mhchem.js + * + * This file implements a KaTeX version of mhchem version 3.3.0. + * It is adapted from MathJax/extensions/TeX/mhchem.js + * It differs from the MathJax version as follows: + * 1. The interface is changed so that it can be called from KaTeX, not MathJax. + * 2. \rlap and \llap are replaced with \mathrlap and \mathllap. + * 3. Four lines of code are edited in order to use \raisebox instead of \raise. + * 4. The reaction arrow code is simplified. All reaction arrows are rendered + * using KaTeX extensible arrows instead of building non-extensible arrows. + * 5. \tripledash vertical alignment is slightly adjusted. + * + * This code, as other KaTeX code, is released under the MIT license. + * + * /************************************************************* + * + * MathJax/extensions/TeX/mhchem.js + * + * Implements the \ce command for handling chemical formulas + * from the mhchem LaTeX package. + * + * --------------------------------------------------------------------- + * + * Copyright (c) 2011-2015 The MathJax Consortium + * Copyright (c) 2015-2018 Martin Hensel + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// +// Coding Style +// - use '' for identifiers that can by minified/uglified +// - use "" for strings that need to stay untouched +// version: "3.3.0" for MathJax and KaTeX +// Add \ce, \pu, and \tripledash to the KaTeX macros. +katex__WEBPACK_IMPORTED_MODULE_0___default.a.__defineMacro("\\ce", function (context) { + return chemParse(context.consumeArgs(1)[0], "ce"); +}); + +katex__WEBPACK_IMPORTED_MODULE_0___default.a.__defineMacro("\\pu", function (context) { + return chemParse(context.consumeArgs(1)[0], "pu"); +}); // Needed for \bond for the ~ forms +// Raise by 2.56mu, not 2mu. We're raising a hyphen-minus, U+002D, not +// a mathematical minus, U+2212. So we need that extra 0.56. + + +katex__WEBPACK_IMPORTED_MODULE_0___default.a.__defineMacro("\\tripledash", "{\\vphantom{-}\\raisebox{2.56mu}{$\\mkern2mu" + "\\tiny\\text{-}\\mkern1mu\\text{-}\\mkern1mu\\text{-}\\mkern2mu$}}"); + + // +// This is the main function for handing the \ce and \pu commands. +// It takes the argument to \ce or \pu and returns the corresponding TeX string. +// + +var chemParse = function chemParse(tokens, stateMachine) { + // Recreate the argument string from KaTeX's array of tokens. + var str = ""; + var expectedLoc = tokens[tokens.length - 1].loc.start; + + for (var i = tokens.length - 1; i >= 0; i--) { + if (tokens[i].loc.start > expectedLoc) { + // context.consumeArgs has eaten a space. + str += " "; + expectedLoc = tokens[i].loc.start; + } + + str += tokens[i].text; + expectedLoc += tokens[i].text.length; + } + + var tex = texify.go(mhchemParser.go(str, stateMachine)); + return tex; +}; // +// Core parser for mhchem syntax (recursive) +// + +/** @type {MhchemParser} */ + + +var mhchemParser = { + // + // Parses mchem \ce syntax + // + // Call like + // go("H2O"); + // + go: function go(input, stateMachine) { + if (!input) { + return []; + } + + if (stateMachine === undefined) { + stateMachine = 'ce'; + } + + var state = '0'; // + // String buffers for parsing: + // + // buffer.a == amount + // buffer.o == element + // buffer.b == left-side superscript + // buffer.p == left-side subscript + // buffer.q == right-side subscript + // buffer.d == right-side superscript + // + // buffer.r == arrow + // buffer.rdt == arrow, script above, type + // buffer.rd == arrow, script above, content + // buffer.rqt == arrow, script below, type + // buffer.rq == arrow, script below, content + // + // buffer.text_ + // buffer.rm + // etc. + // + // buffer.parenthesisLevel == int, starting at 0 + // buffer.sb == bool, space before + // buffer.beginsWithBond == bool + // + // These letters are also used as state names. + // + // Other states: + // 0 == begin of main part (arrow/operator unlikely) + // 1 == next entity + // 2 == next entity (arrow/operator unlikely) + // 3 == next atom + // c == macro + // + + /** @type {Buffer} */ + + var buffer = {}; + buffer['parenthesisLevel'] = 0; + input = input.replace(/\n/g, " "); + input = input.replace(/[\u2212\u2013\u2014\u2010]/g, "-"); + input = input.replace(/[\u2026]/g, "..."); // + // Looks through mhchemParser.transitions, to execute a matching action + // (recursive) + // + + var lastInput; + var watchdog = 10; + /** @type {ParserOutput[]} */ + + var output = []; + + while (true) { + if (lastInput !== input) { + watchdog = 10; + lastInput = input; + } else { + watchdog--; + } // + // Find actions in transition table + // + + + var machine = mhchemParser.stateMachines[stateMachine]; + var t = machine.transitions[state] || machine.transitions['*']; + + iterateTransitions: for (var i = 0; i < t.length; i++) { + var matches = mhchemParser.patterns.match_(t[i].pattern, input); + + if (matches) { + // + // Execute actions + // + var task = t[i].task; + + for (var iA = 0; iA < task.action_.length; iA++) { + var o; // + // Find and execute action + // + + if (machine.actions[task.action_[iA].type_]) { + o = machine.actions[task.action_[iA].type_](buffer, matches.match_, task.action_[iA].option); + } else if (mhchemParser.actions[task.action_[iA].type_]) { + o = mhchemParser.actions[task.action_[iA].type_](buffer, matches.match_, task.action_[iA].option); + } else { + throw ["MhchemBugA", "mhchem bug A. Please report. (" + task.action_[iA].type_ + ")"]; // Trying to use non-existing action + } // + // Add output + // + + + mhchemParser.concatArray(output, o); + } // + // Set next state, + // Shorten input, + // Continue with next character + // (= apply only one transition per position) + // + + + state = task.nextState || state; + + if (input.length > 0) { + if (!task.revisit) { + input = matches.remainder; + } + + if (!task.toContinue) { + break iterateTransitions; + } + } else { + return output; + } + } + } // + // Prevent infinite loop + // + + + if (watchdog <= 0) { + throw ["MhchemBugU", "mhchem bug U. Please report."]; // Unexpected character + } + } + }, + concatArray: function concatArray(a, b) { + if (b) { + if (Array.isArray(b)) { + for (var iB = 0; iB < b.length; iB++) { + a.push(b[iB]); + } + } else { + a.push(b); + } + } + }, + patterns: { + // + // Matching patterns + // either regexps or function that return null or {match_:"a", remainder:"bc"} + // + patterns: { + // property names must not look like integers ("2") for correct property traversal order, later on + 'empty': /^$/, + 'else': /^./, + 'else2': /^./, + 'space': /^\s/, + 'space A': /^\s(?=[A-Z\\$])/, + 'space$': /^\s$/, + 'a-z': /^[a-z]/, + 'x': /^x/, + 'x$': /^x$/, + 'i$': /^i$/, + 'letters': /^(?:[a-zA-Z\u03B1-\u03C9\u0391-\u03A9?@]|(?:\\(?:alpha|beta|gamma|delta|epsilon|zeta|eta|theta|iota|kappa|lambda|mu|nu|xi|omicron|pi|rho|sigma|tau|upsilon|phi|chi|psi|omega|Gamma|Delta|Theta|Lambda|Xi|Pi|Sigma|Upsilon|Phi|Psi|Omega)(?:\s+|\{\}|(?![a-zA-Z]))))+/, + '\\greek': /^\\(?:alpha|beta|gamma|delta|epsilon|zeta|eta|theta|iota|kappa|lambda|mu|nu|xi|omicron|pi|rho|sigma|tau|upsilon|phi|chi|psi|omega|Gamma|Delta|Theta|Lambda|Xi|Pi|Sigma|Upsilon|Phi|Psi|Omega)(?:\s+|\{\}|(?![a-zA-Z]))/, + 'one lowercase latin letter $': /^(?:([a-z])(?:$|[^a-zA-Z]))$/, + '$one lowercase latin letter$ $': /^\$(?:([a-z])(?:$|[^a-zA-Z]))\$$/, + 'one lowercase greek letter $': /^(?:\$?[\u03B1-\u03C9]\$?|\$?\\(?:alpha|beta|gamma|delta|epsilon|zeta|eta|theta|iota|kappa|lambda|mu|nu|xi|omicron|pi|rho|sigma|tau|upsilon|phi|chi|psi|omega)\s*\$?)(?:\s+|\{\}|(?![a-zA-Z]))$/, + 'digits': /^[0-9]+/, + '-9.,9': /^[+\-]?(?:[0-9]+(?:[,.][0-9]+)?|[0-9]*(?:\.[0-9]+))/, + '-9.,9 no missing 0': /^[+\-]?[0-9]+(?:[.,][0-9]+)?/, + '(-)(9.,9)(e)(99)': function e99(input) { + var m = input.match(/^(\+\-|\+\/\-|\+|\-|\\pm\s?)?([0-9]+(?:[,.][0-9]+)?|[0-9]*(?:\.[0-9]+))?(\((?:[0-9]+(?:[,.][0-9]+)?|[0-9]*(?:\.[0-9]+))\))?(?:([eE]|\s*(\*|x|\\times|\u00D7)\s*10\^)([+\-]?[0-9]+|\{[+\-]?[0-9]+\}))?/); + + if (m && m[0]) { + return { + match_: m.splice(1), + remainder: input.substr(m[0].length) + }; + } + + return null; + }, + '(-)(9)^(-9)': function _(input) { + var m = input.match(/^(\+\-|\+\/\-|\+|\-|\\pm\s?)?([0-9]+(?:[,.][0-9]+)?|[0-9]*(?:\.[0-9]+)?)\^([+\-]?[0-9]+|\{[+\-]?[0-9]+\})/); + + if (m && m[0]) { + return { + match_: m.splice(1), + remainder: input.substr(m[0].length) + }; + } + + return null; + }, + 'state of aggregation $': function stateOfAggregation$(input) { + // ... or crystal system + var a = mhchemParser.patterns.findObserveGroups(input, "", /^\([a-z]{1,3}(?=[\),])/, ")", ""); // (aq), (aq,$\infty$), (aq, sat) + + if (a && a.remainder.match(/^($|[\s,;\)\]\}])/)) { + return a; + } // AND end of 'phrase' + + + var m = input.match(/^(?:\((?:\\ca\s?)?\$[amothc]\$\))/); // OR crystal system ($o$) (\ca$c$) + + if (m) { + return { + match_: m[0], + remainder: input.substr(m[0].length) + }; + } + + return null; + }, + '_{(state of aggregation)}$': /^_\{(\([a-z]{1,3}\))\}/, + '{[(': /^(?:\\\{|\[|\()/, + ')]}': /^(?:\)|\]|\\\})/, + ', ': /^[,;]\s*/, + ',': /^[,;]/, + '.': /^[.]/, + '. ': /^([.\u22C5\u00B7\u2022])\s*/, + '...': /^\.\.\.(?=$|[^.])/, + '* ': /^([*])\s*/, + '^{(...)}': function _(input) { + return mhchemParser.patterns.findObserveGroups(input, "^{", "", "", "}"); + }, + '^($...$)': function $$(input) { + return mhchemParser.patterns.findObserveGroups(input, "^", "$", "$", ""); + }, + '^a': /^\^([0-9]+|[^\\_])/, + '^\\x{}{}': function x(input) { + return mhchemParser.patterns.findObserveGroups(input, "^", /^\\[a-zA-Z]+\{/, "}", "", "", "{", "}", "", true); + }, + '^\\x{}': function x(input) { + return mhchemParser.patterns.findObserveGroups(input, "^", /^\\[a-zA-Z]+\{/, "}", ""); + }, + '^\\x': /^\^(\\[a-zA-Z]+)\s*/, + '^(-1)': /^\^(-?\d+)/, + '\'': /^'/, + '_{(...)}': function _(input) { + return mhchemParser.patterns.findObserveGroups(input, "_{", "", "", "}"); + }, + '_($...$)': function _$$(input) { + return mhchemParser.patterns.findObserveGroups(input, "_", "$", "$", ""); + }, + '_9': /^_([+\-]?[0-9]+|[^\\])/, + '_\\x{}{}': function _X(input) { + return mhchemParser.patterns.findObserveGroups(input, "_", /^\\[a-zA-Z]+\{/, "}", "", "", "{", "}", "", true); + }, + '_\\x{}': function _X(input) { + return mhchemParser.patterns.findObserveGroups(input, "_", /^\\[a-zA-Z]+\{/, "}", ""); + }, + '_\\x': /^_(\\[a-zA-Z]+)\s*/, + '^_': /^(?:\^(?=_)|\_(?=\^)|[\^_]$)/, + '{}': /^\{\}/, + '{...}': function _(input) { + return mhchemParser.patterns.findObserveGroups(input, "", "{", "}", ""); + }, + '{(...)}': function _(input) { + return mhchemParser.patterns.findObserveGroups(input, "{", "", "", "}"); + }, + '$...$': function $$(input) { + return mhchemParser.patterns.findObserveGroups(input, "", "$", "$", ""); + }, + '${(...)}$': function $$(input) { + return mhchemParser.patterns.findObserveGroups(input, "${", "", "", "}$"); + }, + '$(...)$': function $$(input) { + return mhchemParser.patterns.findObserveGroups(input, "$", "", "", "$"); + }, + '=<>': /^[=<>]/, + '#': /^[#\u2261]/, + '+': /^\+/, + '-$': /^-(?=[\s_},;\]/]|$|\([a-z]+\))/, + // -space -, -; -] -/ -$ -state-of-aggregation + '-9': /^-(?=[0-9])/, + '- orbital overlap': /^-(?=(?:[spd]|sp)(?:$|[\s,;\)\]\}]))/, + '-': /^-/, + 'pm-operator': /^(?:\\pm|\$\\pm\$|\+-|\+\/-)/, + 'operator': /^(?:\+|(?:[\-=<>]|<<|>>|\\approx|\$\\approx\$)(?=\s|$|-?[0-9]))/, + 'arrowUpDown': /^(?:v|\(v\)|\^|\(\^\))(?=$|[\s,;\)\]\}])/, + '\\bond{(...)}': function bond(input) { + return mhchemParser.patterns.findObserveGroups(input, "\\bond{", "", "", "}"); + }, + '->': /^(?:<->|<-->|->|<-|<=>>|<<=>|<=>|[\u2192\u27F6\u21CC])/, + 'CMT': /^[CMT](?=\[)/, + '[(...)]': function _(input) { + return mhchemParser.patterns.findObserveGroups(input, "[", "", "", "]"); + }, + '1st-level escape': /^(&|\\\\|\\hline)\s*/, + '\\,': /^(?:\\[,\ ;:])/, + // \\x - but output no space before + '\\x{}{}': function x(input) { + return mhchemParser.patterns.findObserveGroups(input, "", /^\\[a-zA-Z]+\{/, "}", "", "", "{", "}", "", true); + }, + '\\x{}': function x(input) { + return mhchemParser.patterns.findObserveGroups(input, "", /^\\[a-zA-Z]+\{/, "}", ""); + }, + '\\ca': /^\\ca(?:\s+|(?![a-zA-Z]))/, + '\\x': /^(?:\\[a-zA-Z]+\s*|\\[_&{}%])/, + 'orbital': /^(?:[0-9]{1,2}[spdfgh]|[0-9]{0,2}sp)(?=$|[^a-zA-Z])/, + // only those with numbers in front, because the others will be formatted correctly anyway + 'others': /^[\/~|]/, + '\\frac{(...)}': function frac(input) { + return mhchemParser.patterns.findObserveGroups(input, "\\frac{", "", "", "}", "{", "", "", "}"); + }, + '\\overset{(...)}': function overset(input) { + return mhchemParser.patterns.findObserveGroups(input, "\\overset{", "", "", "}", "{", "", "", "}"); + }, + "\\underset{(...)}": function underset(input) { + return mhchemParser.patterns.findObserveGroups(input, "\\underset{", "", "", "}", "{", "", "", "}"); + }, + "\\underbrace{(...)}": function underbrace(input) { + return mhchemParser.patterns.findObserveGroups(input, "\\underbrace{", "", "", "}_", "{", "", "", "}"); + }, + '\\color{(...)}0': function color0(input) { + return mhchemParser.patterns.findObserveGroups(input, "\\color{", "", "", "}"); + }, + '\\color{(...)}{(...)}1': function color1(input) { + return mhchemParser.patterns.findObserveGroups(input, "\\color{", "", "", "}", "{", "", "", "}"); + }, + '\\color(...){(...)}2': function color2(input) { + return mhchemParser.patterns.findObserveGroups(input, "\\color", "\\", "", /^(?=\{)/, "{", "", "", "}"); + }, + '\\ce{(...)}': function ce(input) { + return mhchemParser.patterns.findObserveGroups(input, "\\ce{", "", "", "}"); + }, + 'oxidation$': /^(?:[+-][IVX]+|\\pm\s*0|\$\\pm\$\s*0)$/, + 'd-oxidation$': /^(?:[+-]?\s?[IVX]+|\\pm\s*0|\$\\pm\$\s*0)$/, + // 0 could be oxidation or charge + 'roman numeral': /^[IVX]+/, + '1/2$': /^[+\-]?(?:[0-9]+|\$[a-z]\$|[a-z])\/[0-9]+(?:\$[a-z]\$|[a-z])?$/, + 'amount': function amount(input) { + var match; // e.g. 2, 0.5, 1/2, -2, n/2, +; $a$ could be added later in parsing + + match = input.match(/^(?:(?:(?:\([+\-]?[0-9]+\/[0-9]+\)|[+\-]?(?:[0-9]+|\$[a-z]\$|[a-z])\/[0-9]+|[+\-]?[0-9]+[.,][0-9]+|[+\-]?\.[0-9]+|[+\-]?[0-9]+)(?:[a-z](?=\s*[A-Z]))?)|[+\-]?[a-z](?=\s*[A-Z])|\+(?!\s))/); + + if (match) { + return { + match_: match[0], + remainder: input.substr(match[0].length) + }; + } + + var a = mhchemParser.patterns.findObserveGroups(input, "", "$", "$", ""); + + if (a) { + // e.g. $2n-1$, $-$ + match = a.match_.match(/^\$(?:\(?[+\-]?(?:[0-9]*[a-z]?[+\-])?[0-9]*[a-z](?:[+\-][0-9]*[a-z]?)?\)?|\+|-)\$$/); + + if (match) { + return { + match_: match[0], + remainder: input.substr(match[0].length) + }; + } + } + + return null; + }, + 'amount2': function amount2(input) { + return this['amount'](input); + }, + '(KV letters),': /^(?:[A-Z][a-z]{0,2}|i)(?=,)/, + 'formula$': function formula$(input) { + if (input.match(/^\([a-z]+\)$/)) { + return null; + } // state of aggregation = no formula + + + var match = input.match(/^(?:[a-z]|(?:[0-9\ \+\-\,\.\(\)]+[a-z])+[0-9\ \+\-\,\.\(\)]*|(?:[a-z][0-9\ \+\-\,\.\(\)]+)+[a-z]?)$/); + + if (match) { + return { + match_: match[0], + remainder: input.substr(match[0].length) + }; + } + + return null; + }, + 'uprightEntities': /^(?:pH|pOH|pC|pK|iPr|iBu)(?=$|[^a-zA-Z])/, + '/': /^\s*(\/)\s*/, + '//': /^\s*(\/\/)\s*/, + '*': /^\s*[*.]\s*/ + }, + findObserveGroups: function findObserveGroups(input, begExcl, begIncl, endIncl, endExcl, beg2Excl, beg2Incl, end2Incl, end2Excl, combine) { + /** @type {{(input: string, pattern: string | RegExp): string | string[] | null;}} */ + var _match = function _match(input, pattern) { + if (typeof pattern === "string") { + if (input.indexOf(pattern) !== 0) { + return null; + } + + return pattern; + } else { + var match = input.match(pattern); + + if (!match) { + return null; + } + + return match[0]; + } + }; + /** @type {{(input: string, i: number, endChars: string | RegExp): {endMatchBegin: number, endMatchEnd: number} | null;}} */ + + + var _findObserveGroups = function _findObserveGroups(input, i, endChars) { + var braces = 0; + + while (i < input.length) { + var a = input.charAt(i); + + var match = _match(input.substr(i), endChars); + + if (match !== null && braces === 0) { + return { + endMatchBegin: i, + endMatchEnd: i + match.length + }; + } else if (a === "{") { + braces++; + } else if (a === "}") { + if (braces === 0) { + throw ["ExtraCloseMissingOpen", "Extra close brace or missing open brace"]; + } else { + braces--; + } + } + + i++; + } + + if (braces > 0) { + return null; + } + + return null; + }; + + var match = _match(input, begExcl); + + if (match === null) { + return null; + } + + input = input.substr(match.length); + match = _match(input, begIncl); + + if (match === null) { + return null; + } + + var e = _findObserveGroups(input, match.length, endIncl || endExcl); + + if (e === null) { + return null; + } + + var match1 = input.substring(0, endIncl ? e.endMatchEnd : e.endMatchBegin); + + if (!(beg2Excl || beg2Incl)) { + return { + match_: match1, + remainder: input.substr(e.endMatchEnd) + }; + } else { + var group2 = this.findObserveGroups(input.substr(e.endMatchEnd), beg2Excl, beg2Incl, end2Incl, end2Excl); + + if (group2 === null) { + return null; + } + /** @type {string[]} */ + + + var matchRet = [match1, group2.match_]; + return { + match_: combine ? matchRet.join("") : matchRet, + remainder: group2.remainder + }; + } + }, + // + // Matching function + // e.g. match("a", input) will look for the regexp called "a" and see if it matches + // returns null or {match_:"a", remainder:"bc"} + // + match_: function match_(m, input) { + var pattern = mhchemParser.patterns.patterns[m]; + + if (pattern === undefined) { + throw ["MhchemBugP", "mhchem bug P. Please report. (" + m + ")"]; // Trying to use non-existing pattern + } else if (typeof pattern === "function") { + return mhchemParser.patterns.patterns[m](input); // cannot use cached var pattern here, because some pattern functions need this===mhchemParser + } else { + // RegExp + var match = input.match(pattern); + + if (match) { + var mm; + + if (match[2]) { + mm = [match[1], match[2]]; + } else if (match[1]) { + mm = match[1]; + } else { + mm = match[0]; + } + + return { + match_: mm, + remainder: input.substr(match[0].length) + }; + } + + return null; + } + } + }, + // + // Generic state machine actions + // + actions: { + 'a=': function a(buffer, m) { + buffer.a = (buffer.a || "") + m; + }, + 'b=': function b(buffer, m) { + buffer.b = (buffer.b || "") + m; + }, + 'p=': function p(buffer, m) { + buffer.p = (buffer.p || "") + m; + }, + 'o=': function o(buffer, m) { + buffer.o = (buffer.o || "") + m; + }, + 'q=': function q(buffer, m) { + buffer.q = (buffer.q || "") + m; + }, + 'd=': function d(buffer, m) { + buffer.d = (buffer.d || "") + m; + }, + 'rm=': function rm(buffer, m) { + buffer.rm = (buffer.rm || "") + m; + }, + 'text=': function text(buffer, m) { + buffer.text_ = (buffer.text_ || "") + m; + }, + 'insert': function insert(buffer, m, a) { + return { + type_: a + }; + }, + 'insert+p1': function insertP1(buffer, m, a) { + return { + type_: a, + p1: m + }; + }, + 'insert+p1+p2': function insertP1P2(buffer, m, a) { + return { + type_: a, + p1: m[0], + p2: m[1] + }; + }, + 'copy': function copy(buffer, m) { + return m; + }, + 'rm': function rm(buffer, m) { + return { + type_: 'rm', + p1: m || "" + }; + }, + 'text': function text(buffer, m) { + return mhchemParser.go(m, 'text'); + }, + '{text}': function text(buffer, m) { + var ret = ["{"]; + mhchemParser.concatArray(ret, mhchemParser.go(m, 'text')); + ret.push("}"); + return ret; + }, + 'tex-math': function texMath(buffer, m) { + return mhchemParser.go(m, 'tex-math'); + }, + 'tex-math tight': function texMathTight(buffer, m) { + return mhchemParser.go(m, 'tex-math tight'); + }, + 'bond': function bond(buffer, m, k) { + return { + type_: 'bond', + kind_: k || m + }; + }, + 'color0-output': function color0Output(buffer, m) { + return { + type_: 'color0', + color: m[0] + }; + }, + 'ce': function ce(buffer, m) { + return mhchemParser.go(m); + }, + '1/2': function _(buffer, m) { + /** @type {ParserOutput[]} */ + var ret = []; + + if (m.match(/^[+\-]/)) { + ret.push(m.substr(0, 1)); + m = m.substr(1); + } + + var n = m.match(/^([0-9]+|\$[a-z]\$|[a-z])\/([0-9]+)(\$[a-z]\$|[a-z])?$/); + n[1] = n[1].replace(/\$/g, ""); + ret.push({ + type_: 'frac', + p1: n[1], + p2: n[2] + }); + + if (n[3]) { + n[3] = n[3].replace(/\$/g, ""); + ret.push({ + type_: 'tex-math', + p1: n[3] + }); + } + + return ret; + }, + '9,9': function _(buffer, m) { + return mhchemParser.go(m, '9,9'); + } + }, + // + // createTransitions + // convert { 'letter': { 'state': { action_: 'output' } } } to { 'state' => [ { pattern: 'letter', task: { action_: [{type_: 'output'}] } } ] } + // with expansion of 'a|b' to 'a' and 'b' (at 2 places) + // + createTransitions: function createTransitions(o) { + var pattern, state; + /** @type {string[]} */ + + var stateArray; + var i; // + // 1. Collect all states + // + + /** @type {Transitions} */ + + var transitions = {}; + + for (pattern in o) { + for (state in o[pattern]) { + stateArray = state.split("|"); + o[pattern][state].stateArray = stateArray; + + for (i = 0; i < stateArray.length; i++) { + transitions[stateArray[i]] = []; + } + } + } // + // 2. Fill states + // + + + for (pattern in o) { + for (state in o[pattern]) { + stateArray = o[pattern][state].stateArray || []; + + for (i = 0; i < stateArray.length; i++) { + // + // 2a. Normalize actions into array: 'text=' ==> [{type_:'text='}] + // (Note to myself: Resolving the function here would be problematic. It would need .bind (for *this*) and currying (for *option*).) + // + + /** @type {any} */ + var p = o[pattern][state]; + + if (p.action_) { + p.action_ = [].concat(p.action_); + + for (var k = 0; k < p.action_.length; k++) { + if (typeof p.action_[k] === "string") { + p.action_[k] = { + type_: p.action_[k] + }; + } + } + } else { + p.action_ = []; + } // + // 2.b Multi-insert + // + + + var patternArray = pattern.split("|"); + + for (var j = 0; j < patternArray.length; j++) { + if (stateArray[i] === '*') { + // insert into all + for (var t in transitions) { + transitions[t].push({ + pattern: patternArray[j], + task: p + }); + } + } else { + transitions[stateArray[i]].push({ + pattern: patternArray[j], + task: p + }); + } + } + } + } + } + + return transitions; + }, + stateMachines: {} +}; // +// Definition of state machines +// + +mhchemParser.stateMachines = { + // + // \ce state machines + // + //#region ce + 'ce': { + // main parser + transitions: mhchemParser.createTransitions({ + 'empty': { + '*': { + action_: 'output' + } + }, + 'else': { + '0|1|2': { + action_: 'beginsWithBond=false', + revisit: true, + toContinue: true + } + }, + 'oxidation$': { + '0': { + action_: 'oxidation-output' + } + }, + 'CMT': { + 'r': { + action_: 'rdt=', + nextState: 'rt' + }, + 'rd': { + action_: 'rqt=', + nextState: 'rdt' + } + }, + 'arrowUpDown': { + '0|1|2|as': { + action_: ['sb=false', 'output', 'operator'], + nextState: '1' + } + }, + 'uprightEntities': { + '0|1|2': { + action_: ['o=', 'output'], + nextState: '1' + } + }, + 'orbital': { + '0|1|2|3': { + action_: 'o=', + nextState: 'o' + } + }, + '->': { + '0|1|2|3': { + action_: 'r=', + nextState: 'r' + }, + 'a|as': { + action_: ['output', 'r='], + nextState: 'r' + }, + '*': { + action_: ['output', 'r='], + nextState: 'r' + } + }, + '+': { + 'o': { + action_: 'd= kv', + nextState: 'd' + }, + 'd|D': { + action_: 'd=', + nextState: 'd' + }, + 'q': { + action_: 'd=', + nextState: 'qd' + }, + 'qd|qD': { + action_: 'd=', + nextState: 'qd' + }, + 'dq': { + action_: ['output', 'd='], + nextState: 'd' + }, + '3': { + action_: ['sb=false', 'output', 'operator'], + nextState: '0' + } + }, + 'amount': { + '0|2': { + action_: 'a=', + nextState: 'a' + } + }, + 'pm-operator': { + '0|1|2|a|as': { + action_: ['sb=false', 'output', { + type_: 'operator', + option: '\\pm' + }], + nextState: '0' + } + }, + 'operator': { + '0|1|2|a|as': { + action_: ['sb=false', 'output', 'operator'], + nextState: '0' + } + }, + '-$': { + 'o|q': { + action_: ['charge or bond', 'output'], + nextState: 'qd' + }, + 'd': { + action_: 'd=', + nextState: 'd' + }, + 'D': { + action_: ['output', { + type_: 'bond', + option: "-" + }], + nextState: '3' + }, + 'q': { + action_: 'd=', + nextState: 'qd' + }, + 'qd': { + action_: 'd=', + nextState: 'qd' + }, + 'qD|dq': { + action_: ['output', { + type_: 'bond', + option: "-" + }], + nextState: '3' + } + }, + '-9': { + '3|o': { + action_: ['output', { + type_: 'insert', + option: 'hyphen' + }], + nextState: '3' + } + }, + '- orbital overlap': { + 'o': { + action_: ['output', { + type_: 'insert', + option: 'hyphen' + }], + nextState: '2' + }, + 'd': { + action_: ['output', { + type_: 'insert', + option: 'hyphen' + }], + nextState: '2' + } + }, + '-': { + '0|1|2': { + action_: [{ + type_: 'output', + option: 1 + }, 'beginsWithBond=true', { + type_: 'bond', + option: "-" + }], + nextState: '3' + }, + '3': { + action_: { + type_: 'bond', + option: "-" + } + }, + 'a': { + action_: ['output', { + type_: 'insert', + option: 'hyphen' + }], + nextState: '2' + }, + 'as': { + action_: [{ + type_: 'output', + option: 2 + }, { + type_: 'bond', + option: "-" + }], + nextState: '3' + }, + 'b': { + action_: 'b=' + }, + 'o': { + action_: { + type_: '- after o/d', + option: false + }, + nextState: '2' + }, + 'q': { + action_: { + type_: '- after o/d', + option: false + }, + nextState: '2' + }, + 'd|qd|dq': { + action_: { + type_: '- after o/d', + option: true + }, + nextState: '2' + }, + 'D|qD|p': { + action_: ['output', { + type_: 'bond', + option: "-" + }], + nextState: '3' + } + }, + 'amount2': { + '1|3': { + action_: 'a=', + nextState: 'a' + } + }, + 'letters': { + '0|1|2|3|a|as|b|p|bp|o': { + action_: 'o=', + nextState: 'o' + }, + 'q|dq': { + action_: ['output', 'o='], + nextState: 'o' + }, + 'd|D|qd|qD': { + action_: 'o after d', + nextState: 'o' + } + }, + 'digits': { + 'o': { + action_: 'q=', + nextState: 'q' + }, + 'd|D': { + action_: 'q=', + nextState: 'dq' + }, + 'q': { + action_: ['output', 'o='], + nextState: 'o' + }, + 'a': { + action_: 'o=', + nextState: 'o' + } + }, + 'space A': { + 'b|p|bp': {} + }, + 'space': { + 'a': { + nextState: 'as' + }, + '0': { + action_: 'sb=false' + }, + '1|2': { + action_: 'sb=true' + }, + 'r|rt|rd|rdt|rdq': { + action_: 'output', + nextState: '0' + }, + '*': { + action_: ['output', 'sb=true'], + nextState: '1' + } + }, + '1st-level escape': { + '1|2': { + action_: ['output', { + type_: 'insert+p1', + option: '1st-level escape' + }] + }, + '*': { + action_: ['output', { + type_: 'insert+p1', + option: '1st-level escape' + }], + nextState: '0' + } + }, + '[(...)]': { + 'r|rt': { + action_: 'rd=', + nextState: 'rd' + }, + 'rd|rdt': { + action_: 'rq=', + nextState: 'rdq' + } + }, + '...': { + 'o|d|D|dq|qd|qD': { + action_: ['output', { + type_: 'bond', + option: "..." + }], + nextState: '3' + }, + '*': { + action_: [{ + type_: 'output', + option: 1 + }, { + type_: 'insert', + option: 'ellipsis' + }], + nextState: '1' + } + }, + '. |* ': { + '*': { + action_: ['output', { + type_: 'insert', + option: 'addition compound' + }], + nextState: '1' + } + }, + 'state of aggregation $': { + '*': { + action_: ['output', 'state of aggregation'], + nextState: '1' + } + }, + '{[(': { + 'a|as|o': { + action_: ['o=', 'output', 'parenthesisLevel++'], + nextState: '2' + }, + '0|1|2|3': { + action_: ['o=', 'output', 'parenthesisLevel++'], + nextState: '2' + }, + '*': { + action_: ['output', 'o=', 'output', 'parenthesisLevel++'], + nextState: '2' + } + }, + ')]}': { + '0|1|2|3|b|p|bp|o': { + action_: ['o=', 'parenthesisLevel--'], + nextState: 'o' + }, + 'a|as|d|D|q|qd|qD|dq': { + action_: ['output', 'o=', 'parenthesisLevel--'], + nextState: 'o' + } + }, + ', ': { + '*': { + action_: ['output', 'comma'], + nextState: '0' + } + }, + '^_': { + // ^ and _ without a sensible argument + '*': {} + }, + '^{(...)}|^($...$)': { + '0|1|2|as': { + action_: 'b=', + nextState: 'b' + }, + 'p': { + action_: 'b=', + nextState: 'bp' + }, + '3|o': { + action_: 'd= kv', + nextState: 'D' + }, + 'q': { + action_: 'd=', + nextState: 'qD' + }, + 'd|D|qd|qD|dq': { + action_: ['output', 'd='], + nextState: 'D' + } + }, + '^a|^\\x{}{}|^\\x{}|^\\x|\'': { + '0|1|2|as': { + action_: 'b=', + nextState: 'b' + }, + 'p': { + action_: 'b=', + nextState: 'bp' + }, + '3|o': { + action_: 'd= kv', + nextState: 'd' + }, + 'q': { + action_: 'd=', + nextState: 'qd' + }, + 'd|qd|D|qD': { + action_: 'd=' + }, + 'dq': { + action_: ['output', 'd='], + nextState: 'd' + } + }, + '_{(state of aggregation)}$': { + 'd|D|q|qd|qD|dq': { + action_: ['output', 'q='], + nextState: 'q' + } + }, + '_{(...)}|_($...$)|_9|_\\x{}{}|_\\x{}|_\\x': { + '0|1|2|as': { + action_: 'p=', + nextState: 'p' + }, + 'b': { + action_: 'p=', + nextState: 'bp' + }, + '3|o': { + action_: 'q=', + nextState: 'q' + }, + 'd|D': { + action_: 'q=', + nextState: 'dq' + }, + 'q|qd|qD|dq': { + action_: ['output', 'q='], + nextState: 'q' + } + }, + '=<>': { + '0|1|2|3|a|as|o|q|d|D|qd|qD|dq': { + action_: [{ + type_: 'output', + option: 2 + }, 'bond'], + nextState: '3' + } + }, + '#': { + '0|1|2|3|a|as|o': { + action_: [{ + type_: 'output', + option: 2 + }, { + type_: 'bond', + option: "#" + }], + nextState: '3' + } + }, + '{}': { + '*': { + action_: { + type_: 'output', + option: 1 + }, + nextState: '1' + } + }, + '{...}': { + '0|1|2|3|a|as|b|p|bp': { + action_: 'o=', + nextState: 'o' + }, + 'o|d|D|q|qd|qD|dq': { + action_: ['output', 'o='], + nextState: 'o' + } + }, + '$...$': { + 'a': { + action_: 'a=' + }, + // 2$n$ + '0|1|2|3|as|b|p|bp|o': { + action_: 'o=', + nextState: 'o' + }, + // not 'amount' + 'as|o': { + action_: 'o=' + }, + 'q|d|D|qd|qD|dq': { + action_: ['output', 'o='], + nextState: 'o' + } + }, + '\\bond{(...)}': { + '*': { + action_: [{ + type_: 'output', + option: 2 + }, 'bond'], + nextState: "3" + } + }, + '\\frac{(...)}': { + '*': { + action_: [{ + type_: 'output', + option: 1 + }, 'frac-output'], + nextState: '3' + } + }, + '\\overset{(...)}': { + '*': { + action_: [{ + type_: 'output', + option: 2 + }, 'overset-output'], + nextState: '3' + } + }, + "\\underset{(...)}": { + '*': { + action_: [{ + type_: 'output', + option: 2 + }, 'underset-output'], + nextState: '3' + } + }, + "\\underbrace{(...)}": { + '*': { + action_: [{ + type_: 'output', + option: 2 + }, 'underbrace-output'], + nextState: '3' + } + }, + '\\color{(...)}{(...)}1|\\color(...){(...)}2': { + '*': { + action_: [{ + type_: 'output', + option: 2 + }, 'color-output'], + nextState: '3' + } + }, + '\\color{(...)}0': { + '*': { + action_: [{ + type_: 'output', + option: 2 + }, 'color0-output'] + } + }, + '\\ce{(...)}': { + '*': { + action_: [{ + type_: 'output', + option: 2 + }, 'ce'], + nextState: '3' + } + }, + '\\,': { + '*': { + action_: [{ + type_: 'output', + option: 1 + }, 'copy'], + nextState: '1' + } + }, + '\\x{}{}|\\x{}|\\x': { + '0|1|2|3|a|as|b|p|bp|o|c0': { + action_: ['o=', 'output'], + nextState: '3' + }, + '*': { + action_: ['output', 'o=', 'output'], + nextState: '3' + } + }, + 'others': { + '*': { + action_: [{ + type_: 'output', + option: 1 + }, 'copy'], + nextState: '3' + } + }, + 'else2': { + 'a': { + action_: 'a to o', + nextState: 'o', + revisit: true + }, + 'as': { + action_: ['output', 'sb=true'], + nextState: '1', + revisit: true + }, + 'r|rt|rd|rdt|rdq': { + action_: ['output'], + nextState: '0', + revisit: true + }, + '*': { + action_: ['output', 'copy'], + nextState: '3' + } + } + }), + actions: { + 'o after d': function oAfterD(buffer, m) { + var ret; + + if ((buffer.d || "").match(/^[0-9]+$/)) { + var tmp = buffer.d; + buffer.d = undefined; + ret = this['output'](buffer); + buffer.b = tmp; + } else { + ret = this['output'](buffer); + } + + mhchemParser.actions['o='](buffer, m); + return ret; + }, + 'd= kv': function dKv(buffer, m) { + buffer.d = m; + buffer.dType = 'kv'; + }, + 'charge or bond': function chargeOrBond(buffer, m) { + if (buffer['beginsWithBond']) { + /** @type {ParserOutput[]} */ + var ret = []; + mhchemParser.concatArray(ret, this['output'](buffer)); + mhchemParser.concatArray(ret, mhchemParser.actions['bond'](buffer, m, "-")); + return ret; + } else { + buffer.d = m; + } + }, + '- after o/d': function afterOD(buffer, m, isAfterD) { + var c1 = mhchemParser.patterns.match_('orbital', buffer.o || ""); + var c2 = mhchemParser.patterns.match_('one lowercase greek letter $', buffer.o || ""); + var c3 = mhchemParser.patterns.match_('one lowercase latin letter $', buffer.o || ""); + var c4 = mhchemParser.patterns.match_('$one lowercase latin letter$ $', buffer.o || ""); + var hyphenFollows = m === "-" && (c1 && c1.remainder === "" || c2 || c3 || c4); + + if (hyphenFollows && !buffer.a && !buffer.b && !buffer.p && !buffer.d && !buffer.q && !c1 && c3) { + buffer.o = '$' + buffer.o + '$'; + } + /** @type {ParserOutput[]} */ + + + var ret = []; + + if (hyphenFollows) { + mhchemParser.concatArray(ret, this['output'](buffer)); + ret.push({ + type_: 'hyphen' + }); + } else { + c1 = mhchemParser.patterns.match_('digits', buffer.d || ""); + + if (isAfterD && c1 && c1.remainder === '') { + mhchemParser.concatArray(ret, mhchemParser.actions['d='](buffer, m)); + mhchemParser.concatArray(ret, this['output'](buffer)); + } else { + mhchemParser.concatArray(ret, this['output'](buffer)); + mhchemParser.concatArray(ret, mhchemParser.actions['bond'](buffer, m, "-")); + } + } + + return ret; + }, + 'a to o': function aToO(buffer) { + buffer.o = buffer.a; + buffer.a = undefined; + }, + 'sb=true': function sbTrue(buffer) { + buffer.sb = true; + }, + 'sb=false': function sbFalse(buffer) { + buffer.sb = false; + }, + 'beginsWithBond=true': function beginsWithBondTrue(buffer) { + buffer['beginsWithBond'] = true; + }, + 'beginsWithBond=false': function beginsWithBondFalse(buffer) { + buffer['beginsWithBond'] = false; + }, + 'parenthesisLevel++': function parenthesisLevel(buffer) { + buffer['parenthesisLevel']++; + }, + 'parenthesisLevel--': function parenthesisLevel(buffer) { + buffer['parenthesisLevel']--; + }, + 'state of aggregation': function stateOfAggregation(buffer, m) { + return { + type_: 'state of aggregation', + p1: mhchemParser.go(m, 'o') + }; + }, + 'comma': function comma(buffer, m) { + var a = m.replace(/\s*$/, ''); + var withSpace = a !== m; + + if (withSpace && buffer['parenthesisLevel'] === 0) { + return { + type_: 'comma enumeration L', + p1: a + }; + } else { + return { + type_: 'comma enumeration M', + p1: a + }; + } + }, + 'output': function output(buffer, m, entityFollows) { + // entityFollows: + // undefined = if we have nothing else to output, also ignore the just read space (buffer.sb) + // 1 = an entity follows, never omit the space if there was one just read before (can only apply to state 1) + // 2 = 1 + the entity can have an amount, so output a\, instead of converting it to o (can only apply to states a|as) + + /** @type {ParserOutput | ParserOutput[]} */ + var ret; + + if (!buffer.r) { + ret = []; + + if (!buffer.a && !buffer.b && !buffer.p && !buffer.o && !buffer.q && !buffer.d && !entityFollows) {//ret = []; + } else { + if (buffer.sb) { + ret.push({ + type_: 'entitySkip' + }); + } + + if (!buffer.o && !buffer.q && !buffer.d && !buffer.b && !buffer.p && entityFollows !== 2) { + buffer.o = buffer.a; + buffer.a = undefined; + } else if (!buffer.o && !buffer.q && !buffer.d && (buffer.b || buffer.p)) { + buffer.o = buffer.a; + buffer.d = buffer.b; + buffer.q = buffer.p; + buffer.a = buffer.b = buffer.p = undefined; + } else { + if (buffer.o && buffer.dType === 'kv' && mhchemParser.patterns.match_('d-oxidation$', buffer.d || "")) { + buffer.dType = 'oxidation'; + } else if (buffer.o && buffer.dType === 'kv' && !buffer.q) { + buffer.dType = undefined; + } + } + + ret.push({ + type_: 'chemfive', + a: mhchemParser.go(buffer.a, 'a'), + b: mhchemParser.go(buffer.b, 'bd'), + p: mhchemParser.go(buffer.p, 'pq'), + o: mhchemParser.go(buffer.o, 'o'), + q: mhchemParser.go(buffer.q, 'pq'), + d: mhchemParser.go(buffer.d, buffer.dType === 'oxidation' ? 'oxidation' : 'bd'), + dType: buffer.dType + }); + } + } else { + // r + + /** @type {ParserOutput[]} */ + var rd; + + if (buffer.rdt === 'M') { + rd = mhchemParser.go(buffer.rd, 'tex-math'); + } else if (buffer.rdt === 'T') { + rd = [{ + type_: 'text', + p1: buffer.rd || "" + }]; + } else { + rd = mhchemParser.go(buffer.rd); + } + /** @type {ParserOutput[]} */ + + + var rq; + + if (buffer.rqt === 'M') { + rq = mhchemParser.go(buffer.rq, 'tex-math'); + } else if (buffer.rqt === 'T') { + rq = [{ + type_: 'text', + p1: buffer.rq || "" + }]; + } else { + rq = mhchemParser.go(buffer.rq); + } + + ret = { + type_: 'arrow', + r: buffer.r, + rd: rd, + rq: rq + }; + } + + for (var p in buffer) { + if (p !== 'parenthesisLevel' && p !== 'beginsWithBond') { + delete buffer[p]; + } + } + + return ret; + }, + 'oxidation-output': function oxidationOutput(buffer, m) { + var ret = ["{"]; + mhchemParser.concatArray(ret, mhchemParser.go(m, 'oxidation')); + ret.push("}"); + return ret; + }, + 'frac-output': function fracOutput(buffer, m) { + return { + type_: 'frac-ce', + p1: mhchemParser.go(m[0]), + p2: mhchemParser.go(m[1]) + }; + }, + 'overset-output': function oversetOutput(buffer, m) { + return { + type_: 'overset', + p1: mhchemParser.go(m[0]), + p2: mhchemParser.go(m[1]) + }; + }, + 'underset-output': function undersetOutput(buffer, m) { + return { + type_: 'underset', + p1: mhchemParser.go(m[0]), + p2: mhchemParser.go(m[1]) + }; + }, + 'underbrace-output': function underbraceOutput(buffer, m) { + return { + type_: 'underbrace', + p1: mhchemParser.go(m[0]), + p2: mhchemParser.go(m[1]) + }; + }, + 'color-output': function colorOutput(buffer, m) { + return { + type_: 'color', + color1: m[0], + color2: mhchemParser.go(m[1]) + }; + }, + 'r=': function r(buffer, m) { + buffer.r = m; + }, + 'rdt=': function rdt(buffer, m) { + buffer.rdt = m; + }, + 'rd=': function rd(buffer, m) { + buffer.rd = m; + }, + 'rqt=': function rqt(buffer, m) { + buffer.rqt = m; + }, + 'rq=': function rq(buffer, m) { + buffer.rq = m; + }, + 'operator': function operator(buffer, m, p1) { + return { + type_: 'operator', + kind_: p1 || m + }; + } + } + }, + 'a': { + transitions: mhchemParser.createTransitions({ + 'empty': { + '*': {} + }, + '1/2$': { + '0': { + action_: '1/2' + } + }, + 'else': { + '0': { + nextState: '1', + revisit: true + } + }, + '$(...)$': { + '*': { + action_: 'tex-math tight', + nextState: '1' + } + }, + ',': { + '*': { + action_: { + type_: 'insert', + option: 'commaDecimal' + } + } + }, + 'else2': { + '*': { + action_: 'copy' + } + } + }), + actions: {} + }, + 'o': { + transitions: mhchemParser.createTransitions({ + 'empty': { + '*': {} + }, + '1/2$': { + '0': { + action_: '1/2' + } + }, + 'else': { + '0': { + nextState: '1', + revisit: true + } + }, + 'letters': { + '*': { + action_: 'rm' + } + }, + '\\ca': { + '*': { + action_: { + type_: 'insert', + option: 'circa' + } + } + }, + '\\x{}{}|\\x{}|\\x': { + '*': { + action_: 'copy' + } + }, + '${(...)}$|$(...)$': { + '*': { + action_: 'tex-math' + } + }, + '{(...)}': { + '*': { + action_: '{text}' + } + }, + 'else2': { + '*': { + action_: 'copy' + } + } + }), + actions: {} + }, + 'text': { + transitions: mhchemParser.createTransitions({ + 'empty': { + '*': { + action_: 'output' + } + }, + '{...}': { + '*': { + action_: 'text=' + } + }, + '${(...)}$|$(...)$': { + '*': { + action_: 'tex-math' + } + }, + '\\greek': { + '*': { + action_: ['output', 'rm'] + } + }, + '\\,|\\x{}{}|\\x{}|\\x': { + '*': { + action_: ['output', 'copy'] + } + }, + 'else': { + '*': { + action_: 'text=' + } + } + }), + actions: { + 'output': function output(buffer) { + if (buffer.text_) { + /** @type {ParserOutput} */ + var ret = { + type_: 'text', + p1: buffer.text_ + }; + + for (var p in buffer) { + delete buffer[p]; + } + + return ret; + } + } + } + }, + 'pq': { + transitions: mhchemParser.createTransitions({ + 'empty': { + '*': {} + }, + 'state of aggregation $': { + '*': { + action_: 'state of aggregation' + } + }, + 'i$': { + '0': { + nextState: '!f', + revisit: true + } + }, + '(KV letters),': { + '0': { + action_: 'rm', + nextState: '0' + } + }, + 'formula$': { + '0': { + nextState: 'f', + revisit: true + } + }, + '1/2$': { + '0': { + action_: '1/2' + } + }, + 'else': { + '0': { + nextState: '!f', + revisit: true + } + }, + '${(...)}$|$(...)$': { + '*': { + action_: 'tex-math' + } + }, + '{(...)}': { + '*': { + action_: 'text' + } + }, + 'a-z': { + 'f': { + action_: 'tex-math' + } + }, + 'letters': { + '*': { + action_: 'rm' + } + }, + '-9.,9': { + '*': { + action_: '9,9' + } + }, + ',': { + '*': { + action_: { + type_: 'insert+p1', + option: 'comma enumeration S' + } + } + }, + '\\color{(...)}{(...)}1|\\color(...){(...)}2': { + '*': { + action_: 'color-output' + } + }, + '\\color{(...)}0': { + '*': { + action_: 'color0-output' + } + }, + '\\ce{(...)}': { + '*': { + action_: 'ce' + } + }, + '\\,|\\x{}{}|\\x{}|\\x': { + '*': { + action_: 'copy' + } + }, + 'else2': { + '*': { + action_: 'copy' + } + } + }), + actions: { + 'state of aggregation': function stateOfAggregation(buffer, m) { + return { + type_: 'state of aggregation subscript', + p1: mhchemParser.go(m, 'o') + }; + }, + 'color-output': function colorOutput(buffer, m) { + return { + type_: 'color', + color1: m[0], + color2: mhchemParser.go(m[1], 'pq') + }; + } + } + }, + 'bd': { + transitions: mhchemParser.createTransitions({ + 'empty': { + '*': {} + }, + 'x$': { + '0': { + nextState: '!f', + revisit: true + } + }, + 'formula$': { + '0': { + nextState: 'f', + revisit: true + } + }, + 'else': { + '0': { + nextState: '!f', + revisit: true + } + }, + '-9.,9 no missing 0': { + '*': { + action_: '9,9' + } + }, + '.': { + '*': { + action_: { + type_: 'insert', + option: 'electron dot' + } + } + }, + 'a-z': { + 'f': { + action_: 'tex-math' + } + }, + 'x': { + '*': { + action_: { + type_: 'insert', + option: 'KV x' + } + } + }, + 'letters': { + '*': { + action_: 'rm' + } + }, + '\'': { + '*': { + action_: { + type_: 'insert', + option: 'prime' + } + } + }, + '${(...)}$|$(...)$': { + '*': { + action_: 'tex-math' + } + }, + '{(...)}': { + '*': { + action_: 'text' + } + }, + '\\color{(...)}{(...)}1|\\color(...){(...)}2': { + '*': { + action_: 'color-output' + } + }, + '\\color{(...)}0': { + '*': { + action_: 'color0-output' + } + }, + '\\ce{(...)}': { + '*': { + action_: 'ce' + } + }, + '\\,|\\x{}{}|\\x{}|\\x': { + '*': { + action_: 'copy' + } + }, + 'else2': { + '*': { + action_: 'copy' + } + } + }), + actions: { + 'color-output': function colorOutput(buffer, m) { + return { + type_: 'color', + color1: m[0], + color2: mhchemParser.go(m[1], 'bd') + }; + } + } + }, + 'oxidation': { + transitions: mhchemParser.createTransitions({ + 'empty': { + '*': {} + }, + 'roman numeral': { + '*': { + action_: 'roman-numeral' + } + }, + '${(...)}$|$(...)$': { + '*': { + action_: 'tex-math' + } + }, + 'else': { + '*': { + action_: 'copy' + } + } + }), + actions: { + 'roman-numeral': function romanNumeral(buffer, m) { + return { + type_: 'roman numeral', + p1: m || "" + }; + } + } + }, + 'tex-math': { + transitions: mhchemParser.createTransitions({ + 'empty': { + '*': { + action_: 'output' + } + }, + '\\ce{(...)}': { + '*': { + action_: ['output', 'ce'] + } + }, + '{...}|\\,|\\x{}{}|\\x{}|\\x': { + '*': { + action_: 'o=' + } + }, + 'else': { + '*': { + action_: 'o=' + } + } + }), + actions: { + 'output': function output(buffer) { + if (buffer.o) { + /** @type {ParserOutput} */ + var ret = { + type_: 'tex-math', + p1: buffer.o + }; + + for (var p in buffer) { + delete buffer[p]; + } + + return ret; + } + } + } + }, + 'tex-math tight': { + transitions: mhchemParser.createTransitions({ + 'empty': { + '*': { + action_: 'output' + } + }, + '\\ce{(...)}': { + '*': { + action_: ['output', 'ce'] + } + }, + '{...}|\\,|\\x{}{}|\\x{}|\\x': { + '*': { + action_: 'o=' + } + }, + '-|+': { + '*': { + action_: 'tight operator' + } + }, + 'else': { + '*': { + action_: 'o=' + } + } + }), + actions: { + 'tight operator': function tightOperator(buffer, m) { + buffer.o = (buffer.o || "") + "{" + m + "}"; + }, + 'output': function output(buffer) { + if (buffer.o) { + /** @type {ParserOutput} */ + var ret = { + type_: 'tex-math', + p1: buffer.o + }; + + for (var p in buffer) { + delete buffer[p]; + } + + return ret; + } + } + } + }, + '9,9': { + transitions: mhchemParser.createTransitions({ + 'empty': { + '*': {} + }, + ',': { + '*': { + action_: 'comma' + } + }, + 'else': { + '*': { + action_: 'copy' + } + } + }), + actions: { + 'comma': function comma() { + return { + type_: 'commaDecimal' + }; + } + } + }, + //#endregion + // + // \pu state machines + // + //#region pu + 'pu': { + transitions: mhchemParser.createTransitions({ + 'empty': { + '*': { + action_: 'output' + } + }, + 'space$': { + '*': { + action_: ['output', 'space'] + } + }, + '{[(|)]}': { + '0|a': { + action_: 'copy' + } + }, + '(-)(9)^(-9)': { + '0': { + action_: 'number^', + nextState: 'a' + } + }, + '(-)(9.,9)(e)(99)': { + '0': { + action_: 'enumber', + nextState: 'a' + } + }, + 'space': { + '0|a': {} + }, + 'pm-operator': { + '0|a': { + action_: { + type_: 'operator', + option: '\\pm' + }, + nextState: '0' + } + }, + 'operator': { + '0|a': { + action_: 'copy', + nextState: '0' + } + }, + '//': { + 'd': { + action_: 'o=', + nextState: '/' + } + }, + '/': { + 'd': { + action_: 'o=', + nextState: '/' + } + }, + '{...}|else': { + '0|d': { + action_: 'd=', + nextState: 'd' + }, + 'a': { + action_: ['space', 'd='], + nextState: 'd' + }, + '/|q': { + action_: 'q=', + nextState: 'q' + } + } + }), + actions: { + 'enumber': function enumber(buffer, m) { + /** @type {ParserOutput[]} */ + var ret = []; + + if (m[0] === "+-" || m[0] === "+/-") { + ret.push("\\pm "); + } else if (m[0]) { + ret.push(m[0]); + } + + if (m[1]) { + mhchemParser.concatArray(ret, mhchemParser.go(m[1], 'pu-9,9')); + + if (m[2]) { + if (m[2].match(/[,.]/)) { + mhchemParser.concatArray(ret, mhchemParser.go(m[2], 'pu-9,9')); + } else { + ret.push(m[2]); + } + } + + m[3] = m[4] || m[3]; + + if (m[3]) { + m[3] = m[3].trim(); + + if (m[3] === "e" || m[3].substr(0, 1) === "*") { + ret.push({ + type_: 'cdot' + }); + } else { + ret.push({ + type_: 'times' + }); + } + } + } + + if (m[3]) { + ret.push("10^{" + m[5] + "}"); + } + + return ret; + }, + 'number^': function number(buffer, m) { + /** @type {ParserOutput[]} */ + var ret = []; + + if (m[0] === "+-" || m[0] === "+/-") { + ret.push("\\pm "); + } else if (m[0]) { + ret.push(m[0]); + } + + mhchemParser.concatArray(ret, mhchemParser.go(m[1], 'pu-9,9')); + ret.push("^{" + m[2] + "}"); + return ret; + }, + 'operator': function operator(buffer, m, p1) { + return { + type_: 'operator', + kind_: p1 || m + }; + }, + 'space': function space() { + return { + type_: 'pu-space-1' + }; + }, + 'output': function output(buffer) { + /** @type {ParserOutput | ParserOutput[]} */ + var ret; + var md = mhchemParser.patterns.match_('{(...)}', buffer.d || ""); + + if (md && md.remainder === '') { + buffer.d = md.match_; + } + + var mq = mhchemParser.patterns.match_('{(...)}', buffer.q || ""); + + if (mq && mq.remainder === '') { + buffer.q = mq.match_; + } + + if (buffer.d) { + buffer.d = buffer.d.replace(/\u00B0C|\^oC|\^{o}C/g, "{}^{\\circ}C"); + buffer.d = buffer.d.replace(/\u00B0F|\^oF|\^{o}F/g, "{}^{\\circ}F"); + } + + if (buffer.q) { + // fraction + buffer.q = buffer.q.replace(/\u00B0C|\^oC|\^{o}C/g, "{}^{\\circ}C"); + buffer.q = buffer.q.replace(/\u00B0F|\^oF|\^{o}F/g, "{}^{\\circ}F"); + var b5 = { + d: mhchemParser.go(buffer.d, 'pu'), + q: mhchemParser.go(buffer.q, 'pu') + }; + + if (buffer.o === '//') { + ret = { + type_: 'pu-frac', + p1: b5.d, + p2: b5.q + }; + } else { + ret = b5.d; + + if (b5.d.length > 1 || b5.q.length > 1) { + ret.push({ + type_: ' / ' + }); + } else { + ret.push({ + type_: '/' + }); + } + + mhchemParser.concatArray(ret, b5.q); + } + } else { + // no fraction + ret = mhchemParser.go(buffer.d, 'pu-2'); + } + + for (var p in buffer) { + delete buffer[p]; + } + + return ret; + } + } + }, + 'pu-2': { + transitions: mhchemParser.createTransitions({ + 'empty': { + '*': { + action_: 'output' + } + }, + '*': { + '*': { + action_: ['output', 'cdot'], + nextState: '0' + } + }, + '\\x': { + '*': { + action_: 'rm=' + } + }, + 'space': { + '*': { + action_: ['output', 'space'], + nextState: '0' + } + }, + '^{(...)}|^(-1)': { + '1': { + action_: '^(-1)' + } + }, + '-9.,9': { + '0': { + action_: 'rm=', + nextState: '0' + }, + '1': { + action_: '^(-1)', + nextState: '0' + } + }, + '{...}|else': { + '*': { + action_: 'rm=', + nextState: '1' + } + } + }), + actions: { + 'cdot': function cdot() { + return { + type_: 'tight cdot' + }; + }, + '^(-1)': function _(buffer, m) { + buffer.rm += "^{" + m + "}"; + }, + 'space': function space() { + return { + type_: 'pu-space-2' + }; + }, + 'output': function output(buffer) { + /** @type {ParserOutput | ParserOutput[]} */ + var ret = []; + + if (buffer.rm) { + var mrm = mhchemParser.patterns.match_('{(...)}', buffer.rm || ""); + + if (mrm && mrm.remainder === '') { + ret = mhchemParser.go(mrm.match_, 'pu'); + } else { + ret = { + type_: 'rm', + p1: buffer.rm + }; + } + } + + for (var p in buffer) { + delete buffer[p]; + } + + return ret; + } + } + }, + 'pu-9,9': { + transitions: mhchemParser.createTransitions({ + 'empty': { + '0': { + action_: 'output-0' + }, + 'o': { + action_: 'output-o' + } + }, + ',': { + '0': { + action_: ['output-0', 'comma'], + nextState: 'o' + } + }, + '.': { + '0': { + action_: ['output-0', 'copy'], + nextState: 'o' + } + }, + 'else': { + '*': { + action_: 'text=' + } + } + }), + actions: { + 'comma': function comma() { + return { + type_: 'commaDecimal' + }; + }, + 'output-0': function output0(buffer) { + /** @type {ParserOutput[]} */ + var ret = []; + buffer.text_ = buffer.text_ || ""; + + if (buffer.text_.length > 4) { + var a = buffer.text_.length % 3; + + if (a === 0) { + a = 3; + } + + for (var i = buffer.text_.length - 3; i > 0; i -= 3) { + ret.push(buffer.text_.substr(i, 3)); + ret.push({ + type_: '1000 separator' + }); + } + + ret.push(buffer.text_.substr(0, a)); + ret.reverse(); + } else { + ret.push(buffer.text_); + } + + for (var p in buffer) { + delete buffer[p]; + } + + return ret; + }, + 'output-o': function outputO(buffer) { + /** @type {ParserOutput[]} */ + var ret = []; + buffer.text_ = buffer.text_ || ""; + + if (buffer.text_.length > 4) { + var a = buffer.text_.length - 3; + + for (var i = 0; i < a; i += 3) { + ret.push(buffer.text_.substr(i, 3)); + ret.push({ + type_: '1000 separator' + }); + } + + ret.push(buffer.text_.substr(i)); + } else { + ret.push(buffer.text_); + } + + for (var p in buffer) { + delete buffer[p]; + } + + return ret; + } + } //#endregion + + } +}; // +// texify: Take MhchemParser output and convert it to TeX +// + +/** @type {Texify} */ + +var texify = { + go: function go(input, isInner) { + // (recursive, max 4 levels) + if (!input) { + return ""; + } + + var res = ""; + var cee = false; + + for (var i = 0; i < input.length; i++) { + var inputi = input[i]; + + if (typeof inputi === "string") { + res += inputi; + } else { + res += texify._go2(inputi); + + if (inputi.type_ === '1st-level escape') { + cee = true; + } + } + } + + if (!isInner && !cee && res) { + res = "{" + res + "}"; + } + + return res; + }, + _goInner: function _goInner(input) { + if (!input) { + return input; + } + + return texify.go(input, true); + }, + _go2: function _go2(buf) { + /** @type {undefined | string} */ + var res; + + switch (buf.type_) { + case 'chemfive': + res = ""; + var b5 = { + a: texify._goInner(buf.a), + b: texify._goInner(buf.b), + p: texify._goInner(buf.p), + o: texify._goInner(buf.o), + q: texify._goInner(buf.q), + d: texify._goInner(buf.d) + }; // + // a + // + + if (b5.a) { + if (b5.a.match(/^[+\-]/)) { + b5.a = "{" + b5.a + "}"; + } + + res += b5.a + "\\,"; + } // + // b and p + // + + + if (b5.b || b5.p) { + res += "{\\vphantom{X}}"; + res += "^{\\hphantom{" + (b5.b || "") + "}}_{\\hphantom{" + (b5.p || "") + "}}"; + res += "{\\vphantom{X}}"; + res += "^{\\smash[t]{\\vphantom{2}}\\mathllap{" + (b5.b || "") + "}}"; + res += "_{\\vphantom{2}\\mathllap{\\smash[t]{" + (b5.p || "") + "}}}"; + } // + // o + // + + + if (b5.o) { + if (b5.o.match(/^[+\-]/)) { + b5.o = "{" + b5.o + "}"; + } + + res += b5.o; + } // + // q and d + // + + + if (buf.dType === 'kv') { + if (b5.d || b5.q) { + res += "{\\vphantom{X}}"; + } + + if (b5.d) { + res += "^{" + b5.d + "}"; + } + + if (b5.q) { + res += "_{\\smash[t]{" + b5.q + "}}"; + } + } else if (buf.dType === 'oxidation') { + if (b5.d) { + res += "{\\vphantom{X}}"; + res += "^{" + b5.d + "}"; + } + + if (b5.q) { + res += "{\\vphantom{X}}"; + res += "_{\\smash[t]{" + b5.q + "}}"; + } + } else { + if (b5.q) { + res += "{\\vphantom{X}}"; + res += "_{\\smash[t]{" + b5.q + "}}"; + } + + if (b5.d) { + res += "{\\vphantom{X}}"; + res += "^{" + b5.d + "}"; + } + } + + break; + + case 'rm': + res = "\\mathrm{" + buf.p1 + "}"; + break; + + case 'text': + if (buf.p1.match(/[\^_]/)) { + buf.p1 = buf.p1.replace(" ", "~").replace("-", "\\text{-}"); + res = "\\mathrm{" + buf.p1 + "}"; + } else { + res = "\\text{" + buf.p1 + "}"; + } + + break; + + case 'roman numeral': + res = "\\mathrm{" + buf.p1 + "}"; + break; + + case 'state of aggregation': + res = "\\mskip2mu " + texify._goInner(buf.p1); + break; + + case 'state of aggregation subscript': + res = "\\mskip1mu " + texify._goInner(buf.p1); + break; + + case 'bond': + res = texify._getBond(buf.kind_); + + if (!res) { + throw ["MhchemErrorBond", "mhchem Error. Unknown bond type (" + buf.kind_ + ")"]; + } + + break; + + case 'frac': + var c = "\\frac{" + buf.p1 + "}{" + buf.p2 + "}"; + res = "\\mathchoice{\\textstyle" + c + "}{" + c + "}{" + c + "}{" + c + "}"; + break; + + case 'pu-frac': + var d = "\\frac{" + texify._goInner(buf.p1) + "}{" + texify._goInner(buf.p2) + "}"; + res = "\\mathchoice{\\textstyle" + d + "}{" + d + "}{" + d + "}{" + d + "}"; + break; + + case 'tex-math': + res = buf.p1 + " "; + break; + + case 'frac-ce': + res = "\\frac{" + texify._goInner(buf.p1) + "}{" + texify._goInner(buf.p2) + "}"; + break; + + case 'overset': + res = "\\overset{" + texify._goInner(buf.p1) + "}{" + texify._goInner(buf.p2) + "}"; + break; + + case 'underset': + res = "\\underset{" + texify._goInner(buf.p1) + "}{" + texify._goInner(buf.p2) + "}"; + break; + + case 'underbrace': + res = "\\underbrace{" + texify._goInner(buf.p1) + "}_{" + texify._goInner(buf.p2) + "}"; + break; + + case 'color': + res = "{\\color{" + buf.color1 + "}{" + texify._goInner(buf.color2) + "}}"; + break; + + case 'color0': + res = "\\color{" + buf.color + "}"; + break; + + case 'arrow': + var b6 = { + rd: texify._goInner(buf.rd), + rq: texify._goInner(buf.rq) + }; + + var arrow = "\\x" + texify._getArrow(buf.r); + + if (b6.rq) { + arrow += "[{" + b6.rq + "}]"; + } + + if (b6.rd) { + arrow += "{" + b6.rd + "}"; + } else { + arrow += "{}"; + } + + res = arrow; + break; + + case 'operator': + res = texify._getOperator(buf.kind_); + break; + + case '1st-level escape': + res = buf.p1 + " "; // &, \\\\, \\hlin + + break; + + case 'space': + res = " "; + break; + + case 'entitySkip': + res = "~"; + break; + + case 'pu-space-1': + res = "~"; + break; + + case 'pu-space-2': + res = "\\mkern3mu "; + break; + + case '1000 separator': + res = "\\mkern2mu "; + break; + + case 'commaDecimal': + res = "{,}"; + break; + + case 'comma enumeration L': + res = "{" + buf.p1 + "}\\mkern6mu "; + break; + + case 'comma enumeration M': + res = "{" + buf.p1 + "}\\mkern3mu "; + break; + + case 'comma enumeration S': + res = "{" + buf.p1 + "}\\mkern1mu "; + break; + + case 'hyphen': + res = "\\text{-}"; + break; + + case 'addition compound': + res = "\\,{\\cdot}\\,"; + break; + + case 'electron dot': + res = "\\mkern1mu \\bullet\\mkern1mu "; + break; + + case 'KV x': + res = "{\\times}"; + break; + + case 'prime': + res = "\\prime "; + break; + + case 'cdot': + res = "\\cdot "; + break; + + case 'tight cdot': + res = "\\mkern1mu{\\cdot}\\mkern1mu "; + break; + + case 'times': + res = "\\times "; + break; + + case 'circa': + res = "{\\sim}"; + break; + + case '^': + res = "uparrow"; + break; + + case 'v': + res = "downarrow"; + break; + + case 'ellipsis': + res = "\\ldots "; + break; + + case '/': + res = "/"; + break; + + case ' / ': + res = "\\,/\\,"; + break; + + default: + assertNever(buf); + throw ["MhchemBugT", "mhchem bug T. Please report."]; + // Missing texify rule or unknown MhchemParser output + } + + assertString(res); + return res; + }, + _getArrow: function _getArrow(a) { + switch (a) { + case "->": + return "rightarrow"; + + case "\u2192": + return "rightarrow"; + + case "\u27F6": + return "rightarrow"; + + case "<-": + return "leftarrow"; + + case "<->": + return "leftrightarrow"; + + case "<-->": + return "rightleftarrows"; + + case "<=>": + return "rightleftharpoons"; + + case "\u21CC": + return "rightleftharpoons"; + + case "<=>>": + return "rightequilibrium"; + + case "<<=>": + return "leftequilibrium"; + + default: + assertNever(a); + throw ["MhchemBugT", "mhchem bug T. Please report."]; + } + }, + _getBond: function _getBond(a) { + switch (a) { + case "-": + return "{-}"; + + case "1": + return "{-}"; + + case "=": + return "{=}"; + + case "2": + return "{=}"; + + case "#": + return "{\\equiv}"; + + case "3": + return "{\\equiv}"; + + case "~": + return "{\\tripledash}"; + + case "~-": + return "{\\mathrlap{\\raisebox{-.1em}{$-$}}\\raisebox{.1em}{$\\tripledash$}}"; + + case "~=": + return "{\\mathrlap{\\raisebox{-.2em}{$-$}}\\mathrlap{\\raisebox{.2em}{$\\tripledash$}}-}"; + + case "~--": + return "{\\mathrlap{\\raisebox{-.2em}{$-$}}\\mathrlap{\\raisebox{.2em}{$\\tripledash$}}-}"; + + case "-~-": + return "{\\mathrlap{\\raisebox{-.2em}{$-$}}\\mathrlap{\\raisebox{.2em}{$-$}}\\tripledash}"; + + case "...": + return "{{\\cdot}{\\cdot}{\\cdot}}"; + + case "....": + return "{{\\cdot}{\\cdot}{\\cdot}{\\cdot}}"; + + case "->": + return "{\\rightarrow}"; + + case "<-": + return "{\\leftarrow}"; + + case "<": + return "{<}"; + + case ">": + return "{>}"; + + default: + assertNever(a); + throw ["MhchemBugT", "mhchem bug T. Please report."]; + } + }, + _getOperator: function _getOperator(a) { + switch (a) { + case "+": + return " {}+{} "; + + case "-": + return " {}-{} "; + + case "=": + return " {}={} "; + + case "<": + return " {}<{} "; + + case ">": + return " {}>{} "; + + case "<<": + return " {}\\ll{} "; + + case ">>": + return " {}\\gg{} "; + + case "\\pm": + return " {}\\pm{} "; + + case "\\approx": + return " {}\\approx{} "; + + case "$\\approx$": + return " {}\\approx{} "; + + case "v": + return " \\downarrow{} "; + + case "(v)": + return " \\downarrow{} "; + + case "^": + return " \\uparrow{} "; + + case "(^)": + return " \\uparrow{} "; + + default: + assertNever(a); + throw ["MhchemBugT", "mhchem bug T. Please report."]; + } + } +}; // +// Helpers for code anaylsis +// Will show type error at calling position +// + +/** @param {number} a */ + +function assertNever(a) {} +/** @param {string} a */ + + +function assertString(a) {} + +/***/ }) +/******/ ])["default"]; +}); \ No newline at end of file diff --git a/adoc/katex/contrib/mhchem.min.js b/adoc/katex/contrib/mhchem.min.js new file mode 100644 index 00000000..8fd9cca8 --- /dev/null +++ b/adoc/katex/contrib/mhchem.min.js @@ -0,0 +1 @@ +!function(t,e){if("object"==typeof exports&&"object"==typeof module)module.exports=e(require("katex"));else if("function"==typeof define&&define.amd)define(["katex"],e);else{var n="object"==typeof exports?e(require("katex")):e(t.katex);for(var o in n)("object"==typeof exports?exports:t)[o]=n[o]}}("undefined"!=typeof self?self:this,function(t){return function(t){var e={};function n(o){if(e[o])return e[o].exports;var a=e[o]={i:o,l:!1,exports:{}};return t[o].call(a.exports,a,a.exports,n),a.l=!0,a.exports}return n.m=t,n.c=e,n.d=function(t,e,o){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:o})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var o=Object.create(null);if(n.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var a in t)n.d(o,a,function(e){return t[e]}.bind(null,a));return o},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="",n(n.s=1)}([function(e,n){e.exports=t},function(t,e,n){"use strict";n.r(e);var o=n(0),a=n.n(o);a.a.__defineMacro("\\ce",function(t){return r(t.consumeArgs(1)[0],"ce")}),a.a.__defineMacro("\\pu",function(t){return r(t.consumeArgs(1)[0],"pu")}),a.a.__defineMacro("\\tripledash","{\\vphantom{-}\\raisebox{2.56mu}{$\\mkern2mu\\tiny\\text{-}\\mkern1mu\\text{-}\\mkern1mu\\text{-}\\mkern2mu$}}");var r=function(t,e){for(var n="",o=t[t.length-1].loc.start,a=t.length-1;a>=0;a--)t[a].loc.start>o&&(n+=" ",o=t[a].loc.start),n+=t[a].text,o+=t[a].text.length;return c.go(i.go(n,e))},i={go:function(t,e){if(!t)return[];void 0===e&&(e="ce");var n,o="0",a={};a.parenthesisLevel=0,t=(t=(t=t.replace(/\n/g," ")).replace(/[\u2212\u2013\u2014\u2010]/g,"-")).replace(/[\u2026]/g,"...");for(var r=10,c=[];;){n!==t?(r=10,n=t):r--;var u=i.stateMachines[e],p=u.transitions[o]||u.transitions["*"];t:for(var s=0;s0))return c;if(d.revisit||(t=_.remainder),!d.toContinue)break t}}if(r<=0)throw["MhchemBugU","mhchem bug U. Please report."]}},concatArray:function(t,e){if(e)if(Array.isArray(e))for(var n=0;n":/^[=<>]/,"#":/^[#\u2261]/,"+":/^\+/,"-$":/^-(?=[\s_},;\]\/]|$|\([a-z]+\))/,"-9":/^-(?=[0-9])/,"- orbital overlap":/^-(?=(?:[spd]|sp)(?:$|[\s,;\)\]\}]))/,"-":/^-/,"pm-operator":/^(?:\\pm|\$\\pm\$|\+-|\+\/-)/,operator:/^(?:\+|(?:[\-=<>]|<<|>>|\\approx|\$\\approx\$)(?=\s|$|-?[0-9]))/,arrowUpDown:/^(?:v|\(v\)|\^|\(\^\))(?=$|[\s,;\)\]\}])/,"\\bond{(...)}":function(t){return i.patterns.findObserveGroups(t,"\\bond{","","","}")},"->":/^(?:<->|<-->|->|<-|<=>>|<<=>|<=>|[\u2192\u27F6\u21CC])/,CMT:/^[CMT](?=\[)/,"[(...)]":function(t){return i.patterns.findObserveGroups(t,"[","","","]")},"1st-level escape":/^(&|\\\\|\\hline)\s*/,"\\,":/^(?:\\[,\ ;:])/,"\\x{}{}":function(t){return i.patterns.findObserveGroups(t,"",/^\\[a-zA-Z]+\{/,"}","","","{","}","",!0)},"\\x{}":function(t){return i.patterns.findObserveGroups(t,"",/^\\[a-zA-Z]+\{/,"}","")},"\\ca":/^\\ca(?:\s+|(?![a-zA-Z]))/,"\\x":/^(?:\\[a-zA-Z]+\s*|\\[_&{}%])/,orbital:/^(?:[0-9]{1,2}[spdfgh]|[0-9]{0,2}sp)(?=$|[^a-zA-Z])/,others:/^[\/~|]/,"\\frac{(...)}":function(t){return i.patterns.findObserveGroups(t,"\\frac{","","","}","{","","","}")},"\\overset{(...)}":function(t){return i.patterns.findObserveGroups(t,"\\overset{","","","}","{","","","}")},"\\underset{(...)}":function(t){return i.patterns.findObserveGroups(t,"\\underset{","","","}","{","","","}")},"\\underbrace{(...)}":function(t){return i.patterns.findObserveGroups(t,"\\underbrace{","","","}_","{","","","}")},"\\color{(...)}0":function(t){return i.patterns.findObserveGroups(t,"\\color{","","","}")},"\\color{(...)}{(...)}1":function(t){return i.patterns.findObserveGroups(t,"\\color{","","","}","{","","","}")},"\\color(...){(...)}2":function(t){return i.patterns.findObserveGroups(t,"\\color","\\","",/^(?=\{)/,"{","","","}")},"\\ce{(...)}":function(t){return i.patterns.findObserveGroups(t,"\\ce{","","","}")},oxidation$:/^(?:[+-][IVX]+|\\pm\s*0|\$\\pm\$\s*0)$/,"d-oxidation$":/^(?:[+-]?\s?[IVX]+|\\pm\s*0|\$\\pm\$\s*0)$/,"roman numeral":/^[IVX]+/,"1/2$":/^[+\-]?(?:[0-9]+|\$[a-z]\$|[a-z])\/[0-9]+(?:\$[a-z]\$|[a-z])?$/,amount:function(t){var e;if(e=t.match(/^(?:(?:(?:\([+\-]?[0-9]+\/[0-9]+\)|[+\-]?(?:[0-9]+|\$[a-z]\$|[a-z])\/[0-9]+|[+\-]?[0-9]+[.,][0-9]+|[+\-]?\.[0-9]+|[+\-]?[0-9]+)(?:[a-z](?=\s*[A-Z]))?)|[+\-]?[a-z](?=\s*[A-Z])|\+(?!\s))/))return{match_:e[0],remainder:t.substr(e[0].length)};var n=i.patterns.findObserveGroups(t,"","$","$","");return n&&(e=n.match_.match(/^\$(?:\(?[+\-]?(?:[0-9]*[a-z]?[+\-])?[0-9]*[a-z](?:[+\-][0-9]*[a-z]?)?\)?|\+|-)\$$/))?{match_:e[0],remainder:t.substr(e[0].length)}:null},amount2:function(t){return this.amount(t)},"(KV letters),":/^(?:[A-Z][a-z]{0,2}|i)(?=,)/,formula$:function(t){if(t.match(/^\([a-z]+\)$/))return null;var e=t.match(/^(?:[a-z]|(?:[0-9\ \+\-\,\.\(\)]+[a-z])+[0-9\ \+\-\,\.\(\)]*|(?:[a-z][0-9\ \+\-\,\.\(\)]+)+[a-z]?)$/);return e?{match_:e[0],remainder:t.substr(e[0].length)}:null},uprightEntities:/^(?:pH|pOH|pC|pK|iPr|iBu)(?=$|[^a-zA-Z])/,"/":/^\s*(\/)\s*/,"//":/^\s*(\/\/)\s*/,"*":/^\s*[*.]\s*/},findObserveGroups:function(t,e,n,o,a,r,i,c,u,p){var s=function(t,e){if("string"==typeof e)return 0!==t.indexOf(e)?null:e;var n=t.match(e);return n?n[0]:null},_=s(t,e);if(null===_)return null;if(t=t.substr(_.length),null===(_=s(t,n)))return null;var d=function(t,e,n){for(var o=0;e":{"0|1|2|3":{action_:"r=",nextState:"r"},"a|as":{action_:["output","r="],nextState:"r"},"*":{action_:["output","r="],nextState:"r"}},"+":{o:{action_:"d= kv",nextState:"d"},"d|D":{action_:"d=",nextState:"d"},q:{action_:"d=",nextState:"qd"},"qd|qD":{action_:"d=",nextState:"qd"},dq:{action_:["output","d="],nextState:"d"},3:{action_:["sb=false","output","operator"],nextState:"0"}},amount:{"0|2":{action_:"a=",nextState:"a"}},"pm-operator":{"0|1|2|a|as":{action_:["sb=false","output",{type_:"operator",option:"\\pm"}],nextState:"0"}},operator:{"0|1|2|a|as":{action_:["sb=false","output","operator"],nextState:"0"}},"-$":{"o|q":{action_:["charge or bond","output"],nextState:"qd"},d:{action_:"d=",nextState:"d"},D:{action_:["output",{type_:"bond",option:"-"}],nextState:"3"},q:{action_:"d=",nextState:"qd"},qd:{action_:"d=",nextState:"qd"},"qD|dq":{action_:["output",{type_:"bond",option:"-"}],nextState:"3"}},"-9":{"3|o":{action_:["output",{type_:"insert",option:"hyphen"}],nextState:"3"}},"- orbital overlap":{o:{action_:["output",{type_:"insert",option:"hyphen"}],nextState:"2"},d:{action_:["output",{type_:"insert",option:"hyphen"}],nextState:"2"}},"-":{"0|1|2":{action_:[{type_:"output",option:1},"beginsWithBond=true",{type_:"bond",option:"-"}],nextState:"3"},3:{action_:{type_:"bond",option:"-"}},a:{action_:["output",{type_:"insert",option:"hyphen"}],nextState:"2"},as:{action_:[{type_:"output",option:2},{type_:"bond",option:"-"}],nextState:"3"},b:{action_:"b="},o:{action_:{type_:"- after o/d",option:!1},nextState:"2"},q:{action_:{type_:"- after o/d",option:!1},nextState:"2"},"d|qd|dq":{action_:{type_:"- after o/d",option:!0},nextState:"2"},"D|qD|p":{action_:["output",{type_:"bond",option:"-"}],nextState:"3"}},amount2:{"1|3":{action_:"a=",nextState:"a"}},letters:{"0|1|2|3|a|as|b|p|bp|o":{action_:"o=",nextState:"o"},"q|dq":{action_:["output","o="],nextState:"o"},"d|D|qd|qD":{action_:"o after d",nextState:"o"}},digits:{o:{action_:"q=",nextState:"q"},"d|D":{action_:"q=",nextState:"dq"},q:{action_:["output","o="],nextState:"o"},a:{action_:"o=",nextState:"o"}},"space A":{"b|p|bp":{}},space:{a:{nextState:"as"},0:{action_:"sb=false"},"1|2":{action_:"sb=true"},"r|rt|rd|rdt|rdq":{action_:"output",nextState:"0"},"*":{action_:["output","sb=true"],nextState:"1"}},"1st-level escape":{"1|2":{action_:["output",{type_:"insert+p1",option:"1st-level escape"}]},"*":{action_:["output",{type_:"insert+p1",option:"1st-level escape"}],nextState:"0"}},"[(...)]":{"r|rt":{action_:"rd=",nextState:"rd"},"rd|rdt":{action_:"rq=",nextState:"rdq"}},"...":{"o|d|D|dq|qd|qD":{action_:["output",{type_:"bond",option:"..."}],nextState:"3"},"*":{action_:[{type_:"output",option:1},{type_:"insert",option:"ellipsis"}],nextState:"1"}},". |* ":{"*":{action_:["output",{type_:"insert",option:"addition compound"}],nextState:"1"}},"state of aggregation $":{"*":{action_:["output","state of aggregation"],nextState:"1"}},"{[(":{"a|as|o":{action_:["o=","output","parenthesisLevel++"],nextState:"2"},"0|1|2|3":{action_:["o=","output","parenthesisLevel++"],nextState:"2"},"*":{action_:["output","o=","output","parenthesisLevel++"],nextState:"2"}},")]}":{"0|1|2|3|b|p|bp|o":{action_:["o=","parenthesisLevel--"],nextState:"o"},"a|as|d|D|q|qd|qD|dq":{action_:["output","o=","parenthesisLevel--"],nextState:"o"}},", ":{"*":{action_:["output","comma"],nextState:"0"}},"^_":{"*":{}},"^{(...)}|^($...$)":{"0|1|2|as":{action_:"b=",nextState:"b"},p:{action_:"b=",nextState:"bp"},"3|o":{action_:"d= kv",nextState:"D"},q:{action_:"d=",nextState:"qD"},"d|D|qd|qD|dq":{action_:["output","d="],nextState:"D"}},"^a|^\\x{}{}|^\\x{}|^\\x|'":{"0|1|2|as":{action_:"b=",nextState:"b"},p:{action_:"b=",nextState:"bp"},"3|o":{action_:"d= kv",nextState:"d"},q:{action_:"d=",nextState:"qd"},"d|qd|D|qD":{action_:"d="},dq:{action_:["output","d="],nextState:"d"}},"_{(state of aggregation)}$":{"d|D|q|qd|qD|dq":{action_:["output","q="],nextState:"q"}},"_{(...)}|_($...$)|_9|_\\x{}{}|_\\x{}|_\\x":{"0|1|2|as":{action_:"p=",nextState:"p"},b:{action_:"p=",nextState:"bp"},"3|o":{action_:"q=",nextState:"q"},"d|D":{action_:"q=",nextState:"dq"},"q|qd|qD|dq":{action_:["output","q="],nextState:"q"}},"=<>":{"0|1|2|3|a|as|o|q|d|D|qd|qD|dq":{action_:[{type_:"output",option:2},"bond"],nextState:"3"}},"#":{"0|1|2|3|a|as|o":{action_:[{type_:"output",option:2},{type_:"bond",option:"#"}],nextState:"3"}},"{}":{"*":{action_:{type_:"output",option:1},nextState:"1"}},"{...}":{"0|1|2|3|a|as|b|p|bp":{action_:"o=",nextState:"o"},"o|d|D|q|qd|qD|dq":{action_:["output","o="],nextState:"o"}},"$...$":{a:{action_:"a="},"0|1|2|3|as|b|p|bp|o":{action_:"o=",nextState:"o"},"as|o":{action_:"o="},"q|d|D|qd|qD|dq":{action_:["output","o="],nextState:"o"}},"\\bond{(...)}":{"*":{action_:[{type_:"output",option:2},"bond"],nextState:"3"}},"\\frac{(...)}":{"*":{action_:[{type_:"output",option:1},"frac-output"],nextState:"3"}},"\\overset{(...)}":{"*":{action_:[{type_:"output",option:2},"overset-output"],nextState:"3"}},"\\underset{(...)}":{"*":{action_:[{type_:"output",option:2},"underset-output"],nextState:"3"}},"\\underbrace{(...)}":{"*":{action_:[{type_:"output",option:2},"underbrace-output"],nextState:"3"}},"\\color{(...)}{(...)}1|\\color(...){(...)}2":{"*":{action_:[{type_:"output",option:2},"color-output"],nextState:"3"}},"\\color{(...)}0":{"*":{action_:[{type_:"output",option:2},"color0-output"]}},"\\ce{(...)}":{"*":{action_:[{type_:"output",option:2},"ce"],nextState:"3"}},"\\,":{"*":{action_:[{type_:"output",option:1},"copy"],nextState:"1"}},"\\x{}{}|\\x{}|\\x":{"0|1|2|3|a|as|b|p|bp|o|c0":{action_:["o=","output"],nextState:"3"},"*":{action_:["output","o=","output"],nextState:"3"}},others:{"*":{action_:[{type_:"output",option:1},"copy"],nextState:"3"}},else2:{a:{action_:"a to o",nextState:"o",revisit:!0},as:{action_:["output","sb=true"],nextState:"1",revisit:!0},"r|rt|rd|rdt|rdq":{action_:["output"],nextState:"0",revisit:!0},"*":{action_:["output","copy"],nextState:"3"}}}),actions:{"o after d":function(t,e){var n;if((t.d||"").match(/^[0-9]+$/)){var o=t.d;t.d=void 0,n=this.output(t),t.b=o}else n=this.output(t);return i.actions["o="](t,e),n},"d= kv":function(t,e){t.d=e,t.dType="kv"},"charge or bond":function(t,e){if(t.beginsWithBond){var n=[];return i.concatArray(n,this.output(t)),i.concatArray(n,i.actions.bond(t,e,"-")),n}t.d=e},"- after o/d":function(t,e,n){var o=i.patterns.match_("orbital",t.o||""),a=i.patterns.match_("one lowercase greek letter $",t.o||""),r=i.patterns.match_("one lowercase latin letter $",t.o||""),c=i.patterns.match_("$one lowercase latin letter$ $",t.o||""),u="-"===e&&(o&&""===o.remainder||a||r||c);!u||t.a||t.b||t.p||t.d||t.q||o||!r||(t.o="$"+t.o+"$");var p=[];return u?(i.concatArray(p,this.output(t)),p.push({type_:"hyphen"})):(o=i.patterns.match_("digits",t.d||""),n&&o&&""===o.remainder?(i.concatArray(p,i.actions["d="](t,e)),i.concatArray(p,this.output(t))):(i.concatArray(p,this.output(t)),i.concatArray(p,i.actions.bond(t,e,"-")))),p},"a to o":function(t){t.o=t.a,t.a=void 0},"sb=true":function(t){t.sb=!0},"sb=false":function(t){t.sb=!1},"beginsWithBond=true":function(t){t.beginsWithBond=!0},"beginsWithBond=false":function(t){t.beginsWithBond=!1},"parenthesisLevel++":function(t){t.parenthesisLevel++},"parenthesisLevel--":function(t){t.parenthesisLevel--},"state of aggregation":function(t,e){return{type_:"state of aggregation",p1:i.go(e,"o")}},comma:function(t,e){var n=e.replace(/\s*$/,"");return n!==e&&0===t.parenthesisLevel?{type_:"comma enumeration L",p1:n}:{type_:"comma enumeration M",p1:n}},output:function(t,e,n){var o,a,r;t.r?(a="M"===t.rdt?i.go(t.rd,"tex-math"):"T"===t.rdt?[{type_:"text",p1:t.rd||""}]:i.go(t.rd),r="M"===t.rqt?i.go(t.rq,"tex-math"):"T"===t.rqt?[{type_:"text",p1:t.rq||""}]:i.go(t.rq),o={type_:"arrow",r:t.r,rd:a,rq:r}):(o=[],(t.a||t.b||t.p||t.o||t.q||t.d||n)&&(t.sb&&o.push({type_:"entitySkip"}),t.o||t.q||t.d||t.b||t.p||2===n?t.o||t.q||t.d||!t.b&&!t.p?t.o&&"kv"===t.dType&&i.patterns.match_("d-oxidation$",t.d||"")?t.dType="oxidation":t.o&&"kv"===t.dType&&!t.q&&(t.dType=void 0):(t.o=t.a,t.d=t.b,t.q=t.p,t.a=t.b=t.p=void 0):(t.o=t.a,t.a=void 0),o.push({type_:"chemfive",a:i.go(t.a,"a"),b:i.go(t.b,"bd"),p:i.go(t.p,"pq"),o:i.go(t.o,"o"),q:i.go(t.q,"pq"),d:i.go(t.d,"oxidation"===t.dType?"oxidation":"bd"),dType:t.dType})));for(var c in t)"parenthesisLevel"!==c&&"beginsWithBond"!==c&&delete t[c];return o},"oxidation-output":function(t,e){var n=["{"];return i.concatArray(n,i.go(e,"oxidation")),n.push("}"),n},"frac-output":function(t,e){return{type_:"frac-ce",p1:i.go(e[0]),p2:i.go(e[1])}},"overset-output":function(t,e){return{type_:"overset",p1:i.go(e[0]),p2:i.go(e[1])}},"underset-output":function(t,e){return{type_:"underset",p1:i.go(e[0]),p2:i.go(e[1])}},"underbrace-output":function(t,e){return{type_:"underbrace",p1:i.go(e[0]),p2:i.go(e[1])}},"color-output":function(t,e){return{type_:"color",color1:e[0],color2:i.go(e[1])}},"r=":function(t,e){t.r=e},"rdt=":function(t,e){t.rdt=e},"rd=":function(t,e){t.rd=e},"rqt=":function(t,e){t.rqt=e},"rq=":function(t,e){t.rq=e},operator:function(t,e,n){return{type_:"operator",kind_:n||e}}}},a:{transitions:i.createTransitions({empty:{"*":{}},"1/2$":{0:{action_:"1/2"}},else:{0:{nextState:"1",revisit:!0}},"$(...)$":{"*":{action_:"tex-math tight",nextState:"1"}},",":{"*":{action_:{type_:"insert",option:"commaDecimal"}}},else2:{"*":{action_:"copy"}}}),actions:{}},o:{transitions:i.createTransitions({empty:{"*":{}},"1/2$":{0:{action_:"1/2"}},else:{0:{nextState:"1",revisit:!0}},letters:{"*":{action_:"rm"}},"\\ca":{"*":{action_:{type_:"insert",option:"circa"}}},"\\x{}{}|\\x{}|\\x":{"*":{action_:"copy"}},"${(...)}$|$(...)$":{"*":{action_:"tex-math"}},"{(...)}":{"*":{action_:"{text}"}},else2:{"*":{action_:"copy"}}}),actions:{}},text:{transitions:i.createTransitions({empty:{"*":{action_:"output"}},"{...}":{"*":{action_:"text="}},"${(...)}$|$(...)$":{"*":{action_:"tex-math"}},"\\greek":{"*":{action_:["output","rm"]}},"\\,|\\x{}{}|\\x{}|\\x":{"*":{action_:["output","copy"]}},else:{"*":{action_:"text="}}}),actions:{output:function(t){if(t.text_){var e={type_:"text",p1:t.text_};for(var n in t)delete t[n];return e}}}},pq:{transitions:i.createTransitions({empty:{"*":{}},"state of aggregation $":{"*":{action_:"state of aggregation"}},i$:{0:{nextState:"!f",revisit:!0}},"(KV letters),":{0:{action_:"rm",nextState:"0"}},formula$:{0:{nextState:"f",revisit:!0}},"1/2$":{0:{action_:"1/2"}},else:{0:{nextState:"!f",revisit:!0}},"${(...)}$|$(...)$":{"*":{action_:"tex-math"}},"{(...)}":{"*":{action_:"text"}},"a-z":{f:{action_:"tex-math"}},letters:{"*":{action_:"rm"}},"-9.,9":{"*":{action_:"9,9"}},",":{"*":{action_:{type_:"insert+p1",option:"comma enumeration S"}}},"\\color{(...)}{(...)}1|\\color(...){(...)}2":{"*":{action_:"color-output"}},"\\color{(...)}0":{"*":{action_:"color0-output"}},"\\ce{(...)}":{"*":{action_:"ce"}},"\\,|\\x{}{}|\\x{}|\\x":{"*":{action_:"copy"}},else2:{"*":{action_:"copy"}}}),actions:{"state of aggregation":function(t,e){return{type_:"state of aggregation subscript",p1:i.go(e,"o")}},"color-output":function(t,e){return{type_:"color",color1:e[0],color2:i.go(e[1],"pq")}}}},bd:{transitions:i.createTransitions({empty:{"*":{}},x$:{0:{nextState:"!f",revisit:!0}},formula$:{0:{nextState:"f",revisit:!0}},else:{0:{nextState:"!f",revisit:!0}},"-9.,9 no missing 0":{"*":{action_:"9,9"}},".":{"*":{action_:{type_:"insert",option:"electron dot"}}},"a-z":{f:{action_:"tex-math"}},x:{"*":{action_:{type_:"insert",option:"KV x"}}},letters:{"*":{action_:"rm"}},"'":{"*":{action_:{type_:"insert",option:"prime"}}},"${(...)}$|$(...)$":{"*":{action_:"tex-math"}},"{(...)}":{"*":{action_:"text"}},"\\color{(...)}{(...)}1|\\color(...){(...)}2":{"*":{action_:"color-output"}},"\\color{(...)}0":{"*":{action_:"color0-output"}},"\\ce{(...)}":{"*":{action_:"ce"}},"\\,|\\x{}{}|\\x{}|\\x":{"*":{action_:"copy"}},else2:{"*":{action_:"copy"}}}),actions:{"color-output":function(t,e){return{type_:"color",color1:e[0],color2:i.go(e[1],"bd")}}}},oxidation:{transitions:i.createTransitions({empty:{"*":{}},"roman numeral":{"*":{action_:"roman-numeral"}},"${(...)}$|$(...)$":{"*":{action_:"tex-math"}},else:{"*":{action_:"copy"}}}),actions:{"roman-numeral":function(t,e){return{type_:"roman numeral",p1:e||""}}}},"tex-math":{transitions:i.createTransitions({empty:{"*":{action_:"output"}},"\\ce{(...)}":{"*":{action_:["output","ce"]}},"{...}|\\,|\\x{}{}|\\x{}|\\x":{"*":{action_:"o="}},else:{"*":{action_:"o="}}}),actions:{output:function(t){if(t.o){var e={type_:"tex-math",p1:t.o};for(var n in t)delete t[n];return e}}}},"tex-math tight":{transitions:i.createTransitions({empty:{"*":{action_:"output"}},"\\ce{(...)}":{"*":{action_:["output","ce"]}},"{...}|\\,|\\x{}{}|\\x{}|\\x":{"*":{action_:"o="}},"-|+":{"*":{action_:"tight operator"}},else:{"*":{action_:"o="}}}),actions:{"tight operator":function(t,e){t.o=(t.o||"")+"{"+e+"}"},output:function(t){if(t.o){var e={type_:"tex-math",p1:t.o};for(var n in t)delete t[n];return e}}}},"9,9":{transitions:i.createTransitions({empty:{"*":{}},",":{"*":{action_:"comma"}},else:{"*":{action_:"copy"}}}),actions:{comma:function(){return{type_:"commaDecimal"}}}},pu:{transitions:i.createTransitions({empty:{"*":{action_:"output"}},space$:{"*":{action_:["output","space"]}},"{[(|)]}":{"0|a":{action_:"copy"}},"(-)(9)^(-9)":{0:{action_:"number^",nextState:"a"}},"(-)(9.,9)(e)(99)":{0:{action_:"enumber",nextState:"a"}},space:{"0|a":{}},"pm-operator":{"0|a":{action_:{type_:"operator",option:"\\pm"},nextState:"0"}},operator:{"0|a":{action_:"copy",nextState:"0"}},"//":{d:{action_:"o=",nextState:"/"}},"/":{d:{action_:"o=",nextState:"/"}},"{...}|else":{"0|d":{action_:"d=",nextState:"d"},a:{action_:["space","d="],nextState:"d"},"/|q":{action_:"q=",nextState:"q"}}}),actions:{enumber:function(t,e){var n=[];return"+-"===e[0]||"+/-"===e[0]?n.push("\\pm "):e[0]&&n.push(e[0]),e[1]&&(i.concatArray(n,i.go(e[1],"pu-9,9")),e[2]&&(e[2].match(/[,.]/)?i.concatArray(n,i.go(e[2],"pu-9,9")):n.push(e[2])),e[3]=e[4]||e[3],e[3]&&(e[3]=e[3].trim(),"e"===e[3]||"*"===e[3].substr(0,1)?n.push({type_:"cdot"}):n.push({type_:"times"}))),e[3]&&n.push("10^{"+e[5]+"}"),n},"number^":function(t,e){var n=[];return"+-"===e[0]||"+/-"===e[0]?n.push("\\pm "):e[0]&&n.push(e[0]),i.concatArray(n,i.go(e[1],"pu-9,9")),n.push("^{"+e[2]+"}"),n},operator:function(t,e,n){return{type_:"operator",kind_:n||e}},space:function(){return{type_:"pu-space-1"}},output:function(t){var e,n=i.patterns.match_("{(...)}",t.d||"");n&&""===n.remainder&&(t.d=n.match_);var o=i.patterns.match_("{(...)}",t.q||"");if(o&&""===o.remainder&&(t.q=o.match_),t.d&&(t.d=t.d.replace(/\u00B0C|\^oC|\^{o}C/g,"{}^{\\circ}C"),t.d=t.d.replace(/\u00B0F|\^oF|\^{o}F/g,"{}^{\\circ}F")),t.q){t.q=t.q.replace(/\u00B0C|\^oC|\^{o}C/g,"{}^{\\circ}C"),t.q=t.q.replace(/\u00B0F|\^oF|\^{o}F/g,"{}^{\\circ}F");var a={d:i.go(t.d,"pu"),q:i.go(t.q,"pu")};"//"===t.o?e={type_:"pu-frac",p1:a.d,p2:a.q}:(e=a.d,a.d.length>1||a.q.length>1?e.push({type_:" / "}):e.push({type_:"/"}),i.concatArray(e,a.q))}else e=i.go(t.d,"pu-2");for(var r in t)delete t[r];return e}}},"pu-2":{transitions:i.createTransitions({empty:{"*":{action_:"output"}},"*":{"*":{action_:["output","cdot"],nextState:"0"}},"\\x":{"*":{action_:"rm="}},space:{"*":{action_:["output","space"],nextState:"0"}},"^{(...)}|^(-1)":{1:{action_:"^(-1)"}},"-9.,9":{0:{action_:"rm=",nextState:"0"},1:{action_:"^(-1)",nextState:"0"}},"{...}|else":{"*":{action_:"rm=",nextState:"1"}}}),actions:{cdot:function(){return{type_:"tight cdot"}},"^(-1)":function(t,e){t.rm+="^{"+e+"}"},space:function(){return{type_:"pu-space-2"}},output:function(t){var e=[];if(t.rm){var n=i.patterns.match_("{(...)}",t.rm||"");e=n&&""===n.remainder?i.go(n.match_,"pu"):{type_:"rm",p1:t.rm}}for(var o in t)delete t[o];return e}}},"pu-9,9":{transitions:i.createTransitions({empty:{0:{action_:"output-0"},o:{action_:"output-o"}},",":{0:{action_:["output-0","comma"],nextState:"o"}},".":{0:{action_:["output-0","copy"],nextState:"o"}},else:{"*":{action_:"text="}}}),actions:{comma:function(){return{type_:"commaDecimal"}},"output-0":function(t){var e=[];if(t.text_=t.text_||"",t.text_.length>4){var n=t.text_.length%3;0===n&&(n=3);for(var o=t.text_.length-3;o>0;o-=3)e.push(t.text_.substr(o,3)),e.push({type_:"1000 separator"});e.push(t.text_.substr(0,n)),e.reverse()}else e.push(t.text_);for(var a in t)delete t[a];return e},"output-o":function(t){var e=[];if(t.text_=t.text_||"",t.text_.length>4){for(var n=t.text_.length-3,o=0;o":case"\u2192":case"\u27f6":return"rightarrow";case"<-":return"leftarrow";case"<->":return"leftrightarrow";case"<--\x3e":return"rightleftarrows";case"<=>":case"\u21cc":return"rightleftharpoons";case"<=>>":return"rightequilibrium";case"<<=>":return"leftequilibrium";default:throw["MhchemBugT","mhchem bug T. Please report."]}},_getBond:function(t){switch(t){case"-":case"1":return"{-}";case"=":case"2":return"{=}";case"#":case"3":return"{\\equiv}";case"~":return"{\\tripledash}";case"~-":return"{\\mathrlap{\\raisebox{-.1em}{$-$}}\\raisebox{.1em}{$\\tripledash$}}";case"~=":case"~--":return"{\\mathrlap{\\raisebox{-.2em}{$-$}}\\mathrlap{\\raisebox{.2em}{$\\tripledash$}}-}";case"-~-":return"{\\mathrlap{\\raisebox{-.2em}{$-$}}\\mathrlap{\\raisebox{.2em}{$-$}}\\tripledash}";case"...":return"{{\\cdot}{\\cdot}{\\cdot}}";case"....":return"{{\\cdot}{\\cdot}{\\cdot}{\\cdot}}";case"->":return"{\\rightarrow}";case"<-":return"{\\leftarrow}";case"<":return"{<}";case">":return"{>}";default:throw["MhchemBugT","mhchem bug T. Please report."]}},_getOperator:function(t){switch(t){case"+":return" {}+{} ";case"-":return" {}-{} ";case"=":return" {}={} ";case"<":return" {}<{} ";case">":return" {}>{} ";case"<<":return" {}\\ll{} ";case">>":return" {}\\gg{} ";case"\\pm":return" {}\\pm{} ";case"\\approx":case"$\\approx$":return" {}\\approx{} ";case"v":case"(v)":return" \\downarrow{} ";case"^":case"(^)":return" \\uparrow{} ";default:throw["MhchemBugT","mhchem bug T. Please report."]}}}}]).default}); \ No newline at end of file diff --git a/adoc/katex/contrib/mhchem.mjs b/adoc/katex/contrib/mhchem.mjs new file mode 100644 index 00000000..46241b5f --- /dev/null +++ b/adoc/katex/contrib/mhchem.mjs @@ -0,0 +1,3109 @@ +import katex from '../katex.mjs'; + +/* eslint-disable */ + +/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */ + +/* vim: set ts=2 et sw=2 tw=80: */ + +/************************************************************* + * + * KaTeX mhchem.js + * + * This file implements a KaTeX version of mhchem version 3.3.0. + * It is adapted from MathJax/extensions/TeX/mhchem.js + * It differs from the MathJax version as follows: + * 1. The interface is changed so that it can be called from KaTeX, not MathJax. + * 2. \rlap and \llap are replaced with \mathrlap and \mathllap. + * 3. Four lines of code are edited in order to use \raisebox instead of \raise. + * 4. The reaction arrow code is simplified. All reaction arrows are rendered + * using KaTeX extensible arrows instead of building non-extensible arrows. + * 5. \tripledash vertical alignment is slightly adjusted. + * + * This code, as other KaTeX code, is released under the MIT license. + * + * /************************************************************* + * + * MathJax/extensions/TeX/mhchem.js + * + * Implements the \ce command for handling chemical formulas + * from the mhchem LaTeX package. + * + * --------------------------------------------------------------------- + * + * Copyright (c) 2011-2015 The MathJax Consortium + * Copyright (c) 2015-2018 Martin Hensel + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// +// Coding Style +// - use '' for identifiers that can by minified/uglified +// - use "" for strings that need to stay untouched +// version: "3.3.0" for MathJax and KaTeX +// Add \ce, \pu, and \tripledash to the KaTeX macros. +katex.__defineMacro("\\ce", function (context) { + return chemParse(context.consumeArgs(1)[0], "ce"); +}); + +katex.__defineMacro("\\pu", function (context) { + return chemParse(context.consumeArgs(1)[0], "pu"); +}); // Needed for \bond for the ~ forms +// Raise by 2.56mu, not 2mu. We're raising a hyphen-minus, U+002D, not +// a mathematical minus, U+2212. So we need that extra 0.56. + + +katex.__defineMacro("\\tripledash", "{\\vphantom{-}\\raisebox{2.56mu}{$\\mkern2mu" + "\\tiny\\text{-}\\mkern1mu\\text{-}\\mkern1mu\\text{-}\\mkern2mu$}}"); +// This is the main function for handing the \ce and \pu commands. +// It takes the argument to \ce or \pu and returns the corresponding TeX string. +// + +var chemParse = function chemParse(tokens, stateMachine) { + // Recreate the argument string from KaTeX's array of tokens. + var str = ""; + var expectedLoc = tokens[tokens.length - 1].loc.start; + + for (var i = tokens.length - 1; i >= 0; i--) { + if (tokens[i].loc.start > expectedLoc) { + // context.consumeArgs has eaten a space. + str += " "; + expectedLoc = tokens[i].loc.start; + } + + str += tokens[i].text; + expectedLoc += tokens[i].text.length; + } + + var tex = texify.go(mhchemParser.go(str, stateMachine)); + return tex; +}; // +// Core parser for mhchem syntax (recursive) +// + +/** @type {MhchemParser} */ + + +var mhchemParser = { + // + // Parses mchem \ce syntax + // + // Call like + // go("H2O"); + // + go: function go(input, stateMachine) { + if (!input) { + return []; + } + + if (stateMachine === undefined) { + stateMachine = 'ce'; + } + + var state = '0'; // + // String buffers for parsing: + // + // buffer.a == amount + // buffer.o == element + // buffer.b == left-side superscript + // buffer.p == left-side subscript + // buffer.q == right-side subscript + // buffer.d == right-side superscript + // + // buffer.r == arrow + // buffer.rdt == arrow, script above, type + // buffer.rd == arrow, script above, content + // buffer.rqt == arrow, script below, type + // buffer.rq == arrow, script below, content + // + // buffer.text_ + // buffer.rm + // etc. + // + // buffer.parenthesisLevel == int, starting at 0 + // buffer.sb == bool, space before + // buffer.beginsWithBond == bool + // + // These letters are also used as state names. + // + // Other states: + // 0 == begin of main part (arrow/operator unlikely) + // 1 == next entity + // 2 == next entity (arrow/operator unlikely) + // 3 == next atom + // c == macro + // + + /** @type {Buffer} */ + + var buffer = {}; + buffer['parenthesisLevel'] = 0; + input = input.replace(/\n/g, " "); + input = input.replace(/[\u2212\u2013\u2014\u2010]/g, "-"); + input = input.replace(/[\u2026]/g, "..."); // + // Looks through mhchemParser.transitions, to execute a matching action + // (recursive) + // + + var lastInput; + var watchdog = 10; + /** @type {ParserOutput[]} */ + + var output = []; + + while (true) { + if (lastInput !== input) { + watchdog = 10; + lastInput = input; + } else { + watchdog--; + } // + // Find actions in transition table + // + + + var machine = mhchemParser.stateMachines[stateMachine]; + var t = machine.transitions[state] || machine.transitions['*']; + + iterateTransitions: for (var i = 0; i < t.length; i++) { + var matches = mhchemParser.patterns.match_(t[i].pattern, input); + + if (matches) { + // + // Execute actions + // + var task = t[i].task; + + for (var iA = 0; iA < task.action_.length; iA++) { + var o; // + // Find and execute action + // + + if (machine.actions[task.action_[iA].type_]) { + o = machine.actions[task.action_[iA].type_](buffer, matches.match_, task.action_[iA].option); + } else if (mhchemParser.actions[task.action_[iA].type_]) { + o = mhchemParser.actions[task.action_[iA].type_](buffer, matches.match_, task.action_[iA].option); + } else { + throw ["MhchemBugA", "mhchem bug A. Please report. (" + task.action_[iA].type_ + ")"]; // Trying to use non-existing action + } // + // Add output + // + + + mhchemParser.concatArray(output, o); + } // + // Set next state, + // Shorten input, + // Continue with next character + // (= apply only one transition per position) + // + + + state = task.nextState || state; + + if (input.length > 0) { + if (!task.revisit) { + input = matches.remainder; + } + + if (!task.toContinue) { + break iterateTransitions; + } + } else { + return output; + } + } + } // + // Prevent infinite loop + // + + + if (watchdog <= 0) { + throw ["MhchemBugU", "mhchem bug U. Please report."]; // Unexpected character + } + } + }, + concatArray: function concatArray(a, b) { + if (b) { + if (Array.isArray(b)) { + for (var iB = 0; iB < b.length; iB++) { + a.push(b[iB]); + } + } else { + a.push(b); + } + } + }, + patterns: { + // + // Matching patterns + // either regexps or function that return null or {match_:"a", remainder:"bc"} + // + patterns: { + // property names must not look like integers ("2") for correct property traversal order, later on + 'empty': /^$/, + 'else': /^./, + 'else2': /^./, + 'space': /^\s/, + 'space A': /^\s(?=[A-Z\\$])/, + 'space$': /^\s$/, + 'a-z': /^[a-z]/, + 'x': /^x/, + 'x$': /^x$/, + 'i$': /^i$/, + 'letters': /^(?:[a-zA-Z\u03B1-\u03C9\u0391-\u03A9?@]|(?:\\(?:alpha|beta|gamma|delta|epsilon|zeta|eta|theta|iota|kappa|lambda|mu|nu|xi|omicron|pi|rho|sigma|tau|upsilon|phi|chi|psi|omega|Gamma|Delta|Theta|Lambda|Xi|Pi|Sigma|Upsilon|Phi|Psi|Omega)(?:\s+|\{\}|(?![a-zA-Z]))))+/, + '\\greek': /^\\(?:alpha|beta|gamma|delta|epsilon|zeta|eta|theta|iota|kappa|lambda|mu|nu|xi|omicron|pi|rho|sigma|tau|upsilon|phi|chi|psi|omega|Gamma|Delta|Theta|Lambda|Xi|Pi|Sigma|Upsilon|Phi|Psi|Omega)(?:\s+|\{\}|(?![a-zA-Z]))/, + 'one lowercase latin letter $': /^(?:([a-z])(?:$|[^a-zA-Z]))$/, + '$one lowercase latin letter$ $': /^\$(?:([a-z])(?:$|[^a-zA-Z]))\$$/, + 'one lowercase greek letter $': /^(?:\$?[\u03B1-\u03C9]\$?|\$?\\(?:alpha|beta|gamma|delta|epsilon|zeta|eta|theta|iota|kappa|lambda|mu|nu|xi|omicron|pi|rho|sigma|tau|upsilon|phi|chi|psi|omega)\s*\$?)(?:\s+|\{\}|(?![a-zA-Z]))$/, + 'digits': /^[0-9]+/, + '-9.,9': /^[+\-]?(?:[0-9]+(?:[,.][0-9]+)?|[0-9]*(?:\.[0-9]+))/, + '-9.,9 no missing 0': /^[+\-]?[0-9]+(?:[.,][0-9]+)?/, + '(-)(9.,9)(e)(99)': function e99(input) { + var m = input.match(/^(\+\-|\+\/\-|\+|\-|\\pm\s?)?([0-9]+(?:[,.][0-9]+)?|[0-9]*(?:\.[0-9]+))?(\((?:[0-9]+(?:[,.][0-9]+)?|[0-9]*(?:\.[0-9]+))\))?(?:([eE]|\s*(\*|x|\\times|\u00D7)\s*10\^)([+\-]?[0-9]+|\{[+\-]?[0-9]+\}))?/); + + if (m && m[0]) { + return { + match_: m.splice(1), + remainder: input.substr(m[0].length) + }; + } + + return null; + }, + '(-)(9)^(-9)': function _(input) { + var m = input.match(/^(\+\-|\+\/\-|\+|\-|\\pm\s?)?([0-9]+(?:[,.][0-9]+)?|[0-9]*(?:\.[0-9]+)?)\^([+\-]?[0-9]+|\{[+\-]?[0-9]+\})/); + + if (m && m[0]) { + return { + match_: m.splice(1), + remainder: input.substr(m[0].length) + }; + } + + return null; + }, + 'state of aggregation $': function stateOfAggregation$(input) { + // ... or crystal system + var a = mhchemParser.patterns.findObserveGroups(input, "", /^\([a-z]{1,3}(?=[\),])/, ")", ""); // (aq), (aq,$\infty$), (aq, sat) + + if (a && a.remainder.match(/^($|[\s,;\)\]\}])/)) { + return a; + } // AND end of 'phrase' + + + var m = input.match(/^(?:\((?:\\ca\s?)?\$[amothc]\$\))/); // OR crystal system ($o$) (\ca$c$) + + if (m) { + return { + match_: m[0], + remainder: input.substr(m[0].length) + }; + } + + return null; + }, + '_{(state of aggregation)}$': /^_\{(\([a-z]{1,3}\))\}/, + '{[(': /^(?:\\\{|\[|\()/, + ')]}': /^(?:\)|\]|\\\})/, + ', ': /^[,;]\s*/, + ',': /^[,;]/, + '.': /^[.]/, + '. ': /^([.\u22C5\u00B7\u2022])\s*/, + '...': /^\.\.\.(?=$|[^.])/, + '* ': /^([*])\s*/, + '^{(...)}': function _(input) { + return mhchemParser.patterns.findObserveGroups(input, "^{", "", "", "}"); + }, + '^($...$)': function $$(input) { + return mhchemParser.patterns.findObserveGroups(input, "^", "$", "$", ""); + }, + '^a': /^\^([0-9]+|[^\\_])/, + '^\\x{}{}': function x(input) { + return mhchemParser.patterns.findObserveGroups(input, "^", /^\\[a-zA-Z]+\{/, "}", "", "", "{", "}", "", true); + }, + '^\\x{}': function x(input) { + return mhchemParser.patterns.findObserveGroups(input, "^", /^\\[a-zA-Z]+\{/, "}", ""); + }, + '^\\x': /^\^(\\[a-zA-Z]+)\s*/, + '^(-1)': /^\^(-?\d+)/, + '\'': /^'/, + '_{(...)}': function _(input) { + return mhchemParser.patterns.findObserveGroups(input, "_{", "", "", "}"); + }, + '_($...$)': function _$$(input) { + return mhchemParser.patterns.findObserveGroups(input, "_", "$", "$", ""); + }, + '_9': /^_([+\-]?[0-9]+|[^\\])/, + '_\\x{}{}': function _X(input) { + return mhchemParser.patterns.findObserveGroups(input, "_", /^\\[a-zA-Z]+\{/, "}", "", "", "{", "}", "", true); + }, + '_\\x{}': function _X(input) { + return mhchemParser.patterns.findObserveGroups(input, "_", /^\\[a-zA-Z]+\{/, "}", ""); + }, + '_\\x': /^_(\\[a-zA-Z]+)\s*/, + '^_': /^(?:\^(?=_)|\_(?=\^)|[\^_]$)/, + '{}': /^\{\}/, + '{...}': function _(input) { + return mhchemParser.patterns.findObserveGroups(input, "", "{", "}", ""); + }, + '{(...)}': function _(input) { + return mhchemParser.patterns.findObserveGroups(input, "{", "", "", "}"); + }, + '$...$': function $$(input) { + return mhchemParser.patterns.findObserveGroups(input, "", "$", "$", ""); + }, + '${(...)}$': function $$(input) { + return mhchemParser.patterns.findObserveGroups(input, "${", "", "", "}$"); + }, + '$(...)$': function $$(input) { + return mhchemParser.patterns.findObserveGroups(input, "$", "", "", "$"); + }, + '=<>': /^[=<>]/, + '#': /^[#\u2261]/, + '+': /^\+/, + '-$': /^-(?=[\s_},;\]/]|$|\([a-z]+\))/, + // -space -, -; -] -/ -$ -state-of-aggregation + '-9': /^-(?=[0-9])/, + '- orbital overlap': /^-(?=(?:[spd]|sp)(?:$|[\s,;\)\]\}]))/, + '-': /^-/, + 'pm-operator': /^(?:\\pm|\$\\pm\$|\+-|\+\/-)/, + 'operator': /^(?:\+|(?:[\-=<>]|<<|>>|\\approx|\$\\approx\$)(?=\s|$|-?[0-9]))/, + 'arrowUpDown': /^(?:v|\(v\)|\^|\(\^\))(?=$|[\s,;\)\]\}])/, + '\\bond{(...)}': function bond(input) { + return mhchemParser.patterns.findObserveGroups(input, "\\bond{", "", "", "}"); + }, + '->': /^(?:<->|<-->|->|<-|<=>>|<<=>|<=>|[\u2192\u27F6\u21CC])/, + 'CMT': /^[CMT](?=\[)/, + '[(...)]': function _(input) { + return mhchemParser.patterns.findObserveGroups(input, "[", "", "", "]"); + }, + '1st-level escape': /^(&|\\\\|\\hline)\s*/, + '\\,': /^(?:\\[,\ ;:])/, + // \\x - but output no space before + '\\x{}{}': function x(input) { + return mhchemParser.patterns.findObserveGroups(input, "", /^\\[a-zA-Z]+\{/, "}", "", "", "{", "}", "", true); + }, + '\\x{}': function x(input) { + return mhchemParser.patterns.findObserveGroups(input, "", /^\\[a-zA-Z]+\{/, "}", ""); + }, + '\\ca': /^\\ca(?:\s+|(?![a-zA-Z]))/, + '\\x': /^(?:\\[a-zA-Z]+\s*|\\[_&{}%])/, + 'orbital': /^(?:[0-9]{1,2}[spdfgh]|[0-9]{0,2}sp)(?=$|[^a-zA-Z])/, + // only those with numbers in front, because the others will be formatted correctly anyway + 'others': /^[\/~|]/, + '\\frac{(...)}': function frac(input) { + return mhchemParser.patterns.findObserveGroups(input, "\\frac{", "", "", "}", "{", "", "", "}"); + }, + '\\overset{(...)}': function overset(input) { + return mhchemParser.patterns.findObserveGroups(input, "\\overset{", "", "", "}", "{", "", "", "}"); + }, + '\\underset{(...)}': function underset(input) { + return mhchemParser.patterns.findObserveGroups(input, "\\underset{", "", "", "}", "{", "", "", "}"); + }, + '\\underbrace{(...)}': function underbrace(input) { + return mhchemParser.patterns.findObserveGroups(input, "\\underbrace{", "", "", "}_", "{", "", "", "}"); + }, + '\\color{(...)}0': function color0(input) { + return mhchemParser.patterns.findObserveGroups(input, "\\color{", "", "", "}"); + }, + '\\color{(...)}{(...)}1': function color1(input) { + return mhchemParser.patterns.findObserveGroups(input, "\\color{", "", "", "}", "{", "", "", "}"); + }, + '\\color(...){(...)}2': function color2(input) { + return mhchemParser.patterns.findObserveGroups(input, "\\color", "\\", "", /^(?=\{)/, "{", "", "", "}"); + }, + '\\ce{(...)}': function ce(input) { + return mhchemParser.patterns.findObserveGroups(input, "\\ce{", "", "", "}"); + }, + 'oxidation$': /^(?:[+-][IVX]+|\\pm\s*0|\$\\pm\$\s*0)$/, + 'd-oxidation$': /^(?:[+-]?\s?[IVX]+|\\pm\s*0|\$\\pm\$\s*0)$/, + // 0 could be oxidation or charge + 'roman numeral': /^[IVX]+/, + '1/2$': /^[+\-]?(?:[0-9]+|\$[a-z]\$|[a-z])\/[0-9]+(?:\$[a-z]\$|[a-z])?$/, + 'amount': function amount(input) { + var match; // e.g. 2, 0.5, 1/2, -2, n/2, +; $a$ could be added later in parsing + + match = input.match(/^(?:(?:(?:\([+\-]?[0-9]+\/[0-9]+\)|[+\-]?(?:[0-9]+|\$[a-z]\$|[a-z])\/[0-9]+|[+\-]?[0-9]+[.,][0-9]+|[+\-]?\.[0-9]+|[+\-]?[0-9]+)(?:[a-z](?=\s*[A-Z]))?)|[+\-]?[a-z](?=\s*[A-Z])|\+(?!\s))/); + + if (match) { + return { + match_: match[0], + remainder: input.substr(match[0].length) + }; + } + + var a = mhchemParser.patterns.findObserveGroups(input, "", "$", "$", ""); + + if (a) { + // e.g. $2n-1$, $-$ + match = a.match_.match(/^\$(?:\(?[+\-]?(?:[0-9]*[a-z]?[+\-])?[0-9]*[a-z](?:[+\-][0-9]*[a-z]?)?\)?|\+|-)\$$/); + + if (match) { + return { + match_: match[0], + remainder: input.substr(match[0].length) + }; + } + } + + return null; + }, + 'amount2': function amount2(input) { + return this['amount'](input); + }, + '(KV letters),': /^(?:[A-Z][a-z]{0,2}|i)(?=,)/, + 'formula$': function formula$(input) { + if (input.match(/^\([a-z]+\)$/)) { + return null; + } // state of aggregation = no formula + + + var match = input.match(/^(?:[a-z]|(?:[0-9\ \+\-\,\.\(\)]+[a-z])+[0-9\ \+\-\,\.\(\)]*|(?:[a-z][0-9\ \+\-\,\.\(\)]+)+[a-z]?)$/); + + if (match) { + return { + match_: match[0], + remainder: input.substr(match[0].length) + }; + } + + return null; + }, + 'uprightEntities': /^(?:pH|pOH|pC|pK|iPr|iBu)(?=$|[^a-zA-Z])/, + '/': /^\s*(\/)\s*/, + '//': /^\s*(\/\/)\s*/, + '*': /^\s*[*.]\s*/ + }, + findObserveGroups: function findObserveGroups(input, begExcl, begIncl, endIncl, endExcl, beg2Excl, beg2Incl, end2Incl, end2Excl, combine) { + /** @type {{(input: string, pattern: string | RegExp): string | string[] | null;}} */ + var _match = function _match(input, pattern) { + if (typeof pattern === "string") { + if (input.indexOf(pattern) !== 0) { + return null; + } + + return pattern; + } else { + var match = input.match(pattern); + + if (!match) { + return null; + } + + return match[0]; + } + }; + /** @type {{(input: string, i: number, endChars: string | RegExp): {endMatchBegin: number, endMatchEnd: number} | null;}} */ + + + var _findObserveGroups = function _findObserveGroups(input, i, endChars) { + var braces = 0; + + while (i < input.length) { + var a = input.charAt(i); + + var match = _match(input.substr(i), endChars); + + if (match !== null && braces === 0) { + return { + endMatchBegin: i, + endMatchEnd: i + match.length + }; + } else if (a === "{") { + braces++; + } else if (a === "}") { + if (braces === 0) { + throw ["ExtraCloseMissingOpen", "Extra close brace or missing open brace"]; + } else { + braces--; + } + } + + i++; + } + + if (braces > 0) { + return null; + } + + return null; + }; + + var match = _match(input, begExcl); + + if (match === null) { + return null; + } + + input = input.substr(match.length); + match = _match(input, begIncl); + + if (match === null) { + return null; + } + + var e = _findObserveGroups(input, match.length, endIncl || endExcl); + + if (e === null) { + return null; + } + + var match1 = input.substring(0, endIncl ? e.endMatchEnd : e.endMatchBegin); + + if (!(beg2Excl || beg2Incl)) { + return { + match_: match1, + remainder: input.substr(e.endMatchEnd) + }; + } else { + var group2 = this.findObserveGroups(input.substr(e.endMatchEnd), beg2Excl, beg2Incl, end2Incl, end2Excl); + + if (group2 === null) { + return null; + } + /** @type {string[]} */ + + + var matchRet = [match1, group2.match_]; + return { + match_: combine ? matchRet.join("") : matchRet, + remainder: group2.remainder + }; + } + }, + // + // Matching function + // e.g. match("a", input) will look for the regexp called "a" and see if it matches + // returns null or {match_:"a", remainder:"bc"} + // + match_: function match_(m, input) { + var pattern = mhchemParser.patterns.patterns[m]; + + if (pattern === undefined) { + throw ["MhchemBugP", "mhchem bug P. Please report. (" + m + ")"]; // Trying to use non-existing pattern + } else if (typeof pattern === "function") { + return mhchemParser.patterns.patterns[m](input); // cannot use cached var pattern here, because some pattern functions need this===mhchemParser + } else { + // RegExp + var match = input.match(pattern); + + if (match) { + var mm; + + if (match[2]) { + mm = [match[1], match[2]]; + } else if (match[1]) { + mm = match[1]; + } else { + mm = match[0]; + } + + return { + match_: mm, + remainder: input.substr(match[0].length) + }; + } + + return null; + } + } + }, + // + // Generic state machine actions + // + actions: { + 'a=': function a(buffer, m) { + buffer.a = (buffer.a || "") + m; + }, + 'b=': function b(buffer, m) { + buffer.b = (buffer.b || "") + m; + }, + 'p=': function p(buffer, m) { + buffer.p = (buffer.p || "") + m; + }, + 'o=': function o(buffer, m) { + buffer.o = (buffer.o || "") + m; + }, + 'q=': function q(buffer, m) { + buffer.q = (buffer.q || "") + m; + }, + 'd=': function d(buffer, m) { + buffer.d = (buffer.d || "") + m; + }, + 'rm=': function rm(buffer, m) { + buffer.rm = (buffer.rm || "") + m; + }, + 'text=': function text(buffer, m) { + buffer.text_ = (buffer.text_ || "") + m; + }, + 'insert': function insert(buffer, m, a) { + return { + type_: a + }; + }, + 'insert+p1': function insertP1(buffer, m, a) { + return { + type_: a, + p1: m + }; + }, + 'insert+p1+p2': function insertP1P2(buffer, m, a) { + return { + type_: a, + p1: m[0], + p2: m[1] + }; + }, + 'copy': function copy(buffer, m) { + return m; + }, + 'rm': function rm(buffer, m) { + return { + type_: 'rm', + p1: m || "" + }; + }, + 'text': function text(buffer, m) { + return mhchemParser.go(m, 'text'); + }, + '{text}': function text(buffer, m) { + var ret = ["{"]; + mhchemParser.concatArray(ret, mhchemParser.go(m, 'text')); + ret.push("}"); + return ret; + }, + 'tex-math': function texMath(buffer, m) { + return mhchemParser.go(m, 'tex-math'); + }, + 'tex-math tight': function texMathTight(buffer, m) { + return mhchemParser.go(m, 'tex-math tight'); + }, + 'bond': function bond(buffer, m, k) { + return { + type_: 'bond', + kind_: k || m + }; + }, + 'color0-output': function color0Output(buffer, m) { + return { + type_: 'color0', + color: m[0] + }; + }, + 'ce': function ce(buffer, m) { + return mhchemParser.go(m); + }, + '1/2': function _(buffer, m) { + /** @type {ParserOutput[]} */ + var ret = []; + + if (m.match(/^[+\-]/)) { + ret.push(m.substr(0, 1)); + m = m.substr(1); + } + + var n = m.match(/^([0-9]+|\$[a-z]\$|[a-z])\/([0-9]+)(\$[a-z]\$|[a-z])?$/); + n[1] = n[1].replace(/\$/g, ""); + ret.push({ + type_: 'frac', + p1: n[1], + p2: n[2] + }); + + if (n[3]) { + n[3] = n[3].replace(/\$/g, ""); + ret.push({ + type_: 'tex-math', + p1: n[3] + }); + } + + return ret; + }, + '9,9': function _(buffer, m) { + return mhchemParser.go(m, '9,9'); + } + }, + // + // createTransitions + // convert { 'letter': { 'state': { action_: 'output' } } } to { 'state' => [ { pattern: 'letter', task: { action_: [{type_: 'output'}] } } ] } + // with expansion of 'a|b' to 'a' and 'b' (at 2 places) + // + createTransitions: function createTransitions(o) { + var pattern, state; + /** @type {string[]} */ + + var stateArray; + var i; // + // 1. Collect all states + // + + /** @type {Transitions} */ + + var transitions = {}; + + for (pattern in o) { + for (state in o[pattern]) { + stateArray = state.split("|"); + o[pattern][state].stateArray = stateArray; + + for (i = 0; i < stateArray.length; i++) { + transitions[stateArray[i]] = []; + } + } + } // + // 2. Fill states + // + + + for (pattern in o) { + for (state in o[pattern]) { + stateArray = o[pattern][state].stateArray || []; + + for (i = 0; i < stateArray.length; i++) { + // + // 2a. Normalize actions into array: 'text=' ==> [{type_:'text='}] + // (Note to myself: Resolving the function here would be problematic. It would need .bind (for *this*) and currying (for *option*).) + // + + /** @type {any} */ + var p = o[pattern][state]; + + if (p.action_) { + p.action_ = [].concat(p.action_); + + for (var k = 0; k < p.action_.length; k++) { + if (typeof p.action_[k] === "string") { + p.action_[k] = { + type_: p.action_[k] + }; + } + } + } else { + p.action_ = []; + } // + // 2.b Multi-insert + // + + + var patternArray = pattern.split("|"); + + for (var j = 0; j < patternArray.length; j++) { + if (stateArray[i] === '*') { + // insert into all + for (var t in transitions) { + transitions[t].push({ + pattern: patternArray[j], + task: p + }); + } + } else { + transitions[stateArray[i]].push({ + pattern: patternArray[j], + task: p + }); + } + } + } + } + } + + return transitions; + }, + stateMachines: {} +}; // +// Definition of state machines +// + +mhchemParser.stateMachines = { + // + // \ce state machines + // + //#region ce + 'ce': { + // main parser + transitions: mhchemParser.createTransitions({ + 'empty': { + '*': { + action_: 'output' + } + }, + 'else': { + '0|1|2': { + action_: 'beginsWithBond=false', + revisit: true, + toContinue: true + } + }, + 'oxidation$': { + '0': { + action_: 'oxidation-output' + } + }, + 'CMT': { + 'r': { + action_: 'rdt=', + nextState: 'rt' + }, + 'rd': { + action_: 'rqt=', + nextState: 'rdt' + } + }, + 'arrowUpDown': { + '0|1|2|as': { + action_: ['sb=false', 'output', 'operator'], + nextState: '1' + } + }, + 'uprightEntities': { + '0|1|2': { + action_: ['o=', 'output'], + nextState: '1' + } + }, + 'orbital': { + '0|1|2|3': { + action_: 'o=', + nextState: 'o' + } + }, + '->': { + '0|1|2|3': { + action_: 'r=', + nextState: 'r' + }, + 'a|as': { + action_: ['output', 'r='], + nextState: 'r' + }, + '*': { + action_: ['output', 'r='], + nextState: 'r' + } + }, + '+': { + 'o': { + action_: 'd= kv', + nextState: 'd' + }, + 'd|D': { + action_: 'd=', + nextState: 'd' + }, + 'q': { + action_: 'd=', + nextState: 'qd' + }, + 'qd|qD': { + action_: 'd=', + nextState: 'qd' + }, + 'dq': { + action_: ['output', 'd='], + nextState: 'd' + }, + '3': { + action_: ['sb=false', 'output', 'operator'], + nextState: '0' + } + }, + 'amount': { + '0|2': { + action_: 'a=', + nextState: 'a' + } + }, + 'pm-operator': { + '0|1|2|a|as': { + action_: ['sb=false', 'output', { + type_: 'operator', + option: '\\pm' + }], + nextState: '0' + } + }, + 'operator': { + '0|1|2|a|as': { + action_: ['sb=false', 'output', 'operator'], + nextState: '0' + } + }, + '-$': { + 'o|q': { + action_: ['charge or bond', 'output'], + nextState: 'qd' + }, + 'd': { + action_: 'd=', + nextState: 'd' + }, + 'D': { + action_: ['output', { + type_: 'bond', + option: "-" + }], + nextState: '3' + }, + 'q': { + action_: 'd=', + nextState: 'qd' + }, + 'qd': { + action_: 'd=', + nextState: 'qd' + }, + 'qD|dq': { + action_: ['output', { + type_: 'bond', + option: "-" + }], + nextState: '3' + } + }, + '-9': { + '3|o': { + action_: ['output', { + type_: 'insert', + option: 'hyphen' + }], + nextState: '3' + } + }, + '- orbital overlap': { + 'o': { + action_: ['output', { + type_: 'insert', + option: 'hyphen' + }], + nextState: '2' + }, + 'd': { + action_: ['output', { + type_: 'insert', + option: 'hyphen' + }], + nextState: '2' + } + }, + '-': { + '0|1|2': { + action_: [{ + type_: 'output', + option: 1 + }, 'beginsWithBond=true', { + type_: 'bond', + option: "-" + }], + nextState: '3' + }, + '3': { + action_: { + type_: 'bond', + option: "-" + } + }, + 'a': { + action_: ['output', { + type_: 'insert', + option: 'hyphen' + }], + nextState: '2' + }, + 'as': { + action_: [{ + type_: 'output', + option: 2 + }, { + type_: 'bond', + option: "-" + }], + nextState: '3' + }, + 'b': { + action_: 'b=' + }, + 'o': { + action_: { + type_: '- after o/d', + option: false + }, + nextState: '2' + }, + 'q': { + action_: { + type_: '- after o/d', + option: false + }, + nextState: '2' + }, + 'd|qd|dq': { + action_: { + type_: '- after o/d', + option: true + }, + nextState: '2' + }, + 'D|qD|p': { + action_: ['output', { + type_: 'bond', + option: "-" + }], + nextState: '3' + } + }, + 'amount2': { + '1|3': { + action_: 'a=', + nextState: 'a' + } + }, + 'letters': { + '0|1|2|3|a|as|b|p|bp|o': { + action_: 'o=', + nextState: 'o' + }, + 'q|dq': { + action_: ['output', 'o='], + nextState: 'o' + }, + 'd|D|qd|qD': { + action_: 'o after d', + nextState: 'o' + } + }, + 'digits': { + 'o': { + action_: 'q=', + nextState: 'q' + }, + 'd|D': { + action_: 'q=', + nextState: 'dq' + }, + 'q': { + action_: ['output', 'o='], + nextState: 'o' + }, + 'a': { + action_: 'o=', + nextState: 'o' + } + }, + 'space A': { + 'b|p|bp': {} + }, + 'space': { + 'a': { + nextState: 'as' + }, + '0': { + action_: 'sb=false' + }, + '1|2': { + action_: 'sb=true' + }, + 'r|rt|rd|rdt|rdq': { + action_: 'output', + nextState: '0' + }, + '*': { + action_: ['output', 'sb=true'], + nextState: '1' + } + }, + '1st-level escape': { + '1|2': { + action_: ['output', { + type_: 'insert+p1', + option: '1st-level escape' + }] + }, + '*': { + action_: ['output', { + type_: 'insert+p1', + option: '1st-level escape' + }], + nextState: '0' + } + }, + '[(...)]': { + 'r|rt': { + action_: 'rd=', + nextState: 'rd' + }, + 'rd|rdt': { + action_: 'rq=', + nextState: 'rdq' + } + }, + '...': { + 'o|d|D|dq|qd|qD': { + action_: ['output', { + type_: 'bond', + option: "..." + }], + nextState: '3' + }, + '*': { + action_: [{ + type_: 'output', + option: 1 + }, { + type_: 'insert', + option: 'ellipsis' + }], + nextState: '1' + } + }, + '. |* ': { + '*': { + action_: ['output', { + type_: 'insert', + option: 'addition compound' + }], + nextState: '1' + } + }, + 'state of aggregation $': { + '*': { + action_: ['output', 'state of aggregation'], + nextState: '1' + } + }, + '{[(': { + 'a|as|o': { + action_: ['o=', 'output', 'parenthesisLevel++'], + nextState: '2' + }, + '0|1|2|3': { + action_: ['o=', 'output', 'parenthesisLevel++'], + nextState: '2' + }, + '*': { + action_: ['output', 'o=', 'output', 'parenthesisLevel++'], + nextState: '2' + } + }, + ')]}': { + '0|1|2|3|b|p|bp|o': { + action_: ['o=', 'parenthesisLevel--'], + nextState: 'o' + }, + 'a|as|d|D|q|qd|qD|dq': { + action_: ['output', 'o=', 'parenthesisLevel--'], + nextState: 'o' + } + }, + ', ': { + '*': { + action_: ['output', 'comma'], + nextState: '0' + } + }, + '^_': { + // ^ and _ without a sensible argument + '*': {} + }, + '^{(...)}|^($...$)': { + '0|1|2|as': { + action_: 'b=', + nextState: 'b' + }, + 'p': { + action_: 'b=', + nextState: 'bp' + }, + '3|o': { + action_: 'd= kv', + nextState: 'D' + }, + 'q': { + action_: 'd=', + nextState: 'qD' + }, + 'd|D|qd|qD|dq': { + action_: ['output', 'd='], + nextState: 'D' + } + }, + '^a|^\\x{}{}|^\\x{}|^\\x|\'': { + '0|1|2|as': { + action_: 'b=', + nextState: 'b' + }, + 'p': { + action_: 'b=', + nextState: 'bp' + }, + '3|o': { + action_: 'd= kv', + nextState: 'd' + }, + 'q': { + action_: 'd=', + nextState: 'qd' + }, + 'd|qd|D|qD': { + action_: 'd=' + }, + 'dq': { + action_: ['output', 'd='], + nextState: 'd' + } + }, + '_{(state of aggregation)}$': { + 'd|D|q|qd|qD|dq': { + action_: ['output', 'q='], + nextState: 'q' + } + }, + '_{(...)}|_($...$)|_9|_\\x{}{}|_\\x{}|_\\x': { + '0|1|2|as': { + action_: 'p=', + nextState: 'p' + }, + 'b': { + action_: 'p=', + nextState: 'bp' + }, + '3|o': { + action_: 'q=', + nextState: 'q' + }, + 'd|D': { + action_: 'q=', + nextState: 'dq' + }, + 'q|qd|qD|dq': { + action_: ['output', 'q='], + nextState: 'q' + } + }, + '=<>': { + '0|1|2|3|a|as|o|q|d|D|qd|qD|dq': { + action_: [{ + type_: 'output', + option: 2 + }, 'bond'], + nextState: '3' + } + }, + '#': { + '0|1|2|3|a|as|o': { + action_: [{ + type_: 'output', + option: 2 + }, { + type_: 'bond', + option: "#" + }], + nextState: '3' + } + }, + '{}': { + '*': { + action_: { + type_: 'output', + option: 1 + }, + nextState: '1' + } + }, + '{...}': { + '0|1|2|3|a|as|b|p|bp': { + action_: 'o=', + nextState: 'o' + }, + 'o|d|D|q|qd|qD|dq': { + action_: ['output', 'o='], + nextState: 'o' + } + }, + '$...$': { + 'a': { + action_: 'a=' + }, + // 2$n$ + '0|1|2|3|as|b|p|bp|o': { + action_: 'o=', + nextState: 'o' + }, + // not 'amount' + 'as|o': { + action_: 'o=' + }, + 'q|d|D|qd|qD|dq': { + action_: ['output', 'o='], + nextState: 'o' + } + }, + '\\bond{(...)}': { + '*': { + action_: [{ + type_: 'output', + option: 2 + }, 'bond'], + nextState: "3" + } + }, + '\\frac{(...)}': { + '*': { + action_: [{ + type_: 'output', + option: 1 + }, 'frac-output'], + nextState: '3' + } + }, + '\\overset{(...)}': { + '*': { + action_: [{ + type_: 'output', + option: 2 + }, 'overset-output'], + nextState: '3' + } + }, + '\\underset{(...)}': { + '*': { + action_: [{ + type_: 'output', + option: 2 + }, 'underset-output'], + nextState: '3' + } + }, + '\\underbrace{(...)}': { + '*': { + action_: [{ + type_: 'output', + option: 2 + }, 'underbrace-output'], + nextState: '3' + } + }, + '\\color{(...)}{(...)}1|\\color(...){(...)}2': { + '*': { + action_: [{ + type_: 'output', + option: 2 + }, 'color-output'], + nextState: '3' + } + }, + '\\color{(...)}0': { + '*': { + action_: [{ + type_: 'output', + option: 2 + }, 'color0-output'] + } + }, + '\\ce{(...)}': { + '*': { + action_: [{ + type_: 'output', + option: 2 + }, 'ce'], + nextState: '3' + } + }, + '\\,': { + '*': { + action_: [{ + type_: 'output', + option: 1 + }, 'copy'], + nextState: '1' + } + }, + '\\x{}{}|\\x{}|\\x': { + '0|1|2|3|a|as|b|p|bp|o|c0': { + action_: ['o=', 'output'], + nextState: '3' + }, + '*': { + action_: ['output', 'o=', 'output'], + nextState: '3' + } + }, + 'others': { + '*': { + action_: [{ + type_: 'output', + option: 1 + }, 'copy'], + nextState: '3' + } + }, + 'else2': { + 'a': { + action_: 'a to o', + nextState: 'o', + revisit: true + }, + 'as': { + action_: ['output', 'sb=true'], + nextState: '1', + revisit: true + }, + 'r|rt|rd|rdt|rdq': { + action_: ['output'], + nextState: '0', + revisit: true + }, + '*': { + action_: ['output', 'copy'], + nextState: '3' + } + } + }), + actions: { + 'o after d': function oAfterD(buffer, m) { + var ret; + + if ((buffer.d || "").match(/^[0-9]+$/)) { + var tmp = buffer.d; + buffer.d = undefined; + ret = this['output'](buffer); + buffer.b = tmp; + } else { + ret = this['output'](buffer); + } + + mhchemParser.actions['o='](buffer, m); + return ret; + }, + 'd= kv': function dKv(buffer, m) { + buffer.d = m; + buffer.dType = 'kv'; + }, + 'charge or bond': function chargeOrBond(buffer, m) { + if (buffer['beginsWithBond']) { + /** @type {ParserOutput[]} */ + var ret = []; + mhchemParser.concatArray(ret, this['output'](buffer)); + mhchemParser.concatArray(ret, mhchemParser.actions['bond'](buffer, m, "-")); + return ret; + } else { + buffer.d = m; + } + }, + '- after o/d': function afterOD(buffer, m, isAfterD) { + var c1 = mhchemParser.patterns.match_('orbital', buffer.o || ""); + var c2 = mhchemParser.patterns.match_('one lowercase greek letter $', buffer.o || ""); + var c3 = mhchemParser.patterns.match_('one lowercase latin letter $', buffer.o || ""); + var c4 = mhchemParser.patterns.match_('$one lowercase latin letter$ $', buffer.o || ""); + var hyphenFollows = m === "-" && (c1 && c1.remainder === "" || c2 || c3 || c4); + + if (hyphenFollows && !buffer.a && !buffer.b && !buffer.p && !buffer.d && !buffer.q && !c1 && c3) { + buffer.o = '$' + buffer.o + '$'; + } + /** @type {ParserOutput[]} */ + + + var ret = []; + + if (hyphenFollows) { + mhchemParser.concatArray(ret, this['output'](buffer)); + ret.push({ + type_: 'hyphen' + }); + } else { + c1 = mhchemParser.patterns.match_('digits', buffer.d || ""); + + if (isAfterD && c1 && c1.remainder === '') { + mhchemParser.concatArray(ret, mhchemParser.actions['d='](buffer, m)); + mhchemParser.concatArray(ret, this['output'](buffer)); + } else { + mhchemParser.concatArray(ret, this['output'](buffer)); + mhchemParser.concatArray(ret, mhchemParser.actions['bond'](buffer, m, "-")); + } + } + + return ret; + }, + 'a to o': function aToO(buffer) { + buffer.o = buffer.a; + buffer.a = undefined; + }, + 'sb=true': function sbTrue(buffer) { + buffer.sb = true; + }, + 'sb=false': function sbFalse(buffer) { + buffer.sb = false; + }, + 'beginsWithBond=true': function beginsWithBondTrue(buffer) { + buffer['beginsWithBond'] = true; + }, + 'beginsWithBond=false': function beginsWithBondFalse(buffer) { + buffer['beginsWithBond'] = false; + }, + 'parenthesisLevel++': function parenthesisLevel(buffer) { + buffer['parenthesisLevel']++; + }, + 'parenthesisLevel--': function parenthesisLevel(buffer) { + buffer['parenthesisLevel']--; + }, + 'state of aggregation': function stateOfAggregation(buffer, m) { + return { + type_: 'state of aggregation', + p1: mhchemParser.go(m, 'o') + }; + }, + 'comma': function comma(buffer, m) { + var a = m.replace(/\s*$/, ''); + var withSpace = a !== m; + + if (withSpace && buffer['parenthesisLevel'] === 0) { + return { + type_: 'comma enumeration L', + p1: a + }; + } else { + return { + type_: 'comma enumeration M', + p1: a + }; + } + }, + 'output': function output(buffer, m, entityFollows) { + // entityFollows: + // undefined = if we have nothing else to output, also ignore the just read space (buffer.sb) + // 1 = an entity follows, never omit the space if there was one just read before (can only apply to state 1) + // 2 = 1 + the entity can have an amount, so output a\, instead of converting it to o (can only apply to states a|as) + + /** @type {ParserOutput | ParserOutput[]} */ + var ret; + + if (!buffer.r) { + ret = []; + + if (!buffer.a && !buffer.b && !buffer.p && !buffer.o && !buffer.q && !buffer.d && !entityFollows) ; else { + if (buffer.sb) { + ret.push({ + type_: 'entitySkip' + }); + } + + if (!buffer.o && !buffer.q && !buffer.d && !buffer.b && !buffer.p && entityFollows !== 2) { + buffer.o = buffer.a; + buffer.a = undefined; + } else if (!buffer.o && !buffer.q && !buffer.d && (buffer.b || buffer.p)) { + buffer.o = buffer.a; + buffer.d = buffer.b; + buffer.q = buffer.p; + buffer.a = buffer.b = buffer.p = undefined; + } else { + if (buffer.o && buffer.dType === 'kv' && mhchemParser.patterns.match_('d-oxidation$', buffer.d || "")) { + buffer.dType = 'oxidation'; + } else if (buffer.o && buffer.dType === 'kv' && !buffer.q) { + buffer.dType = undefined; + } + } + + ret.push({ + type_: 'chemfive', + a: mhchemParser.go(buffer.a, 'a'), + b: mhchemParser.go(buffer.b, 'bd'), + p: mhchemParser.go(buffer.p, 'pq'), + o: mhchemParser.go(buffer.o, 'o'), + q: mhchemParser.go(buffer.q, 'pq'), + d: mhchemParser.go(buffer.d, buffer.dType === 'oxidation' ? 'oxidation' : 'bd'), + dType: buffer.dType + }); + } + } else { + // r + + /** @type {ParserOutput[]} */ + var rd; + + if (buffer.rdt === 'M') { + rd = mhchemParser.go(buffer.rd, 'tex-math'); + } else if (buffer.rdt === 'T') { + rd = [{ + type_: 'text', + p1: buffer.rd || "" + }]; + } else { + rd = mhchemParser.go(buffer.rd); + } + /** @type {ParserOutput[]} */ + + + var rq; + + if (buffer.rqt === 'M') { + rq = mhchemParser.go(buffer.rq, 'tex-math'); + } else if (buffer.rqt === 'T') { + rq = [{ + type_: 'text', + p1: buffer.rq || "" + }]; + } else { + rq = mhchemParser.go(buffer.rq); + } + + ret = { + type_: 'arrow', + r: buffer.r, + rd: rd, + rq: rq + }; + } + + for (var p in buffer) { + if (p !== 'parenthesisLevel' && p !== 'beginsWithBond') { + delete buffer[p]; + } + } + + return ret; + }, + 'oxidation-output': function oxidationOutput(buffer, m) { + var ret = ["{"]; + mhchemParser.concatArray(ret, mhchemParser.go(m, 'oxidation')); + ret.push("}"); + return ret; + }, + 'frac-output': function fracOutput(buffer, m) { + return { + type_: 'frac-ce', + p1: mhchemParser.go(m[0]), + p2: mhchemParser.go(m[1]) + }; + }, + 'overset-output': function oversetOutput(buffer, m) { + return { + type_: 'overset', + p1: mhchemParser.go(m[0]), + p2: mhchemParser.go(m[1]) + }; + }, + 'underset-output': function undersetOutput(buffer, m) { + return { + type_: 'underset', + p1: mhchemParser.go(m[0]), + p2: mhchemParser.go(m[1]) + }; + }, + 'underbrace-output': function underbraceOutput(buffer, m) { + return { + type_: 'underbrace', + p1: mhchemParser.go(m[0]), + p2: mhchemParser.go(m[1]) + }; + }, + 'color-output': function colorOutput(buffer, m) { + return { + type_: 'color', + color1: m[0], + color2: mhchemParser.go(m[1]) + }; + }, + 'r=': function r(buffer, m) { + buffer.r = m; + }, + 'rdt=': function rdt(buffer, m) { + buffer.rdt = m; + }, + 'rd=': function rd(buffer, m) { + buffer.rd = m; + }, + 'rqt=': function rqt(buffer, m) { + buffer.rqt = m; + }, + 'rq=': function rq(buffer, m) { + buffer.rq = m; + }, + 'operator': function operator(buffer, m, p1) { + return { + type_: 'operator', + kind_: p1 || m + }; + } + } + }, + 'a': { + transitions: mhchemParser.createTransitions({ + 'empty': { + '*': {} + }, + '1/2$': { + '0': { + action_: '1/2' + } + }, + 'else': { + '0': { + nextState: '1', + revisit: true + } + }, + '$(...)$': { + '*': { + action_: 'tex-math tight', + nextState: '1' + } + }, + ',': { + '*': { + action_: { + type_: 'insert', + option: 'commaDecimal' + } + } + }, + 'else2': { + '*': { + action_: 'copy' + } + } + }), + actions: {} + }, + 'o': { + transitions: mhchemParser.createTransitions({ + 'empty': { + '*': {} + }, + '1/2$': { + '0': { + action_: '1/2' + } + }, + 'else': { + '0': { + nextState: '1', + revisit: true + } + }, + 'letters': { + '*': { + action_: 'rm' + } + }, + '\\ca': { + '*': { + action_: { + type_: 'insert', + option: 'circa' + } + } + }, + '\\x{}{}|\\x{}|\\x': { + '*': { + action_: 'copy' + } + }, + '${(...)}$|$(...)$': { + '*': { + action_: 'tex-math' + } + }, + '{(...)}': { + '*': { + action_: '{text}' + } + }, + 'else2': { + '*': { + action_: 'copy' + } + } + }), + actions: {} + }, + 'text': { + transitions: mhchemParser.createTransitions({ + 'empty': { + '*': { + action_: 'output' + } + }, + '{...}': { + '*': { + action_: 'text=' + } + }, + '${(...)}$|$(...)$': { + '*': { + action_: 'tex-math' + } + }, + '\\greek': { + '*': { + action_: ['output', 'rm'] + } + }, + '\\,|\\x{}{}|\\x{}|\\x': { + '*': { + action_: ['output', 'copy'] + } + }, + 'else': { + '*': { + action_: 'text=' + } + } + }), + actions: { + 'output': function output(buffer) { + if (buffer.text_) { + /** @type {ParserOutput} */ + var ret = { + type_: 'text', + p1: buffer.text_ + }; + + for (var p in buffer) { + delete buffer[p]; + } + + return ret; + } + } + } + }, + 'pq': { + transitions: mhchemParser.createTransitions({ + 'empty': { + '*': {} + }, + 'state of aggregation $': { + '*': { + action_: 'state of aggregation' + } + }, + 'i$': { + '0': { + nextState: '!f', + revisit: true + } + }, + '(KV letters),': { + '0': { + action_: 'rm', + nextState: '0' + } + }, + 'formula$': { + '0': { + nextState: 'f', + revisit: true + } + }, + '1/2$': { + '0': { + action_: '1/2' + } + }, + 'else': { + '0': { + nextState: '!f', + revisit: true + } + }, + '${(...)}$|$(...)$': { + '*': { + action_: 'tex-math' + } + }, + '{(...)}': { + '*': { + action_: 'text' + } + }, + 'a-z': { + 'f': { + action_: 'tex-math' + } + }, + 'letters': { + '*': { + action_: 'rm' + } + }, + '-9.,9': { + '*': { + action_: '9,9' + } + }, + ',': { + '*': { + action_: { + type_: 'insert+p1', + option: 'comma enumeration S' + } + } + }, + '\\color{(...)}{(...)}1|\\color(...){(...)}2': { + '*': { + action_: 'color-output' + } + }, + '\\color{(...)}0': { + '*': { + action_: 'color0-output' + } + }, + '\\ce{(...)}': { + '*': { + action_: 'ce' + } + }, + '\\,|\\x{}{}|\\x{}|\\x': { + '*': { + action_: 'copy' + } + }, + 'else2': { + '*': { + action_: 'copy' + } + } + }), + actions: { + 'state of aggregation': function stateOfAggregation(buffer, m) { + return { + type_: 'state of aggregation subscript', + p1: mhchemParser.go(m, 'o') + }; + }, + 'color-output': function colorOutput(buffer, m) { + return { + type_: 'color', + color1: m[0], + color2: mhchemParser.go(m[1], 'pq') + }; + } + } + }, + 'bd': { + transitions: mhchemParser.createTransitions({ + 'empty': { + '*': {} + }, + 'x$': { + '0': { + nextState: '!f', + revisit: true + } + }, + 'formula$': { + '0': { + nextState: 'f', + revisit: true + } + }, + 'else': { + '0': { + nextState: '!f', + revisit: true + } + }, + '-9.,9 no missing 0': { + '*': { + action_: '9,9' + } + }, + '.': { + '*': { + action_: { + type_: 'insert', + option: 'electron dot' + } + } + }, + 'a-z': { + 'f': { + action_: 'tex-math' + } + }, + 'x': { + '*': { + action_: { + type_: 'insert', + option: 'KV x' + } + } + }, + 'letters': { + '*': { + action_: 'rm' + } + }, + '\'': { + '*': { + action_: { + type_: 'insert', + option: 'prime' + } + } + }, + '${(...)}$|$(...)$': { + '*': { + action_: 'tex-math' + } + }, + '{(...)}': { + '*': { + action_: 'text' + } + }, + '\\color{(...)}{(...)}1|\\color(...){(...)}2': { + '*': { + action_: 'color-output' + } + }, + '\\color{(...)}0': { + '*': { + action_: 'color0-output' + } + }, + '\\ce{(...)}': { + '*': { + action_: 'ce' + } + }, + '\\,|\\x{}{}|\\x{}|\\x': { + '*': { + action_: 'copy' + } + }, + 'else2': { + '*': { + action_: 'copy' + } + } + }), + actions: { + 'color-output': function colorOutput(buffer, m) { + return { + type_: 'color', + color1: m[0], + color2: mhchemParser.go(m[1], 'bd') + }; + } + } + }, + 'oxidation': { + transitions: mhchemParser.createTransitions({ + 'empty': { + '*': {} + }, + 'roman numeral': { + '*': { + action_: 'roman-numeral' + } + }, + '${(...)}$|$(...)$': { + '*': { + action_: 'tex-math' + } + }, + 'else': { + '*': { + action_: 'copy' + } + } + }), + actions: { + 'roman-numeral': function romanNumeral(buffer, m) { + return { + type_: 'roman numeral', + p1: m || "" + }; + } + } + }, + 'tex-math': { + transitions: mhchemParser.createTransitions({ + 'empty': { + '*': { + action_: 'output' + } + }, + '\\ce{(...)}': { + '*': { + action_: ['output', 'ce'] + } + }, + '{...}|\\,|\\x{}{}|\\x{}|\\x': { + '*': { + action_: 'o=' + } + }, + 'else': { + '*': { + action_: 'o=' + } + } + }), + actions: { + 'output': function output(buffer) { + if (buffer.o) { + /** @type {ParserOutput} */ + var ret = { + type_: 'tex-math', + p1: buffer.o + }; + + for (var p in buffer) { + delete buffer[p]; + } + + return ret; + } + } + } + }, + 'tex-math tight': { + transitions: mhchemParser.createTransitions({ + 'empty': { + '*': { + action_: 'output' + } + }, + '\\ce{(...)}': { + '*': { + action_: ['output', 'ce'] + } + }, + '{...}|\\,|\\x{}{}|\\x{}|\\x': { + '*': { + action_: 'o=' + } + }, + '-|+': { + '*': { + action_: 'tight operator' + } + }, + 'else': { + '*': { + action_: 'o=' + } + } + }), + actions: { + 'tight operator': function tightOperator(buffer, m) { + buffer.o = (buffer.o || "") + "{" + m + "}"; + }, + 'output': function output(buffer) { + if (buffer.o) { + /** @type {ParserOutput} */ + var ret = { + type_: 'tex-math', + p1: buffer.o + }; + + for (var p in buffer) { + delete buffer[p]; + } + + return ret; + } + } + } + }, + '9,9': { + transitions: mhchemParser.createTransitions({ + 'empty': { + '*': {} + }, + ',': { + '*': { + action_: 'comma' + } + }, + 'else': { + '*': { + action_: 'copy' + } + } + }), + actions: { + 'comma': function comma() { + return { + type_: 'commaDecimal' + }; + } + } + }, + //#endregion + // + // \pu state machines + // + //#region pu + 'pu': { + transitions: mhchemParser.createTransitions({ + 'empty': { + '*': { + action_: 'output' + } + }, + 'space$': { + '*': { + action_: ['output', 'space'] + } + }, + '{[(|)]}': { + '0|a': { + action_: 'copy' + } + }, + '(-)(9)^(-9)': { + '0': { + action_: 'number^', + nextState: 'a' + } + }, + '(-)(9.,9)(e)(99)': { + '0': { + action_: 'enumber', + nextState: 'a' + } + }, + 'space': { + '0|a': {} + }, + 'pm-operator': { + '0|a': { + action_: { + type_: 'operator', + option: '\\pm' + }, + nextState: '0' + } + }, + 'operator': { + '0|a': { + action_: 'copy', + nextState: '0' + } + }, + '//': { + 'd': { + action_: 'o=', + nextState: '/' + } + }, + '/': { + 'd': { + action_: 'o=', + nextState: '/' + } + }, + '{...}|else': { + '0|d': { + action_: 'd=', + nextState: 'd' + }, + 'a': { + action_: ['space', 'd='], + nextState: 'd' + }, + '/|q': { + action_: 'q=', + nextState: 'q' + } + } + }), + actions: { + 'enumber': function enumber(buffer, m) { + /** @type {ParserOutput[]} */ + var ret = []; + + if (m[0] === "+-" || m[0] === "+/-") { + ret.push("\\pm "); + } else if (m[0]) { + ret.push(m[0]); + } + + if (m[1]) { + mhchemParser.concatArray(ret, mhchemParser.go(m[1], 'pu-9,9')); + + if (m[2]) { + if (m[2].match(/[,.]/)) { + mhchemParser.concatArray(ret, mhchemParser.go(m[2], 'pu-9,9')); + } else { + ret.push(m[2]); + } + } + + m[3] = m[4] || m[3]; + + if (m[3]) { + m[3] = m[3].trim(); + + if (m[3] === "e" || m[3].substr(0, 1) === "*") { + ret.push({ + type_: 'cdot' + }); + } else { + ret.push({ + type_: 'times' + }); + } + } + } + + if (m[3]) { + ret.push("10^{" + m[5] + "}"); + } + + return ret; + }, + 'number^': function number(buffer, m) { + /** @type {ParserOutput[]} */ + var ret = []; + + if (m[0] === "+-" || m[0] === "+/-") { + ret.push("\\pm "); + } else if (m[0]) { + ret.push(m[0]); + } + + mhchemParser.concatArray(ret, mhchemParser.go(m[1], 'pu-9,9')); + ret.push("^{" + m[2] + "}"); + return ret; + }, + 'operator': function operator(buffer, m, p1) { + return { + type_: 'operator', + kind_: p1 || m + }; + }, + 'space': function space() { + return { + type_: 'pu-space-1' + }; + }, + 'output': function output(buffer) { + /** @type {ParserOutput | ParserOutput[]} */ + var ret; + var md = mhchemParser.patterns.match_('{(...)}', buffer.d || ""); + + if (md && md.remainder === '') { + buffer.d = md.match_; + } + + var mq = mhchemParser.patterns.match_('{(...)}', buffer.q || ""); + + if (mq && mq.remainder === '') { + buffer.q = mq.match_; + } + + if (buffer.d) { + buffer.d = buffer.d.replace(/\u00B0C|\^oC|\^{o}C/g, "{}^{\\circ}C"); + buffer.d = buffer.d.replace(/\u00B0F|\^oF|\^{o}F/g, "{}^{\\circ}F"); + } + + if (buffer.q) { + // fraction + buffer.q = buffer.q.replace(/\u00B0C|\^oC|\^{o}C/g, "{}^{\\circ}C"); + buffer.q = buffer.q.replace(/\u00B0F|\^oF|\^{o}F/g, "{}^{\\circ}F"); + var b5 = { + d: mhchemParser.go(buffer.d, 'pu'), + q: mhchemParser.go(buffer.q, 'pu') + }; + + if (buffer.o === '//') { + ret = { + type_: 'pu-frac', + p1: b5.d, + p2: b5.q + }; + } else { + ret = b5.d; + + if (b5.d.length > 1 || b5.q.length > 1) { + ret.push({ + type_: ' / ' + }); + } else { + ret.push({ + type_: '/' + }); + } + + mhchemParser.concatArray(ret, b5.q); + } + } else { + // no fraction + ret = mhchemParser.go(buffer.d, 'pu-2'); + } + + for (var p in buffer) { + delete buffer[p]; + } + + return ret; + } + } + }, + 'pu-2': { + transitions: mhchemParser.createTransitions({ + 'empty': { + '*': { + action_: 'output' + } + }, + '*': { + '*': { + action_: ['output', 'cdot'], + nextState: '0' + } + }, + '\\x': { + '*': { + action_: 'rm=' + } + }, + 'space': { + '*': { + action_: ['output', 'space'], + nextState: '0' + } + }, + '^{(...)}|^(-1)': { + '1': { + action_: '^(-1)' + } + }, + '-9.,9': { + '0': { + action_: 'rm=', + nextState: '0' + }, + '1': { + action_: '^(-1)', + nextState: '0' + } + }, + '{...}|else': { + '*': { + action_: 'rm=', + nextState: '1' + } + } + }), + actions: { + 'cdot': function cdot() { + return { + type_: 'tight cdot' + }; + }, + '^(-1)': function _(buffer, m) { + buffer.rm += "^{" + m + "}"; + }, + 'space': function space() { + return { + type_: 'pu-space-2' + }; + }, + 'output': function output(buffer) { + /** @type {ParserOutput | ParserOutput[]} */ + var ret = []; + + if (buffer.rm) { + var mrm = mhchemParser.patterns.match_('{(...)}', buffer.rm || ""); + + if (mrm && mrm.remainder === '') { + ret = mhchemParser.go(mrm.match_, 'pu'); + } else { + ret = { + type_: 'rm', + p1: buffer.rm + }; + } + } + + for (var p in buffer) { + delete buffer[p]; + } + + return ret; + } + } + }, + 'pu-9,9': { + transitions: mhchemParser.createTransitions({ + 'empty': { + '0': { + action_: 'output-0' + }, + 'o': { + action_: 'output-o' + } + }, + ',': { + '0': { + action_: ['output-0', 'comma'], + nextState: 'o' + } + }, + '.': { + '0': { + action_: ['output-0', 'copy'], + nextState: 'o' + } + }, + 'else': { + '*': { + action_: 'text=' + } + } + }), + actions: { + 'comma': function comma() { + return { + type_: 'commaDecimal' + }; + }, + 'output-0': function output0(buffer) { + /** @type {ParserOutput[]} */ + var ret = []; + buffer.text_ = buffer.text_ || ""; + + if (buffer.text_.length > 4) { + var a = buffer.text_.length % 3; + + if (a === 0) { + a = 3; + } + + for (var i = buffer.text_.length - 3; i > 0; i -= 3) { + ret.push(buffer.text_.substr(i, 3)); + ret.push({ + type_: '1000 separator' + }); + } + + ret.push(buffer.text_.substr(0, a)); + ret.reverse(); + } else { + ret.push(buffer.text_); + } + + for (var p in buffer) { + delete buffer[p]; + } + + return ret; + }, + 'output-o': function outputO(buffer) { + /** @type {ParserOutput[]} */ + var ret = []; + buffer.text_ = buffer.text_ || ""; + + if (buffer.text_.length > 4) { + var a = buffer.text_.length - 3; + + for (var i = 0; i < a; i += 3) { + ret.push(buffer.text_.substr(i, 3)); + ret.push({ + type_: '1000 separator' + }); + } + + ret.push(buffer.text_.substr(i)); + } else { + ret.push(buffer.text_); + } + + for (var p in buffer) { + delete buffer[p]; + } + + return ret; + } + } //#endregion + + } +}; // +// texify: Take MhchemParser output and convert it to TeX +// + +/** @type {Texify} */ + +var texify = { + go: function go(input, isInner) { + // (recursive, max 4 levels) + if (!input) { + return ""; + } + + var res = ""; + var cee = false; + + for (var i = 0; i < input.length; i++) { + var inputi = input[i]; + + if (typeof inputi === "string") { + res += inputi; + } else { + res += texify._go2(inputi); + + if (inputi.type_ === '1st-level escape') { + cee = true; + } + } + } + + if (!isInner && !cee && res) { + res = "{" + res + "}"; + } + + return res; + }, + _goInner: function _goInner(input) { + if (!input) { + return input; + } + + return texify.go(input, true); + }, + _go2: function _go2(buf) { + /** @type {undefined | string} */ + var res; + + switch (buf.type_) { + case 'chemfive': + res = ""; + var b5 = { + a: texify._goInner(buf.a), + b: texify._goInner(buf.b), + p: texify._goInner(buf.p), + o: texify._goInner(buf.o), + q: texify._goInner(buf.q), + d: texify._goInner(buf.d) + }; // + // a + // + + if (b5.a) { + if (b5.a.match(/^[+\-]/)) { + b5.a = "{" + b5.a + "}"; + } + + res += b5.a + "\\,"; + } // + // b and p + // + + + if (b5.b || b5.p) { + res += "{\\vphantom{X}}"; + res += "^{\\hphantom{" + (b5.b || "") + "}}_{\\hphantom{" + (b5.p || "") + "}}"; + res += "{\\vphantom{X}}"; + res += "^{\\smash[t]{\\vphantom{2}}\\mathllap{" + (b5.b || "") + "}}"; + res += "_{\\vphantom{2}\\mathllap{\\smash[t]{" + (b5.p || "") + "}}}"; + } // + // o + // + + + if (b5.o) { + if (b5.o.match(/^[+\-]/)) { + b5.o = "{" + b5.o + "}"; + } + + res += b5.o; + } // + // q and d + // + + + if (buf.dType === 'kv') { + if (b5.d || b5.q) { + res += "{\\vphantom{X}}"; + } + + if (b5.d) { + res += "^{" + b5.d + "}"; + } + + if (b5.q) { + res += "_{\\smash[t]{" + b5.q + "}}"; + } + } else if (buf.dType === 'oxidation') { + if (b5.d) { + res += "{\\vphantom{X}}"; + res += "^{" + b5.d + "}"; + } + + if (b5.q) { + res += "{\\vphantom{X}}"; + res += "_{\\smash[t]{" + b5.q + "}}"; + } + } else { + if (b5.q) { + res += "{\\vphantom{X}}"; + res += "_{\\smash[t]{" + b5.q + "}}"; + } + + if (b5.d) { + res += "{\\vphantom{X}}"; + res += "^{" + b5.d + "}"; + } + } + + break; + + case 'rm': + res = "\\mathrm{" + buf.p1 + "}"; + break; + + case 'text': + if (buf.p1.match(/[\^_]/)) { + buf.p1 = buf.p1.replace(" ", "~").replace("-", "\\text{-}"); + res = "\\mathrm{" + buf.p1 + "}"; + } else { + res = "\\text{" + buf.p1 + "}"; + } + + break; + + case 'roman numeral': + res = "\\mathrm{" + buf.p1 + "}"; + break; + + case 'state of aggregation': + res = "\\mskip2mu " + texify._goInner(buf.p1); + break; + + case 'state of aggregation subscript': + res = "\\mskip1mu " + texify._goInner(buf.p1); + break; + + case 'bond': + res = texify._getBond(buf.kind_); + + if (!res) { + throw ["MhchemErrorBond", "mhchem Error. Unknown bond type (" + buf.kind_ + ")"]; + } + + break; + + case 'frac': + var c = "\\frac{" + buf.p1 + "}{" + buf.p2 + "}"; + res = "\\mathchoice{\\textstyle" + c + "}{" + c + "}{" + c + "}{" + c + "}"; + break; + + case 'pu-frac': + var d = "\\frac{" + texify._goInner(buf.p1) + "}{" + texify._goInner(buf.p2) + "}"; + res = "\\mathchoice{\\textstyle" + d + "}{" + d + "}{" + d + "}{" + d + "}"; + break; + + case 'tex-math': + res = buf.p1 + " "; + break; + + case 'frac-ce': + res = "\\frac{" + texify._goInner(buf.p1) + "}{" + texify._goInner(buf.p2) + "}"; + break; + + case 'overset': + res = "\\overset{" + texify._goInner(buf.p1) + "}{" + texify._goInner(buf.p2) + "}"; + break; + + case 'underset': + res = "\\underset{" + texify._goInner(buf.p1) + "}{" + texify._goInner(buf.p2) + "}"; + break; + + case 'underbrace': + res = "\\underbrace{" + texify._goInner(buf.p1) + "}_{" + texify._goInner(buf.p2) + "}"; + break; + + case 'color': + res = "{\\color{" + buf.color1 + "}{" + texify._goInner(buf.color2) + "}}"; + break; + + case 'color0': + res = "\\color{" + buf.color + "}"; + break; + + case 'arrow': + var b6 = { + rd: texify._goInner(buf.rd), + rq: texify._goInner(buf.rq) + }; + + var arrow = "\\x" + texify._getArrow(buf.r); + + if (b6.rq) { + arrow += "[{" + b6.rq + "}]"; + } + + if (b6.rd) { + arrow += "{" + b6.rd + "}"; + } else { + arrow += "{}"; + } + + res = arrow; + break; + + case 'operator': + res = texify._getOperator(buf.kind_); + break; + + case '1st-level escape': + res = buf.p1 + " "; // &, \\\\, \\hlin + + break; + + case 'space': + res = " "; + break; + + case 'entitySkip': + res = "~"; + break; + + case 'pu-space-1': + res = "~"; + break; + + case 'pu-space-2': + res = "\\mkern3mu "; + break; + + case '1000 separator': + res = "\\mkern2mu "; + break; + + case 'commaDecimal': + res = "{,}"; + break; + + case 'comma enumeration L': + res = "{" + buf.p1 + "}\\mkern6mu "; + break; + + case 'comma enumeration M': + res = "{" + buf.p1 + "}\\mkern3mu "; + break; + + case 'comma enumeration S': + res = "{" + buf.p1 + "}\\mkern1mu "; + break; + + case 'hyphen': + res = "\\text{-}"; + break; + + case 'addition compound': + res = "\\,{\\cdot}\\,"; + break; + + case 'electron dot': + res = "\\mkern1mu \\bullet\\mkern1mu "; + break; + + case 'KV x': + res = "{\\times}"; + break; + + case 'prime': + res = "\\prime "; + break; + + case 'cdot': + res = "\\cdot "; + break; + + case 'tight cdot': + res = "\\mkern1mu{\\cdot}\\mkern1mu "; + break; + + case 'times': + res = "\\times "; + break; + + case 'circa': + res = "{\\sim}"; + break; + + case '^': + res = "uparrow"; + break; + + case 'v': + res = "downarrow"; + break; + + case 'ellipsis': + res = "\\ldots "; + break; + + case '/': + res = "/"; + break; + + case ' / ': + res = "\\,/\\,"; + break; + + default: + throw ["MhchemBugT", "mhchem bug T. Please report."]; + // Missing texify rule or unknown MhchemParser output + } + return res; + }, + _getArrow: function _getArrow(a) { + switch (a) { + case "->": + return "rightarrow"; + + case "\u2192": + return "rightarrow"; + + case "\u27F6": + return "rightarrow"; + + case "<-": + return "leftarrow"; + + case "<->": + return "leftrightarrow"; + + case "<-->": + return "rightleftarrows"; + + case "<=>": + return "rightleftharpoons"; + + case "\u21CC": + return "rightleftharpoons"; + + case "<=>>": + return "rightequilibrium"; + + case "<<=>": + return "leftequilibrium"; + + default: + throw ["MhchemBugT", "mhchem bug T. Please report."]; + } + }, + _getBond: function _getBond(a) { + switch (a) { + case "-": + return "{-}"; + + case "1": + return "{-}"; + + case "=": + return "{=}"; + + case "2": + return "{=}"; + + case "#": + return "{\\equiv}"; + + case "3": + return "{\\equiv}"; + + case "~": + return "{\\tripledash}"; + + case "~-": + return "{\\mathrlap{\\raisebox{-.1em}{$-$}}\\raisebox{.1em}{$\\tripledash$}}"; + + case "~=": + return "{\\mathrlap{\\raisebox{-.2em}{$-$}}\\mathrlap{\\raisebox{.2em}{$\\tripledash$}}-}"; + + case "~--": + return "{\\mathrlap{\\raisebox{-.2em}{$-$}}\\mathrlap{\\raisebox{.2em}{$\\tripledash$}}-}"; + + case "-~-": + return "{\\mathrlap{\\raisebox{-.2em}{$-$}}\\mathrlap{\\raisebox{.2em}{$-$}}\\tripledash}"; + + case "...": + return "{{\\cdot}{\\cdot}{\\cdot}}"; + + case "....": + return "{{\\cdot}{\\cdot}{\\cdot}{\\cdot}}"; + + case "->": + return "{\\rightarrow}"; + + case "<-": + return "{\\leftarrow}"; + + case "<": + return "{<}"; + + case ">": + return "{>}"; + + default: + throw ["MhchemBugT", "mhchem bug T. Please report."]; + } + }, + _getOperator: function _getOperator(a) { + switch (a) { + case "+": + return " {}+{} "; + + case "-": + return " {}-{} "; + + case "=": + return " {}={} "; + + case "<": + return " {}<{} "; + + case ">": + return " {}>{} "; + + case "<<": + return " {}\\ll{} "; + + case ">>": + return " {}\\gg{} "; + + case "\\pm": + return " {}\\pm{} "; + + case "\\approx": + return " {}\\approx{} "; + + case "$\\approx$": + return " {}\\approx{} "; + + case "v": + return " \\downarrow{} "; + + case "(v)": + return " \\downarrow{} "; + + case "^": + return " \\uparrow{} "; + + case "(^)": + return " \\uparrow{} "; + + default: + throw ["MhchemBugT", "mhchem bug T. Please report."]; + } + } +}; // diff --git a/adoc/katex/contrib/render-a11y-string.js b/adoc/katex/contrib/render-a11y-string.js new file mode 100644 index 00000000..34643ec2 --- /dev/null +++ b/adoc/katex/contrib/render-a11y-string.js @@ -0,0 +1,858 @@ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(require("katex")); + else if(typeof define === 'function' && define.amd) + define(["katex"], factory); + else { + var a = typeof exports === 'object' ? factory(require("katex")) : factory(root["katex"]); + for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i]; + } +})((typeof self !== 'undefined' ? self : this), function(__WEBPACK_EXTERNAL_MODULE__0__) { +return /******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); +/******/ } +/******/ }; +/******/ +/******/ // define __esModule on exports +/******/ __webpack_require__.r = function(exports) { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ +/******/ // create a fake namespace object +/******/ // mode & 1: value is a module id, require it +/******/ // mode & 2: merge all properties of value into the ns +/******/ // mode & 4: return value when already ns object +/******/ // mode & 8|1: behave like require +/******/ __webpack_require__.t = function(value, mode) { +/******/ if(mode & 1) value = __webpack_require__(value); +/******/ if(mode & 8) return value; +/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; +/******/ var ns = Object.create(null); +/******/ __webpack_require__.r(ns); +/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); +/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); +/******/ return ns; +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; +/******/ +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = 1); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ (function(module, exports) { + +module.exports = __WEBPACK_EXTERNAL_MODULE__0__; + +/***/ }), +/* 1 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var katex__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(0); +/* harmony import */ var katex__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(katex__WEBPACK_IMPORTED_MODULE_0__); +/** + * renderA11yString returns a readable string. + * + * In some cases the string will have the proper semantic math + * meaning,: + * renderA11yString("\\frac{1}{2}"") + * -> "start fraction, 1, divided by, 2, end fraction" + * + * However, other cases do not: + * renderA11yString("f(x) = x^2") + * -> "f, left parenthesis, x, right parenthesis, equals, x, squared" + * + * The commas in the string aim to increase ease of understanding + * when read by a screenreader. + */ +// NOTE: since we're importing types here these files won't actually be +// included in the build. +// $FlowIgnore: we import the types directly anyways + +var stringMap = { + "(": "left parenthesis", + ")": "right parenthesis", + "[": "open bracket", + "]": "close bracket", + "\\{": "left brace", + "\\}": "right brace", + "\\lvert": "open vertical bar", + "\\rvert": "close vertical bar", + "|": "vertical bar", + "\\uparrow": "up arrow", + "\\Uparrow": "up arrow", + "\\downarrow": "down arrow", + "\\Downarrow": "down arrow", + "\\updownarrow": "up down arrow", + "\\leftarrow": "left arrow", + "\\Leftarrow": "left arrow", + "\\rightarrow": "right arrow", + "\\Rightarrow": "right arrow", + "\\langle": "open angle", + "\\rangle": "close angle", + "\\lfloor": "open floor", + "\\rfloor": "close floor", + "\\int": "integral", + "\\intop": "integral", + "\\lim": "limit", + "\\ln": "natural log", + "\\log": "log", + "\\sin": "sine", + "\\cos": "cosine", + "\\tan": "tangent", + "\\cot": "cotangent", + "\\sum": "sum", + "/": "slash", + ",": "comma", + ".": "point", + "-": "negative", + "+": "plus", + "~": "tilde", + ":": "colon", + "?": "question mark", + "'": "apostrophe", + "\\%": "percent", + " ": "space", + "\\ ": "space", + "\\$": "dollar sign", + "\\angle": "angle", + "\\degree": "degree", + "\\circ": "circle", + "\\vec": "vector", + "\\triangle": "triangle", + "\\pi": "pi", + "\\prime": "prime", + "\\infty": "infinity", + "\\alpha": "alpha", + "\\beta": "beta", + "\\gamma": "gamma", + "\\omega": "omega", + "\\theta": "theta", + "\\sigma": "sigma", + "\\lambda": "lambda", + "\\tau": "tau", + "\\Delta": "delta", + "\\delta": "delta", + "\\mu": "mu", + "\\rho": "rho", + "\\nabla": "del", + "\\ell": "ell", + "\\ldots": "dots", + // TODO: add entries for all accents + "\\hat": "hat", + "\\acute": "acute" +}; +var powerMap = { + "prime": "prime", + "degree": "degrees", + "circle": "degrees", + "2": "squared", + "3": "cubed" +}; +var openMap = { + "|": "open vertical bar", + ".": "" +}; +var closeMap = { + "|": "close vertical bar", + ".": "" +}; +var binMap = { + "+": "plus", + "-": "minus", + "\\pm": "plus minus", + "\\cdot": "dot", + "*": "times", + "/": "divided by", + "\\times": "times", + "\\div": "divided by", + "\\circ": "circle", + "\\bullet": "bullet" +}; +var relMap = { + "=": "equals", + "\\approx": "approximately equals", + "≠": "does not equal", + "\\geq": "is greater than or equal to", + "\\ge": "is greater than or equal to", + "\\leq": "is less than or equal to", + "\\le": "is less than or equal to", + ">": "is greater than", + "<": "is less than", + "\\leftarrow": "left arrow", + "\\Leftarrow": "left arrow", + "\\rightarrow": "right arrow", + "\\Rightarrow": "right arrow", + ":": "colon" +}; +var accentUnderMap = { + "\\underleftarrow": "left arrow", + "\\underrightarrow": "right arrow", + "\\underleftrightarrow": "left-right arrow", + "\\undergroup": "group", + "\\underlinesegment": "line segment", + "\\utilde": "tilde" +}; + +var buildString = function buildString(str, type, a11yStrings) { + if (!str) { + return; + } + + var ret; + + if (type === "open") { + ret = str in openMap ? openMap[str] : stringMap[str] || str; + } else if (type === "close") { + ret = str in closeMap ? closeMap[str] : stringMap[str] || str; + } else if (type === "bin") { + ret = binMap[str] || str; + } else if (type === "rel") { + ret = relMap[str] || str; + } else { + ret = stringMap[str] || str; + } // If the text to add is a number and there is already a string + // in the list and the last string is a number then we should + // combine them into a single number + + + if (/^\d+$/.test(ret) && a11yStrings.length > 0 && // TODO(kevinb): check that the last item in a11yStrings is a string + // I think we might be able to drop the nested arrays, which would make + // this easier to type - $FlowFixMe + /^\d+$/.test(a11yStrings[a11yStrings.length - 1])) { + a11yStrings[a11yStrings.length - 1] += ret; + } else if (ret) { + a11yStrings.push(ret); + } +}; + +var buildRegion = function buildRegion(a11yStrings, callback) { + var regionStrings = []; + a11yStrings.push(regionStrings); + callback(regionStrings); +}; + +var handleObject = function handleObject(tree, a11yStrings, atomType) { + // Everything else is assumed to be an object... + switch (tree.type) { + case "accent": + { + buildRegion(a11yStrings, function (a11yStrings) { + buildA11yStrings(tree.base, a11yStrings, atomType); + a11yStrings.push("with"); + buildString(tree.label, "normal", a11yStrings); + a11yStrings.push("on top"); + }); + break; + } + + case "accentUnder": + { + buildRegion(a11yStrings, function (a11yStrings) { + buildA11yStrings(tree.base, a11yStrings, atomType); + a11yStrings.push("with"); + buildString(accentUnderMap[tree.label], "normal", a11yStrings); + a11yStrings.push("underneath"); + }); + break; + } + + case "accent-token": + { + // Used internally by accent symbols. + break; + } + + case "atom": + { + var text = tree.text; + + switch (tree.family) { + case "bin": + { + buildString(text, "bin", a11yStrings); + break; + } + + case "close": + { + buildString(text, "close", a11yStrings); + break; + } + // TODO(kevinb): figure out what should be done for inner + + case "inner": + { + buildString(tree.text, "inner", a11yStrings); + break; + } + + case "open": + { + buildString(text, "open", a11yStrings); + break; + } + + case "punct": + { + buildString(text, "punct", a11yStrings); + break; + } + + case "rel": + { + buildString(text, "rel", a11yStrings); + break; + } + + default: + { + tree.family; + throw new Error("\"" + tree.family + "\" is not a valid atom type"); + } + } + + break; + } + + case "color": + { + var color = tree.color.replace(/katex-/, ""); + buildRegion(a11yStrings, function (regionStrings) { + regionStrings.push("start color " + color); + buildA11yStrings(tree.body, regionStrings, atomType); + regionStrings.push("end color " + color); + }); + break; + } + + case "color-token": + { + // Used by \color, \colorbox, and \fcolorbox but not directly rendered. + // It's a leaf node and has no children so just break. + break; + } + + case "delimsizing": + { + if (tree.delim && tree.delim !== ".") { + buildString(tree.delim, "normal", a11yStrings); + } + + break; + } + + case "genfrac": + { + buildRegion(a11yStrings, function (regionStrings) { + // genfrac can have unbalanced delimiters + var leftDelim = tree.leftDelim, + rightDelim = tree.rightDelim; // NOTE: Not sure if this is a safe assumption + // hasBarLine true -> fraction, false -> binomial + + if (tree.hasBarLine) { + regionStrings.push("start fraction"); + leftDelim && buildString(leftDelim, "open", regionStrings); + buildA11yStrings(tree.numer, regionStrings, atomType); + regionStrings.push("divided by"); + buildA11yStrings(tree.denom, regionStrings, atomType); + rightDelim && buildString(rightDelim, "close", regionStrings); + regionStrings.push("end fraction"); + } else { + regionStrings.push("start binomial"); + leftDelim && buildString(leftDelim, "open", regionStrings); + buildA11yStrings(tree.numer, regionStrings, atomType); + regionStrings.push("over"); + buildA11yStrings(tree.denom, regionStrings, atomType); + rightDelim && buildString(rightDelim, "close", regionStrings); + regionStrings.push("end binomial"); + } + }); + break; + } + + case "kern": + { + // No op: we don't attempt to present kerning information + // to the screen reader. + break; + } + + case "leftright": + { + buildRegion(a11yStrings, function (regionStrings) { + buildString(tree.left, "open", regionStrings); + buildA11yStrings(tree.body, regionStrings, atomType); + buildString(tree.right, "close", regionStrings); + }); + break; + } + + case "leftright-right": + { + // TODO: double check that this is a no-op + break; + } + + case "lap": + { + buildA11yStrings(tree.body, a11yStrings, atomType); + break; + } + + case "mathord": + { + buildString(tree.text, "normal", a11yStrings); + break; + } + + case "op": + { + var body = tree.body, + name = tree.name; + + if (body) { + buildA11yStrings(body, a11yStrings, atomType); + } else if (name) { + buildString(name, "normal", a11yStrings); + } + + break; + } + + case "op-token": + { + // Used internally by operator symbols. + buildString(tree.text, atomType, a11yStrings); + break; + } + + case "ordgroup": + { + buildA11yStrings(tree.body, a11yStrings, atomType); + break; + } + + case "overline": + { + buildRegion(a11yStrings, function (a11yStrings) { + a11yStrings.push("start overline"); + buildA11yStrings(tree.body, a11yStrings, atomType); + a11yStrings.push("end overline"); + }); + break; + } + + case "phantom": + { + a11yStrings.push("empty space"); + break; + } + + case "raisebox": + { + buildA11yStrings(tree.body, a11yStrings, atomType); + break; + } + + case "rule": + { + a11yStrings.push("rectangle"); + break; + } + + case "sizing": + { + buildA11yStrings(tree.body, a11yStrings, atomType); + break; + } + + case "spacing": + { + a11yStrings.push("space"); + break; + } + + case "styling": + { + // We ignore the styling and just pass through the contents + buildA11yStrings(tree.body, a11yStrings, atomType); + break; + } + + case "sqrt": + { + buildRegion(a11yStrings, function (regionStrings) { + var body = tree.body, + index = tree.index; + + if (index) { + var indexString = flatten(buildA11yStrings(index, [], atomType)).join(","); + + if (indexString === "3") { + regionStrings.push("cube root of"); + buildA11yStrings(body, regionStrings, atomType); + regionStrings.push("end cube root"); + return; + } + + regionStrings.push("root"); + regionStrings.push("start index"); + buildA11yStrings(index, regionStrings, atomType); + regionStrings.push("end index"); + return; + } + + regionStrings.push("square root of"); + buildA11yStrings(body, regionStrings, atomType); + regionStrings.push("end square root"); + }); + break; + } + + case "supsub": + { + var base = tree.base, + sub = tree.sub, + sup = tree.sup; + var isLog = false; + + if (base) { + buildA11yStrings(base, a11yStrings, atomType); + isLog = base.type === "op" && base.name === "\\log"; + } + + if (sub) { + var regionName = isLog ? "base" : "subscript"; + buildRegion(a11yStrings, function (regionStrings) { + regionStrings.push("start " + regionName); + buildA11yStrings(sub, regionStrings, atomType); + regionStrings.push("end " + regionName); + }); + } + + if (sup) { + buildRegion(a11yStrings, function (regionStrings) { + var supString = flatten(buildA11yStrings(sup, [], atomType)).join(","); + + if (supString in powerMap) { + regionStrings.push(powerMap[supString]); + return; + } + + regionStrings.push("start superscript"); + buildA11yStrings(sup, regionStrings, atomType); + regionStrings.push("end superscript"); + }); + } + + break; + } + + case "text": + { + // TODO: handle other fonts + if (tree.font === "\\textbf") { + buildRegion(a11yStrings, function (regionStrings) { + regionStrings.push("start bold text"); + buildA11yStrings(tree.body, regionStrings, atomType); + regionStrings.push("end bold text"); + }); + break; + } + + buildRegion(a11yStrings, function (regionStrings) { + regionStrings.push("start text"); + buildA11yStrings(tree.body, regionStrings, atomType); + regionStrings.push("end text"); + }); + break; + } + + case "textord": + { + buildString(tree.text, atomType, a11yStrings); + break; + } + + case "smash": + { + buildA11yStrings(tree.body, a11yStrings, atomType); + break; + } + + case "enclose": + { + // TODO: create a map for these. + // TODO: differentiate between a body with a single atom, e.g. + // "cancel a" instead of "start cancel, a, end cancel" + if (/cancel/.test(tree.label)) { + buildRegion(a11yStrings, function (regionStrings) { + regionStrings.push("start cancel"); + buildA11yStrings(tree.body, regionStrings, atomType); + regionStrings.push("end cancel"); + }); + break; + } else if (/box/.test(tree.label)) { + buildRegion(a11yStrings, function (regionStrings) { + regionStrings.push("start box"); + buildA11yStrings(tree.body, regionStrings, atomType); + regionStrings.push("end box"); + }); + break; + } else if (/sout/.test(tree.label)) { + buildRegion(a11yStrings, function (regionStrings) { + regionStrings.push("start strikeout"); + buildA11yStrings(tree.body, regionStrings, atomType); + regionStrings.push("end strikeout"); + }); + break; + } + + throw new Error("KaTeX-a11y: enclose node with " + tree.label + " not supported yet"); + } + + case "vphantom": + { + throw new Error("KaTeX-a11y: vphantom not implemented yet"); + } + + case "hphantom": + { + throw new Error("KaTeX-a11y: hphantom not implemented yet"); + } + + case "operatorname": + { + buildA11yStrings(tree.body, a11yStrings, atomType); + break; + } + + case "array": + { + throw new Error("KaTeX-a11y: array not implemented yet"); + } + + case "raw": + { + throw new Error("KaTeX-a11y: raw not implemented yet"); + } + + case "size": + { + // Although there are nodes of type "size" in the parse tree, they have + // no semantic meaning and should be ignored. + break; + } + + case "url": + { + throw new Error("KaTeX-a11y: url not implemented yet"); + } + + case "tag": + { + throw new Error("KaTeX-a11y: tag not implemented yet"); + } + + case "verb": + { + buildString("start verbatim", "normal", a11yStrings); + buildString(tree.body, "normal", a11yStrings); + buildString("end verbatim", "normal", a11yStrings); + break; + } + + case "environment": + { + throw new Error("KaTeX-a11y: environment not implemented yet"); + } + + case "horizBrace": + { + buildString("start " + tree.label.slice(1), "normal", a11yStrings); + buildA11yStrings(tree.base, a11yStrings, atomType); + buildString("end " + tree.label.slice(1), "normal", a11yStrings); + break; + } + + case "infix": + { + // All infix nodes are replace with other nodes. + break; + } + + case "includegraphics": + { + throw new Error("KaTeX-a11y: includegraphics not implemented yet"); + } + + case "font": + { + // TODO: callout the start/end of specific fonts + // TODO: map \BBb{N} to "the naturals" or something like that + buildA11yStrings(tree.body, a11yStrings, atomType); + break; + } + + case "href": + { + throw new Error("KaTeX-a11y: href not implemented yet"); + } + + case "cr": + { + // This is used by environments. + throw new Error("KaTeX-a11y: cr not implemented yet"); + } + + case "underline": + { + buildRegion(a11yStrings, function (a11yStrings) { + a11yStrings.push("start underline"); + buildA11yStrings(tree.body, a11yStrings, atomType); + a11yStrings.push("end underline"); + }); + break; + } + + case "xArrow": + { + throw new Error("KaTeX-a11y: xArrow not implemented yet"); + } + + case "mclass": + { + // \neq and \ne are macros so we let "htmlmathml" render the mathmal + // side of things and extract the text from that. + var _atomType = tree.mclass.slice(1); // $FlowFixMe: drop the leading "m" from the values in mclass + + + buildA11yStrings(tree.body, a11yStrings, _atomType); + break; + } + + case "mathchoice": + { + // TODO: track which which style we're using, e.g. dispaly, text, etc. + // default to text style if even that may not be the correct style + buildA11yStrings(tree.text, a11yStrings, atomType); + break; + } + + case "htmlmathml": + { + buildA11yStrings(tree.mathml, a11yStrings, atomType); + break; + } + + case "middle": + { + buildString(tree.delim, atomType, a11yStrings); + break; + } + + default: + tree.type; + throw new Error("KaTeX a11y un-recognized type: " + tree.type); + } +}; + +var buildA11yStrings = function buildA11yStrings(tree, a11yStrings, atomType) { + if (a11yStrings === void 0) { + a11yStrings = []; + } + + if (tree instanceof Array) { + for (var i = 0; i < tree.length; i++) { + buildA11yStrings(tree[i], a11yStrings, atomType); + } + } else { + handleObject(tree, a11yStrings, atomType); + } + + return a11yStrings; +}; + +var flatten = function flatten(array) { + var result = []; + array.forEach(function (item) { + if (item instanceof Array) { + result = result.concat(flatten(item)); + } else { + result.push(item); + } + }); + return result; +}; + +var renderA11yString = function renderA11yString(text, settings) { + var tree = katex__WEBPACK_IMPORTED_MODULE_0___default.a.__parse(text, settings); + + var a11yStrings = buildA11yStrings(tree, [], "normal"); + return flatten(a11yStrings).join(", "); +}; + +/* harmony default export */ __webpack_exports__["default"] = (renderA11yString); + +/***/ }) +/******/ ])["default"]; +}); \ No newline at end of file diff --git a/adoc/katex/contrib/render-a11y-string.min.js b/adoc/katex/contrib/render-a11y-string.min.js new file mode 100644 index 00000000..0dcac271 --- /dev/null +++ b/adoc/katex/contrib/render-a11y-string.min.js @@ -0,0 +1 @@ +!function(e,r){if("object"==typeof exports&&"object"==typeof module)module.exports=r(require("katex"));else if("function"==typeof define&&define.amd)define(["katex"],r);else{var t="object"==typeof exports?r(require("katex")):r(e.katex);for(var a in t)("object"==typeof exports?exports:e)[a]=t[a]}}("undefined"!=typeof self?self:this,function(e){return function(e){var r={};function t(a){if(r[a])return r[a].exports;var o=r[a]={i:a,l:!1,exports:{}};return e[a].call(o.exports,o,o.exports,t),o.l=!0,o.exports}return t.m=e,t.c=r,t.d=function(e,r,a){t.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:a})},t.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t.t=function(e,r){if(1&r&&(e=t(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var a=Object.create(null);if(t.r(a),Object.defineProperty(a,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var o in e)t.d(a,o,function(r){return e[r]}.bind(null,o));return a},t.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(r,"a",r),r},t.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},t.p="",t(t.s=1)}([function(r,t){r.exports=e},function(e,r,t){"use strict";t.r(r);var a=t(0),o=t.n(a),n={"(":"left parenthesis",")":"right parenthesis","[":"open bracket","]":"close bracket","\\{":"left brace","\\}":"right brace","\\lvert":"open vertical bar","\\rvert":"close vertical bar","|":"vertical bar","\\uparrow":"up arrow","\\Uparrow":"up arrow","\\downarrow":"down arrow","\\Downarrow":"down arrow","\\updownarrow":"up down arrow","\\leftarrow":"left arrow","\\Leftarrow":"left arrow","\\rightarrow":"right arrow","\\Rightarrow":"right arrow","\\langle":"open angle","\\rangle":"close angle","\\lfloor":"open floor","\\rfloor":"close floor","\\int":"integral","\\intop":"integral","\\lim":"limit","\\ln":"natural log","\\log":"log","\\sin":"sine","\\cos":"cosine","\\tan":"tangent","\\cot":"cotangent","\\sum":"sum","/":"slash",",":"comma",".":"point","-":"negative","+":"plus","~":"tilde",":":"colon","?":"question mark","'":"apostrophe","\\%":"percent"," ":"space","\\ ":"space","\\$":"dollar sign","\\angle":"angle","\\degree":"degree","\\circ":"circle","\\vec":"vector","\\triangle":"triangle","\\pi":"pi","\\prime":"prime","\\infty":"infinity","\\alpha":"alpha","\\beta":"beta","\\gamma":"gamma","\\omega":"omega","\\theta":"theta","\\sigma":"sigma","\\lambda":"lambda","\\tau":"tau","\\Delta":"delta","\\delta":"delta","\\mu":"mu","\\rho":"rho","\\nabla":"del","\\ell":"ell","\\ldots":"dots","\\hat":"hat","\\acute":"acute"},s={prime:"prime",degree:"degrees",circle:"degrees",2:"squared",3:"cubed"},i={"|":"open vertical bar",".":""},l={"|":"close vertical bar",".":""},c={"+":"plus","-":"minus","\\pm":"plus minus","\\cdot":"dot","*":"times","/":"divided by","\\times":"times","\\div":"divided by","\\circ":"circle","\\bullet":"bullet"},u={"=":"equals","\\approx":"approximately equals","\u2260":"does not equal","\\geq":"is greater than or equal to","\\ge":"is greater than or equal to","\\leq":"is less than or equal to","\\le":"is less than or equal to",">":"is greater than","<":"is less than","\\leftarrow":"left arrow","\\Leftarrow":"left arrow","\\rightarrow":"right arrow","\\Rightarrow":"right arrow",":":"colon"},p={"\\underleftarrow":"left arrow","\\underrightarrow":"right arrow","\\underleftrightarrow":"left-right arrow","\\undergroup":"group","\\underlinesegment":"line segment","\\utilde":"tilde"},d=function(e,r,t){var a;e&&(/^\d+$/.test(a="open"===r?e in i?i[e]:n[e]||e:"close"===r?e in l?l[e]:n[e]||e:"bin"===r?c[e]||e:"rel"===r?u[e]||e:n[e]||e)&&t.length>0&&/^\d+$/.test(t[t.length-1])?t[t.length-1]+=a:a&&t.push(a))},b=function(e,r){var t=[];e.push(t),r(t)},h=function(e,r,t){switch(e.type){case"accent":b(r,function(r){f(e.base,r,t),r.push("with"),d(e.label,"normal",r),r.push("on top")});break;case"accentUnder":b(r,function(r){f(e.base,r,t),r.push("with"),d(p[e.label],"normal",r),r.push("underneath")});break;case"accent-token":break;case"atom":var a=e.text;switch(e.family){case"bin":d(a,"bin",r);break;case"close":d(a,"close",r);break;case"inner":d(e.text,"inner",r);break;case"open":d(a,"open",r);break;case"punct":d(a,"punct",r);break;case"rel":d(a,"rel",r);break;default:throw e.family,new Error('"'+e.family+'" is not a valid atom type')}break;case"color":var o=e.color.replace(/katex-/,"");b(r,function(r){r.push("start color "+o),f(e.body,r,t),r.push("end color "+o)});break;case"color-token":break;case"delimsizing":e.delim&&"."!==e.delim&&d(e.delim,"normal",r);break;case"genfrac":b(r,function(r){var a=e.leftDelim,o=e.rightDelim;e.hasBarLine?(r.push("start fraction"),a&&d(a,"open",r),f(e.numer,r,t),r.push("divided by"),f(e.denom,r,t),o&&d(o,"close",r),r.push("end fraction")):(r.push("start binomial"),a&&d(a,"open",r),f(e.numer,r,t),r.push("over"),f(e.denom,r,t),o&&d(o,"close",r),r.push("end binomial"))});break;case"kern":break;case"leftright":b(r,function(r){d(e.left,"open",r),f(e.body,r,t),d(e.right,"close",r)});break;case"leftright-right":break;case"lap":f(e.body,r,t);break;case"mathord":d(e.text,"normal",r);break;case"op":var n=e.body,i=e.name;n?f(n,r,t):i&&d(i,"normal",r);break;case"op-token":d(e.text,t,r);break;case"ordgroup":f(e.body,r,t);break;case"overline":b(r,function(r){r.push("start overline"),f(e.body,r,t),r.push("end overline")});break;case"phantom":r.push("empty space");break;case"raisebox":f(e.body,r,t);break;case"rule":r.push("rectangle");break;case"sizing":f(e.body,r,t);break;case"spacing":r.push("space");break;case"styling":f(e.body,r,t);break;case"sqrt":b(r,function(r){var a=e.body,o=e.index;if(o)return"3"===m(f(o,[],t)).join(",")?(r.push("cube root of"),f(a,r,t),void r.push("end cube root")):(r.push("root"),r.push("start index"),f(o,r,t),void r.push("end index"));r.push("square root of"),f(a,r,t),r.push("end square root")});break;case"supsub":var l=e.base,c=e.sub,u=e.sup,h=!1;if(l&&(f(l,r,t),h="op"===l.type&&"\\log"===l.name),c){var y=h?"base":"subscript";b(r,function(e){e.push("start "+y),f(c,e,t),e.push("end "+y)})}u&&b(r,function(e){var r=m(f(u,[],t)).join(",");r in s?e.push(s[r]):(e.push("start superscript"),f(u,e,t),e.push("end superscript"))});break;case"text":if("\\textbf"===e.font){b(r,function(r){r.push("start bold text"),f(e.body,r,t),r.push("end bold text")});break}b(r,function(r){r.push("start text"),f(e.body,r,t),r.push("end text")});break;case"textord":d(e.text,t,r);break;case"smash":f(e.body,r,t);break;case"enclose":if(/cancel/.test(e.label)){b(r,function(r){r.push("start cancel"),f(e.body,r,t),r.push("end cancel")});break}if(/box/.test(e.label)){b(r,function(r){r.push("start box"),f(e.body,r,t),r.push("end box")});break}if(/sout/.test(e.label)){b(r,function(r){r.push("start strikeout"),f(e.body,r,t),r.push("end strikeout")});break}throw new Error("KaTeX-a11y: enclose node with "+e.label+" not supported yet");case"vphantom":throw new Error("KaTeX-a11y: vphantom not implemented yet");case"hphantom":throw new Error("KaTeX-a11y: hphantom not implemented yet");case"operatorname":f(e.body,r,t);break;case"array":throw new Error("KaTeX-a11y: array not implemented yet");case"raw":throw new Error("KaTeX-a11y: raw not implemented yet");case"size":break;case"url":throw new Error("KaTeX-a11y: url not implemented yet");case"tag":throw new Error("KaTeX-a11y: tag not implemented yet");case"verb":d("start verbatim","normal",r),d(e.body,"normal",r),d("end verbatim","normal",r);break;case"environment":throw new Error("KaTeX-a11y: environment not implemented yet");case"horizBrace":d("start "+e.label.slice(1),"normal",r),f(e.base,r,t),d("end "+e.label.slice(1),"normal",r);break;case"infix":break;case"includegraphics":throw new Error("KaTeX-a11y: includegraphics not implemented yet");case"font":f(e.body,r,t);break;case"href":throw new Error("KaTeX-a11y: href not implemented yet");case"cr":throw new Error("KaTeX-a11y: cr not implemented yet");case"underline":b(r,function(r){r.push("start underline"),f(e.body,r,t),r.push("end underline")});break;case"xArrow":throw new Error("KaTeX-a11y: xArrow not implemented yet");case"mclass":var g=e.mclass.slice(1);f(e.body,r,g);break;case"mathchoice":f(e.text,r,t);break;case"htmlmathml":f(e.mathml,r,t);break;case"middle":d(e.delim,t,r);break;default:throw e.type,new Error("KaTeX a11y un-recognized type: "+e.type)}},f=function e(r,t,a){if(void 0===t&&(t=[]),r instanceof Array)for(var o=0;o "start fraction, 1, divided by, 2, end fraction" + * + * However, other cases do not: + * renderA11yString("f(x) = x^2") + * -> "f, left parenthesis, x, right parenthesis, equals, x, squared" + * + * The commas in the string aim to increase ease of understanding + * when read by a screenreader. + */ +const stringMap = { + "(": "left parenthesis", + ")": "right parenthesis", + "[": "open bracket", + "]": "close bracket", + "\\{": "left brace", + "\\}": "right brace", + "\\lvert": "open vertical bar", + "\\rvert": "close vertical bar", + "|": "vertical bar", + "\\uparrow": "up arrow", + "\\Uparrow": "up arrow", + "\\downarrow": "down arrow", + "\\Downarrow": "down arrow", + "\\updownarrow": "up down arrow", + "\\leftarrow": "left arrow", + "\\Leftarrow": "left arrow", + "\\rightarrow": "right arrow", + "\\Rightarrow": "right arrow", + "\\langle": "open angle", + "\\rangle": "close angle", + "\\lfloor": "open floor", + "\\rfloor": "close floor", + "\\int": "integral", + "\\intop": "integral", + "\\lim": "limit", + "\\ln": "natural log", + "\\log": "log", + "\\sin": "sine", + "\\cos": "cosine", + "\\tan": "tangent", + "\\cot": "cotangent", + "\\sum": "sum", + "/": "slash", + ",": "comma", + ".": "point", + "-": "negative", + "+": "plus", + "~": "tilde", + ":": "colon", + "?": "question mark", + "'": "apostrophe", + "\\%": "percent", + " ": "space", + "\\ ": "space", + "\\$": "dollar sign", + "\\angle": "angle", + "\\degree": "degree", + "\\circ": "circle", + "\\vec": "vector", + "\\triangle": "triangle", + "\\pi": "pi", + "\\prime": "prime", + "\\infty": "infinity", + "\\alpha": "alpha", + "\\beta": "beta", + "\\gamma": "gamma", + "\\omega": "omega", + "\\theta": "theta", + "\\sigma": "sigma", + "\\lambda": "lambda", + "\\tau": "tau", + "\\Delta": "delta", + "\\delta": "delta", + "\\mu": "mu", + "\\rho": "rho", + "\\nabla": "del", + "\\ell": "ell", + "\\ldots": "dots", + // TODO: add entries for all accents + "\\hat": "hat", + "\\acute": "acute" +}; +const powerMap = { + "prime": "prime", + "degree": "degrees", + "circle": "degrees", + "2": "squared", + "3": "cubed" +}; +const openMap = { + "|": "open vertical bar", + ".": "" +}; +const closeMap = { + "|": "close vertical bar", + ".": "" +}; +const binMap = { + "+": "plus", + "-": "minus", + "\\pm": "plus minus", + "\\cdot": "dot", + "*": "times", + "/": "divided by", + "\\times": "times", + "\\div": "divided by", + "\\circ": "circle", + "\\bullet": "bullet" +}; +const relMap = { + "=": "equals", + "\\approx": "approximately equals", + "≠": "does not equal", + "\\geq": "is greater than or equal to", + "\\ge": "is greater than or equal to", + "\\leq": "is less than or equal to", + "\\le": "is less than or equal to", + ">": "is greater than", + "<": "is less than", + "\\leftarrow": "left arrow", + "\\Leftarrow": "left arrow", + "\\rightarrow": "right arrow", + "\\Rightarrow": "right arrow", + ":": "colon" +}; +const accentUnderMap = { + "\\underleftarrow": "left arrow", + "\\underrightarrow": "right arrow", + "\\underleftrightarrow": "left-right arrow", + "\\undergroup": "group", + "\\underlinesegment": "line segment", + "\\utilde": "tilde" +}; + +const buildString = (str, type, a11yStrings) => { + if (!str) { + return; + } + + let ret; + + if (type === "open") { + ret = str in openMap ? openMap[str] : stringMap[str] || str; + } else if (type === "close") { + ret = str in closeMap ? closeMap[str] : stringMap[str] || str; + } else if (type === "bin") { + ret = binMap[str] || str; + } else if (type === "rel") { + ret = relMap[str] || str; + } else { + ret = stringMap[str] || str; + } // If the text to add is a number and there is already a string + // in the list and the last string is a number then we should + // combine them into a single number + + + if (/^\d+$/.test(ret) && a11yStrings.length > 0 && // TODO(kevinb): check that the last item in a11yStrings is a string + // I think we might be able to drop the nested arrays, which would make + // this easier to type - $FlowFixMe + /^\d+$/.test(a11yStrings[a11yStrings.length - 1])) { + a11yStrings[a11yStrings.length - 1] += ret; + } else if (ret) { + a11yStrings.push(ret); + } +}; + +const buildRegion = (a11yStrings, callback) => { + const regionStrings = []; + a11yStrings.push(regionStrings); + callback(regionStrings); +}; + +const handleObject = (tree, a11yStrings, atomType) => { + // Everything else is assumed to be an object... + switch (tree.type) { + case "accent": + { + buildRegion(a11yStrings, a11yStrings => { + buildA11yStrings(tree.base, a11yStrings, atomType); + a11yStrings.push("with"); + buildString(tree.label, "normal", a11yStrings); + a11yStrings.push("on top"); + }); + break; + } + + case "accentUnder": + { + buildRegion(a11yStrings, a11yStrings => { + buildA11yStrings(tree.base, a11yStrings, atomType); + a11yStrings.push("with"); + buildString(accentUnderMap[tree.label], "normal", a11yStrings); + a11yStrings.push("underneath"); + }); + break; + } + + case "accent-token": + { + // Used internally by accent symbols. + break; + } + + case "atom": + { + const text = tree.text; + + switch (tree.family) { + case "bin": + { + buildString(text, "bin", a11yStrings); + break; + } + + case "close": + { + buildString(text, "close", a11yStrings); + break; + } + // TODO(kevinb): figure out what should be done for inner + + case "inner": + { + buildString(tree.text, "inner", a11yStrings); + break; + } + + case "open": + { + buildString(text, "open", a11yStrings); + break; + } + + case "punct": + { + buildString(text, "punct", a11yStrings); + break; + } + + case "rel": + { + buildString(text, "rel", a11yStrings); + break; + } + + default: + { + tree.family; + throw new Error(`"${tree.family}" is not a valid atom type`); + } + } + + break; + } + + case "color": + { + const color = tree.color.replace(/katex-/, ""); + buildRegion(a11yStrings, regionStrings => { + regionStrings.push("start color " + color); + buildA11yStrings(tree.body, regionStrings, atomType); + regionStrings.push("end color " + color); + }); + break; + } + + case "color-token": + { + // Used by \color, \colorbox, and \fcolorbox but not directly rendered. + // It's a leaf node and has no children so just break. + break; + } + + case "delimsizing": + { + if (tree.delim && tree.delim !== ".") { + buildString(tree.delim, "normal", a11yStrings); + } + + break; + } + + case "genfrac": + { + buildRegion(a11yStrings, regionStrings => { + // genfrac can have unbalanced delimiters + const leftDelim = tree.leftDelim, + rightDelim = tree.rightDelim; // NOTE: Not sure if this is a safe assumption + // hasBarLine true -> fraction, false -> binomial + + if (tree.hasBarLine) { + regionStrings.push("start fraction"); + leftDelim && buildString(leftDelim, "open", regionStrings); + buildA11yStrings(tree.numer, regionStrings, atomType); + regionStrings.push("divided by"); + buildA11yStrings(tree.denom, regionStrings, atomType); + rightDelim && buildString(rightDelim, "close", regionStrings); + regionStrings.push("end fraction"); + } else { + regionStrings.push("start binomial"); + leftDelim && buildString(leftDelim, "open", regionStrings); + buildA11yStrings(tree.numer, regionStrings, atomType); + regionStrings.push("over"); + buildA11yStrings(tree.denom, regionStrings, atomType); + rightDelim && buildString(rightDelim, "close", regionStrings); + regionStrings.push("end binomial"); + } + }); + break; + } + + case "kern": + { + // No op: we don't attempt to present kerning information + // to the screen reader. + break; + } + + case "leftright": + { + buildRegion(a11yStrings, regionStrings => { + buildString(tree.left, "open", regionStrings); + buildA11yStrings(tree.body, regionStrings, atomType); + buildString(tree.right, "close", regionStrings); + }); + break; + } + + case "leftright-right": + { + // TODO: double check that this is a no-op + break; + } + + case "lap": + { + buildA11yStrings(tree.body, a11yStrings, atomType); + break; + } + + case "mathord": + { + buildString(tree.text, "normal", a11yStrings); + break; + } + + case "op": + { + const body = tree.body, + name = tree.name; + + if (body) { + buildA11yStrings(body, a11yStrings, atomType); + } else if (name) { + buildString(name, "normal", a11yStrings); + } + + break; + } + + case "op-token": + { + // Used internally by operator symbols. + buildString(tree.text, atomType, a11yStrings); + break; + } + + case "ordgroup": + { + buildA11yStrings(tree.body, a11yStrings, atomType); + break; + } + + case "overline": + { + buildRegion(a11yStrings, function (a11yStrings) { + a11yStrings.push("start overline"); + buildA11yStrings(tree.body, a11yStrings, atomType); + a11yStrings.push("end overline"); + }); + break; + } + + case "phantom": + { + a11yStrings.push("empty space"); + break; + } + + case "raisebox": + { + buildA11yStrings(tree.body, a11yStrings, atomType); + break; + } + + case "rule": + { + a11yStrings.push("rectangle"); + break; + } + + case "sizing": + { + buildA11yStrings(tree.body, a11yStrings, atomType); + break; + } + + case "spacing": + { + a11yStrings.push("space"); + break; + } + + case "styling": + { + // We ignore the styling and just pass through the contents + buildA11yStrings(tree.body, a11yStrings, atomType); + break; + } + + case "sqrt": + { + buildRegion(a11yStrings, regionStrings => { + const body = tree.body, + index = tree.index; + + if (index) { + const indexString = flatten(buildA11yStrings(index, [], atomType)).join(","); + + if (indexString === "3") { + regionStrings.push("cube root of"); + buildA11yStrings(body, regionStrings, atomType); + regionStrings.push("end cube root"); + return; + } + + regionStrings.push("root"); + regionStrings.push("start index"); + buildA11yStrings(index, regionStrings, atomType); + regionStrings.push("end index"); + return; + } + + regionStrings.push("square root of"); + buildA11yStrings(body, regionStrings, atomType); + regionStrings.push("end square root"); + }); + break; + } + + case "supsub": + { + const base = tree.base, + sub = tree.sub, + sup = tree.sup; + let isLog = false; + + if (base) { + buildA11yStrings(base, a11yStrings, atomType); + isLog = base.type === "op" && base.name === "\\log"; + } + + if (sub) { + const regionName = isLog ? "base" : "subscript"; + buildRegion(a11yStrings, function (regionStrings) { + regionStrings.push(`start ${regionName}`); + buildA11yStrings(sub, regionStrings, atomType); + regionStrings.push(`end ${regionName}`); + }); + } + + if (sup) { + buildRegion(a11yStrings, function (regionStrings) { + const supString = flatten(buildA11yStrings(sup, [], atomType)).join(","); + + if (supString in powerMap) { + regionStrings.push(powerMap[supString]); + return; + } + + regionStrings.push("start superscript"); + buildA11yStrings(sup, regionStrings, atomType); + regionStrings.push("end superscript"); + }); + } + + break; + } + + case "text": + { + // TODO: handle other fonts + if (tree.font === "\\textbf") { + buildRegion(a11yStrings, function (regionStrings) { + regionStrings.push("start bold text"); + buildA11yStrings(tree.body, regionStrings, atomType); + regionStrings.push("end bold text"); + }); + break; + } + + buildRegion(a11yStrings, function (regionStrings) { + regionStrings.push("start text"); + buildA11yStrings(tree.body, regionStrings, atomType); + regionStrings.push("end text"); + }); + break; + } + + case "textord": + { + buildString(tree.text, atomType, a11yStrings); + break; + } + + case "smash": + { + buildA11yStrings(tree.body, a11yStrings, atomType); + break; + } + + case "enclose": + { + // TODO: create a map for these. + // TODO: differentiate between a body with a single atom, e.g. + // "cancel a" instead of "start cancel, a, end cancel" + if (/cancel/.test(tree.label)) { + buildRegion(a11yStrings, function (regionStrings) { + regionStrings.push("start cancel"); + buildA11yStrings(tree.body, regionStrings, atomType); + regionStrings.push("end cancel"); + }); + break; + } else if (/box/.test(tree.label)) { + buildRegion(a11yStrings, function (regionStrings) { + regionStrings.push("start box"); + buildA11yStrings(tree.body, regionStrings, atomType); + regionStrings.push("end box"); + }); + break; + } else if (/sout/.test(tree.label)) { + buildRegion(a11yStrings, function (regionStrings) { + regionStrings.push("start strikeout"); + buildA11yStrings(tree.body, regionStrings, atomType); + regionStrings.push("end strikeout"); + }); + break; + } + + throw new Error(`KaTeX-a11y: enclose node with ${tree.label} not supported yet`); + } + + case "vphantom": + { + throw new Error("KaTeX-a11y: vphantom not implemented yet"); + } + + case "hphantom": + { + throw new Error("KaTeX-a11y: hphantom not implemented yet"); + } + + case "operatorname": + { + buildA11yStrings(tree.body, a11yStrings, atomType); + break; + } + + case "array": + { + throw new Error("KaTeX-a11y: array not implemented yet"); + } + + case "raw": + { + throw new Error("KaTeX-a11y: raw not implemented yet"); + } + + case "size": + { + // Although there are nodes of type "size" in the parse tree, they have + // no semantic meaning and should be ignored. + break; + } + + case "url": + { + throw new Error("KaTeX-a11y: url not implemented yet"); + } + + case "tag": + { + throw new Error("KaTeX-a11y: tag not implemented yet"); + } + + case "verb": + { + buildString(`start verbatim`, "normal", a11yStrings); + buildString(tree.body, "normal", a11yStrings); + buildString(`end verbatim`, "normal", a11yStrings); + break; + } + + case "environment": + { + throw new Error("KaTeX-a11y: environment not implemented yet"); + } + + case "horizBrace": + { + buildString(`start ${tree.label.slice(1)}`, "normal", a11yStrings); + buildA11yStrings(tree.base, a11yStrings, atomType); + buildString(`end ${tree.label.slice(1)}`, "normal", a11yStrings); + break; + } + + case "infix": + { + // All infix nodes are replace with other nodes. + break; + } + + case "includegraphics": + { + throw new Error("KaTeX-a11y: includegraphics not implemented yet"); + } + + case "font": + { + // TODO: callout the start/end of specific fonts + // TODO: map \BBb{N} to "the naturals" or something like that + buildA11yStrings(tree.body, a11yStrings, atomType); + break; + } + + case "href": + { + throw new Error("KaTeX-a11y: href not implemented yet"); + } + + case "cr": + { + // This is used by environments. + throw new Error("KaTeX-a11y: cr not implemented yet"); + } + + case "underline": + { + buildRegion(a11yStrings, function (a11yStrings) { + a11yStrings.push("start underline"); + buildA11yStrings(tree.body, a11yStrings, atomType); + a11yStrings.push("end underline"); + }); + break; + } + + case "xArrow": + { + throw new Error("KaTeX-a11y: xArrow not implemented yet"); + } + + case "mclass": + { + // \neq and \ne are macros so we let "htmlmathml" render the mathmal + // side of things and extract the text from that. + const atomType = tree.mclass.slice(1); // $FlowFixMe: drop the leading "m" from the values in mclass + + buildA11yStrings(tree.body, a11yStrings, atomType); + break; + } + + case "mathchoice": + { + // TODO: track which which style we're using, e.g. dispaly, text, etc. + // default to text style if even that may not be the correct style + buildA11yStrings(tree.text, a11yStrings, atomType); + break; + } + + case "htmlmathml": + { + buildA11yStrings(tree.mathml, a11yStrings, atomType); + break; + } + + case "middle": + { + buildString(tree.delim, atomType, a11yStrings); + break; + } + + default: + tree.type; + throw new Error("KaTeX a11y un-recognized type: " + tree.type); + } +}; + +const buildA11yStrings = function buildA11yStrings(tree, a11yStrings, atomType) { + if (a11yStrings === void 0) { + a11yStrings = []; + } + + if (tree instanceof Array) { + for (let i = 0; i < tree.length; i++) { + buildA11yStrings(tree[i], a11yStrings, atomType); + } + } else { + handleObject(tree, a11yStrings, atomType); + } + + return a11yStrings; +}; + +const flatten = function flatten(array) { + let result = []; + array.forEach(function (item) { + if (item instanceof Array) { + result = result.concat(flatten(item)); + } else { + result.push(item); + } + }); + return result; +}; + +const renderA11yString = function renderA11yString(text, settings) { + const tree = katex.__parse(text, settings); + + const a11yStrings = buildA11yStrings(tree, [], "normal"); + return flatten(a11yStrings).join(", "); +}; + +export default renderA11yString; diff --git a/adoc/katex/fonts/KaTeX_AMS-Regular.ttf b/adoc/katex/fonts/KaTeX_AMS-Regular.ttf new file mode 100644 index 00000000..afcd2eb4 Binary files /dev/null and b/adoc/katex/fonts/KaTeX_AMS-Regular.ttf differ diff --git a/adoc/katex/fonts/KaTeX_AMS-Regular.woff b/adoc/katex/fonts/KaTeX_AMS-Regular.woff new file mode 100644 index 00000000..4f575152 Binary files /dev/null and b/adoc/katex/fonts/KaTeX_AMS-Regular.woff differ diff --git a/adoc/katex/fonts/KaTeX_AMS-Regular.woff2 b/adoc/katex/fonts/KaTeX_AMS-Regular.woff2 new file mode 100644 index 00000000..b982d6ea Binary files /dev/null and b/adoc/katex/fonts/KaTeX_AMS-Regular.woff2 differ diff --git a/adoc/katex/fonts/KaTeX_Caligraphic-Bold.ttf b/adoc/katex/fonts/KaTeX_Caligraphic-Bold.ttf new file mode 100644 index 00000000..f84148db Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Caligraphic-Bold.ttf differ diff --git a/adoc/katex/fonts/KaTeX_Caligraphic-Bold.woff b/adoc/katex/fonts/KaTeX_Caligraphic-Bold.woff new file mode 100644 index 00000000..ab56ab7f Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Caligraphic-Bold.woff differ diff --git a/adoc/katex/fonts/KaTeX_Caligraphic-Bold.woff2 b/adoc/katex/fonts/KaTeX_Caligraphic-Bold.woff2 new file mode 100644 index 00000000..710c2617 Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Caligraphic-Bold.woff2 differ diff --git a/adoc/katex/fonts/KaTeX_Caligraphic-Regular.ttf b/adoc/katex/fonts/KaTeX_Caligraphic-Regular.ttf new file mode 100644 index 00000000..97814db7 Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Caligraphic-Regular.ttf differ diff --git a/adoc/katex/fonts/KaTeX_Caligraphic-Regular.woff b/adoc/katex/fonts/KaTeX_Caligraphic-Regular.woff new file mode 100644 index 00000000..aec8a333 Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Caligraphic-Regular.woff differ diff --git a/adoc/katex/fonts/KaTeX_Caligraphic-Regular.woff2 b/adoc/katex/fonts/KaTeX_Caligraphic-Regular.woff2 new file mode 100644 index 00000000..ee5193d7 Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Caligraphic-Regular.woff2 differ diff --git a/adoc/katex/fonts/KaTeX_Fraktur-Bold.ttf b/adoc/katex/fonts/KaTeX_Fraktur-Bold.ttf new file mode 100644 index 00000000..483a7cdd Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Fraktur-Bold.ttf differ diff --git a/adoc/katex/fonts/KaTeX_Fraktur-Bold.woff b/adoc/katex/fonts/KaTeX_Fraktur-Bold.woff new file mode 100644 index 00000000..189fea5e Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Fraktur-Bold.woff differ diff --git a/adoc/katex/fonts/KaTeX_Fraktur-Bold.woff2 b/adoc/katex/fonts/KaTeX_Fraktur-Bold.woff2 new file mode 100644 index 00000000..dc3bd4c0 Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Fraktur-Bold.woff2 differ diff --git a/adoc/katex/fonts/KaTeX_Fraktur-Regular.ttf b/adoc/katex/fonts/KaTeX_Fraktur-Regular.ttf new file mode 100644 index 00000000..9aa5f674 Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Fraktur-Regular.ttf differ diff --git a/adoc/katex/fonts/KaTeX_Fraktur-Regular.woff b/adoc/katex/fonts/KaTeX_Fraktur-Regular.woff new file mode 100644 index 00000000..d01450e9 Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Fraktur-Regular.woff differ diff --git a/adoc/katex/fonts/KaTeX_Fraktur-Regular.woff2 b/adoc/katex/fonts/KaTeX_Fraktur-Regular.woff2 new file mode 100644 index 00000000..7eeba377 Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Fraktur-Regular.woff2 differ diff --git a/adoc/katex/fonts/KaTeX_Main-Bold.ttf b/adoc/katex/fonts/KaTeX_Main-Bold.ttf new file mode 100644 index 00000000..dc0185a1 Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Main-Bold.ttf differ diff --git a/adoc/katex/fonts/KaTeX_Main-Bold.woff b/adoc/katex/fonts/KaTeX_Main-Bold.woff new file mode 100644 index 00000000..acf48e66 Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Main-Bold.woff differ diff --git a/adoc/katex/fonts/KaTeX_Main-Bold.woff2 b/adoc/katex/fonts/KaTeX_Main-Bold.woff2 new file mode 100644 index 00000000..cf5ababf Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Main-Bold.woff2 differ diff --git a/adoc/katex/fonts/KaTeX_Main-BoldItalic.ttf b/adoc/katex/fonts/KaTeX_Main-BoldItalic.ttf new file mode 100644 index 00000000..4346f173 Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Main-BoldItalic.ttf differ diff --git a/adoc/katex/fonts/KaTeX_Main-BoldItalic.woff b/adoc/katex/fonts/KaTeX_Main-BoldItalic.woff new file mode 100644 index 00000000..d2cfe4e3 Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Main-BoldItalic.woff differ diff --git a/adoc/katex/fonts/KaTeX_Main-BoldItalic.woff2 b/adoc/katex/fonts/KaTeX_Main-BoldItalic.woff2 new file mode 100644 index 00000000..d0178f42 Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Main-BoldItalic.woff2 differ diff --git a/adoc/katex/fonts/KaTeX_Main-Italic.ttf b/adoc/katex/fonts/KaTeX_Main-Italic.ttf new file mode 100644 index 00000000..f2c3ebae Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Main-Italic.ttf differ diff --git a/adoc/katex/fonts/KaTeX_Main-Italic.woff b/adoc/katex/fonts/KaTeX_Main-Italic.woff new file mode 100644 index 00000000..1184295d Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Main-Italic.woff differ diff --git a/adoc/katex/fonts/KaTeX_Main-Italic.woff2 b/adoc/katex/fonts/KaTeX_Main-Italic.woff2 new file mode 100644 index 00000000..aa05e142 Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Main-Italic.woff2 differ diff --git a/adoc/katex/fonts/KaTeX_Main-Regular.ttf b/adoc/katex/fonts/KaTeX_Main-Regular.ttf new file mode 100644 index 00000000..8acb3654 Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Main-Regular.ttf differ diff --git a/adoc/katex/fonts/KaTeX_Main-Regular.woff b/adoc/katex/fonts/KaTeX_Main-Regular.woff new file mode 100644 index 00000000..9f8228fc Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Main-Regular.woff differ diff --git a/adoc/katex/fonts/KaTeX_Main-Regular.woff2 b/adoc/katex/fonts/KaTeX_Main-Regular.woff2 new file mode 100644 index 00000000..e3f71eb7 Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Main-Regular.woff2 differ diff --git a/adoc/katex/fonts/KaTeX_Math-BoldItalic.ttf b/adoc/katex/fonts/KaTeX_Math-BoldItalic.ttf new file mode 100644 index 00000000..a645df64 Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Math-BoldItalic.ttf differ diff --git a/adoc/katex/fonts/KaTeX_Math-BoldItalic.woff b/adoc/katex/fonts/KaTeX_Math-BoldItalic.woff new file mode 100644 index 00000000..87d4f223 Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Math-BoldItalic.woff differ diff --git a/adoc/katex/fonts/KaTeX_Math-BoldItalic.woff2 b/adoc/katex/fonts/KaTeX_Math-BoldItalic.woff2 new file mode 100644 index 00000000..83b49962 Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Math-BoldItalic.woff2 differ diff --git a/adoc/katex/fonts/KaTeX_Math-Italic.ttf b/adoc/katex/fonts/KaTeX_Math-Italic.ttf new file mode 100644 index 00000000..9c38359c Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Math-Italic.ttf differ diff --git a/adoc/katex/fonts/KaTeX_Math-Italic.woff b/adoc/katex/fonts/KaTeX_Math-Italic.woff new file mode 100644 index 00000000..959746ef Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Math-Italic.woff differ diff --git a/adoc/katex/fonts/KaTeX_Math-Italic.woff2 b/adoc/katex/fonts/KaTeX_Math-Italic.woff2 new file mode 100644 index 00000000..e3ea522a Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Math-Italic.woff2 differ diff --git a/adoc/katex/fonts/KaTeX_SansSerif-Bold.ttf b/adoc/katex/fonts/KaTeX_SansSerif-Bold.ttf new file mode 100644 index 00000000..ff108512 Binary files /dev/null and b/adoc/katex/fonts/KaTeX_SansSerif-Bold.ttf differ diff --git a/adoc/katex/fonts/KaTeX_SansSerif-Bold.woff b/adoc/katex/fonts/KaTeX_SansSerif-Bold.woff new file mode 100644 index 00000000..f0d6ea73 Binary files /dev/null and b/adoc/katex/fonts/KaTeX_SansSerif-Bold.woff differ diff --git a/adoc/katex/fonts/KaTeX_SansSerif-Bold.woff2 b/adoc/katex/fonts/KaTeX_SansSerif-Bold.woff2 new file mode 100644 index 00000000..4cf8f146 Binary files /dev/null and b/adoc/katex/fonts/KaTeX_SansSerif-Bold.woff2 differ diff --git a/adoc/katex/fonts/KaTeX_SansSerif-Italic.ttf b/adoc/katex/fonts/KaTeX_SansSerif-Italic.ttf new file mode 100644 index 00000000..3dd76713 Binary files /dev/null and b/adoc/katex/fonts/KaTeX_SansSerif-Italic.ttf differ diff --git a/adoc/katex/fonts/KaTeX_SansSerif-Italic.woff b/adoc/katex/fonts/KaTeX_SansSerif-Italic.woff new file mode 100644 index 00000000..9da0dfe3 Binary files /dev/null and b/adoc/katex/fonts/KaTeX_SansSerif-Italic.woff differ diff --git a/adoc/katex/fonts/KaTeX_SansSerif-Italic.woff2 b/adoc/katex/fonts/KaTeX_SansSerif-Italic.woff2 new file mode 100644 index 00000000..ce19ae03 Binary files /dev/null and b/adoc/katex/fonts/KaTeX_SansSerif-Italic.woff2 differ diff --git a/adoc/katex/fonts/KaTeX_SansSerif-Regular.ttf b/adoc/katex/fonts/KaTeX_SansSerif-Regular.ttf new file mode 100644 index 00000000..f117cd61 Binary files /dev/null and b/adoc/katex/fonts/KaTeX_SansSerif-Regular.ttf differ diff --git a/adoc/katex/fonts/KaTeX_SansSerif-Regular.woff b/adoc/katex/fonts/KaTeX_SansSerif-Regular.woff new file mode 100644 index 00000000..6ed98780 Binary files /dev/null and b/adoc/katex/fonts/KaTeX_SansSerif-Regular.woff differ diff --git a/adoc/katex/fonts/KaTeX_SansSerif-Regular.woff2 b/adoc/katex/fonts/KaTeX_SansSerif-Regular.woff2 new file mode 100644 index 00000000..27611491 Binary files /dev/null and b/adoc/katex/fonts/KaTeX_SansSerif-Regular.woff2 differ diff --git a/adoc/katex/fonts/KaTeX_Script-Regular.ttf b/adoc/katex/fonts/KaTeX_Script-Regular.ttf new file mode 100644 index 00000000..e6f34542 Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Script-Regular.ttf differ diff --git a/adoc/katex/fonts/KaTeX_Script-Regular.woff b/adoc/katex/fonts/KaTeX_Script-Regular.woff new file mode 100644 index 00000000..4a48e65f Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Script-Regular.woff differ diff --git a/adoc/katex/fonts/KaTeX_Script-Regular.woff2 b/adoc/katex/fonts/KaTeX_Script-Regular.woff2 new file mode 100644 index 00000000..b0aed195 Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Script-Regular.woff2 differ diff --git a/adoc/katex/fonts/KaTeX_Size1-Regular.ttf b/adoc/katex/fonts/KaTeX_Size1-Regular.ttf new file mode 100644 index 00000000..37faa0f9 Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Size1-Regular.ttf differ diff --git a/adoc/katex/fonts/KaTeX_Size1-Regular.woff b/adoc/katex/fonts/KaTeX_Size1-Regular.woff new file mode 100644 index 00000000..0832f7a4 Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Size1-Regular.woff differ diff --git a/adoc/katex/fonts/KaTeX_Size1-Regular.woff2 b/adoc/katex/fonts/KaTeX_Size1-Regular.woff2 new file mode 100644 index 00000000..483e7b66 Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Size1-Regular.woff2 differ diff --git a/adoc/katex/fonts/KaTeX_Size2-Regular.ttf b/adoc/katex/fonts/KaTeX_Size2-Regular.ttf new file mode 100644 index 00000000..cf326236 Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Size2-Regular.ttf differ diff --git a/adoc/katex/fonts/KaTeX_Size2-Regular.woff b/adoc/katex/fonts/KaTeX_Size2-Regular.woff new file mode 100644 index 00000000..14f6485a Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Size2-Regular.woff differ diff --git a/adoc/katex/fonts/KaTeX_Size2-Regular.woff2 b/adoc/katex/fonts/KaTeX_Size2-Regular.woff2 new file mode 100644 index 00000000..5ff70606 Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Size2-Regular.woff2 differ diff --git a/adoc/katex/fonts/KaTeX_Size3-Regular.ttf b/adoc/katex/fonts/KaTeX_Size3-Regular.ttf new file mode 100644 index 00000000..ff7e2b90 Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Size3-Regular.ttf differ diff --git a/adoc/katex/fonts/KaTeX_Size3-Regular.woff b/adoc/katex/fonts/KaTeX_Size3-Regular.woff new file mode 100644 index 00000000..d3626cef Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Size3-Regular.woff differ diff --git a/adoc/katex/fonts/KaTeX_Size3-Regular.woff2 b/adoc/katex/fonts/KaTeX_Size3-Regular.woff2 new file mode 100644 index 00000000..e45ca49d Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Size3-Regular.woff2 differ diff --git a/adoc/katex/fonts/KaTeX_Size4-Regular.ttf b/adoc/katex/fonts/KaTeX_Size4-Regular.ttf new file mode 100644 index 00000000..3034091c Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Size4-Regular.ttf differ diff --git a/adoc/katex/fonts/KaTeX_Size4-Regular.woff b/adoc/katex/fonts/KaTeX_Size4-Regular.woff new file mode 100644 index 00000000..93c57a6f Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Size4-Regular.woff differ diff --git a/adoc/katex/fonts/KaTeX_Size4-Regular.woff2 b/adoc/katex/fonts/KaTeX_Size4-Regular.woff2 new file mode 100644 index 00000000..53b65afc Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Size4-Regular.woff2 differ diff --git a/adoc/katex/fonts/KaTeX_Typewriter-Regular.ttf b/adoc/katex/fonts/KaTeX_Typewriter-Regular.ttf new file mode 100644 index 00000000..2fd85294 Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Typewriter-Regular.ttf differ diff --git a/adoc/katex/fonts/KaTeX_Typewriter-Regular.woff b/adoc/katex/fonts/KaTeX_Typewriter-Regular.woff new file mode 100644 index 00000000..e90fa2bc Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Typewriter-Regular.woff differ diff --git a/adoc/katex/fonts/KaTeX_Typewriter-Regular.woff2 b/adoc/katex/fonts/KaTeX_Typewriter-Regular.woff2 new file mode 100644 index 00000000..e40ab151 Binary files /dev/null and b/adoc/katex/fonts/KaTeX_Typewriter-Regular.woff2 differ diff --git a/adoc/katex/katex.css b/adoc/katex/katex.css new file mode 100644 index 00000000..7c97e926 --- /dev/null +++ b/adoc/katex/katex.css @@ -0,0 +1,1012 @@ +/* stylelint-disable font-family-no-missing-generic-family-keyword */ +@font-face { + font-family: 'KaTeX_AMS'; + src: url(fonts/KaTeX_AMS-Regular.woff2) format('woff2'), url(fonts/KaTeX_AMS-Regular.woff) format('woff'), url(fonts/KaTeX_AMS-Regular.ttf) format('truetype'); + font-weight: normal; + font-style: normal; +} +@font-face { + font-family: 'KaTeX_Caligraphic'; + src: url(fonts/KaTeX_Caligraphic-Bold.woff2) format('woff2'), url(fonts/KaTeX_Caligraphic-Bold.woff) format('woff'), url(fonts/KaTeX_Caligraphic-Bold.ttf) format('truetype'); + font-weight: bold; + font-style: normal; +} +@font-face { + font-family: 'KaTeX_Caligraphic'; + src: url(fonts/KaTeX_Caligraphic-Regular.woff2) format('woff2'), url(fonts/KaTeX_Caligraphic-Regular.woff) format('woff'), url(fonts/KaTeX_Caligraphic-Regular.ttf) format('truetype'); + font-weight: normal; + font-style: normal; +} +@font-face { + font-family: 'KaTeX_Fraktur'; + src: url(fonts/KaTeX_Fraktur-Bold.woff2) format('woff2'), url(fonts/KaTeX_Fraktur-Bold.woff) format('woff'), url(fonts/KaTeX_Fraktur-Bold.ttf) format('truetype'); + font-weight: bold; + font-style: normal; +} +@font-face { + font-family: 'KaTeX_Fraktur'; + src: url(fonts/KaTeX_Fraktur-Regular.woff2) format('woff2'), url(fonts/KaTeX_Fraktur-Regular.woff) format('woff'), url(fonts/KaTeX_Fraktur-Regular.ttf) format('truetype'); + font-weight: normal; + font-style: normal; +} +@font-face { + font-family: 'KaTeX_Main'; + src: url(fonts/KaTeX_Main-Bold.woff2) format('woff2'), url(fonts/KaTeX_Main-Bold.woff) format('woff'), url(fonts/KaTeX_Main-Bold.ttf) format('truetype'); + font-weight: bold; + font-style: normal; +} +@font-face { + font-family: 'KaTeX_Main'; + src: url(fonts/KaTeX_Main-BoldItalic.woff2) format('woff2'), url(fonts/KaTeX_Main-BoldItalic.woff) format('woff'), url(fonts/KaTeX_Main-BoldItalic.ttf) format('truetype'); + font-weight: bold; + font-style: italic; +} +@font-face { + font-family: 'KaTeX_Main'; + src: url(fonts/KaTeX_Main-Italic.woff2) format('woff2'), url(fonts/KaTeX_Main-Italic.woff) format('woff'), url(fonts/KaTeX_Main-Italic.ttf) format('truetype'); + font-weight: normal; + font-style: italic; +} +@font-face { + font-family: 'KaTeX_Main'; + src: url(fonts/KaTeX_Main-Regular.woff2) format('woff2'), url(fonts/KaTeX_Main-Regular.woff) format('woff'), url(fonts/KaTeX_Main-Regular.ttf) format('truetype'); + font-weight: normal; + font-style: normal; +} +@font-face { + font-family: 'KaTeX_Math'; + src: url(fonts/KaTeX_Math-BoldItalic.woff2) format('woff2'), url(fonts/KaTeX_Math-BoldItalic.woff) format('woff'), url(fonts/KaTeX_Math-BoldItalic.ttf) format('truetype'); + font-weight: bold; + font-style: italic; +} +@font-face { + font-family: 'KaTeX_Math'; + src: url(fonts/KaTeX_Math-Italic.woff2) format('woff2'), url(fonts/KaTeX_Math-Italic.woff) format('woff'), url(fonts/KaTeX_Math-Italic.ttf) format('truetype'); + font-weight: normal; + font-style: italic; +} +@font-face { + font-family: 'KaTeX_SansSerif'; + src: url(fonts/KaTeX_SansSerif-Bold.woff2) format('woff2'), url(fonts/KaTeX_SansSerif-Bold.woff) format('woff'), url(fonts/KaTeX_SansSerif-Bold.ttf) format('truetype'); + font-weight: bold; + font-style: normal; +} +@font-face { + font-family: 'KaTeX_SansSerif'; + src: url(fonts/KaTeX_SansSerif-Italic.woff2) format('woff2'), url(fonts/KaTeX_SansSerif-Italic.woff) format('woff'), url(fonts/KaTeX_SansSerif-Italic.ttf) format('truetype'); + font-weight: normal; + font-style: italic; +} +@font-face { + font-family: 'KaTeX_SansSerif'; + src: url(fonts/KaTeX_SansSerif-Regular.woff2) format('woff2'), url(fonts/KaTeX_SansSerif-Regular.woff) format('woff'), url(fonts/KaTeX_SansSerif-Regular.ttf) format('truetype'); + font-weight: normal; + font-style: normal; +} +@font-face { + font-family: 'KaTeX_Script'; + src: url(fonts/KaTeX_Script-Regular.woff2) format('woff2'), url(fonts/KaTeX_Script-Regular.woff) format('woff'), url(fonts/KaTeX_Script-Regular.ttf) format('truetype'); + font-weight: normal; + font-style: normal; +} +@font-face { + font-family: 'KaTeX_Size1'; + src: url(fonts/KaTeX_Size1-Regular.woff2) format('woff2'), url(fonts/KaTeX_Size1-Regular.woff) format('woff'), url(fonts/KaTeX_Size1-Regular.ttf) format('truetype'); + font-weight: normal; + font-style: normal; +} +@font-face { + font-family: 'KaTeX_Size2'; + src: url(fonts/KaTeX_Size2-Regular.woff2) format('woff2'), url(fonts/KaTeX_Size2-Regular.woff) format('woff'), url(fonts/KaTeX_Size2-Regular.ttf) format('truetype'); + font-weight: normal; + font-style: normal; +} +@font-face { + font-family: 'KaTeX_Size3'; + src: url(fonts/KaTeX_Size3-Regular.woff2) format('woff2'), url(fonts/KaTeX_Size3-Regular.woff) format('woff'), url(fonts/KaTeX_Size3-Regular.ttf) format('truetype'); + font-weight: normal; + font-style: normal; +} +@font-face { + font-family: 'KaTeX_Size4'; + src: url(fonts/KaTeX_Size4-Regular.woff2) format('woff2'), url(fonts/KaTeX_Size4-Regular.woff) format('woff'), url(fonts/KaTeX_Size4-Regular.ttf) format('truetype'); + font-weight: normal; + font-style: normal; +} +@font-face { + font-family: 'KaTeX_Typewriter'; + src: url(fonts/KaTeX_Typewriter-Regular.woff2) format('woff2'), url(fonts/KaTeX_Typewriter-Regular.woff) format('woff'), url(fonts/KaTeX_Typewriter-Regular.ttf) format('truetype'); + font-weight: normal; + font-style: normal; +} +.katex { + font: normal 1.21em KaTeX_Main, Times New Roman, serif; + line-height: 1.2; + text-indent: 0; + text-rendering: auto; +} +.katex * { + -ms-high-contrast-adjust: none !important; +} +.katex .katex-version::after { + content: "0.11.1"; +} +.katex .katex-mathml { + position: absolute; + clip: rect(1px, 1px, 1px, 1px); + padding: 0; + border: 0; + height: 1px; + width: 1px; + overflow: hidden; +} +.katex .katex-html { + /* \newline is an empty block at top level, between .base elements */ +} +.katex .katex-html > .newline { + display: block; +} +.katex .base { + position: relative; + display: inline-block; + white-space: nowrap; + width: min-content; +} +.katex .strut { + display: inline-block; +} +.katex .textbf { + font-weight: bold; +} +.katex .textit { + font-style: italic; +} +.katex .textrm { + font-family: KaTeX_Main; +} +.katex .textsf { + font-family: KaTeX_SansSerif; +} +.katex .texttt { + font-family: KaTeX_Typewriter; +} +.katex .mathdefault { + font-family: KaTeX_Math; + font-style: italic; +} +.katex .mathit { + font-family: KaTeX_Main; + font-style: italic; +} +.katex .mathrm { + font-style: normal; +} +.katex .mathbf { + font-family: KaTeX_Main; + font-weight: bold; +} +.katex .boldsymbol { + font-family: KaTeX_Math; + font-weight: bold; + font-style: italic; +} +.katex .amsrm { + font-family: KaTeX_AMS; +} +.katex .mathbb, +.katex .textbb { + font-family: KaTeX_AMS; +} +.katex .mathcal { + font-family: KaTeX_Caligraphic; +} +.katex .mathfrak, +.katex .textfrak { + font-family: KaTeX_Fraktur; +} +.katex .mathtt { + font-family: KaTeX_Typewriter; +} +.katex .mathscr, +.katex .textscr { + font-family: KaTeX_Script; +} +.katex .mathsf, +.katex .textsf { + font-family: KaTeX_SansSerif; +} +.katex .mathboldsf, +.katex .textboldsf { + font-family: KaTeX_SansSerif; + font-weight: bold; +} +.katex .mathitsf, +.katex .textitsf { + font-family: KaTeX_SansSerif; + font-style: italic; +} +.katex .mainrm { + font-family: KaTeX_Main; + font-style: normal; +} +.katex .vlist-t { + display: inline-table; + table-layout: fixed; +} +.katex .vlist-r { + display: table-row; +} +.katex .vlist { + display: table-cell; + vertical-align: bottom; + position: relative; +} +.katex .vlist > span { + display: block; + height: 0; + position: relative; +} +.katex .vlist > span > span { + display: inline-block; +} +.katex .vlist > span > .pstrut { + overflow: hidden; + width: 0; +} +.katex .vlist-t2 { + margin-right: -2px; +} +.katex .vlist-s { + display: table-cell; + vertical-align: bottom; + font-size: 1px; + width: 2px; + min-width: 2px; +} +.katex .msupsub { + text-align: left; +} +.katex .mfrac > span > span { + text-align: center; +} +.katex .mfrac .frac-line { + display: inline-block; + width: 100%; + border-bottom-style: solid; +} +.katex .mfrac .frac-line, +.katex .overline .overline-line, +.katex .underline .underline-line, +.katex .hline, +.katex .hdashline, +.katex .rule { + min-height: 1px; +} +.katex .mspace { + display: inline-block; +} +.katex .llap, +.katex .rlap, +.katex .clap { + width: 0; + position: relative; +} +.katex .llap > .inner, +.katex .rlap > .inner, +.katex .clap > .inner { + position: absolute; +} +.katex .llap > .fix, +.katex .rlap > .fix, +.katex .clap > .fix { + display: inline-block; +} +.katex .llap > .inner { + right: 0; +} +.katex .rlap > .inner, +.katex .clap > .inner { + left: 0; +} +.katex .clap > .inner > span { + margin-left: -50%; + margin-right: 50%; +} +.katex .rule { + display: inline-block; + border: solid 0; + position: relative; +} +.katex .overline .overline-line, +.katex .underline .underline-line, +.katex .hline { + display: inline-block; + width: 100%; + border-bottom-style: solid; +} +.katex .hdashline { + display: inline-block; + width: 100%; + border-bottom-style: dashed; +} +.katex .sqrt > .root { + margin-left: 0.27777778em; + margin-right: -0.55555556em; +} +.katex .sizing.reset-size1.size1, +.katex .fontsize-ensurer.reset-size1.size1 { + font-size: 1em; +} +.katex .sizing.reset-size1.size2, +.katex .fontsize-ensurer.reset-size1.size2 { + font-size: 1.2em; +} +.katex .sizing.reset-size1.size3, +.katex .fontsize-ensurer.reset-size1.size3 { + font-size: 1.4em; +} +.katex .sizing.reset-size1.size4, +.katex .fontsize-ensurer.reset-size1.size4 { + font-size: 1.6em; +} +.katex .sizing.reset-size1.size5, +.katex .fontsize-ensurer.reset-size1.size5 { + font-size: 1.8em; +} +.katex .sizing.reset-size1.size6, +.katex .fontsize-ensurer.reset-size1.size6 { + font-size: 2em; +} +.katex .sizing.reset-size1.size7, +.katex .fontsize-ensurer.reset-size1.size7 { + font-size: 2.4em; +} +.katex .sizing.reset-size1.size8, +.katex .fontsize-ensurer.reset-size1.size8 { + font-size: 2.88em; +} +.katex .sizing.reset-size1.size9, +.katex .fontsize-ensurer.reset-size1.size9 { + font-size: 3.456em; +} +.katex .sizing.reset-size1.size10, +.katex .fontsize-ensurer.reset-size1.size10 { + font-size: 4.148em; +} +.katex .sizing.reset-size1.size11, +.katex .fontsize-ensurer.reset-size1.size11 { + font-size: 4.976em; +} +.katex .sizing.reset-size2.size1, +.katex .fontsize-ensurer.reset-size2.size1 { + font-size: 0.83333333em; +} +.katex .sizing.reset-size2.size2, +.katex .fontsize-ensurer.reset-size2.size2 { + font-size: 1em; +} +.katex .sizing.reset-size2.size3, +.katex .fontsize-ensurer.reset-size2.size3 { + font-size: 1.16666667em; +} +.katex .sizing.reset-size2.size4, +.katex .fontsize-ensurer.reset-size2.size4 { + font-size: 1.33333333em; +} +.katex .sizing.reset-size2.size5, +.katex .fontsize-ensurer.reset-size2.size5 { + font-size: 1.5em; +} +.katex .sizing.reset-size2.size6, +.katex .fontsize-ensurer.reset-size2.size6 { + font-size: 1.66666667em; +} +.katex .sizing.reset-size2.size7, +.katex .fontsize-ensurer.reset-size2.size7 { + font-size: 2em; +} +.katex .sizing.reset-size2.size8, +.katex .fontsize-ensurer.reset-size2.size8 { + font-size: 2.4em; +} +.katex .sizing.reset-size2.size9, +.katex .fontsize-ensurer.reset-size2.size9 { + font-size: 2.88em; +} +.katex .sizing.reset-size2.size10, +.katex .fontsize-ensurer.reset-size2.size10 { + font-size: 3.45666667em; +} +.katex .sizing.reset-size2.size11, +.katex .fontsize-ensurer.reset-size2.size11 { + font-size: 4.14666667em; +} +.katex .sizing.reset-size3.size1, +.katex .fontsize-ensurer.reset-size3.size1 { + font-size: 0.71428571em; +} +.katex .sizing.reset-size3.size2, +.katex .fontsize-ensurer.reset-size3.size2 { + font-size: 0.85714286em; +} +.katex .sizing.reset-size3.size3, +.katex .fontsize-ensurer.reset-size3.size3 { + font-size: 1em; +} +.katex .sizing.reset-size3.size4, +.katex .fontsize-ensurer.reset-size3.size4 { + font-size: 1.14285714em; +} +.katex .sizing.reset-size3.size5, +.katex .fontsize-ensurer.reset-size3.size5 { + font-size: 1.28571429em; +} +.katex .sizing.reset-size3.size6, +.katex .fontsize-ensurer.reset-size3.size6 { + font-size: 1.42857143em; +} +.katex .sizing.reset-size3.size7, +.katex .fontsize-ensurer.reset-size3.size7 { + font-size: 1.71428571em; +} +.katex .sizing.reset-size3.size8, +.katex .fontsize-ensurer.reset-size3.size8 { + font-size: 2.05714286em; +} +.katex .sizing.reset-size3.size9, +.katex .fontsize-ensurer.reset-size3.size9 { + font-size: 2.46857143em; +} +.katex .sizing.reset-size3.size10, +.katex .fontsize-ensurer.reset-size3.size10 { + font-size: 2.96285714em; +} +.katex .sizing.reset-size3.size11, +.katex .fontsize-ensurer.reset-size3.size11 { + font-size: 3.55428571em; +} +.katex .sizing.reset-size4.size1, +.katex .fontsize-ensurer.reset-size4.size1 { + font-size: 0.625em; +} +.katex .sizing.reset-size4.size2, +.katex .fontsize-ensurer.reset-size4.size2 { + font-size: 0.75em; +} +.katex .sizing.reset-size4.size3, +.katex .fontsize-ensurer.reset-size4.size3 { + font-size: 0.875em; +} +.katex .sizing.reset-size4.size4, +.katex .fontsize-ensurer.reset-size4.size4 { + font-size: 1em; +} +.katex .sizing.reset-size4.size5, +.katex .fontsize-ensurer.reset-size4.size5 { + font-size: 1.125em; +} +.katex .sizing.reset-size4.size6, +.katex .fontsize-ensurer.reset-size4.size6 { + font-size: 1.25em; +} +.katex .sizing.reset-size4.size7, +.katex .fontsize-ensurer.reset-size4.size7 { + font-size: 1.5em; +} +.katex .sizing.reset-size4.size8, +.katex .fontsize-ensurer.reset-size4.size8 { + font-size: 1.8em; +} +.katex .sizing.reset-size4.size9, +.katex .fontsize-ensurer.reset-size4.size9 { + font-size: 2.16em; +} +.katex .sizing.reset-size4.size10, +.katex .fontsize-ensurer.reset-size4.size10 { + font-size: 2.5925em; +} +.katex .sizing.reset-size4.size11, +.katex .fontsize-ensurer.reset-size4.size11 { + font-size: 3.11em; +} +.katex .sizing.reset-size5.size1, +.katex .fontsize-ensurer.reset-size5.size1 { + font-size: 0.55555556em; +} +.katex .sizing.reset-size5.size2, +.katex .fontsize-ensurer.reset-size5.size2 { + font-size: 0.66666667em; +} +.katex .sizing.reset-size5.size3, +.katex .fontsize-ensurer.reset-size5.size3 { + font-size: 0.77777778em; +} +.katex .sizing.reset-size5.size4, +.katex .fontsize-ensurer.reset-size5.size4 { + font-size: 0.88888889em; +} +.katex .sizing.reset-size5.size5, +.katex .fontsize-ensurer.reset-size5.size5 { + font-size: 1em; +} +.katex .sizing.reset-size5.size6, +.katex .fontsize-ensurer.reset-size5.size6 { + font-size: 1.11111111em; +} +.katex .sizing.reset-size5.size7, +.katex .fontsize-ensurer.reset-size5.size7 { + font-size: 1.33333333em; +} +.katex .sizing.reset-size5.size8, +.katex .fontsize-ensurer.reset-size5.size8 { + font-size: 1.6em; +} +.katex .sizing.reset-size5.size9, +.katex .fontsize-ensurer.reset-size5.size9 { + font-size: 1.92em; +} +.katex .sizing.reset-size5.size10, +.katex .fontsize-ensurer.reset-size5.size10 { + font-size: 2.30444444em; +} +.katex .sizing.reset-size5.size11, +.katex .fontsize-ensurer.reset-size5.size11 { + font-size: 2.76444444em; +} +.katex .sizing.reset-size6.size1, +.katex .fontsize-ensurer.reset-size6.size1 { + font-size: 0.5em; +} +.katex .sizing.reset-size6.size2, +.katex .fontsize-ensurer.reset-size6.size2 { + font-size: 0.6em; +} +.katex .sizing.reset-size6.size3, +.katex .fontsize-ensurer.reset-size6.size3 { + font-size: 0.7em; +} +.katex .sizing.reset-size6.size4, +.katex .fontsize-ensurer.reset-size6.size4 { + font-size: 0.8em; +} +.katex .sizing.reset-size6.size5, +.katex .fontsize-ensurer.reset-size6.size5 { + font-size: 0.9em; +} +.katex .sizing.reset-size6.size6, +.katex .fontsize-ensurer.reset-size6.size6 { + font-size: 1em; +} +.katex .sizing.reset-size6.size7, +.katex .fontsize-ensurer.reset-size6.size7 { + font-size: 1.2em; +} +.katex .sizing.reset-size6.size8, +.katex .fontsize-ensurer.reset-size6.size8 { + font-size: 1.44em; +} +.katex .sizing.reset-size6.size9, +.katex .fontsize-ensurer.reset-size6.size9 { + font-size: 1.728em; +} +.katex .sizing.reset-size6.size10, +.katex .fontsize-ensurer.reset-size6.size10 { + font-size: 2.074em; +} +.katex .sizing.reset-size6.size11, +.katex .fontsize-ensurer.reset-size6.size11 { + font-size: 2.488em; +} +.katex .sizing.reset-size7.size1, +.katex .fontsize-ensurer.reset-size7.size1 { + font-size: 0.41666667em; +} +.katex .sizing.reset-size7.size2, +.katex .fontsize-ensurer.reset-size7.size2 { + font-size: 0.5em; +} +.katex .sizing.reset-size7.size3, +.katex .fontsize-ensurer.reset-size7.size3 { + font-size: 0.58333333em; +} +.katex .sizing.reset-size7.size4, +.katex .fontsize-ensurer.reset-size7.size4 { + font-size: 0.66666667em; +} +.katex .sizing.reset-size7.size5, +.katex .fontsize-ensurer.reset-size7.size5 { + font-size: 0.75em; +} +.katex .sizing.reset-size7.size6, +.katex .fontsize-ensurer.reset-size7.size6 { + font-size: 0.83333333em; +} +.katex .sizing.reset-size7.size7, +.katex .fontsize-ensurer.reset-size7.size7 { + font-size: 1em; +} +.katex .sizing.reset-size7.size8, +.katex .fontsize-ensurer.reset-size7.size8 { + font-size: 1.2em; +} +.katex .sizing.reset-size7.size9, +.katex .fontsize-ensurer.reset-size7.size9 { + font-size: 1.44em; +} +.katex .sizing.reset-size7.size10, +.katex .fontsize-ensurer.reset-size7.size10 { + font-size: 1.72833333em; +} +.katex .sizing.reset-size7.size11, +.katex .fontsize-ensurer.reset-size7.size11 { + font-size: 2.07333333em; +} +.katex .sizing.reset-size8.size1, +.katex .fontsize-ensurer.reset-size8.size1 { + font-size: 0.34722222em; +} +.katex .sizing.reset-size8.size2, +.katex .fontsize-ensurer.reset-size8.size2 { + font-size: 0.41666667em; +} +.katex .sizing.reset-size8.size3, +.katex .fontsize-ensurer.reset-size8.size3 { + font-size: 0.48611111em; +} +.katex .sizing.reset-size8.size4, +.katex .fontsize-ensurer.reset-size8.size4 { + font-size: 0.55555556em; +} +.katex .sizing.reset-size8.size5, +.katex .fontsize-ensurer.reset-size8.size5 { + font-size: 0.625em; +} +.katex .sizing.reset-size8.size6, +.katex .fontsize-ensurer.reset-size8.size6 { + font-size: 0.69444444em; +} +.katex .sizing.reset-size8.size7, +.katex .fontsize-ensurer.reset-size8.size7 { + font-size: 0.83333333em; +} +.katex .sizing.reset-size8.size8, +.katex .fontsize-ensurer.reset-size8.size8 { + font-size: 1em; +} +.katex .sizing.reset-size8.size9, +.katex .fontsize-ensurer.reset-size8.size9 { + font-size: 1.2em; +} +.katex .sizing.reset-size8.size10, +.katex .fontsize-ensurer.reset-size8.size10 { + font-size: 1.44027778em; +} +.katex .sizing.reset-size8.size11, +.katex .fontsize-ensurer.reset-size8.size11 { + font-size: 1.72777778em; +} +.katex .sizing.reset-size9.size1, +.katex .fontsize-ensurer.reset-size9.size1 { + font-size: 0.28935185em; +} +.katex .sizing.reset-size9.size2, +.katex .fontsize-ensurer.reset-size9.size2 { + font-size: 0.34722222em; +} +.katex .sizing.reset-size9.size3, +.katex .fontsize-ensurer.reset-size9.size3 { + font-size: 0.40509259em; +} +.katex .sizing.reset-size9.size4, +.katex .fontsize-ensurer.reset-size9.size4 { + font-size: 0.46296296em; +} +.katex .sizing.reset-size9.size5, +.katex .fontsize-ensurer.reset-size9.size5 { + font-size: 0.52083333em; +} +.katex .sizing.reset-size9.size6, +.katex .fontsize-ensurer.reset-size9.size6 { + font-size: 0.5787037em; +} +.katex .sizing.reset-size9.size7, +.katex .fontsize-ensurer.reset-size9.size7 { + font-size: 0.69444444em; +} +.katex .sizing.reset-size9.size8, +.katex .fontsize-ensurer.reset-size9.size8 { + font-size: 0.83333333em; +} +.katex .sizing.reset-size9.size9, +.katex .fontsize-ensurer.reset-size9.size9 { + font-size: 1em; +} +.katex .sizing.reset-size9.size10, +.katex .fontsize-ensurer.reset-size9.size10 { + font-size: 1.20023148em; +} +.katex .sizing.reset-size9.size11, +.katex .fontsize-ensurer.reset-size9.size11 { + font-size: 1.43981481em; +} +.katex .sizing.reset-size10.size1, +.katex .fontsize-ensurer.reset-size10.size1 { + font-size: 0.24108004em; +} +.katex .sizing.reset-size10.size2, +.katex .fontsize-ensurer.reset-size10.size2 { + font-size: 0.28929605em; +} +.katex .sizing.reset-size10.size3, +.katex .fontsize-ensurer.reset-size10.size3 { + font-size: 0.33751205em; +} +.katex .sizing.reset-size10.size4, +.katex .fontsize-ensurer.reset-size10.size4 { + font-size: 0.38572806em; +} +.katex .sizing.reset-size10.size5, +.katex .fontsize-ensurer.reset-size10.size5 { + font-size: 0.43394407em; +} +.katex .sizing.reset-size10.size6, +.katex .fontsize-ensurer.reset-size10.size6 { + font-size: 0.48216008em; +} +.katex .sizing.reset-size10.size7, +.katex .fontsize-ensurer.reset-size10.size7 { + font-size: 0.57859209em; +} +.katex .sizing.reset-size10.size8, +.katex .fontsize-ensurer.reset-size10.size8 { + font-size: 0.69431051em; +} +.katex .sizing.reset-size10.size9, +.katex .fontsize-ensurer.reset-size10.size9 { + font-size: 0.83317261em; +} +.katex .sizing.reset-size10.size10, +.katex .fontsize-ensurer.reset-size10.size10 { + font-size: 1em; +} +.katex .sizing.reset-size10.size11, +.katex .fontsize-ensurer.reset-size10.size11 { + font-size: 1.19961427em; +} +.katex .sizing.reset-size11.size1, +.katex .fontsize-ensurer.reset-size11.size1 { + font-size: 0.20096463em; +} +.katex .sizing.reset-size11.size2, +.katex .fontsize-ensurer.reset-size11.size2 { + font-size: 0.24115756em; +} +.katex .sizing.reset-size11.size3, +.katex .fontsize-ensurer.reset-size11.size3 { + font-size: 0.28135048em; +} +.katex .sizing.reset-size11.size4, +.katex .fontsize-ensurer.reset-size11.size4 { + font-size: 0.32154341em; +} +.katex .sizing.reset-size11.size5, +.katex .fontsize-ensurer.reset-size11.size5 { + font-size: 0.36173633em; +} +.katex .sizing.reset-size11.size6, +.katex .fontsize-ensurer.reset-size11.size6 { + font-size: 0.40192926em; +} +.katex .sizing.reset-size11.size7, +.katex .fontsize-ensurer.reset-size11.size7 { + font-size: 0.48231511em; +} +.katex .sizing.reset-size11.size8, +.katex .fontsize-ensurer.reset-size11.size8 { + font-size: 0.57877814em; +} +.katex .sizing.reset-size11.size9, +.katex .fontsize-ensurer.reset-size11.size9 { + font-size: 0.69453376em; +} +.katex .sizing.reset-size11.size10, +.katex .fontsize-ensurer.reset-size11.size10 { + font-size: 0.83360129em; +} +.katex .sizing.reset-size11.size11, +.katex .fontsize-ensurer.reset-size11.size11 { + font-size: 1em; +} +.katex .delimsizing.size1 { + font-family: KaTeX_Size1; +} +.katex .delimsizing.size2 { + font-family: KaTeX_Size2; +} +.katex .delimsizing.size3 { + font-family: KaTeX_Size3; +} +.katex .delimsizing.size4 { + font-family: KaTeX_Size4; +} +.katex .delimsizing.mult .delim-size1 > span { + font-family: KaTeX_Size1; +} +.katex .delimsizing.mult .delim-size4 > span { + font-family: KaTeX_Size4; +} +.katex .nulldelimiter { + display: inline-block; + width: 0.12em; +} +.katex .delimcenter { + position: relative; +} +.katex .op-symbol { + position: relative; +} +.katex .op-symbol.small-op { + font-family: KaTeX_Size1; +} +.katex .op-symbol.large-op { + font-family: KaTeX_Size2; +} +.katex .op-limits > .vlist-t { + text-align: center; +} +.katex .accent > .vlist-t { + text-align: center; +} +.katex .accent .accent-body { + position: relative; +} +.katex .accent .accent-body:not(.accent-full) { + width: 0; +} +.katex .overlay { + display: block; +} +.katex .mtable .vertical-separator { + display: inline-block; + min-width: 1px; +} +.katex .mtable .arraycolsep { + display: inline-block; +} +.katex .mtable .col-align-c > .vlist-t { + text-align: center; +} +.katex .mtable .col-align-l > .vlist-t { + text-align: left; +} +.katex .mtable .col-align-r > .vlist-t { + text-align: right; +} +.katex .svg-align { + text-align: left; +} +.katex svg { + display: block; + position: absolute; + width: 100%; + height: inherit; + fill: currentColor; + stroke: currentColor; + fill-rule: nonzero; + fill-opacity: 1; + stroke-width: 1; + stroke-linecap: butt; + stroke-linejoin: miter; + stroke-miterlimit: 4; + stroke-dasharray: none; + stroke-dashoffset: 0; + stroke-opacity: 1; +} +.katex svg path { + stroke: none; +} +.katex img { + border-style: none; + min-width: 0; + min-height: 0; + max-width: none; + max-height: none; +} +.katex .stretchy { + width: 100%; + display: block; + position: relative; + overflow: hidden; +} +.katex .stretchy::before, +.katex .stretchy::after { + content: ""; +} +.katex .hide-tail { + width: 100%; + position: relative; + overflow: hidden; +} +.katex .halfarrow-left { + position: absolute; + left: 0; + width: 50.2%; + overflow: hidden; +} +.katex .halfarrow-right { + position: absolute; + right: 0; + width: 50.2%; + overflow: hidden; +} +.katex .brace-left { + position: absolute; + left: 0; + width: 25.1%; + overflow: hidden; +} +.katex .brace-center { + position: absolute; + left: 25%; + width: 50%; + overflow: hidden; +} +.katex .brace-right { + position: absolute; + right: 0; + width: 25.1%; + overflow: hidden; +} +.katex .x-arrow-pad { + padding: 0 0.5em; +} +.katex .x-arrow, +.katex .mover, +.katex .munder { + text-align: center; +} +.katex .boxpad { + padding: 0 0.3em 0 0.3em; +} +.katex .fbox, +.katex .fcolorbox { + box-sizing: border-box; + border: 0.04em solid; +} +.katex .cancel-pad { + padding: 0 0.2em 0 0.2em; +} +.katex .cancel-lap { + margin-left: -0.2em; + margin-right: -0.2em; +} +.katex .sout { + border-bottom-style: solid; + border-bottom-width: 0.08em; +} +.katex-display { + display: block; + margin: 1em 0; + text-align: center; +} +.katex-display > .katex { + display: block; + text-align: center; + white-space: nowrap; +} +.katex-display > .katex > .katex-html { + display: block; + position: relative; +} +.katex-display > .katex > .katex-html > .tag { + position: absolute; + right: 0; +} +.katex-display.leqno > .katex > .katex-html > .tag { + left: 0; + right: auto; +} +.katex-display.fleqn > .katex { + text-align: left; +} + diff --git a/adoc/katex/katex.js b/adoc/katex/katex.js new file mode 100644 index 00000000..2aa2c917 --- /dev/null +++ b/adoc/katex/katex.js @@ -0,0 +1,17425 @@ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports["katex"] = factory(); + else + root["katex"] = factory(); +})((typeof self !== 'undefined' ? self : this), function() { +return /******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); +/******/ } +/******/ }; +/******/ +/******/ // define __esModule on exports +/******/ __webpack_require__.r = function(exports) { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ +/******/ // create a fake namespace object +/******/ // mode & 1: value is a module id, require it +/******/ // mode & 2: merge all properties of value into the ns +/******/ // mode & 4: return value when already ns object +/******/ // mode & 8|1: behave like require +/******/ __webpack_require__.t = function(value, mode) { +/******/ if(mode & 1) value = __webpack_require__(value); +/******/ if(mode & 8) return value; +/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; +/******/ var ns = Object.create(null); +/******/ __webpack_require__.r(ns); +/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); +/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); +/******/ return ns; +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; +/******/ +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = 1); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ (function(module, exports, __webpack_require__) { + +// extracted by mini-css-extract-plugin + +/***/ }), +/* 1 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); + +// EXTERNAL MODULE: ./src/katex.less +var katex = __webpack_require__(0); + +// CONCATENATED MODULE: ./src/SourceLocation.js +/** + * Lexing or parsing positional information for error reporting. + * This object is immutable. + */ +var SourceLocation = +/*#__PURE__*/ +function () { + // The + prefix indicates that these fields aren't writeable + // Lexer holding the input string. + // Start offset, zero-based inclusive. + // End offset, zero-based exclusive. + function SourceLocation(lexer, start, end) { + this.lexer = void 0; + this.start = void 0; + this.end = void 0; + this.lexer = lexer; + this.start = start; + this.end = end; + } + /** + * Merges two `SourceLocation`s from location providers, given they are + * provided in order of appearance. + * - Returns the first one's location if only the first is provided. + * - Returns a merged range of the first and the last if both are provided + * and their lexers match. + * - Otherwise, returns null. + */ + + + SourceLocation.range = function range(first, second) { + if (!second) { + return first && first.loc; + } else if (!first || !first.loc || !second.loc || first.loc.lexer !== second.loc.lexer) { + return null; + } else { + return new SourceLocation(first.loc.lexer, first.loc.start, second.loc.end); + } + }; + + return SourceLocation; +}(); + + +// CONCATENATED MODULE: ./src/Token.js + +/** + * Interface required to break circular dependency between Token, Lexer, and + * ParseError. + */ + +/** + * The resulting token returned from `lex`. + * + * It consists of the token text plus some position information. + * The position information is essentially a range in an input string, + * but instead of referencing the bare input string, we refer to the lexer. + * That way it is possible to attach extra metadata to the input string, + * like for example a file name or similar. + * + * The position information is optional, so it is OK to construct synthetic + * tokens if appropriate. Not providing available position information may + * lead to degraded error reporting, though. + */ +var Token_Token = +/*#__PURE__*/ +function () { + function Token(text, // the text of this token + loc) { + this.text = void 0; + this.loc = void 0; + this.text = text; + this.loc = loc; + } + /** + * Given a pair of tokens (this and endToken), compute a `Token` encompassing + * the whole input range enclosed by these two. + */ + + + var _proto = Token.prototype; + + _proto.range = function range(endToken, // last token of the range, inclusive + text) // the text of the newly constructed token + { + return new Token(text, SourceLocation.range(this, endToken)); + }; + + return Token; +}(); +// CONCATENATED MODULE: ./src/ParseError.js + + +/** + * This is the ParseError class, which is the main error thrown by KaTeX + * functions when something has gone wrong. This is used to distinguish internal + * errors from errors in the expression that the user provided. + * + * If possible, a caller should provide a Token or ParseNode with information + * about where in the source string the problem occurred. + */ +var ParseError = // Error position based on passed-in Token or ParseNode. +function ParseError(message, // The error message +token) // An object providing position information +{ + this.position = void 0; + var error = "KaTeX parse error: " + message; + var start; + var loc = token && token.loc; + + if (loc && loc.start <= loc.end) { + // If we have the input and a position, make the error a bit fancier + // Get the input + var input = loc.lexer.input; // Prepend some information + + start = loc.start; + var end = loc.end; + + if (start === input.length) { + error += " at end of input: "; + } else { + error += " at position " + (start + 1) + ": "; + } // Underline token in question using combining underscores + + + var underlined = input.slice(start, end).replace(/[^]/g, "$&\u0332"); // Extract some context from the input and add it to the error + + var left; + + if (start > 15) { + left = "…" + input.slice(start - 15, start); + } else { + left = input.slice(0, start); + } + + var right; + + if (end + 15 < input.length) { + right = input.slice(end, end + 15) + "…"; + } else { + right = input.slice(end); + } + + error += left + underlined + right; + } // Some hackery to make ParseError a prototype of Error + // See http://stackoverflow.com/a/8460753 + + + var self = new Error(error); + self.name = "ParseError"; // $FlowFixMe + + self.__proto__ = ParseError.prototype; // $FlowFixMe + + self.position = start; + return self; +}; // $FlowFixMe More hackery + + +ParseError.prototype.__proto__ = Error.prototype; +/* harmony default export */ var src_ParseError = (ParseError); +// CONCATENATED MODULE: ./src/utils.js +/** + * This file contains a list of utility functions which are useful in other + * files. + */ + +/** + * Return whether an element is contained in a list + */ +var contains = function contains(list, elem) { + return list.indexOf(elem) !== -1; +}; +/** + * Provide a default value if a setting is undefined + * NOTE: Couldn't use `T` as the output type due to facebook/flow#5022. + */ + + +var deflt = function deflt(setting, defaultIfUndefined) { + return setting === undefined ? defaultIfUndefined : setting; +}; // hyphenate and escape adapted from Facebook's React under Apache 2 license + + +var uppercase = /([A-Z])/g; + +var hyphenate = function hyphenate(str) { + return str.replace(uppercase, "-$1").toLowerCase(); +}; + +var ESCAPE_LOOKUP = { + "&": "&", + ">": ">", + "<": "<", + "\"": """, + "'": "'" +}; +var ESCAPE_REGEX = /[&><"']/g; +/** + * Escapes text to prevent scripting attacks. + */ + +function utils_escape(text) { + return String(text).replace(ESCAPE_REGEX, function (match) { + return ESCAPE_LOOKUP[match]; + }); +} +/** + * Sometimes we want to pull out the innermost element of a group. In most + * cases, this will just be the group itself, but when ordgroups and colors have + * a single element, we want to pull that out. + */ + + +var getBaseElem = function getBaseElem(group) { + if (group.type === "ordgroup") { + if (group.body.length === 1) { + return getBaseElem(group.body[0]); + } else { + return group; + } + } else if (group.type === "color") { + if (group.body.length === 1) { + return getBaseElem(group.body[0]); + } else { + return group; + } + } else if (group.type === "font") { + return getBaseElem(group.body); + } else { + return group; + } +}; +/** + * TeXbook algorithms often reference "character boxes", which are simply groups + * with a single character in them. To decide if something is a character box, + * we find its innermost group, and see if it is a single character. + */ + + +var utils_isCharacterBox = function isCharacterBox(group) { + var baseElem = getBaseElem(group); // These are all they types of groups which hold single characters + + return baseElem.type === "mathord" || baseElem.type === "textord" || baseElem.type === "atom"; +}; + +var assert = function assert(value) { + if (!value) { + throw new Error('Expected non-null, but got ' + String(value)); + } + + return value; +}; +/** + * Return the protocol of a URL, or "_relative" if the URL does not specify a + * protocol (and thus is relative). + */ + +var protocolFromUrl = function protocolFromUrl(url) { + var protocol = /^\s*([^\\/#]*?)(?::|�*58|�*3a)/i.exec(url); + return protocol != null ? protocol[1] : "_relative"; +}; +/* harmony default export */ var utils = ({ + contains: contains, + deflt: deflt, + escape: utils_escape, + hyphenate: hyphenate, + getBaseElem: getBaseElem, + isCharacterBox: utils_isCharacterBox, + protocolFromUrl: protocolFromUrl +}); +// CONCATENATED MODULE: ./src/Settings.js +/* eslint no-console:0 */ + +/** + * This is a module for storing settings passed into KaTeX. It correctly handles + * default settings. + */ + + + + +/** + * The main Settings object + * + * The current options stored are: + * - displayMode: Whether the expression should be typeset as inline math + * (false, the default), meaning that the math starts in + * \textstyle and is placed in an inline-block); or as display + * math (true), meaning that the math starts in \displaystyle + * and is placed in a block with vertical margin. + */ +var Settings_Settings = +/*#__PURE__*/ +function () { + function Settings(options) { + this.displayMode = void 0; + this.output = void 0; + this.leqno = void 0; + this.fleqn = void 0; + this.throwOnError = void 0; + this.errorColor = void 0; + this.macros = void 0; + this.minRuleThickness = void 0; + this.colorIsTextColor = void 0; + this.strict = void 0; + this.trust = void 0; + this.maxSize = void 0; + this.maxExpand = void 0; + // allow null options + options = options || {}; + this.displayMode = utils.deflt(options.displayMode, false); + this.output = utils.deflt(options.output, "htmlAndMathml"); + this.leqno = utils.deflt(options.leqno, false); + this.fleqn = utils.deflt(options.fleqn, false); + this.throwOnError = utils.deflt(options.throwOnError, true); + this.errorColor = utils.deflt(options.errorColor, "#cc0000"); + this.macros = options.macros || {}; + this.minRuleThickness = Math.max(0, utils.deflt(options.minRuleThickness, 0)); + this.colorIsTextColor = utils.deflt(options.colorIsTextColor, false); + this.strict = utils.deflt(options.strict, "warn"); + this.trust = utils.deflt(options.trust, false); + this.maxSize = Math.max(0, utils.deflt(options.maxSize, Infinity)); + this.maxExpand = Math.max(0, utils.deflt(options.maxExpand, 1000)); + } + /** + * Report nonstrict (non-LaTeX-compatible) input. + * Can safely not be called if `this.strict` is false in JavaScript. + */ + + + var _proto = Settings.prototype; + + _proto.reportNonstrict = function reportNonstrict(errorCode, errorMsg, token) { + var strict = this.strict; + + if (typeof strict === "function") { + // Allow return value of strict function to be boolean or string + // (or null/undefined, meaning no further processing). + strict = strict(errorCode, errorMsg, token); + } + + if (!strict || strict === "ignore") { + return; + } else if (strict === true || strict === "error") { + throw new src_ParseError("LaTeX-incompatible input and strict mode is set to 'error': " + (errorMsg + " [" + errorCode + "]"), token); + } else if (strict === "warn") { + typeof console !== "undefined" && console.warn("LaTeX-incompatible input and strict mode is set to 'warn': " + (errorMsg + " [" + errorCode + "]")); + } else { + // won't happen in type-safe code + typeof console !== "undefined" && console.warn("LaTeX-incompatible input and strict mode is set to " + ("unrecognized '" + strict + "': " + errorMsg + " [" + errorCode + "]")); + } + } + /** + * Check whether to apply strict (LaTeX-adhering) behavior for unusual + * input (like `\\`). Unlike `nonstrict`, will not throw an error; + * instead, "error" translates to a return value of `true`, while "ignore" + * translates to a return value of `false`. May still print a warning: + * "warn" prints a warning and returns `false`. + * This is for the second category of `errorCode`s listed in the README. + */ + ; + + _proto.useStrictBehavior = function useStrictBehavior(errorCode, errorMsg, token) { + var strict = this.strict; + + if (typeof strict === "function") { + // Allow return value of strict function to be boolean or string + // (or null/undefined, meaning no further processing). + // But catch any exceptions thrown by function, treating them + // like "error". + try { + strict = strict(errorCode, errorMsg, token); + } catch (error) { + strict = "error"; + } + } + + if (!strict || strict === "ignore") { + return false; + } else if (strict === true || strict === "error") { + return true; + } else if (strict === "warn") { + typeof console !== "undefined" && console.warn("LaTeX-incompatible input and strict mode is set to 'warn': " + (errorMsg + " [" + errorCode + "]")); + return false; + } else { + // won't happen in type-safe code + typeof console !== "undefined" && console.warn("LaTeX-incompatible input and strict mode is set to " + ("unrecognized '" + strict + "': " + errorMsg + " [" + errorCode + "]")); + return false; + } + } + /** + * Check whether to test potentially dangerous input, and return + * `true` (trusted) or `false` (untrusted). The sole argument `context` + * should be an object with `command` field specifying the relevant LaTeX + * command (as a string starting with `\`), and any other arguments, etc. + * If `context` has a `url` field, a `protocol` field will automatically + * get added by this function (changing the specified object). + */ + ; + + _proto.isTrusted = function isTrusted(context) { + if (context.url && !context.protocol) { + context.protocol = utils.protocolFromUrl(context.url); + } + + var trust = typeof this.trust === "function" ? this.trust(context) : this.trust; + return Boolean(trust); + }; + + return Settings; +}(); + + +// CONCATENATED MODULE: ./src/Style.js +/** + * This file contains information and classes for the various kinds of styles + * used in TeX. It provides a generic `Style` class, which holds information + * about a specific style. It then provides instances of all the different kinds + * of styles possible, and provides functions to move between them and get + * information about them. + */ + +/** + * The main style class. Contains a unique id for the style, a size (which is + * the same for cramped and uncramped version of a style), and a cramped flag. + */ +var Style = +/*#__PURE__*/ +function () { + function Style(id, size, cramped) { + this.id = void 0; + this.size = void 0; + this.cramped = void 0; + this.id = id; + this.size = size; + this.cramped = cramped; + } + /** + * Get the style of a superscript given a base in the current style. + */ + + + var _proto = Style.prototype; + + _proto.sup = function sup() { + return Style_styles[_sup[this.id]]; + } + /** + * Get the style of a subscript given a base in the current style. + */ + ; + + _proto.sub = function sub() { + return Style_styles[_sub[this.id]]; + } + /** + * Get the style of a fraction numerator given the fraction in the current + * style. + */ + ; + + _proto.fracNum = function fracNum() { + return Style_styles[_fracNum[this.id]]; + } + /** + * Get the style of a fraction denominator given the fraction in the current + * style. + */ + ; + + _proto.fracDen = function fracDen() { + return Style_styles[_fracDen[this.id]]; + } + /** + * Get the cramped version of a style (in particular, cramping a cramped style + * doesn't change the style). + */ + ; + + _proto.cramp = function cramp() { + return Style_styles[_cramp[this.id]]; + } + /** + * Get a text or display version of this style. + */ + ; + + _proto.text = function text() { + return Style_styles[_text[this.id]]; + } + /** + * Return true if this style is tightly spaced (scriptstyle/scriptscriptstyle) + */ + ; + + _proto.isTight = function isTight() { + return this.size >= 2; + }; + + return Style; +}(); // Export an interface for type checking, but don't expose the implementation. +// This way, no more styles can be generated. + + +// IDs of the different styles +var D = 0; +var Dc = 1; +var T = 2; +var Tc = 3; +var S = 4; +var Sc = 5; +var SS = 6; +var SSc = 7; // Instances of the different styles + +var Style_styles = [new Style(D, 0, false), new Style(Dc, 0, true), new Style(T, 1, false), new Style(Tc, 1, true), new Style(S, 2, false), new Style(Sc, 2, true), new Style(SS, 3, false), new Style(SSc, 3, true)]; // Lookup tables for switching from one style to another + +var _sup = [S, Sc, S, Sc, SS, SSc, SS, SSc]; +var _sub = [Sc, Sc, Sc, Sc, SSc, SSc, SSc, SSc]; +var _fracNum = [T, Tc, S, Sc, SS, SSc, SS, SSc]; +var _fracDen = [Tc, Tc, Sc, Sc, SSc, SSc, SSc, SSc]; +var _cramp = [Dc, Dc, Tc, Tc, Sc, Sc, SSc, SSc]; +var _text = [D, Dc, T, Tc, T, Tc, T, Tc]; // We only export some of the styles. + +/* harmony default export */ var src_Style = ({ + DISPLAY: Style_styles[D], + TEXT: Style_styles[T], + SCRIPT: Style_styles[S], + SCRIPTSCRIPT: Style_styles[SS] +}); +// CONCATENATED MODULE: ./src/unicodeScripts.js +/* + * This file defines the Unicode scripts and script families that we + * support. To add new scripts or families, just add a new entry to the + * scriptData array below. Adding scripts to the scriptData array allows + * characters from that script to appear in \text{} environments. + */ + +/** + * Each script or script family has a name and an array of blocks. + * Each block is an array of two numbers which specify the start and + * end points (inclusive) of a block of Unicode codepoints. + */ + +/** + * Unicode block data for the families of scripts we support in \text{}. + * Scripts only need to appear here if they do not have font metrics. + */ +var scriptData = [{ + // Latin characters beyond the Latin-1 characters we have metrics for. + // Needed for Czech, Hungarian and Turkish text, for example. + name: 'latin', + blocks: [[0x0100, 0x024f], // Latin Extended-A and Latin Extended-B + [0x0300, 0x036f]] +}, { + // The Cyrillic script used by Russian and related languages. + // A Cyrillic subset used to be supported as explicitly defined + // symbols in symbols.js + name: 'cyrillic', + blocks: [[0x0400, 0x04ff]] +}, { + // The Brahmic scripts of South and Southeast Asia + // Devanagari (0900–097F) + // Bengali (0980–09FF) + // Gurmukhi (0A00–0A7F) + // Gujarati (0A80–0AFF) + // Oriya (0B00–0B7F) + // Tamil (0B80–0BFF) + // Telugu (0C00–0C7F) + // Kannada (0C80–0CFF) + // Malayalam (0D00–0D7F) + // Sinhala (0D80–0DFF) + // Thai (0E00–0E7F) + // Lao (0E80–0EFF) + // Tibetan (0F00–0FFF) + // Myanmar (1000–109F) + name: 'brahmic', + blocks: [[0x0900, 0x109F]] +}, { + name: 'georgian', + blocks: [[0x10A0, 0x10ff]] +}, { + // Chinese and Japanese. + // The "k" in cjk is for Korean, but we've separated Korean out + name: "cjk", + blocks: [[0x3000, 0x30FF], // CJK symbols and punctuation, Hiragana, Katakana + [0x4E00, 0x9FAF], // CJK ideograms + [0xFF00, 0xFF60]] +}, { + // Korean + name: 'hangul', + blocks: [[0xAC00, 0xD7AF]] +}]; +/** + * Given a codepoint, return the name of the script or script family + * it is from, or null if it is not part of a known block + */ + +function scriptFromCodepoint(codepoint) { + for (var i = 0; i < scriptData.length; i++) { + var script = scriptData[i]; + + for (var _i = 0; _i < script.blocks.length; _i++) { + var block = script.blocks[_i]; + + if (codepoint >= block[0] && codepoint <= block[1]) { + return script.name; + } + } + } + + return null; +} +/** + * A flattened version of all the supported blocks in a single array. + * This is an optimization to make supportedCodepoint() fast. + */ + +var allBlocks = []; +scriptData.forEach(function (s) { + return s.blocks.forEach(function (b) { + return allBlocks.push.apply(allBlocks, b); + }); +}); +/** + * Given a codepoint, return true if it falls within one of the + * scripts or script families defined above and false otherwise. + * + * Micro benchmarks shows that this is faster than + * /[\u3000-\u30FF\u4E00-\u9FAF\uFF00-\uFF60\uAC00-\uD7AF\u0900-\u109F]/.test() + * in Firefox, Chrome and Node. + */ + +function supportedCodepoint(codepoint) { + for (var i = 0; i < allBlocks.length; i += 2) { + if (codepoint >= allBlocks[i] && codepoint <= allBlocks[i + 1]) { + return true; + } + } + + return false; +} +// CONCATENATED MODULE: ./src/svgGeometry.js +/** + * This file provides support to domTree.js and delimiter.js. + * It's a storehouse of path geometry for SVG images. + */ +// In all paths below, the viewBox-to-em scale is 1000:1. +var hLinePad = 80; // padding above a sqrt viniculum. Prevents image cropping. +// The viniculum of a \sqrt can be made thicker by a KaTeX rendering option. +// Think of variable extraViniculum as two detours in the SVG path. +// The detour begins at the lower left of the area labeled extraViniculum below. +// The detour proceeds one extraViniculum distance up and slightly to the right, +// displacing the radiused corner between surd and viniculum. The radius is +// traversed as usual, then the detour resumes. It goes right, to the end of +// the very long viniculumn, then down one extraViniculum distance, +// after which it resumes regular path geometry for the radical. + +/* viniculum + / + /▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒←extraViniculum + / █████████████████████←0.04em (40 unit) std viniculum thickness + / / + / / + / /\ + / / surd +*/ + +var sqrtMain = function sqrtMain(extraViniculum, hLinePad) { + // sqrtMain path geometry is from glyph U221A in the font KaTeX Main + return "M95," + (622 + extraViniculum + hLinePad) + "\nc-2.7,0,-7.17,-2.7,-13.5,-8c-5.8,-5.3,-9.5,-10,-9.5,-14\nc0,-2,0.3,-3.3,1,-4c1.3,-2.7,23.83,-20.7,67.5,-54\nc44.2,-33.3,65.8,-50.3,66.5,-51c1.3,-1.3,3,-2,5,-2c4.7,0,8.7,3.3,12,10\ns173,378,173,378c0.7,0,35.3,-71,104,-213c68.7,-142,137.5,-285,206.5,-429\nc69,-144,104.5,-217.7,106.5,-221\nl" + extraViniculum / 2.075 + " -" + extraViniculum + "\nc5.3,-9.3,12,-14,20,-14\nH400000v" + (40 + extraViniculum) + "H845.2724\ns-225.272,467,-225.272,467s-235,486,-235,486c-2.7,4.7,-9,7,-19,7\nc-6,0,-10,-1,-12,-3s-194,-422,-194,-422s-65,47,-65,47z\nM" + (834 + extraViniculum) + " " + hLinePad + "h400000v" + (40 + extraViniculum) + "h-400000z"; +}; + +var sqrtSize1 = function sqrtSize1(extraViniculum, hLinePad) { + // size1 is from glyph U221A in the font KaTeX_Size1-Regular + return "M263," + (601 + extraViniculum + hLinePad) + "c0.7,0,18,39.7,52,119\nc34,79.3,68.167,158.7,102.5,238c34.3,79.3,51.8,119.3,52.5,120\nc340,-704.7,510.7,-1060.3,512,-1067\nl" + extraViniculum / 2.084 + " -" + extraViniculum + "\nc4.7,-7.3,11,-11,19,-11\nH40000v" + (40 + extraViniculum) + "H1012.3\ns-271.3,567,-271.3,567c-38.7,80.7,-84,175,-136,283c-52,108,-89.167,185.3,-111.5,232\nc-22.3,46.7,-33.8,70.3,-34.5,71c-4.7,4.7,-12.3,7,-23,7s-12,-1,-12,-1\ns-109,-253,-109,-253c-72.7,-168,-109.3,-252,-110,-252c-10.7,8,-22,16.7,-34,26\nc-22,17.3,-33.3,26,-34,26s-26,-26,-26,-26s76,-59,76,-59s76,-60,76,-60z\nM" + (1001 + extraViniculum) + " " + hLinePad + "h400000v" + (40 + extraViniculum) + "h-400000z"; +}; + +var sqrtSize2 = function sqrtSize2(extraViniculum, hLinePad) { + // size2 is from glyph U221A in the font KaTeX_Size2-Regular + return "M983 " + (10 + extraViniculum + hLinePad) + "\nl" + extraViniculum / 3.13 + " -" + extraViniculum + "\nc4,-6.7,10,-10,18,-10 H400000v" + (40 + extraViniculum) + "\nH1013.1s-83.4,268,-264.1,840c-180.7,572,-277,876.3,-289,913c-4.7,4.7,-12.7,7,-24,7\ns-12,0,-12,0c-1.3,-3.3,-3.7,-11.7,-7,-25c-35.3,-125.3,-106.7,-373.3,-214,-744\nc-10,12,-21,25,-33,39s-32,39,-32,39c-6,-5.3,-15,-14,-27,-26s25,-30,25,-30\nc26.7,-32.7,52,-63,76,-91s52,-60,52,-60s208,722,208,722\nc56,-175.3,126.3,-397.3,211,-666c84.7,-268.7,153.8,-488.2,207.5,-658.5\nc53.7,-170.3,84.5,-266.8,92.5,-289.5z\nM" + (1001 + extraViniculum) + " " + hLinePad + "h400000v" + (40 + extraViniculum) + "h-400000z"; +}; + +var sqrtSize3 = function sqrtSize3(extraViniculum, hLinePad) { + // size3 is from glyph U221A in the font KaTeX_Size3-Regular + return "M424," + (2398 + extraViniculum + hLinePad) + "\nc-1.3,-0.7,-38.5,-172,-111.5,-514c-73,-342,-109.8,-513.3,-110.5,-514\nc0,-2,-10.7,14.3,-32,49c-4.7,7.3,-9.8,15.7,-15.5,25c-5.7,9.3,-9.8,16,-12.5,20\ns-5,7,-5,7c-4,-3.3,-8.3,-7.7,-13,-13s-13,-13,-13,-13s76,-122,76,-122s77,-121,77,-121\ns209,968,209,968c0,-2,84.7,-361.7,254,-1079c169.3,-717.3,254.7,-1077.7,256,-1081\nl" + extraViniculum / 4.223 + " -" + extraViniculum + "c4,-6.7,10,-10,18,-10 H400000\nv" + (40 + extraViniculum) + "H1014.6\ns-87.3,378.7,-272.6,1166c-185.3,787.3,-279.3,1182.3,-282,1185\nc-2,6,-10,9,-24,9\nc-8,0,-12,-0.7,-12,-2z M" + (1001 + extraViniculum) + " " + hLinePad + "\nh400000v" + (40 + extraViniculum) + "h-400000z"; +}; + +var sqrtSize4 = function sqrtSize4(extraViniculum, hLinePad) { + // size4 is from glyph U221A in the font KaTeX_Size4-Regular + return "M473," + (2713 + extraViniculum + hLinePad) + "\nc339.3,-1799.3,509.3,-2700,510,-2702 l" + extraViniculum / 5.298 + " -" + extraViniculum + "\nc3.3,-7.3,9.3,-11,18,-11 H400000v" + (40 + extraViniculum) + "H1017.7\ns-90.5,478,-276.2,1466c-185.7,988,-279.5,1483,-281.5,1485c-2,6,-10,9,-24,9\nc-8,0,-12,-0.7,-12,-2c0,-1.3,-5.3,-32,-16,-92c-50.7,-293.3,-119.7,-693.3,-207,-1200\nc0,-1.3,-5.3,8.7,-16,30c-10.7,21.3,-21.3,42.7,-32,64s-16,33,-16,33s-26,-26,-26,-26\ns76,-153,76,-153s77,-151,77,-151c0.7,0.7,35.7,202,105,604c67.3,400.7,102,602.7,104,\n606zM" + (1001 + extraViniculum) + " " + hLinePad + "h400000v" + (40 + extraViniculum) + "H1017.7z"; +}; + +var sqrtTall = function sqrtTall(extraViniculum, hLinePad, viewBoxHeight) { + // sqrtTall is from glyph U23B7 in the font KaTeX_Size4-Regular + // One path edge has a variable length. It runs vertically from the viniculumn + // to a point near (14 units) the bottom of the surd. The viniculum + // is normally 40 units thick. So the length of the line in question is: + var vertSegment = viewBoxHeight - 54 - hLinePad - extraViniculum; + return "M702 " + (extraViniculum + hLinePad) + "H400000" + (40 + extraViniculum) + "\nH742v" + vertSegment + "l-4 4-4 4c-.667.7 -2 1.5-4 2.5s-4.167 1.833-6.5 2.5-5.5 1-9.5 1\nh-12l-28-84c-16.667-52-96.667 -294.333-240-727l-212 -643 -85 170\nc-4-3.333-8.333-7.667-13 -13l-13-13l77-155 77-156c66 199.333 139 419.667\n219 661 l218 661zM702 " + hLinePad + "H400000v" + (40 + extraViniculum) + "H742z"; +}; + +var sqrtPath = function sqrtPath(size, extraViniculum, viewBoxHeight) { + extraViniculum = 1000 * extraViniculum; // Convert from document ems to viewBox. + + var path = ""; + + switch (size) { + case "sqrtMain": + path = sqrtMain(extraViniculum, hLinePad); + break; + + case "sqrtSize1": + path = sqrtSize1(extraViniculum, hLinePad); + break; + + case "sqrtSize2": + path = sqrtSize2(extraViniculum, hLinePad); + break; + + case "sqrtSize3": + path = sqrtSize3(extraViniculum, hLinePad); + break; + + case "sqrtSize4": + path = sqrtSize4(extraViniculum, hLinePad); + break; + + case "sqrtTall": + path = sqrtTall(extraViniculum, hLinePad, viewBoxHeight); + } + + return path; +}; +var svgGeometry_path = { + // The doubleleftarrow geometry is from glyph U+21D0 in the font KaTeX Main + doubleleftarrow: "M262 157\nl10-10c34-36 62.7-77 86-123 3.3-8 5-13.3 5-16 0-5.3-6.7-8-20-8-7.3\n 0-12.2.5-14.5 1.5-2.3 1-4.8 4.5-7.5 10.5-49.3 97.3-121.7 169.3-217 216-28\n 14-57.3 25-88 33-6.7 2-11 3.8-13 5.5-2 1.7-3 4.2-3 7.5s1 5.8 3 7.5\nc2 1.7 6.3 3.5 13 5.5 68 17.3 128.2 47.8 180.5 91.5 52.3 43.7 93.8 96.2 124.5\n 157.5 9.3 8 15.3 12.3 18 13h6c12-.7 18-4 18-10 0-2-1.7-7-5-15-23.3-46-52-87\n-86-123l-10-10h399738v-40H218c328 0 0 0 0 0l-10-8c-26.7-20-65.7-43-117-69 2.7\n-2 6-3.7 10-5 36.7-16 72.3-37.3 107-64l10-8h399782v-40z\nm8 0v40h399730v-40zm0 194v40h399730v-40z", + // doublerightarrow is from glyph U+21D2 in font KaTeX Main + doublerightarrow: "M399738 392l\n-10 10c-34 36-62.7 77-86 123-3.3 8-5 13.3-5 16 0 5.3 6.7 8 20 8 7.3 0 12.2-.5\n 14.5-1.5 2.3-1 4.8-4.5 7.5-10.5 49.3-97.3 121.7-169.3 217-216 28-14 57.3-25 88\n-33 6.7-2 11-3.8 13-5.5 2-1.7 3-4.2 3-7.5s-1-5.8-3-7.5c-2-1.7-6.3-3.5-13-5.5-68\n-17.3-128.2-47.8-180.5-91.5-52.3-43.7-93.8-96.2-124.5-157.5-9.3-8-15.3-12.3-18\n-13h-6c-12 .7-18 4-18 10 0 2 1.7 7 5 15 23.3 46 52 87 86 123l10 10H0v40h399782\nc-328 0 0 0 0 0l10 8c26.7 20 65.7 43 117 69-2.7 2-6 3.7-10 5-36.7 16-72.3 37.3\n-107 64l-10 8H0v40zM0 157v40h399730v-40zm0 194v40h399730v-40z", + // leftarrow is from glyph U+2190 in font KaTeX Main + leftarrow: "M400000 241H110l3-3c68.7-52.7 113.7-120\n 135-202 4-14.7 6-23 6-25 0-7.3-7-11-21-11-8 0-13.2.8-15.5 2.5-2.3 1.7-4.2 5.8\n-5.5 12.5-1.3 4.7-2.7 10.3-4 17-12 48.7-34.8 92-68.5 130S65.3 228.3 18 247\nc-10 4-16 7.7-18 11 0 8.7 6 14.3 18 17 47.3 18.7 87.8 47 121.5 85S196 441.3 208\n 490c.7 2 1.3 5 2 9s1.2 6.7 1.5 8c.3 1.3 1 3.3 2 6s2.2 4.5 3.5 5.5c1.3 1 3.3\n 1.8 6 2.5s6 1 10 1c14 0 21-3.7 21-11 0-2-2-10.3-6-25-20-79.3-65-146.7-135-202\n l-3-3h399890zM100 241v40h399900v-40z", + // overbrace is from glyphs U+23A9/23A8/23A7 in font KaTeX_Size4-Regular + leftbrace: "M6 548l-6-6v-35l6-11c56-104 135.3-181.3 238-232 57.3-28.7 117\n-45 179-50h399577v120H403c-43.3 7-81 15-113 26-100.7 33-179.7 91-237 174-2.7\n 5-6 9-10 13-.7 1-7.3 1-20 1H6z", + leftbraceunder: "M0 6l6-6h17c12.688 0 19.313.3 20 1 4 4 7.313 8.3 10 13\n 35.313 51.3 80.813 93.8 136.5 127.5 55.688 33.7 117.188 55.8 184.5 66.5.688\n 0 2 .3 4 1 18.688 2.7 76 4.3 172 5h399450v120H429l-6-1c-124.688-8-235-61.7\n-331-161C60.687 138.7 32.312 99.3 7 54L0 41V6z", + // overgroup is from the MnSymbol package (public domain) + leftgroup: "M400000 80\nH435C64 80 168.3 229.4 21 260c-5.9 1.2-18 0-18 0-2 0-3-1-3-3v-38C76 61 257 0\n 435 0h399565z", + leftgroupunder: "M400000 262\nH435C64 262 168.3 112.6 21 82c-5.9-1.2-18 0-18 0-2 0-3 1-3 3v38c76 158 257 219\n 435 219h399565z", + // Harpoons are from glyph U+21BD in font KaTeX Main + leftharpoon: "M0 267c.7 5.3 3 10 7 14h399993v-40H93c3.3\n-3.3 10.2-9.5 20.5-18.5s17.8-15.8 22.5-20.5c50.7-52 88-110.3 112-175 4-11.3 5\n-18.3 3-21-1.3-4-7.3-6-18-6-8 0-13 .7-15 2s-4.7 6.7-8 16c-42 98.7-107.3 174.7\n-196 228-6.7 4.7-10.7 8-12 10-1.3 2-2 5.7-2 11zm100-26v40h399900v-40z", + leftharpoonplus: "M0 267c.7 5.3 3 10 7 14h399993v-40H93c3.3-3.3 10.2-9.5\n 20.5-18.5s17.8-15.8 22.5-20.5c50.7-52 88-110.3 112-175 4-11.3 5-18.3 3-21-1.3\n-4-7.3-6-18-6-8 0-13 .7-15 2s-4.7 6.7-8 16c-42 98.7-107.3 174.7-196 228-6.7 4.7\n-10.7 8-12 10-1.3 2-2 5.7-2 11zm100-26v40h399900v-40zM0 435v40h400000v-40z\nm0 0v40h400000v-40z", + leftharpoondown: "M7 241c-4 4-6.333 8.667-7 14 0 5.333.667 9 2 11s5.333\n 5.333 12 10c90.667 54 156 130 196 228 3.333 10.667 6.333 16.333 9 17 2 .667 5\n 1 9 1h5c10.667 0 16.667-2 18-6 2-2.667 1-9.667-3-21-32-87.333-82.667-157.667\n-152-211l-3-3h399907v-40zM93 281 H400000 v-40L7 241z", + leftharpoondownplus: "M7 435c-4 4-6.3 8.7-7 14 0 5.3.7 9 2 11s5.3 5.3 12\n 10c90.7 54 156 130 196 228 3.3 10.7 6.3 16.3 9 17 2 .7 5 1 9 1h5c10.7 0 16.7\n-2 18-6 2-2.7 1-9.7-3-21-32-87.3-82.7-157.7-152-211l-3-3h399907v-40H7zm93 0\nv40h399900v-40zM0 241v40h399900v-40zm0 0v40h399900v-40z", + // hook is from glyph U+21A9 in font KaTeX Main + lefthook: "M400000 281 H103s-33-11.2-61-33.5S0 197.3 0 164s14.2-61.2 42.5\n-83.5C70.8 58.2 104 47 142 47 c16.7 0 25 6.7 25 20 0 12-8.7 18.7-26 20-40 3.3\n-68.7 15.7-86 37-10 12-15 25.3-15 40 0 22.7 9.8 40.7 29.5 54 19.7 13.3 43.5 21\n 71.5 23h399859zM103 281v-40h399897v40z", + leftlinesegment: "M40 281 V428 H0 V94 H40 V241 H400000 v40z\nM40 281 V428 H0 V94 H40 V241 H400000 v40z", + leftmapsto: "M40 281 V448H0V74H40V241H400000v40z\nM40 281 V448H0V74H40V241H400000v40z", + // tofrom is from glyph U+21C4 in font KaTeX AMS Regular + leftToFrom: "M0 147h400000v40H0zm0 214c68 40 115.7 95.7 143 167h22c15.3 0 23\n-.3 23-1 0-1.3-5.3-13.7-16-37-18-35.3-41.3-69-70-101l-7-8h399905v-40H95l7-8\nc28.7-32 52-65.7 70-101 10.7-23.3 16-35.7 16-37 0-.7-7.7-1-23-1h-22C115.7 265.3\n 68 321 0 361zm0-174v-40h399900v40zm100 154v40h399900v-40z", + longequal: "M0 50 h400000 v40H0z m0 194h40000v40H0z\nM0 50 h400000 v40H0z m0 194h40000v40H0z", + midbrace: "M200428 334\nc-100.7-8.3-195.3-44-280-108-55.3-42-101.7-93-139-153l-9-14c-2.7 4-5.7 8.7-9 14\n-53.3 86.7-123.7 153-211 199-66.7 36-137.3 56.3-212 62H0V214h199568c178.3-11.7\n 311.7-78.3 403-201 6-8 9.7-12 11-12 .7-.7 6.7-1 18-1s17.3.3 18 1c1.3 0 5 4 11\n 12 44.7 59.3 101.3 106.3 170 141s145.3 54.3 229 60h199572v120z", + midbraceunder: "M199572 214\nc100.7 8.3 195.3 44 280 108 55.3 42 101.7 93 139 153l9 14c2.7-4 5.7-8.7 9-14\n 53.3-86.7 123.7-153 211-199 66.7-36 137.3-56.3 212-62h199568v120H200432c-178.3\n 11.7-311.7 78.3-403 201-6 8-9.7 12-11 12-.7.7-6.7 1-18 1s-17.3-.3-18-1c-1.3 0\n-5-4-11-12-44.7-59.3-101.3-106.3-170-141s-145.3-54.3-229-60H0V214z", + oiintSize1: "M512.6 71.6c272.6 0 320.3 106.8 320.3 178.2 0 70.8-47.7 177.6\n-320.3 177.6S193.1 320.6 193.1 249.8c0-71.4 46.9-178.2 319.5-178.2z\nm368.1 178.2c0-86.4-60.9-215.4-368.1-215.4-306.4 0-367.3 129-367.3 215.4 0 85.8\n60.9 214.8 367.3 214.8 307.2 0 368.1-129 368.1-214.8z", + oiintSize2: "M757.8 100.1c384.7 0 451.1 137.6 451.1 230 0 91.3-66.4 228.8\n-451.1 228.8-386.3 0-452.7-137.5-452.7-228.8 0-92.4 66.4-230 452.7-230z\nm502.4 230c0-111.2-82.4-277.2-502.4-277.2s-504 166-504 277.2\nc0 110 84 276 504 276s502.4-166 502.4-276z", + oiiintSize1: "M681.4 71.6c408.9 0 480.5 106.8 480.5 178.2 0 70.8-71.6 177.6\n-480.5 177.6S202.1 320.6 202.1 249.8c0-71.4 70.5-178.2 479.3-178.2z\nm525.8 178.2c0-86.4-86.8-215.4-525.7-215.4-437.9 0-524.7 129-524.7 215.4 0\n85.8 86.8 214.8 524.7 214.8 438.9 0 525.7-129 525.7-214.8z", + oiiintSize2: "M1021.2 53c603.6 0 707.8 165.8 707.8 277.2 0 110-104.2 275.8\n-707.8 275.8-606 0-710.2-165.8-710.2-275.8C311 218.8 415.2 53 1021.2 53z\nm770.4 277.1c0-131.2-126.4-327.6-770.5-327.6S248.4 198.9 248.4 330.1\nc0 130 128.8 326.4 772.7 326.4s770.5-196.4 770.5-326.4z", + rightarrow: "M0 241v40h399891c-47.3 35.3-84 78-110 128\n-16.7 32-27.7 63.7-33 95 0 1.3-.2 2.7-.5 4-.3 1.3-.5 2.3-.5 3 0 7.3 6.7 11 20\n 11 8 0 13.2-.8 15.5-2.5 2.3-1.7 4.2-5.5 5.5-11.5 2-13.3 5.7-27 11-41 14.7-44.7\n 39-84.5 73-119.5s73.7-60.2 119-75.5c6-2 9-5.7 9-11s-3-9-9-11c-45.3-15.3-85\n-40.5-119-75.5s-58.3-74.8-73-119.5c-4.7-14-8.3-27.3-11-40-1.3-6.7-3.2-10.8-5.5\n-12.5-2.3-1.7-7.5-2.5-15.5-2.5-14 0-21 3.7-21 11 0 2 2 10.3 6 25 20.7 83.3 67\n 151.7 139 205zm0 0v40h399900v-40z", + rightbrace: "M400000 542l\n-6 6h-17c-12.7 0-19.3-.3-20-1-4-4-7.3-8.3-10-13-35.3-51.3-80.8-93.8-136.5-127.5\ns-117.2-55.8-184.5-66.5c-.7 0-2-.3-4-1-18.7-2.7-76-4.3-172-5H0V214h399571l6 1\nc124.7 8 235 61.7 331 161 31.3 33.3 59.7 72.7 85 118l7 13v35z", + rightbraceunder: "M399994 0l6 6v35l-6 11c-56 104-135.3 181.3-238 232-57.3\n 28.7-117 45-179 50H-300V214h399897c43.3-7 81-15 113-26 100.7-33 179.7-91 237\n-174 2.7-5 6-9 10-13 .7-1 7.3-1 20-1h17z", + rightgroup: "M0 80h399565c371 0 266.7 149.4 414 180 5.9 1.2 18 0 18 0 2 0\n 3-1 3-3v-38c-76-158-257-219-435-219H0z", + rightgroupunder: "M0 262h399565c371 0 266.7-149.4 414-180 5.9-1.2 18 0 18\n 0 2 0 3 1 3 3v38c-76 158-257 219-435 219H0z", + rightharpoon: "M0 241v40h399993c4.7-4.7 7-9.3 7-14 0-9.3\n-3.7-15.3-11-18-92.7-56.7-159-133.7-199-231-3.3-9.3-6-14.7-8-16-2-1.3-7-2-15-2\n-10.7 0-16.7 2-18 6-2 2.7-1 9.7 3 21 15.3 42 36.7 81.8 64 119.5 27.3 37.7 58\n 69.2 92 94.5zm0 0v40h399900v-40z", + rightharpoonplus: "M0 241v40h399993c4.7-4.7 7-9.3 7-14 0-9.3-3.7-15.3-11\n-18-92.7-56.7-159-133.7-199-231-3.3-9.3-6-14.7-8-16-2-1.3-7-2-15-2-10.7 0-16.7\n 2-18 6-2 2.7-1 9.7 3 21 15.3 42 36.7 81.8 64 119.5 27.3 37.7 58 69.2 92 94.5z\nm0 0v40h399900v-40z m100 194v40h399900v-40zm0 0v40h399900v-40z", + rightharpoondown: "M399747 511c0 7.3 6.7 11 20 11 8 0 13-.8 15-2.5s4.7-6.8\n 8-15.5c40-94 99.3-166.3 178-217 13.3-8 20.3-12.3 21-13 5.3-3.3 8.5-5.8 9.5\n-7.5 1-1.7 1.5-5.2 1.5-10.5s-2.3-10.3-7-15H0v40h399908c-34 25.3-64.7 57-92 95\n-27.3 38-48.7 77.7-64 119-3.3 8.7-5 14-5 16zM0 241v40h399900v-40z", + rightharpoondownplus: "M399747 705c0 7.3 6.7 11 20 11 8 0 13-.8\n 15-2.5s4.7-6.8 8-15.5c40-94 99.3-166.3 178-217 13.3-8 20.3-12.3 21-13 5.3-3.3\n 8.5-5.8 9.5-7.5 1-1.7 1.5-5.2 1.5-10.5s-2.3-10.3-7-15H0v40h399908c-34 25.3\n-64.7 57-92 95-27.3 38-48.7 77.7-64 119-3.3 8.7-5 14-5 16zM0 435v40h399900v-40z\nm0-194v40h400000v-40zm0 0v40h400000v-40z", + righthook: "M399859 241c-764 0 0 0 0 0 40-3.3 68.7-15.7 86-37 10-12 15-25.3\n 15-40 0-22.7-9.8-40.7-29.5-54-19.7-13.3-43.5-21-71.5-23-17.3-1.3-26-8-26-20 0\n-13.3 8.7-20 26-20 38 0 71 11.2 99 33.5 0 0 7 5.6 21 16.7 14 11.2 21 33.5 21\n 66.8s-14 61.2-42 83.5c-28 22.3-61 33.5-99 33.5L0 241z M0 281v-40h399859v40z", + rightlinesegment: "M399960 241 V94 h40 V428 h-40 V281 H0 v-40z\nM399960 241 V94 h40 V428 h-40 V281 H0 v-40z", + rightToFrom: "M400000 167c-70.7-42-118-97.7-142-167h-23c-15.3 0-23 .3-23\n 1 0 1.3 5.3 13.7 16 37 18 35.3 41.3 69 70 101l7 8H0v40h399905l-7 8c-28.7 32\n-52 65.7-70 101-10.7 23.3-16 35.7-16 37 0 .7 7.7 1 23 1h23c24-69.3 71.3-125 142\n-167z M100 147v40h399900v-40zM0 341v40h399900v-40z", + // twoheadleftarrow is from glyph U+219E in font KaTeX AMS Regular + twoheadleftarrow: "M0 167c68 40\n 115.7 95.7 143 167h22c15.3 0 23-.3 23-1 0-1.3-5.3-13.7-16-37-18-35.3-41.3-69\n-70-101l-7-8h125l9 7c50.7 39.3 85 86 103 140h46c0-4.7-6.3-18.7-19-42-18-35.3\n-40-67.3-66-96l-9-9h399716v-40H284l9-9c26-28.7 48-60.7 66-96 12.7-23.333 19\n-37.333 19-42h-46c-18 54-52.3 100.7-103 140l-9 7H95l7-8c28.7-32 52-65.7 70-101\n 10.7-23.333 16-35.7 16-37 0-.7-7.7-1-23-1h-22C115.7 71.3 68 127 0 167z", + twoheadrightarrow: "M400000 167\nc-68-40-115.7-95.7-143-167h-22c-15.3 0-23 .3-23 1 0 1.3 5.3 13.7 16 37 18 35.3\n 41.3 69 70 101l7 8h-125l-9-7c-50.7-39.3-85-86-103-140h-46c0 4.7 6.3 18.7 19 42\n 18 35.3 40 67.3 66 96l9 9H0v40h399716l-9 9c-26 28.7-48 60.7-66 96-12.7 23.333\n-19 37.333-19 42h46c18-54 52.3-100.7 103-140l9-7h125l-7 8c-28.7 32-52 65.7-70\n 101-10.7 23.333-16 35.7-16 37 0 .7 7.7 1 23 1h22c27.3-71.3 75-127 143-167z", + // tilde1 is a modified version of a glyph from the MnSymbol package + tilde1: "M200 55.538c-77 0-168 73.953-177 73.953-3 0-7\n-2.175-9-5.437L2 97c-1-2-2-4-2-6 0-4 2-7 5-9l20-12C116 12 171 0 207 0c86 0\n 114 68 191 68 78 0 168-68 177-68 4 0 7 2 9 5l12 19c1 2.175 2 4.35 2 6.525 0\n 4.35-2 7.613-5 9.788l-19 13.05c-92 63.077-116.937 75.308-183 76.128\n-68.267.847-113-73.952-191-73.952z", + // ditto tilde2, tilde3, & tilde4 + tilde2: "M344 55.266c-142 0-300.638 81.316-311.5 86.418\n-8.01 3.762-22.5 10.91-23.5 5.562L1 120c-1-2-1-3-1-4 0-5 3-9 8-10l18.4-9C160.9\n 31.9 283 0 358 0c148 0 188 122 331 122s314-97 326-97c4 0 8 2 10 7l7 21.114\nc1 2.14 1 3.21 1 4.28 0 5.347-3 9.626-7 10.696l-22.3 12.622C852.6 158.372 751\n 181.476 676 181.476c-149 0-189-126.21-332-126.21z", + tilde3: "M786 59C457 59 32 175.242 13 175.242c-6 0-10-3.457\n-11-10.37L.15 138c-1-7 3-12 10-13l19.2-6.4C378.4 40.7 634.3 0 804.3 0c337 0\n 411.8 157 746.8 157 328 0 754-112 773-112 5 0 10 3 11 9l1 14.075c1 8.066-.697\n 16.595-6.697 17.492l-21.052 7.31c-367.9 98.146-609.15 122.696-778.15 122.696\n -338 0-409-156.573-744-156.573z", + tilde4: "M786 58C457 58 32 177.487 13 177.487c-6 0-10-3.345\n-11-10.035L.15 143c-1-7 3-12 10-13l22-6.7C381.2 35 637.15 0 807.15 0c337 0 409\n 177 744 177 328 0 754-127 773-127 5 0 10 3 11 9l1 14.794c1 7.805-3 13.38-9\n 14.495l-20.7 5.574c-366.85 99.79-607.3 139.372-776.3 139.372-338 0-409\n -175.236-744-175.236z", + // vec is from glyph U+20D7 in font KaTeX Main + vec: "M377 20c0-5.333 1.833-10 5.5-14S391 0 397 0c4.667 0 8.667 1.667 12 5\n3.333 2.667 6.667 9 10 19 6.667 24.667 20.333 43.667 41 57 7.333 4.667 11\n10.667 11 18 0 6-1 10-3 12s-6.667 5-14 9c-28.667 14.667-53.667 35.667-75 63\n-1.333 1.333-3.167 3.5-5.5 6.5s-4 4.833-5 5.5c-1 .667-2.5 1.333-4.5 2s-4.333 1\n-7 1c-4.667 0-9.167-1.833-13.5-5.5S337 184 337 178c0-12.667 15.667-32.333 47-59\nH213l-171-1c-8.667-6-13-12.333-13-19 0-4.667 4.333-11.333 13-20h359\nc-16-25.333-24-45-24-59z", + // widehat1 is a modified version of a glyph from the MnSymbol package + widehat1: "M529 0h5l519 115c5 1 9 5 9 10 0 1-1 2-1 3l-4 22\nc-1 5-5 9-11 9h-2L532 67 19 159h-2c-5 0-9-4-11-9l-5-22c-1-6 2-12 8-13z", + // ditto widehat2, widehat3, & widehat4 + widehat2: "M1181 0h2l1171 176c6 0 10 5 10 11l-2 23c-1 6-5 10\n-11 10h-1L1182 67 15 220h-1c-6 0-10-4-11-10l-2-23c-1-6 4-11 10-11z", + widehat3: "M1181 0h2l1171 236c6 0 10 5 10 11l-2 23c-1 6-5 10\n-11 10h-1L1182 67 15 280h-1c-6 0-10-4-11-10l-2-23c-1-6 4-11 10-11z", + widehat4: "M1181 0h2l1171 296c6 0 10 5 10 11l-2 23c-1 6-5 10\n-11 10h-1L1182 67 15 340h-1c-6 0-10-4-11-10l-2-23c-1-6 4-11 10-11z", + // widecheck paths are all inverted versions of widehat + widecheck1: "M529,159h5l519,-115c5,-1,9,-5,9,-10c0,-1,-1,-2,-1,-3l-4,-22c-1,\n-5,-5,-9,-11,-9h-2l-512,92l-513,-92h-2c-5,0,-9,4,-11,9l-5,22c-1,6,2,12,8,13z", + widecheck2: "M1181,220h2l1171,-176c6,0,10,-5,10,-11l-2,-23c-1,-6,-5,-10,\n-11,-10h-1l-1168,153l-1167,-153h-1c-6,0,-10,4,-11,10l-2,23c-1,6,4,11,10,11z", + widecheck3: "M1181,280h2l1171,-236c6,0,10,-5,10,-11l-2,-23c-1,-6,-5,-10,\n-11,-10h-1l-1168,213l-1167,-213h-1c-6,0,-10,4,-11,10l-2,23c-1,6,4,11,10,11z", + widecheck4: "M1181,340h2l1171,-296c6,0,10,-5,10,-11l-2,-23c-1,-6,-5,-10,\n-11,-10h-1l-1168,273l-1167,-273h-1c-6,0,-10,4,-11,10l-2,23c-1,6,4,11,10,11z", + // The next ten paths support reaction arrows from the mhchem package. + // Arrows for \ce{<-->} are offset from xAxis by 0.22ex, per mhchem in LaTeX + // baraboveleftarrow is mostly from from glyph U+2190 in font KaTeX Main + baraboveleftarrow: "M400000 620h-399890l3 -3c68.7 -52.7 113.7 -120 135 -202\nc4 -14.7 6 -23 6 -25c0 -7.3 -7 -11 -21 -11c-8 0 -13.2 0.8 -15.5 2.5\nc-2.3 1.7 -4.2 5.8 -5.5 12.5c-1.3 4.7 -2.7 10.3 -4 17c-12 48.7 -34.8 92 -68.5 130\ns-74.2 66.3 -121.5 85c-10 4 -16 7.7 -18 11c0 8.7 6 14.3 18 17c47.3 18.7 87.8 47\n121.5 85s56.5 81.3 68.5 130c0.7 2 1.3 5 2 9s1.2 6.7 1.5 8c0.3 1.3 1 3.3 2 6\ns2.2 4.5 3.5 5.5c1.3 1 3.3 1.8 6 2.5s6 1 10 1c14 0 21 -3.7 21 -11\nc0 -2 -2 -10.3 -6 -25c-20 -79.3 -65 -146.7 -135 -202l-3 -3h399890z\nM100 620v40h399900v-40z M0 241v40h399900v-40zM0 241v40h399900v-40z", + // rightarrowabovebar is mostly from glyph U+2192, KaTeX Main + rightarrowabovebar: "M0 241v40h399891c-47.3 35.3-84 78-110 128-16.7 32\n-27.7 63.7-33 95 0 1.3-.2 2.7-.5 4-.3 1.3-.5 2.3-.5 3 0 7.3 6.7 11 20 11 8 0\n13.2-.8 15.5-2.5 2.3-1.7 4.2-5.5 5.5-11.5 2-13.3 5.7-27 11-41 14.7-44.7 39\n-84.5 73-119.5s73.7-60.2 119-75.5c6-2 9-5.7 9-11s-3-9-9-11c-45.3-15.3-85-40.5\n-119-75.5s-58.3-74.8-73-119.5c-4.7-14-8.3-27.3-11-40-1.3-6.7-3.2-10.8-5.5\n-12.5-2.3-1.7-7.5-2.5-15.5-2.5-14 0-21 3.7-21 11 0 2 2 10.3 6 25 20.7 83.3 67\n151.7 139 205zm96 379h399894v40H0zm0 0h399904v40H0z", + // The short left harpoon has 0.5em (i.e. 500 units) kern on the left end. + // Ref from mhchem.sty: \rlap{\raisebox{-.22ex}{$\kern0.5em + baraboveshortleftharpoon: "M507,435c-4,4,-6.3,8.7,-7,14c0,5.3,0.7,9,2,11\nc1.3,2,5.3,5.3,12,10c90.7,54,156,130,196,228c3.3,10.7,6.3,16.3,9,17\nc2,0.7,5,1,9,1c0,0,5,0,5,0c10.7,0,16.7,-2,18,-6c2,-2.7,1,-9.7,-3,-21\nc-32,-87.3,-82.7,-157.7,-152,-211c0,0,-3,-3,-3,-3l399351,0l0,-40\nc-398570,0,-399437,0,-399437,0z M593 435 v40 H399500 v-40z\nM0 281 v-40 H399908 v40z M0 281 v-40 H399908 v40z", + rightharpoonaboveshortbar: "M0,241 l0,40c399126,0,399993,0,399993,0\nc4.7,-4.7,7,-9.3,7,-14c0,-9.3,-3.7,-15.3,-11,-18c-92.7,-56.7,-159,-133.7,-199,\n-231c-3.3,-9.3,-6,-14.7,-8,-16c-2,-1.3,-7,-2,-15,-2c-10.7,0,-16.7,2,-18,6\nc-2,2.7,-1,9.7,3,21c15.3,42,36.7,81.8,64,119.5c27.3,37.7,58,69.2,92,94.5z\nM0 241 v40 H399908 v-40z M0 475 v-40 H399500 v40z M0 475 v-40 H399500 v40z", + shortbaraboveleftharpoon: "M7,435c-4,4,-6.3,8.7,-7,14c0,5.3,0.7,9,2,11\nc1.3,2,5.3,5.3,12,10c90.7,54,156,130,196,228c3.3,10.7,6.3,16.3,9,17c2,0.7,5,1,9,\n1c0,0,5,0,5,0c10.7,0,16.7,-2,18,-6c2,-2.7,1,-9.7,-3,-21c-32,-87.3,-82.7,-157.7,\n-152,-211c0,0,-3,-3,-3,-3l399907,0l0,-40c-399126,0,-399993,0,-399993,0z\nM93 435 v40 H400000 v-40z M500 241 v40 H400000 v-40z M500 241 v40 H400000 v-40z", + shortrightharpoonabovebar: "M53,241l0,40c398570,0,399437,0,399437,0\nc4.7,-4.7,7,-9.3,7,-14c0,-9.3,-3.7,-15.3,-11,-18c-92.7,-56.7,-159,-133.7,-199,\n-231c-3.3,-9.3,-6,-14.7,-8,-16c-2,-1.3,-7,-2,-15,-2c-10.7,0,-16.7,2,-18,6\nc-2,2.7,-1,9.7,3,21c15.3,42,36.7,81.8,64,119.5c27.3,37.7,58,69.2,92,94.5z\nM500 241 v40 H399408 v-40z M500 435 v40 H400000 v-40z" +}; +// CONCATENATED MODULE: ./src/tree.js + + +/** + * This node represents a document fragment, which contains elements, but when + * placed into the DOM doesn't have any representation itself. It only contains + * children and doesn't have any DOM node properties. + */ +var tree_DocumentFragment = +/*#__PURE__*/ +function () { + // HtmlDomNode + // Never used; needed for satisfying interface. + function DocumentFragment(children) { + this.children = void 0; + this.classes = void 0; + this.height = void 0; + this.depth = void 0; + this.maxFontSize = void 0; + this.style = void 0; + this.children = children; + this.classes = []; + this.height = 0; + this.depth = 0; + this.maxFontSize = 0; + this.style = {}; + } + + var _proto = DocumentFragment.prototype; + + _proto.hasClass = function hasClass(className) { + return utils.contains(this.classes, className); + } + /** Convert the fragment into a node. */ + ; + + _proto.toNode = function toNode() { + var frag = document.createDocumentFragment(); + + for (var i = 0; i < this.children.length; i++) { + frag.appendChild(this.children[i].toNode()); + } + + return frag; + } + /** Convert the fragment into HTML markup. */ + ; + + _proto.toMarkup = function toMarkup() { + var markup = ""; // Simply concatenate the markup for the children together. + + for (var i = 0; i < this.children.length; i++) { + markup += this.children[i].toMarkup(); + } + + return markup; + } + /** + * Converts the math node into a string, similar to innerText. Applies to + * MathDomNode's only. + */ + ; + + _proto.toText = function toText() { + // To avoid this, we would subclass documentFragment separately for + // MathML, but polyfills for subclassing is expensive per PR 1469. + // $FlowFixMe: Only works for ChildType = MathDomNode. + var toText = function toText(child) { + return child.toText(); + }; + + return this.children.map(toText).join(""); + }; + + return DocumentFragment; +}(); +// CONCATENATED MODULE: ./src/domTree.js +/** + * These objects store the data about the DOM nodes we create, as well as some + * extra data. They can then be transformed into real DOM nodes with the + * `toNode` function or HTML markup using `toMarkup`. They are useful for both + * storing extra properties on the nodes, as well as providing a way to easily + * work with the DOM. + * + * Similar functions for working with MathML nodes exist in mathMLTree.js. + * + * TODO: refactor `span` and `anchor` into common superclass when + * target environments support class inheritance + */ + + + + + +/** + * Create an HTML className based on a list of classes. In addition to joining + * with spaces, we also remove empty classes. + */ +var createClass = function createClass(classes) { + return classes.filter(function (cls) { + return cls; + }).join(" "); +}; + +var initNode = function initNode(classes, options, style) { + this.classes = classes || []; + this.attributes = {}; + this.height = 0; + this.depth = 0; + this.maxFontSize = 0; + this.style = style || {}; + + if (options) { + if (options.style.isTight()) { + this.classes.push("mtight"); + } + + var color = options.getColor(); + + if (color) { + this.style.color = color; + } + } +}; +/** + * Convert into an HTML node + */ + + +var _toNode = function toNode(tagName) { + var node = document.createElement(tagName); // Apply the class + + node.className = createClass(this.classes); // Apply inline styles + + for (var style in this.style) { + if (this.style.hasOwnProperty(style)) { + // $FlowFixMe Flow doesn't seem to understand span.style's type. + node.style[style] = this.style[style]; + } + } // Apply attributes + + + for (var attr in this.attributes) { + if (this.attributes.hasOwnProperty(attr)) { + node.setAttribute(attr, this.attributes[attr]); + } + } // Append the children, also as HTML nodes + + + for (var i = 0; i < this.children.length; i++) { + node.appendChild(this.children[i].toNode()); + } + + return node; +}; +/** + * Convert into an HTML markup string + */ + + +var _toMarkup = function toMarkup(tagName) { + var markup = "<" + tagName; // Add the class + + if (this.classes.length) { + markup += " class=\"" + utils.escape(createClass(this.classes)) + "\""; + } + + var styles = ""; // Add the styles, after hyphenation + + for (var style in this.style) { + if (this.style.hasOwnProperty(style)) { + styles += utils.hyphenate(style) + ":" + this.style[style] + ";"; + } + } + + if (styles) { + markup += " style=\"" + utils.escape(styles) + "\""; + } // Add the attributes + + + for (var attr in this.attributes) { + if (this.attributes.hasOwnProperty(attr)) { + markup += " " + attr + "=\"" + utils.escape(this.attributes[attr]) + "\""; + } + } + + markup += ">"; // Add the markup of the children, also as markup + + for (var i = 0; i < this.children.length; i++) { + markup += this.children[i].toMarkup(); + } + + markup += ""; + return markup; +}; // Making the type below exact with all optional fields doesn't work due to +// - https://github.com/facebook/flow/issues/4582 +// - https://github.com/facebook/flow/issues/5688 +// However, since *all* fields are optional, $Shape<> works as suggested in 5688 +// above. +// This type does not include all CSS properties. Additional properties should +// be added as needed. + + +/** + * This node represents a span node, with a className, a list of children, and + * an inline style. It also contains information about its height, depth, and + * maxFontSize. + * + * Represents two types with different uses: SvgSpan to wrap an SVG and DomSpan + * otherwise. This typesafety is important when HTML builders access a span's + * children. + */ +var domTree_Span = +/*#__PURE__*/ +function () { + function Span(classes, children, options, style) { + this.children = void 0; + this.attributes = void 0; + this.classes = void 0; + this.height = void 0; + this.depth = void 0; + this.width = void 0; + this.maxFontSize = void 0; + this.style = void 0; + initNode.call(this, classes, options, style); + this.children = children || []; + } + /** + * Sets an arbitrary attribute on the span. Warning: use this wisely. Not + * all browsers support attributes the same, and having too many custom + * attributes is probably bad. + */ + + + var _proto = Span.prototype; + + _proto.setAttribute = function setAttribute(attribute, value) { + this.attributes[attribute] = value; + }; + + _proto.hasClass = function hasClass(className) { + return utils.contains(this.classes, className); + }; + + _proto.toNode = function toNode() { + return _toNode.call(this, "span"); + }; + + _proto.toMarkup = function toMarkup() { + return _toMarkup.call(this, "span"); + }; + + return Span; +}(); +/** + * This node represents an anchor () element with a hyperlink. See `span` + * for further details. + */ + +var domTree_Anchor = +/*#__PURE__*/ +function () { + function Anchor(href, classes, children, options) { + this.children = void 0; + this.attributes = void 0; + this.classes = void 0; + this.height = void 0; + this.depth = void 0; + this.maxFontSize = void 0; + this.style = void 0; + initNode.call(this, classes, options); + this.children = children || []; + this.setAttribute('href', href); + } + + var _proto2 = Anchor.prototype; + + _proto2.setAttribute = function setAttribute(attribute, value) { + this.attributes[attribute] = value; + }; + + _proto2.hasClass = function hasClass(className) { + return utils.contains(this.classes, className); + }; + + _proto2.toNode = function toNode() { + return _toNode.call(this, "a"); + }; + + _proto2.toMarkup = function toMarkup() { + return _toMarkup.call(this, "a"); + }; + + return Anchor; +}(); +/** + * This node represents an image embed () element. + */ + +var domTree_Img = +/*#__PURE__*/ +function () { + function Img(src, alt, style) { + this.src = void 0; + this.alt = void 0; + this.classes = void 0; + this.height = void 0; + this.depth = void 0; + this.maxFontSize = void 0; + this.style = void 0; + this.alt = alt; + this.src = src; + this.classes = ["mord"]; + this.style = style; + } + + var _proto3 = Img.prototype; + + _proto3.hasClass = function hasClass(className) { + return utils.contains(this.classes, className); + }; + + _proto3.toNode = function toNode() { + var node = document.createElement("img"); + node.src = this.src; + node.alt = this.alt; + node.className = "mord"; // Apply inline styles + + for (var style in this.style) { + if (this.style.hasOwnProperty(style)) { + // $FlowFixMe + node.style[style] = this.style[style]; + } + } + + return node; + }; + + _proto3.toMarkup = function toMarkup() { + var markup = "" + this.alt + " 0) { + span = document.createElement("span"); + span.style.marginRight = this.italic + "em"; + } + + if (this.classes.length > 0) { + span = span || document.createElement("span"); + span.className = createClass(this.classes); + } + + for (var style in this.style) { + if (this.style.hasOwnProperty(style)) { + span = span || document.createElement("span"); // $FlowFixMe Flow doesn't seem to understand span.style's type. + + span.style[style] = this.style[style]; + } + } + + if (span) { + span.appendChild(node); + return span; + } else { + return node; + } + } + /** + * Creates markup for a symbol node. + */ + ; + + _proto4.toMarkup = function toMarkup() { + // TODO(alpert): More duplication than I'd like from + // span.prototype.toMarkup and symbolNode.prototype.toNode... + var needsSpan = false; + var markup = " 0) { + styles += "margin-right:" + this.italic + "em;"; + } + + for (var style in this.style) { + if (this.style.hasOwnProperty(style)) { + styles += utils.hyphenate(style) + ":" + this.style[style] + ";"; + } + } + + if (styles) { + needsSpan = true; + markup += " style=\"" + utils.escape(styles) + "\""; + } + + var escaped = utils.escape(this.text); + + if (needsSpan) { + markup += ">"; + markup += escaped; + markup += ""; + return markup; + } else { + return escaped; + } + }; + + return SymbolNode; +}(); +/** + * SVG nodes are used to render stretchy wide elements. + */ + +var SvgNode = +/*#__PURE__*/ +function () { + function SvgNode(children, attributes) { + this.children = void 0; + this.attributes = void 0; + this.children = children || []; + this.attributes = attributes || {}; + } + + var _proto5 = SvgNode.prototype; + + _proto5.toNode = function toNode() { + var svgNS = "http://www.w3.org/2000/svg"; + var node = document.createElementNS(svgNS, "svg"); // Apply attributes + + for (var attr in this.attributes) { + if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) { + node.setAttribute(attr, this.attributes[attr]); + } + } + + for (var i = 0; i < this.children.length; i++) { + node.appendChild(this.children[i].toNode()); + } + + return node; + }; + + _proto5.toMarkup = function toMarkup() { + var markup = ""; + } else { + return ""; + } + }; + + return PathNode; +}(); +var LineNode = +/*#__PURE__*/ +function () { + function LineNode(attributes) { + this.attributes = void 0; + this.attributes = attributes || {}; + } + + var _proto7 = LineNode.prototype; + + _proto7.toNode = function toNode() { + var svgNS = "http://www.w3.org/2000/svg"; + var node = document.createElementNS(svgNS, "line"); // Apply attributes + + for (var attr in this.attributes) { + if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) { + node.setAttribute(attr, this.attributes[attr]); + } + } + + return node; + }; + + _proto7.toMarkup = function toMarkup() { + var markup = " but got " + String(group) + "."); + } +} +// CONCATENATED MODULE: ./submodules/katex-fonts/fontMetricsData.js +// This file is GENERATED by buildMetrics.sh. DO NOT MODIFY. +/* harmony default export */ var fontMetricsData = ({ + "AMS-Regular": { + "65": [0, 0.68889, 0, 0, 0.72222], + "66": [0, 0.68889, 0, 0, 0.66667], + "67": [0, 0.68889, 0, 0, 0.72222], + "68": [0, 0.68889, 0, 0, 0.72222], + "69": [0, 0.68889, 0, 0, 0.66667], + "70": [0, 0.68889, 0, 0, 0.61111], + "71": [0, 0.68889, 0, 0, 0.77778], + "72": [0, 0.68889, 0, 0, 0.77778], + "73": [0, 0.68889, 0, 0, 0.38889], + "74": [0.16667, 0.68889, 0, 0, 0.5], + "75": [0, 0.68889, 0, 0, 0.77778], + "76": [0, 0.68889, 0, 0, 0.66667], + "77": [0, 0.68889, 0, 0, 0.94445], + "78": [0, 0.68889, 0, 0, 0.72222], + "79": [0.16667, 0.68889, 0, 0, 0.77778], + "80": [0, 0.68889, 0, 0, 0.61111], + "81": [0.16667, 0.68889, 0, 0, 0.77778], + "82": [0, 0.68889, 0, 0, 0.72222], + "83": [0, 0.68889, 0, 0, 0.55556], + "84": [0, 0.68889, 0, 0, 0.66667], + "85": [0, 0.68889, 0, 0, 0.72222], + "86": [0, 0.68889, 0, 0, 0.72222], + "87": [0, 0.68889, 0, 0, 1.0], + "88": [0, 0.68889, 0, 0, 0.72222], + "89": [0, 0.68889, 0, 0, 0.72222], + "90": [0, 0.68889, 0, 0, 0.66667], + "107": [0, 0.68889, 0, 0, 0.55556], + "165": [0, 0.675, 0.025, 0, 0.75], + "174": [0.15559, 0.69224, 0, 0, 0.94666], + "240": [0, 0.68889, 0, 0, 0.55556], + "295": [0, 0.68889, 0, 0, 0.54028], + "710": [0, 0.825, 0, 0, 2.33334], + "732": [0, 0.9, 0, 0, 2.33334], + "770": [0, 0.825, 0, 0, 2.33334], + "771": [0, 0.9, 0, 0, 2.33334], + "989": [0.08167, 0.58167, 0, 0, 0.77778], + "1008": [0, 0.43056, 0.04028, 0, 0.66667], + "8245": [0, 0.54986, 0, 0, 0.275], + "8463": [0, 0.68889, 0, 0, 0.54028], + "8487": [0, 0.68889, 0, 0, 0.72222], + "8498": [0, 0.68889, 0, 0, 0.55556], + "8502": [0, 0.68889, 0, 0, 0.66667], + "8503": [0, 0.68889, 0, 0, 0.44445], + "8504": [0, 0.68889, 0, 0, 0.66667], + "8513": [0, 0.68889, 0, 0, 0.63889], + "8592": [-0.03598, 0.46402, 0, 0, 0.5], + "8594": [-0.03598, 0.46402, 0, 0, 0.5], + "8602": [-0.13313, 0.36687, 0, 0, 1.0], + "8603": [-0.13313, 0.36687, 0, 0, 1.0], + "8606": [0.01354, 0.52239, 0, 0, 1.0], + "8608": [0.01354, 0.52239, 0, 0, 1.0], + "8610": [0.01354, 0.52239, 0, 0, 1.11111], + "8611": [0.01354, 0.52239, 0, 0, 1.11111], + "8619": [0, 0.54986, 0, 0, 1.0], + "8620": [0, 0.54986, 0, 0, 1.0], + "8621": [-0.13313, 0.37788, 0, 0, 1.38889], + "8622": [-0.13313, 0.36687, 0, 0, 1.0], + "8624": [0, 0.69224, 0, 0, 0.5], + "8625": [0, 0.69224, 0, 0, 0.5], + "8630": [0, 0.43056, 0, 0, 1.0], + "8631": [0, 0.43056, 0, 0, 1.0], + "8634": [0.08198, 0.58198, 0, 0, 0.77778], + "8635": [0.08198, 0.58198, 0, 0, 0.77778], + "8638": [0.19444, 0.69224, 0, 0, 0.41667], + "8639": [0.19444, 0.69224, 0, 0, 0.41667], + "8642": [0.19444, 0.69224, 0, 0, 0.41667], + "8643": [0.19444, 0.69224, 0, 0, 0.41667], + "8644": [0.1808, 0.675, 0, 0, 1.0], + "8646": [0.1808, 0.675, 0, 0, 1.0], + "8647": [0.1808, 0.675, 0, 0, 1.0], + "8648": [0.19444, 0.69224, 0, 0, 0.83334], + "8649": [0.1808, 0.675, 0, 0, 1.0], + "8650": [0.19444, 0.69224, 0, 0, 0.83334], + "8651": [0.01354, 0.52239, 0, 0, 1.0], + "8652": [0.01354, 0.52239, 0, 0, 1.0], + "8653": [-0.13313, 0.36687, 0, 0, 1.0], + "8654": [-0.13313, 0.36687, 0, 0, 1.0], + "8655": [-0.13313, 0.36687, 0, 0, 1.0], + "8666": [0.13667, 0.63667, 0, 0, 1.0], + "8667": [0.13667, 0.63667, 0, 0, 1.0], + "8669": [-0.13313, 0.37788, 0, 0, 1.0], + "8672": [-0.064, 0.437, 0, 0, 1.334], + "8674": [-0.064, 0.437, 0, 0, 1.334], + "8705": [0, 0.825, 0, 0, 0.5], + "8708": [0, 0.68889, 0, 0, 0.55556], + "8709": [0.08167, 0.58167, 0, 0, 0.77778], + "8717": [0, 0.43056, 0, 0, 0.42917], + "8722": [-0.03598, 0.46402, 0, 0, 0.5], + "8724": [0.08198, 0.69224, 0, 0, 0.77778], + "8726": [0.08167, 0.58167, 0, 0, 0.77778], + "8733": [0, 0.69224, 0, 0, 0.77778], + "8736": [0, 0.69224, 0, 0, 0.72222], + "8737": [0, 0.69224, 0, 0, 0.72222], + "8738": [0.03517, 0.52239, 0, 0, 0.72222], + "8739": [0.08167, 0.58167, 0, 0, 0.22222], + "8740": [0.25142, 0.74111, 0, 0, 0.27778], + "8741": [0.08167, 0.58167, 0, 0, 0.38889], + "8742": [0.25142, 0.74111, 0, 0, 0.5], + "8756": [0, 0.69224, 0, 0, 0.66667], + "8757": [0, 0.69224, 0, 0, 0.66667], + "8764": [-0.13313, 0.36687, 0, 0, 0.77778], + "8765": [-0.13313, 0.37788, 0, 0, 0.77778], + "8769": [-0.13313, 0.36687, 0, 0, 0.77778], + "8770": [-0.03625, 0.46375, 0, 0, 0.77778], + "8774": [0.30274, 0.79383, 0, 0, 0.77778], + "8776": [-0.01688, 0.48312, 0, 0, 0.77778], + "8778": [0.08167, 0.58167, 0, 0, 0.77778], + "8782": [0.06062, 0.54986, 0, 0, 0.77778], + "8783": [0.06062, 0.54986, 0, 0, 0.77778], + "8785": [0.08198, 0.58198, 0, 0, 0.77778], + "8786": [0.08198, 0.58198, 0, 0, 0.77778], + "8787": [0.08198, 0.58198, 0, 0, 0.77778], + "8790": [0, 0.69224, 0, 0, 0.77778], + "8791": [0.22958, 0.72958, 0, 0, 0.77778], + "8796": [0.08198, 0.91667, 0, 0, 0.77778], + "8806": [0.25583, 0.75583, 0, 0, 0.77778], + "8807": [0.25583, 0.75583, 0, 0, 0.77778], + "8808": [0.25142, 0.75726, 0, 0, 0.77778], + "8809": [0.25142, 0.75726, 0, 0, 0.77778], + "8812": [0.25583, 0.75583, 0, 0, 0.5], + "8814": [0.20576, 0.70576, 0, 0, 0.77778], + "8815": [0.20576, 0.70576, 0, 0, 0.77778], + "8816": [0.30274, 0.79383, 0, 0, 0.77778], + "8817": [0.30274, 0.79383, 0, 0, 0.77778], + "8818": [0.22958, 0.72958, 0, 0, 0.77778], + "8819": [0.22958, 0.72958, 0, 0, 0.77778], + "8822": [0.1808, 0.675, 0, 0, 0.77778], + "8823": [0.1808, 0.675, 0, 0, 0.77778], + "8828": [0.13667, 0.63667, 0, 0, 0.77778], + "8829": [0.13667, 0.63667, 0, 0, 0.77778], + "8830": [0.22958, 0.72958, 0, 0, 0.77778], + "8831": [0.22958, 0.72958, 0, 0, 0.77778], + "8832": [0.20576, 0.70576, 0, 0, 0.77778], + "8833": [0.20576, 0.70576, 0, 0, 0.77778], + "8840": [0.30274, 0.79383, 0, 0, 0.77778], + "8841": [0.30274, 0.79383, 0, 0, 0.77778], + "8842": [0.13597, 0.63597, 0, 0, 0.77778], + "8843": [0.13597, 0.63597, 0, 0, 0.77778], + "8847": [0.03517, 0.54986, 0, 0, 0.77778], + "8848": [0.03517, 0.54986, 0, 0, 0.77778], + "8858": [0.08198, 0.58198, 0, 0, 0.77778], + "8859": [0.08198, 0.58198, 0, 0, 0.77778], + "8861": [0.08198, 0.58198, 0, 0, 0.77778], + "8862": [0, 0.675, 0, 0, 0.77778], + "8863": [0, 0.675, 0, 0, 0.77778], + "8864": [0, 0.675, 0, 0, 0.77778], + "8865": [0, 0.675, 0, 0, 0.77778], + "8872": [0, 0.69224, 0, 0, 0.61111], + "8873": [0, 0.69224, 0, 0, 0.72222], + "8874": [0, 0.69224, 0, 0, 0.88889], + "8876": [0, 0.68889, 0, 0, 0.61111], + "8877": [0, 0.68889, 0, 0, 0.61111], + "8878": [0, 0.68889, 0, 0, 0.72222], + "8879": [0, 0.68889, 0, 0, 0.72222], + "8882": [0.03517, 0.54986, 0, 0, 0.77778], + "8883": [0.03517, 0.54986, 0, 0, 0.77778], + "8884": [0.13667, 0.63667, 0, 0, 0.77778], + "8885": [0.13667, 0.63667, 0, 0, 0.77778], + "8888": [0, 0.54986, 0, 0, 1.11111], + "8890": [0.19444, 0.43056, 0, 0, 0.55556], + "8891": [0.19444, 0.69224, 0, 0, 0.61111], + "8892": [0.19444, 0.69224, 0, 0, 0.61111], + "8901": [0, 0.54986, 0, 0, 0.27778], + "8903": [0.08167, 0.58167, 0, 0, 0.77778], + "8905": [0.08167, 0.58167, 0, 0, 0.77778], + "8906": [0.08167, 0.58167, 0, 0, 0.77778], + "8907": [0, 0.69224, 0, 0, 0.77778], + "8908": [0, 0.69224, 0, 0, 0.77778], + "8909": [-0.03598, 0.46402, 0, 0, 0.77778], + "8910": [0, 0.54986, 0, 0, 0.76042], + "8911": [0, 0.54986, 0, 0, 0.76042], + "8912": [0.03517, 0.54986, 0, 0, 0.77778], + "8913": [0.03517, 0.54986, 0, 0, 0.77778], + "8914": [0, 0.54986, 0, 0, 0.66667], + "8915": [0, 0.54986, 0, 0, 0.66667], + "8916": [0, 0.69224, 0, 0, 0.66667], + "8918": [0.0391, 0.5391, 0, 0, 0.77778], + "8919": [0.0391, 0.5391, 0, 0, 0.77778], + "8920": [0.03517, 0.54986, 0, 0, 1.33334], + "8921": [0.03517, 0.54986, 0, 0, 1.33334], + "8922": [0.38569, 0.88569, 0, 0, 0.77778], + "8923": [0.38569, 0.88569, 0, 0, 0.77778], + "8926": [0.13667, 0.63667, 0, 0, 0.77778], + "8927": [0.13667, 0.63667, 0, 0, 0.77778], + "8928": [0.30274, 0.79383, 0, 0, 0.77778], + "8929": [0.30274, 0.79383, 0, 0, 0.77778], + "8934": [0.23222, 0.74111, 0, 0, 0.77778], + "8935": [0.23222, 0.74111, 0, 0, 0.77778], + "8936": [0.23222, 0.74111, 0, 0, 0.77778], + "8937": [0.23222, 0.74111, 0, 0, 0.77778], + "8938": [0.20576, 0.70576, 0, 0, 0.77778], + "8939": [0.20576, 0.70576, 0, 0, 0.77778], + "8940": [0.30274, 0.79383, 0, 0, 0.77778], + "8941": [0.30274, 0.79383, 0, 0, 0.77778], + "8994": [0.19444, 0.69224, 0, 0, 0.77778], + "8995": [0.19444, 0.69224, 0, 0, 0.77778], + "9416": [0.15559, 0.69224, 0, 0, 0.90222], + "9484": [0, 0.69224, 0, 0, 0.5], + "9488": [0, 0.69224, 0, 0, 0.5], + "9492": [0, 0.37788, 0, 0, 0.5], + "9496": [0, 0.37788, 0, 0, 0.5], + "9585": [0.19444, 0.68889, 0, 0, 0.88889], + "9586": [0.19444, 0.74111, 0, 0, 0.88889], + "9632": [0, 0.675, 0, 0, 0.77778], + "9633": [0, 0.675, 0, 0, 0.77778], + "9650": [0, 0.54986, 0, 0, 0.72222], + "9651": [0, 0.54986, 0, 0, 0.72222], + "9654": [0.03517, 0.54986, 0, 0, 0.77778], + "9660": [0, 0.54986, 0, 0, 0.72222], + "9661": [0, 0.54986, 0, 0, 0.72222], + "9664": [0.03517, 0.54986, 0, 0, 0.77778], + "9674": [0.11111, 0.69224, 0, 0, 0.66667], + "9733": [0.19444, 0.69224, 0, 0, 0.94445], + "10003": [0, 0.69224, 0, 0, 0.83334], + "10016": [0, 0.69224, 0, 0, 0.83334], + "10731": [0.11111, 0.69224, 0, 0, 0.66667], + "10846": [0.19444, 0.75583, 0, 0, 0.61111], + "10877": [0.13667, 0.63667, 0, 0, 0.77778], + "10878": [0.13667, 0.63667, 0, 0, 0.77778], + "10885": [0.25583, 0.75583, 0, 0, 0.77778], + "10886": [0.25583, 0.75583, 0, 0, 0.77778], + "10887": [0.13597, 0.63597, 0, 0, 0.77778], + "10888": [0.13597, 0.63597, 0, 0, 0.77778], + "10889": [0.26167, 0.75726, 0, 0, 0.77778], + "10890": [0.26167, 0.75726, 0, 0, 0.77778], + "10891": [0.48256, 0.98256, 0, 0, 0.77778], + "10892": [0.48256, 0.98256, 0, 0, 0.77778], + "10901": [0.13667, 0.63667, 0, 0, 0.77778], + "10902": [0.13667, 0.63667, 0, 0, 0.77778], + "10933": [0.25142, 0.75726, 0, 0, 0.77778], + "10934": [0.25142, 0.75726, 0, 0, 0.77778], + "10935": [0.26167, 0.75726, 0, 0, 0.77778], + "10936": [0.26167, 0.75726, 0, 0, 0.77778], + "10937": [0.26167, 0.75726, 0, 0, 0.77778], + "10938": [0.26167, 0.75726, 0, 0, 0.77778], + "10949": [0.25583, 0.75583, 0, 0, 0.77778], + "10950": [0.25583, 0.75583, 0, 0, 0.77778], + "10955": [0.28481, 0.79383, 0, 0, 0.77778], + "10956": [0.28481, 0.79383, 0, 0, 0.77778], + "57350": [0.08167, 0.58167, 0, 0, 0.22222], + "57351": [0.08167, 0.58167, 0, 0, 0.38889], + "57352": [0.08167, 0.58167, 0, 0, 0.77778], + "57353": [0, 0.43056, 0.04028, 0, 0.66667], + "57356": [0.25142, 0.75726, 0, 0, 0.77778], + "57357": [0.25142, 0.75726, 0, 0, 0.77778], + "57358": [0.41951, 0.91951, 0, 0, 0.77778], + "57359": [0.30274, 0.79383, 0, 0, 0.77778], + "57360": [0.30274, 0.79383, 0, 0, 0.77778], + "57361": [0.41951, 0.91951, 0, 0, 0.77778], + "57366": [0.25142, 0.75726, 0, 0, 0.77778], + "57367": [0.25142, 0.75726, 0, 0, 0.77778], + "57368": [0.25142, 0.75726, 0, 0, 0.77778], + "57369": [0.25142, 0.75726, 0, 0, 0.77778], + "57370": [0.13597, 0.63597, 0, 0, 0.77778], + "57371": [0.13597, 0.63597, 0, 0, 0.77778] + }, + "Caligraphic-Regular": { + "48": [0, 0.43056, 0, 0, 0.5], + "49": [0, 0.43056, 0, 0, 0.5], + "50": [0, 0.43056, 0, 0, 0.5], + "51": [0.19444, 0.43056, 0, 0, 0.5], + "52": [0.19444, 0.43056, 0, 0, 0.5], + "53": [0.19444, 0.43056, 0, 0, 0.5], + "54": [0, 0.64444, 0, 0, 0.5], + "55": [0.19444, 0.43056, 0, 0, 0.5], + "56": [0, 0.64444, 0, 0, 0.5], + "57": [0.19444, 0.43056, 0, 0, 0.5], + "65": [0, 0.68333, 0, 0.19445, 0.79847], + "66": [0, 0.68333, 0.03041, 0.13889, 0.65681], + "67": [0, 0.68333, 0.05834, 0.13889, 0.52653], + "68": [0, 0.68333, 0.02778, 0.08334, 0.77139], + "69": [0, 0.68333, 0.08944, 0.11111, 0.52778], + "70": [0, 0.68333, 0.09931, 0.11111, 0.71875], + "71": [0.09722, 0.68333, 0.0593, 0.11111, 0.59487], + "72": [0, 0.68333, 0.00965, 0.11111, 0.84452], + "73": [0, 0.68333, 0.07382, 0, 0.54452], + "74": [0.09722, 0.68333, 0.18472, 0.16667, 0.67778], + "75": [0, 0.68333, 0.01445, 0.05556, 0.76195], + "76": [0, 0.68333, 0, 0.13889, 0.68972], + "77": [0, 0.68333, 0, 0.13889, 1.2009], + "78": [0, 0.68333, 0.14736, 0.08334, 0.82049], + "79": [0, 0.68333, 0.02778, 0.11111, 0.79611], + "80": [0, 0.68333, 0.08222, 0.08334, 0.69556], + "81": [0.09722, 0.68333, 0, 0.11111, 0.81667], + "82": [0, 0.68333, 0, 0.08334, 0.8475], + "83": [0, 0.68333, 0.075, 0.13889, 0.60556], + "84": [0, 0.68333, 0.25417, 0, 0.54464], + "85": [0, 0.68333, 0.09931, 0.08334, 0.62583], + "86": [0, 0.68333, 0.08222, 0, 0.61278], + "87": [0, 0.68333, 0.08222, 0.08334, 0.98778], + "88": [0, 0.68333, 0.14643, 0.13889, 0.7133], + "89": [0.09722, 0.68333, 0.08222, 0.08334, 0.66834], + "90": [0, 0.68333, 0.07944, 0.13889, 0.72473] + }, + "Fraktur-Regular": { + "33": [0, 0.69141, 0, 0, 0.29574], + "34": [0, 0.69141, 0, 0, 0.21471], + "38": [0, 0.69141, 0, 0, 0.73786], + "39": [0, 0.69141, 0, 0, 0.21201], + "40": [0.24982, 0.74947, 0, 0, 0.38865], + "41": [0.24982, 0.74947, 0, 0, 0.38865], + "42": [0, 0.62119, 0, 0, 0.27764], + "43": [0.08319, 0.58283, 0, 0, 0.75623], + "44": [0, 0.10803, 0, 0, 0.27764], + "45": [0.08319, 0.58283, 0, 0, 0.75623], + "46": [0, 0.10803, 0, 0, 0.27764], + "47": [0.24982, 0.74947, 0, 0, 0.50181], + "48": [0, 0.47534, 0, 0, 0.50181], + "49": [0, 0.47534, 0, 0, 0.50181], + "50": [0, 0.47534, 0, 0, 0.50181], + "51": [0.18906, 0.47534, 0, 0, 0.50181], + "52": [0.18906, 0.47534, 0, 0, 0.50181], + "53": [0.18906, 0.47534, 0, 0, 0.50181], + "54": [0, 0.69141, 0, 0, 0.50181], + "55": [0.18906, 0.47534, 0, 0, 0.50181], + "56": [0, 0.69141, 0, 0, 0.50181], + "57": [0.18906, 0.47534, 0, 0, 0.50181], + "58": [0, 0.47534, 0, 0, 0.21606], + "59": [0.12604, 0.47534, 0, 0, 0.21606], + "61": [-0.13099, 0.36866, 0, 0, 0.75623], + "63": [0, 0.69141, 0, 0, 0.36245], + "65": [0, 0.69141, 0, 0, 0.7176], + "66": [0, 0.69141, 0, 0, 0.88397], + "67": [0, 0.69141, 0, 0, 0.61254], + "68": [0, 0.69141, 0, 0, 0.83158], + "69": [0, 0.69141, 0, 0, 0.66278], + "70": [0.12604, 0.69141, 0, 0, 0.61119], + "71": [0, 0.69141, 0, 0, 0.78539], + "72": [0.06302, 0.69141, 0, 0, 0.7203], + "73": [0, 0.69141, 0, 0, 0.55448], + "74": [0.12604, 0.69141, 0, 0, 0.55231], + "75": [0, 0.69141, 0, 0, 0.66845], + "76": [0, 0.69141, 0, 0, 0.66602], + "77": [0, 0.69141, 0, 0, 1.04953], + "78": [0, 0.69141, 0, 0, 0.83212], + "79": [0, 0.69141, 0, 0, 0.82699], + "80": [0.18906, 0.69141, 0, 0, 0.82753], + "81": [0.03781, 0.69141, 0, 0, 0.82699], + "82": [0, 0.69141, 0, 0, 0.82807], + "83": [0, 0.69141, 0, 0, 0.82861], + "84": [0, 0.69141, 0, 0, 0.66899], + "85": [0, 0.69141, 0, 0, 0.64576], + "86": [0, 0.69141, 0, 0, 0.83131], + "87": [0, 0.69141, 0, 0, 1.04602], + "88": [0, 0.69141, 0, 0, 0.71922], + "89": [0.18906, 0.69141, 0, 0, 0.83293], + "90": [0.12604, 0.69141, 0, 0, 0.60201], + "91": [0.24982, 0.74947, 0, 0, 0.27764], + "93": [0.24982, 0.74947, 0, 0, 0.27764], + "94": [0, 0.69141, 0, 0, 0.49965], + "97": [0, 0.47534, 0, 0, 0.50046], + "98": [0, 0.69141, 0, 0, 0.51315], + "99": [0, 0.47534, 0, 0, 0.38946], + "100": [0, 0.62119, 0, 0, 0.49857], + "101": [0, 0.47534, 0, 0, 0.40053], + "102": [0.18906, 0.69141, 0, 0, 0.32626], + "103": [0.18906, 0.47534, 0, 0, 0.5037], + "104": [0.18906, 0.69141, 0, 0, 0.52126], + "105": [0, 0.69141, 0, 0, 0.27899], + "106": [0, 0.69141, 0, 0, 0.28088], + "107": [0, 0.69141, 0, 0, 0.38946], + "108": [0, 0.69141, 0, 0, 0.27953], + "109": [0, 0.47534, 0, 0, 0.76676], + "110": [0, 0.47534, 0, 0, 0.52666], + "111": [0, 0.47534, 0, 0, 0.48885], + "112": [0.18906, 0.52396, 0, 0, 0.50046], + "113": [0.18906, 0.47534, 0, 0, 0.48912], + "114": [0, 0.47534, 0, 0, 0.38919], + "115": [0, 0.47534, 0, 0, 0.44266], + "116": [0, 0.62119, 0, 0, 0.33301], + "117": [0, 0.47534, 0, 0, 0.5172], + "118": [0, 0.52396, 0, 0, 0.5118], + "119": [0, 0.52396, 0, 0, 0.77351], + "120": [0.18906, 0.47534, 0, 0, 0.38865], + "121": [0.18906, 0.47534, 0, 0, 0.49884], + "122": [0.18906, 0.47534, 0, 0, 0.39054], + "8216": [0, 0.69141, 0, 0, 0.21471], + "8217": [0, 0.69141, 0, 0, 0.21471], + "58112": [0, 0.62119, 0, 0, 0.49749], + "58113": [0, 0.62119, 0, 0, 0.4983], + "58114": [0.18906, 0.69141, 0, 0, 0.33328], + "58115": [0.18906, 0.69141, 0, 0, 0.32923], + "58116": [0.18906, 0.47534, 0, 0, 0.50343], + "58117": [0, 0.69141, 0, 0, 0.33301], + "58118": [0, 0.62119, 0, 0, 0.33409], + "58119": [0, 0.47534, 0, 0, 0.50073] + }, + "Main-Bold": { + "33": [0, 0.69444, 0, 0, 0.35], + "34": [0, 0.69444, 0, 0, 0.60278], + "35": [0.19444, 0.69444, 0, 0, 0.95833], + "36": [0.05556, 0.75, 0, 0, 0.575], + "37": [0.05556, 0.75, 0, 0, 0.95833], + "38": [0, 0.69444, 0, 0, 0.89444], + "39": [0, 0.69444, 0, 0, 0.31944], + "40": [0.25, 0.75, 0, 0, 0.44722], + "41": [0.25, 0.75, 0, 0, 0.44722], + "42": [0, 0.75, 0, 0, 0.575], + "43": [0.13333, 0.63333, 0, 0, 0.89444], + "44": [0.19444, 0.15556, 0, 0, 0.31944], + "45": [0, 0.44444, 0, 0, 0.38333], + "46": [0, 0.15556, 0, 0, 0.31944], + "47": [0.25, 0.75, 0, 0, 0.575], + "48": [0, 0.64444, 0, 0, 0.575], + "49": [0, 0.64444, 0, 0, 0.575], + "50": [0, 0.64444, 0, 0, 0.575], + "51": [0, 0.64444, 0, 0, 0.575], + "52": [0, 0.64444, 0, 0, 0.575], + "53": [0, 0.64444, 0, 0, 0.575], + "54": [0, 0.64444, 0, 0, 0.575], + "55": [0, 0.64444, 0, 0, 0.575], + "56": [0, 0.64444, 0, 0, 0.575], + "57": [0, 0.64444, 0, 0, 0.575], + "58": [0, 0.44444, 0, 0, 0.31944], + "59": [0.19444, 0.44444, 0, 0, 0.31944], + "60": [0.08556, 0.58556, 0, 0, 0.89444], + "61": [-0.10889, 0.39111, 0, 0, 0.89444], + "62": [0.08556, 0.58556, 0, 0, 0.89444], + "63": [0, 0.69444, 0, 0, 0.54305], + "64": [0, 0.69444, 0, 0, 0.89444], + "65": [0, 0.68611, 0, 0, 0.86944], + "66": [0, 0.68611, 0, 0, 0.81805], + "67": [0, 0.68611, 0, 0, 0.83055], + "68": [0, 0.68611, 0, 0, 0.88194], + "69": [0, 0.68611, 0, 0, 0.75555], + "70": [0, 0.68611, 0, 0, 0.72361], + "71": [0, 0.68611, 0, 0, 0.90416], + "72": [0, 0.68611, 0, 0, 0.9], + "73": [0, 0.68611, 0, 0, 0.43611], + "74": [0, 0.68611, 0, 0, 0.59444], + "75": [0, 0.68611, 0, 0, 0.90138], + "76": [0, 0.68611, 0, 0, 0.69166], + "77": [0, 0.68611, 0, 0, 1.09166], + "78": [0, 0.68611, 0, 0, 0.9], + "79": [0, 0.68611, 0, 0, 0.86388], + "80": [0, 0.68611, 0, 0, 0.78611], + "81": [0.19444, 0.68611, 0, 0, 0.86388], + "82": [0, 0.68611, 0, 0, 0.8625], + "83": [0, 0.68611, 0, 0, 0.63889], + "84": [0, 0.68611, 0, 0, 0.8], + "85": [0, 0.68611, 0, 0, 0.88472], + "86": [0, 0.68611, 0.01597, 0, 0.86944], + "87": [0, 0.68611, 0.01597, 0, 1.18888], + "88": [0, 0.68611, 0, 0, 0.86944], + "89": [0, 0.68611, 0.02875, 0, 0.86944], + "90": [0, 0.68611, 0, 0, 0.70277], + "91": [0.25, 0.75, 0, 0, 0.31944], + "92": [0.25, 0.75, 0, 0, 0.575], + "93": [0.25, 0.75, 0, 0, 0.31944], + "94": [0, 0.69444, 0, 0, 0.575], + "95": [0.31, 0.13444, 0.03194, 0, 0.575], + "97": [0, 0.44444, 0, 0, 0.55902], + "98": [0, 0.69444, 0, 0, 0.63889], + "99": [0, 0.44444, 0, 0, 0.51111], + "100": [0, 0.69444, 0, 0, 0.63889], + "101": [0, 0.44444, 0, 0, 0.52708], + "102": [0, 0.69444, 0.10903, 0, 0.35139], + "103": [0.19444, 0.44444, 0.01597, 0, 0.575], + "104": [0, 0.69444, 0, 0, 0.63889], + "105": [0, 0.69444, 0, 0, 0.31944], + "106": [0.19444, 0.69444, 0, 0, 0.35139], + "107": [0, 0.69444, 0, 0, 0.60694], + "108": [0, 0.69444, 0, 0, 0.31944], + "109": [0, 0.44444, 0, 0, 0.95833], + "110": [0, 0.44444, 0, 0, 0.63889], + "111": [0, 0.44444, 0, 0, 0.575], + "112": [0.19444, 0.44444, 0, 0, 0.63889], + "113": [0.19444, 0.44444, 0, 0, 0.60694], + "114": [0, 0.44444, 0, 0, 0.47361], + "115": [0, 0.44444, 0, 0, 0.45361], + "116": [0, 0.63492, 0, 0, 0.44722], + "117": [0, 0.44444, 0, 0, 0.63889], + "118": [0, 0.44444, 0.01597, 0, 0.60694], + "119": [0, 0.44444, 0.01597, 0, 0.83055], + "120": [0, 0.44444, 0, 0, 0.60694], + "121": [0.19444, 0.44444, 0.01597, 0, 0.60694], + "122": [0, 0.44444, 0, 0, 0.51111], + "123": [0.25, 0.75, 0, 0, 0.575], + "124": [0.25, 0.75, 0, 0, 0.31944], + "125": [0.25, 0.75, 0, 0, 0.575], + "126": [0.35, 0.34444, 0, 0, 0.575], + "168": [0, 0.69444, 0, 0, 0.575], + "172": [0, 0.44444, 0, 0, 0.76666], + "176": [0, 0.69444, 0, 0, 0.86944], + "177": [0.13333, 0.63333, 0, 0, 0.89444], + "184": [0.17014, 0, 0, 0, 0.51111], + "198": [0, 0.68611, 0, 0, 1.04166], + "215": [0.13333, 0.63333, 0, 0, 0.89444], + "216": [0.04861, 0.73472, 0, 0, 0.89444], + "223": [0, 0.69444, 0, 0, 0.59722], + "230": [0, 0.44444, 0, 0, 0.83055], + "247": [0.13333, 0.63333, 0, 0, 0.89444], + "248": [0.09722, 0.54167, 0, 0, 0.575], + "305": [0, 0.44444, 0, 0, 0.31944], + "338": [0, 0.68611, 0, 0, 1.16944], + "339": [0, 0.44444, 0, 0, 0.89444], + "567": [0.19444, 0.44444, 0, 0, 0.35139], + "710": [0, 0.69444, 0, 0, 0.575], + "711": [0, 0.63194, 0, 0, 0.575], + "713": [0, 0.59611, 0, 0, 0.575], + "714": [0, 0.69444, 0, 0, 0.575], + "715": [0, 0.69444, 0, 0, 0.575], + "728": [0, 0.69444, 0, 0, 0.575], + "729": [0, 0.69444, 0, 0, 0.31944], + "730": [0, 0.69444, 0, 0, 0.86944], + "732": [0, 0.69444, 0, 0, 0.575], + "733": [0, 0.69444, 0, 0, 0.575], + "915": [0, 0.68611, 0, 0, 0.69166], + "916": [0, 0.68611, 0, 0, 0.95833], + "920": [0, 0.68611, 0, 0, 0.89444], + "923": [0, 0.68611, 0, 0, 0.80555], + "926": [0, 0.68611, 0, 0, 0.76666], + "928": [0, 0.68611, 0, 0, 0.9], + "931": [0, 0.68611, 0, 0, 0.83055], + "933": [0, 0.68611, 0, 0, 0.89444], + "934": [0, 0.68611, 0, 0, 0.83055], + "936": [0, 0.68611, 0, 0, 0.89444], + "937": [0, 0.68611, 0, 0, 0.83055], + "8211": [0, 0.44444, 0.03194, 0, 0.575], + "8212": [0, 0.44444, 0.03194, 0, 1.14999], + "8216": [0, 0.69444, 0, 0, 0.31944], + "8217": [0, 0.69444, 0, 0, 0.31944], + "8220": [0, 0.69444, 0, 0, 0.60278], + "8221": [0, 0.69444, 0, 0, 0.60278], + "8224": [0.19444, 0.69444, 0, 0, 0.51111], + "8225": [0.19444, 0.69444, 0, 0, 0.51111], + "8242": [0, 0.55556, 0, 0, 0.34444], + "8407": [0, 0.72444, 0.15486, 0, 0.575], + "8463": [0, 0.69444, 0, 0, 0.66759], + "8465": [0, 0.69444, 0, 0, 0.83055], + "8467": [0, 0.69444, 0, 0, 0.47361], + "8472": [0.19444, 0.44444, 0, 0, 0.74027], + "8476": [0, 0.69444, 0, 0, 0.83055], + "8501": [0, 0.69444, 0, 0, 0.70277], + "8592": [-0.10889, 0.39111, 0, 0, 1.14999], + "8593": [0.19444, 0.69444, 0, 0, 0.575], + "8594": [-0.10889, 0.39111, 0, 0, 1.14999], + "8595": [0.19444, 0.69444, 0, 0, 0.575], + "8596": [-0.10889, 0.39111, 0, 0, 1.14999], + "8597": [0.25, 0.75, 0, 0, 0.575], + "8598": [0.19444, 0.69444, 0, 0, 1.14999], + "8599": [0.19444, 0.69444, 0, 0, 1.14999], + "8600": [0.19444, 0.69444, 0, 0, 1.14999], + "8601": [0.19444, 0.69444, 0, 0, 1.14999], + "8636": [-0.10889, 0.39111, 0, 0, 1.14999], + "8637": [-0.10889, 0.39111, 0, 0, 1.14999], + "8640": [-0.10889, 0.39111, 0, 0, 1.14999], + "8641": [-0.10889, 0.39111, 0, 0, 1.14999], + "8656": [-0.10889, 0.39111, 0, 0, 1.14999], + "8657": [0.19444, 0.69444, 0, 0, 0.70277], + "8658": [-0.10889, 0.39111, 0, 0, 1.14999], + "8659": [0.19444, 0.69444, 0, 0, 0.70277], + "8660": [-0.10889, 0.39111, 0, 0, 1.14999], + "8661": [0.25, 0.75, 0, 0, 0.70277], + "8704": [0, 0.69444, 0, 0, 0.63889], + "8706": [0, 0.69444, 0.06389, 0, 0.62847], + "8707": [0, 0.69444, 0, 0, 0.63889], + "8709": [0.05556, 0.75, 0, 0, 0.575], + "8711": [0, 0.68611, 0, 0, 0.95833], + "8712": [0.08556, 0.58556, 0, 0, 0.76666], + "8715": [0.08556, 0.58556, 0, 0, 0.76666], + "8722": [0.13333, 0.63333, 0, 0, 0.89444], + "8723": [0.13333, 0.63333, 0, 0, 0.89444], + "8725": [0.25, 0.75, 0, 0, 0.575], + "8726": [0.25, 0.75, 0, 0, 0.575], + "8727": [-0.02778, 0.47222, 0, 0, 0.575], + "8728": [-0.02639, 0.47361, 0, 0, 0.575], + "8729": [-0.02639, 0.47361, 0, 0, 0.575], + "8730": [0.18, 0.82, 0, 0, 0.95833], + "8733": [0, 0.44444, 0, 0, 0.89444], + "8734": [0, 0.44444, 0, 0, 1.14999], + "8736": [0, 0.69224, 0, 0, 0.72222], + "8739": [0.25, 0.75, 0, 0, 0.31944], + "8741": [0.25, 0.75, 0, 0, 0.575], + "8743": [0, 0.55556, 0, 0, 0.76666], + "8744": [0, 0.55556, 0, 0, 0.76666], + "8745": [0, 0.55556, 0, 0, 0.76666], + "8746": [0, 0.55556, 0, 0, 0.76666], + "8747": [0.19444, 0.69444, 0.12778, 0, 0.56875], + "8764": [-0.10889, 0.39111, 0, 0, 0.89444], + "8768": [0.19444, 0.69444, 0, 0, 0.31944], + "8771": [0.00222, 0.50222, 0, 0, 0.89444], + "8776": [0.02444, 0.52444, 0, 0, 0.89444], + "8781": [0.00222, 0.50222, 0, 0, 0.89444], + "8801": [0.00222, 0.50222, 0, 0, 0.89444], + "8804": [0.19667, 0.69667, 0, 0, 0.89444], + "8805": [0.19667, 0.69667, 0, 0, 0.89444], + "8810": [0.08556, 0.58556, 0, 0, 1.14999], + "8811": [0.08556, 0.58556, 0, 0, 1.14999], + "8826": [0.08556, 0.58556, 0, 0, 0.89444], + "8827": [0.08556, 0.58556, 0, 0, 0.89444], + "8834": [0.08556, 0.58556, 0, 0, 0.89444], + "8835": [0.08556, 0.58556, 0, 0, 0.89444], + "8838": [0.19667, 0.69667, 0, 0, 0.89444], + "8839": [0.19667, 0.69667, 0, 0, 0.89444], + "8846": [0, 0.55556, 0, 0, 0.76666], + "8849": [0.19667, 0.69667, 0, 0, 0.89444], + "8850": [0.19667, 0.69667, 0, 0, 0.89444], + "8851": [0, 0.55556, 0, 0, 0.76666], + "8852": [0, 0.55556, 0, 0, 0.76666], + "8853": [0.13333, 0.63333, 0, 0, 0.89444], + "8854": [0.13333, 0.63333, 0, 0, 0.89444], + "8855": [0.13333, 0.63333, 0, 0, 0.89444], + "8856": [0.13333, 0.63333, 0, 0, 0.89444], + "8857": [0.13333, 0.63333, 0, 0, 0.89444], + "8866": [0, 0.69444, 0, 0, 0.70277], + "8867": [0, 0.69444, 0, 0, 0.70277], + "8868": [0, 0.69444, 0, 0, 0.89444], + "8869": [0, 0.69444, 0, 0, 0.89444], + "8900": [-0.02639, 0.47361, 0, 0, 0.575], + "8901": [-0.02639, 0.47361, 0, 0, 0.31944], + "8902": [-0.02778, 0.47222, 0, 0, 0.575], + "8968": [0.25, 0.75, 0, 0, 0.51111], + "8969": [0.25, 0.75, 0, 0, 0.51111], + "8970": [0.25, 0.75, 0, 0, 0.51111], + "8971": [0.25, 0.75, 0, 0, 0.51111], + "8994": [-0.13889, 0.36111, 0, 0, 1.14999], + "8995": [-0.13889, 0.36111, 0, 0, 1.14999], + "9651": [0.19444, 0.69444, 0, 0, 1.02222], + "9657": [-0.02778, 0.47222, 0, 0, 0.575], + "9661": [0.19444, 0.69444, 0, 0, 1.02222], + "9667": [-0.02778, 0.47222, 0, 0, 0.575], + "9711": [0.19444, 0.69444, 0, 0, 1.14999], + "9824": [0.12963, 0.69444, 0, 0, 0.89444], + "9825": [0.12963, 0.69444, 0, 0, 0.89444], + "9826": [0.12963, 0.69444, 0, 0, 0.89444], + "9827": [0.12963, 0.69444, 0, 0, 0.89444], + "9837": [0, 0.75, 0, 0, 0.44722], + "9838": [0.19444, 0.69444, 0, 0, 0.44722], + "9839": [0.19444, 0.69444, 0, 0, 0.44722], + "10216": [0.25, 0.75, 0, 0, 0.44722], + "10217": [0.25, 0.75, 0, 0, 0.44722], + "10815": [0, 0.68611, 0, 0, 0.9], + "10927": [0.19667, 0.69667, 0, 0, 0.89444], + "10928": [0.19667, 0.69667, 0, 0, 0.89444], + "57376": [0.19444, 0.69444, 0, 0, 0] + }, + "Main-BoldItalic": { + "33": [0, 0.69444, 0.11417, 0, 0.38611], + "34": [0, 0.69444, 0.07939, 0, 0.62055], + "35": [0.19444, 0.69444, 0.06833, 0, 0.94444], + "37": [0.05556, 0.75, 0.12861, 0, 0.94444], + "38": [0, 0.69444, 0.08528, 0, 0.88555], + "39": [0, 0.69444, 0.12945, 0, 0.35555], + "40": [0.25, 0.75, 0.15806, 0, 0.47333], + "41": [0.25, 0.75, 0.03306, 0, 0.47333], + "42": [0, 0.75, 0.14333, 0, 0.59111], + "43": [0.10333, 0.60333, 0.03306, 0, 0.88555], + "44": [0.19444, 0.14722, 0, 0, 0.35555], + "45": [0, 0.44444, 0.02611, 0, 0.41444], + "46": [0, 0.14722, 0, 0, 0.35555], + "47": [0.25, 0.75, 0.15806, 0, 0.59111], + "48": [0, 0.64444, 0.13167, 0, 0.59111], + "49": [0, 0.64444, 0.13167, 0, 0.59111], + "50": [0, 0.64444, 0.13167, 0, 0.59111], + "51": [0, 0.64444, 0.13167, 0, 0.59111], + "52": [0.19444, 0.64444, 0.13167, 0, 0.59111], + "53": [0, 0.64444, 0.13167, 0, 0.59111], + "54": [0, 0.64444, 0.13167, 0, 0.59111], + "55": [0.19444, 0.64444, 0.13167, 0, 0.59111], + "56": [0, 0.64444, 0.13167, 0, 0.59111], + "57": [0, 0.64444, 0.13167, 0, 0.59111], + "58": [0, 0.44444, 0.06695, 0, 0.35555], + "59": [0.19444, 0.44444, 0.06695, 0, 0.35555], + "61": [-0.10889, 0.39111, 0.06833, 0, 0.88555], + "63": [0, 0.69444, 0.11472, 0, 0.59111], + "64": [0, 0.69444, 0.09208, 0, 0.88555], + "65": [0, 0.68611, 0, 0, 0.86555], + "66": [0, 0.68611, 0.0992, 0, 0.81666], + "67": [0, 0.68611, 0.14208, 0, 0.82666], + "68": [0, 0.68611, 0.09062, 0, 0.87555], + "69": [0, 0.68611, 0.11431, 0, 0.75666], + "70": [0, 0.68611, 0.12903, 0, 0.72722], + "71": [0, 0.68611, 0.07347, 0, 0.89527], + "72": [0, 0.68611, 0.17208, 0, 0.8961], + "73": [0, 0.68611, 0.15681, 0, 0.47166], + "74": [0, 0.68611, 0.145, 0, 0.61055], + "75": [0, 0.68611, 0.14208, 0, 0.89499], + "76": [0, 0.68611, 0, 0, 0.69777], + "77": [0, 0.68611, 0.17208, 0, 1.07277], + "78": [0, 0.68611, 0.17208, 0, 0.8961], + "79": [0, 0.68611, 0.09062, 0, 0.85499], + "80": [0, 0.68611, 0.0992, 0, 0.78721], + "81": [0.19444, 0.68611, 0.09062, 0, 0.85499], + "82": [0, 0.68611, 0.02559, 0, 0.85944], + "83": [0, 0.68611, 0.11264, 0, 0.64999], + "84": [0, 0.68611, 0.12903, 0, 0.7961], + "85": [0, 0.68611, 0.17208, 0, 0.88083], + "86": [0, 0.68611, 0.18625, 0, 0.86555], + "87": [0, 0.68611, 0.18625, 0, 1.15999], + "88": [0, 0.68611, 0.15681, 0, 0.86555], + "89": [0, 0.68611, 0.19803, 0, 0.86555], + "90": [0, 0.68611, 0.14208, 0, 0.70888], + "91": [0.25, 0.75, 0.1875, 0, 0.35611], + "93": [0.25, 0.75, 0.09972, 0, 0.35611], + "94": [0, 0.69444, 0.06709, 0, 0.59111], + "95": [0.31, 0.13444, 0.09811, 0, 0.59111], + "97": [0, 0.44444, 0.09426, 0, 0.59111], + "98": [0, 0.69444, 0.07861, 0, 0.53222], + "99": [0, 0.44444, 0.05222, 0, 0.53222], + "100": [0, 0.69444, 0.10861, 0, 0.59111], + "101": [0, 0.44444, 0.085, 0, 0.53222], + "102": [0.19444, 0.69444, 0.21778, 0, 0.4], + "103": [0.19444, 0.44444, 0.105, 0, 0.53222], + "104": [0, 0.69444, 0.09426, 0, 0.59111], + "105": [0, 0.69326, 0.11387, 0, 0.35555], + "106": [0.19444, 0.69326, 0.1672, 0, 0.35555], + "107": [0, 0.69444, 0.11111, 0, 0.53222], + "108": [0, 0.69444, 0.10861, 0, 0.29666], + "109": [0, 0.44444, 0.09426, 0, 0.94444], + "110": [0, 0.44444, 0.09426, 0, 0.64999], + "111": [0, 0.44444, 0.07861, 0, 0.59111], + "112": [0.19444, 0.44444, 0.07861, 0, 0.59111], + "113": [0.19444, 0.44444, 0.105, 0, 0.53222], + "114": [0, 0.44444, 0.11111, 0, 0.50167], + "115": [0, 0.44444, 0.08167, 0, 0.48694], + "116": [0, 0.63492, 0.09639, 0, 0.385], + "117": [0, 0.44444, 0.09426, 0, 0.62055], + "118": [0, 0.44444, 0.11111, 0, 0.53222], + "119": [0, 0.44444, 0.11111, 0, 0.76777], + "120": [0, 0.44444, 0.12583, 0, 0.56055], + "121": [0.19444, 0.44444, 0.105, 0, 0.56166], + "122": [0, 0.44444, 0.13889, 0, 0.49055], + "126": [0.35, 0.34444, 0.11472, 0, 0.59111], + "163": [0, 0.69444, 0, 0, 0.86853], + "168": [0, 0.69444, 0.11473, 0, 0.59111], + "176": [0, 0.69444, 0, 0, 0.94888], + "184": [0.17014, 0, 0, 0, 0.53222], + "198": [0, 0.68611, 0.11431, 0, 1.02277], + "216": [0.04861, 0.73472, 0.09062, 0, 0.88555], + "223": [0.19444, 0.69444, 0.09736, 0, 0.665], + "230": [0, 0.44444, 0.085, 0, 0.82666], + "248": [0.09722, 0.54167, 0.09458, 0, 0.59111], + "305": [0, 0.44444, 0.09426, 0, 0.35555], + "338": [0, 0.68611, 0.11431, 0, 1.14054], + "339": [0, 0.44444, 0.085, 0, 0.82666], + "567": [0.19444, 0.44444, 0.04611, 0, 0.385], + "710": [0, 0.69444, 0.06709, 0, 0.59111], + "711": [0, 0.63194, 0.08271, 0, 0.59111], + "713": [0, 0.59444, 0.10444, 0, 0.59111], + "714": [0, 0.69444, 0.08528, 0, 0.59111], + "715": [0, 0.69444, 0, 0, 0.59111], + "728": [0, 0.69444, 0.10333, 0, 0.59111], + "729": [0, 0.69444, 0.12945, 0, 0.35555], + "730": [0, 0.69444, 0, 0, 0.94888], + "732": [0, 0.69444, 0.11472, 0, 0.59111], + "733": [0, 0.69444, 0.11472, 0, 0.59111], + "915": [0, 0.68611, 0.12903, 0, 0.69777], + "916": [0, 0.68611, 0, 0, 0.94444], + "920": [0, 0.68611, 0.09062, 0, 0.88555], + "923": [0, 0.68611, 0, 0, 0.80666], + "926": [0, 0.68611, 0.15092, 0, 0.76777], + "928": [0, 0.68611, 0.17208, 0, 0.8961], + "931": [0, 0.68611, 0.11431, 0, 0.82666], + "933": [0, 0.68611, 0.10778, 0, 0.88555], + "934": [0, 0.68611, 0.05632, 0, 0.82666], + "936": [0, 0.68611, 0.10778, 0, 0.88555], + "937": [0, 0.68611, 0.0992, 0, 0.82666], + "8211": [0, 0.44444, 0.09811, 0, 0.59111], + "8212": [0, 0.44444, 0.09811, 0, 1.18221], + "8216": [0, 0.69444, 0.12945, 0, 0.35555], + "8217": [0, 0.69444, 0.12945, 0, 0.35555], + "8220": [0, 0.69444, 0.16772, 0, 0.62055], + "8221": [0, 0.69444, 0.07939, 0, 0.62055] + }, + "Main-Italic": { + "33": [0, 0.69444, 0.12417, 0, 0.30667], + "34": [0, 0.69444, 0.06961, 0, 0.51444], + "35": [0.19444, 0.69444, 0.06616, 0, 0.81777], + "37": [0.05556, 0.75, 0.13639, 0, 0.81777], + "38": [0, 0.69444, 0.09694, 0, 0.76666], + "39": [0, 0.69444, 0.12417, 0, 0.30667], + "40": [0.25, 0.75, 0.16194, 0, 0.40889], + "41": [0.25, 0.75, 0.03694, 0, 0.40889], + "42": [0, 0.75, 0.14917, 0, 0.51111], + "43": [0.05667, 0.56167, 0.03694, 0, 0.76666], + "44": [0.19444, 0.10556, 0, 0, 0.30667], + "45": [0, 0.43056, 0.02826, 0, 0.35778], + "46": [0, 0.10556, 0, 0, 0.30667], + "47": [0.25, 0.75, 0.16194, 0, 0.51111], + "48": [0, 0.64444, 0.13556, 0, 0.51111], + "49": [0, 0.64444, 0.13556, 0, 0.51111], + "50": [0, 0.64444, 0.13556, 0, 0.51111], + "51": [0, 0.64444, 0.13556, 0, 0.51111], + "52": [0.19444, 0.64444, 0.13556, 0, 0.51111], + "53": [0, 0.64444, 0.13556, 0, 0.51111], + "54": [0, 0.64444, 0.13556, 0, 0.51111], + "55": [0.19444, 0.64444, 0.13556, 0, 0.51111], + "56": [0, 0.64444, 0.13556, 0, 0.51111], + "57": [0, 0.64444, 0.13556, 0, 0.51111], + "58": [0, 0.43056, 0.0582, 0, 0.30667], + "59": [0.19444, 0.43056, 0.0582, 0, 0.30667], + "61": [-0.13313, 0.36687, 0.06616, 0, 0.76666], + "63": [0, 0.69444, 0.1225, 0, 0.51111], + "64": [0, 0.69444, 0.09597, 0, 0.76666], + "65": [0, 0.68333, 0, 0, 0.74333], + "66": [0, 0.68333, 0.10257, 0, 0.70389], + "67": [0, 0.68333, 0.14528, 0, 0.71555], + "68": [0, 0.68333, 0.09403, 0, 0.755], + "69": [0, 0.68333, 0.12028, 0, 0.67833], + "70": [0, 0.68333, 0.13305, 0, 0.65277], + "71": [0, 0.68333, 0.08722, 0, 0.77361], + "72": [0, 0.68333, 0.16389, 0, 0.74333], + "73": [0, 0.68333, 0.15806, 0, 0.38555], + "74": [0, 0.68333, 0.14028, 0, 0.525], + "75": [0, 0.68333, 0.14528, 0, 0.76888], + "76": [0, 0.68333, 0, 0, 0.62722], + "77": [0, 0.68333, 0.16389, 0, 0.89666], + "78": [0, 0.68333, 0.16389, 0, 0.74333], + "79": [0, 0.68333, 0.09403, 0, 0.76666], + "80": [0, 0.68333, 0.10257, 0, 0.67833], + "81": [0.19444, 0.68333, 0.09403, 0, 0.76666], + "82": [0, 0.68333, 0.03868, 0, 0.72944], + "83": [0, 0.68333, 0.11972, 0, 0.56222], + "84": [0, 0.68333, 0.13305, 0, 0.71555], + "85": [0, 0.68333, 0.16389, 0, 0.74333], + "86": [0, 0.68333, 0.18361, 0, 0.74333], + "87": [0, 0.68333, 0.18361, 0, 0.99888], + "88": [0, 0.68333, 0.15806, 0, 0.74333], + "89": [0, 0.68333, 0.19383, 0, 0.74333], + "90": [0, 0.68333, 0.14528, 0, 0.61333], + "91": [0.25, 0.75, 0.1875, 0, 0.30667], + "93": [0.25, 0.75, 0.10528, 0, 0.30667], + "94": [0, 0.69444, 0.06646, 0, 0.51111], + "95": [0.31, 0.12056, 0.09208, 0, 0.51111], + "97": [0, 0.43056, 0.07671, 0, 0.51111], + "98": [0, 0.69444, 0.06312, 0, 0.46], + "99": [0, 0.43056, 0.05653, 0, 0.46], + "100": [0, 0.69444, 0.10333, 0, 0.51111], + "101": [0, 0.43056, 0.07514, 0, 0.46], + "102": [0.19444, 0.69444, 0.21194, 0, 0.30667], + "103": [0.19444, 0.43056, 0.08847, 0, 0.46], + "104": [0, 0.69444, 0.07671, 0, 0.51111], + "105": [0, 0.65536, 0.1019, 0, 0.30667], + "106": [0.19444, 0.65536, 0.14467, 0, 0.30667], + "107": [0, 0.69444, 0.10764, 0, 0.46], + "108": [0, 0.69444, 0.10333, 0, 0.25555], + "109": [0, 0.43056, 0.07671, 0, 0.81777], + "110": [0, 0.43056, 0.07671, 0, 0.56222], + "111": [0, 0.43056, 0.06312, 0, 0.51111], + "112": [0.19444, 0.43056, 0.06312, 0, 0.51111], + "113": [0.19444, 0.43056, 0.08847, 0, 0.46], + "114": [0, 0.43056, 0.10764, 0, 0.42166], + "115": [0, 0.43056, 0.08208, 0, 0.40889], + "116": [0, 0.61508, 0.09486, 0, 0.33222], + "117": [0, 0.43056, 0.07671, 0, 0.53666], + "118": [0, 0.43056, 0.10764, 0, 0.46], + "119": [0, 0.43056, 0.10764, 0, 0.66444], + "120": [0, 0.43056, 0.12042, 0, 0.46389], + "121": [0.19444, 0.43056, 0.08847, 0, 0.48555], + "122": [0, 0.43056, 0.12292, 0, 0.40889], + "126": [0.35, 0.31786, 0.11585, 0, 0.51111], + "163": [0, 0.69444, 0, 0, 0.76909], + "168": [0, 0.66786, 0.10474, 0, 0.51111], + "176": [0, 0.69444, 0, 0, 0.83129], + "184": [0.17014, 0, 0, 0, 0.46], + "198": [0, 0.68333, 0.12028, 0, 0.88277], + "216": [0.04861, 0.73194, 0.09403, 0, 0.76666], + "223": [0.19444, 0.69444, 0.10514, 0, 0.53666], + "230": [0, 0.43056, 0.07514, 0, 0.71555], + "248": [0.09722, 0.52778, 0.09194, 0, 0.51111], + "305": [0, 0.43056, 0, 0.02778, 0.32246], + "338": [0, 0.68333, 0.12028, 0, 0.98499], + "339": [0, 0.43056, 0.07514, 0, 0.71555], + "567": [0.19444, 0.43056, 0, 0.08334, 0.38403], + "710": [0, 0.69444, 0.06646, 0, 0.51111], + "711": [0, 0.62847, 0.08295, 0, 0.51111], + "713": [0, 0.56167, 0.10333, 0, 0.51111], + "714": [0, 0.69444, 0.09694, 0, 0.51111], + "715": [0, 0.69444, 0, 0, 0.51111], + "728": [0, 0.69444, 0.10806, 0, 0.51111], + "729": [0, 0.66786, 0.11752, 0, 0.30667], + "730": [0, 0.69444, 0, 0, 0.83129], + "732": [0, 0.66786, 0.11585, 0, 0.51111], + "733": [0, 0.69444, 0.1225, 0, 0.51111], + "915": [0, 0.68333, 0.13305, 0, 0.62722], + "916": [0, 0.68333, 0, 0, 0.81777], + "920": [0, 0.68333, 0.09403, 0, 0.76666], + "923": [0, 0.68333, 0, 0, 0.69222], + "926": [0, 0.68333, 0.15294, 0, 0.66444], + "928": [0, 0.68333, 0.16389, 0, 0.74333], + "931": [0, 0.68333, 0.12028, 0, 0.71555], + "933": [0, 0.68333, 0.11111, 0, 0.76666], + "934": [0, 0.68333, 0.05986, 0, 0.71555], + "936": [0, 0.68333, 0.11111, 0, 0.76666], + "937": [0, 0.68333, 0.10257, 0, 0.71555], + "8211": [0, 0.43056, 0.09208, 0, 0.51111], + "8212": [0, 0.43056, 0.09208, 0, 1.02222], + "8216": [0, 0.69444, 0.12417, 0, 0.30667], + "8217": [0, 0.69444, 0.12417, 0, 0.30667], + "8220": [0, 0.69444, 0.1685, 0, 0.51444], + "8221": [0, 0.69444, 0.06961, 0, 0.51444], + "8463": [0, 0.68889, 0, 0, 0.54028] + }, + "Main-Regular": { + "32": [0, 0, 0, 0, 0.25], + "33": [0, 0.69444, 0, 0, 0.27778], + "34": [0, 0.69444, 0, 0, 0.5], + "35": [0.19444, 0.69444, 0, 0, 0.83334], + "36": [0.05556, 0.75, 0, 0, 0.5], + "37": [0.05556, 0.75, 0, 0, 0.83334], + "38": [0, 0.69444, 0, 0, 0.77778], + "39": [0, 0.69444, 0, 0, 0.27778], + "40": [0.25, 0.75, 0, 0, 0.38889], + "41": [0.25, 0.75, 0, 0, 0.38889], + "42": [0, 0.75, 0, 0, 0.5], + "43": [0.08333, 0.58333, 0, 0, 0.77778], + "44": [0.19444, 0.10556, 0, 0, 0.27778], + "45": [0, 0.43056, 0, 0, 0.33333], + "46": [0, 0.10556, 0, 0, 0.27778], + "47": [0.25, 0.75, 0, 0, 0.5], + "48": [0, 0.64444, 0, 0, 0.5], + "49": [0, 0.64444, 0, 0, 0.5], + "50": [0, 0.64444, 0, 0, 0.5], + "51": [0, 0.64444, 0, 0, 0.5], + "52": [0, 0.64444, 0, 0, 0.5], + "53": [0, 0.64444, 0, 0, 0.5], + "54": [0, 0.64444, 0, 0, 0.5], + "55": [0, 0.64444, 0, 0, 0.5], + "56": [0, 0.64444, 0, 0, 0.5], + "57": [0, 0.64444, 0, 0, 0.5], + "58": [0, 0.43056, 0, 0, 0.27778], + "59": [0.19444, 0.43056, 0, 0, 0.27778], + "60": [0.0391, 0.5391, 0, 0, 0.77778], + "61": [-0.13313, 0.36687, 0, 0, 0.77778], + "62": [0.0391, 0.5391, 0, 0, 0.77778], + "63": [0, 0.69444, 0, 0, 0.47222], + "64": [0, 0.69444, 0, 0, 0.77778], + "65": [0, 0.68333, 0, 0, 0.75], + "66": [0, 0.68333, 0, 0, 0.70834], + "67": [0, 0.68333, 0, 0, 0.72222], + "68": [0, 0.68333, 0, 0, 0.76389], + "69": [0, 0.68333, 0, 0, 0.68056], + "70": [0, 0.68333, 0, 0, 0.65278], + "71": [0, 0.68333, 0, 0, 0.78472], + "72": [0, 0.68333, 0, 0, 0.75], + "73": [0, 0.68333, 0, 0, 0.36111], + "74": [0, 0.68333, 0, 0, 0.51389], + "75": [0, 0.68333, 0, 0, 0.77778], + "76": [0, 0.68333, 0, 0, 0.625], + "77": [0, 0.68333, 0, 0, 0.91667], + "78": [0, 0.68333, 0, 0, 0.75], + "79": [0, 0.68333, 0, 0, 0.77778], + "80": [0, 0.68333, 0, 0, 0.68056], + "81": [0.19444, 0.68333, 0, 0, 0.77778], + "82": [0, 0.68333, 0, 0, 0.73611], + "83": [0, 0.68333, 0, 0, 0.55556], + "84": [0, 0.68333, 0, 0, 0.72222], + "85": [0, 0.68333, 0, 0, 0.75], + "86": [0, 0.68333, 0.01389, 0, 0.75], + "87": [0, 0.68333, 0.01389, 0, 1.02778], + "88": [0, 0.68333, 0, 0, 0.75], + "89": [0, 0.68333, 0.025, 0, 0.75], + "90": [0, 0.68333, 0, 0, 0.61111], + "91": [0.25, 0.75, 0, 0, 0.27778], + "92": [0.25, 0.75, 0, 0, 0.5], + "93": [0.25, 0.75, 0, 0, 0.27778], + "94": [0, 0.69444, 0, 0, 0.5], + "95": [0.31, 0.12056, 0.02778, 0, 0.5], + "97": [0, 0.43056, 0, 0, 0.5], + "98": [0, 0.69444, 0, 0, 0.55556], + "99": [0, 0.43056, 0, 0, 0.44445], + "100": [0, 0.69444, 0, 0, 0.55556], + "101": [0, 0.43056, 0, 0, 0.44445], + "102": [0, 0.69444, 0.07778, 0, 0.30556], + "103": [0.19444, 0.43056, 0.01389, 0, 0.5], + "104": [0, 0.69444, 0, 0, 0.55556], + "105": [0, 0.66786, 0, 0, 0.27778], + "106": [0.19444, 0.66786, 0, 0, 0.30556], + "107": [0, 0.69444, 0, 0, 0.52778], + "108": [0, 0.69444, 0, 0, 0.27778], + "109": [0, 0.43056, 0, 0, 0.83334], + "110": [0, 0.43056, 0, 0, 0.55556], + "111": [0, 0.43056, 0, 0, 0.5], + "112": [0.19444, 0.43056, 0, 0, 0.55556], + "113": [0.19444, 0.43056, 0, 0, 0.52778], + "114": [0, 0.43056, 0, 0, 0.39167], + "115": [0, 0.43056, 0, 0, 0.39445], + "116": [0, 0.61508, 0, 0, 0.38889], + "117": [0, 0.43056, 0, 0, 0.55556], + "118": [0, 0.43056, 0.01389, 0, 0.52778], + "119": [0, 0.43056, 0.01389, 0, 0.72222], + "120": [0, 0.43056, 0, 0, 0.52778], + "121": [0.19444, 0.43056, 0.01389, 0, 0.52778], + "122": [0, 0.43056, 0, 0, 0.44445], + "123": [0.25, 0.75, 0, 0, 0.5], + "124": [0.25, 0.75, 0, 0, 0.27778], + "125": [0.25, 0.75, 0, 0, 0.5], + "126": [0.35, 0.31786, 0, 0, 0.5], + "160": [0, 0, 0, 0, 0.25], + "167": [0.19444, 0.69444, 0, 0, 0.44445], + "168": [0, 0.66786, 0, 0, 0.5], + "172": [0, 0.43056, 0, 0, 0.66667], + "176": [0, 0.69444, 0, 0, 0.75], + "177": [0.08333, 0.58333, 0, 0, 0.77778], + "182": [0.19444, 0.69444, 0, 0, 0.61111], + "184": [0.17014, 0, 0, 0, 0.44445], + "198": [0, 0.68333, 0, 0, 0.90278], + "215": [0.08333, 0.58333, 0, 0, 0.77778], + "216": [0.04861, 0.73194, 0, 0, 0.77778], + "223": [0, 0.69444, 0, 0, 0.5], + "230": [0, 0.43056, 0, 0, 0.72222], + "247": [0.08333, 0.58333, 0, 0, 0.77778], + "248": [0.09722, 0.52778, 0, 0, 0.5], + "305": [0, 0.43056, 0, 0, 0.27778], + "338": [0, 0.68333, 0, 0, 1.01389], + "339": [0, 0.43056, 0, 0, 0.77778], + "567": [0.19444, 0.43056, 0, 0, 0.30556], + "710": [0, 0.69444, 0, 0, 0.5], + "711": [0, 0.62847, 0, 0, 0.5], + "713": [0, 0.56778, 0, 0, 0.5], + "714": [0, 0.69444, 0, 0, 0.5], + "715": [0, 0.69444, 0, 0, 0.5], + "728": [0, 0.69444, 0, 0, 0.5], + "729": [0, 0.66786, 0, 0, 0.27778], + "730": [0, 0.69444, 0, 0, 0.75], + "732": [0, 0.66786, 0, 0, 0.5], + "733": [0, 0.69444, 0, 0, 0.5], + "915": [0, 0.68333, 0, 0, 0.625], + "916": [0, 0.68333, 0, 0, 0.83334], + "920": [0, 0.68333, 0, 0, 0.77778], + "923": [0, 0.68333, 0, 0, 0.69445], + "926": [0, 0.68333, 0, 0, 0.66667], + "928": [0, 0.68333, 0, 0, 0.75], + "931": [0, 0.68333, 0, 0, 0.72222], + "933": [0, 0.68333, 0, 0, 0.77778], + "934": [0, 0.68333, 0, 0, 0.72222], + "936": [0, 0.68333, 0, 0, 0.77778], + "937": [0, 0.68333, 0, 0, 0.72222], + "8211": [0, 0.43056, 0.02778, 0, 0.5], + "8212": [0, 0.43056, 0.02778, 0, 1.0], + "8216": [0, 0.69444, 0, 0, 0.27778], + "8217": [0, 0.69444, 0, 0, 0.27778], + "8220": [0, 0.69444, 0, 0, 0.5], + "8221": [0, 0.69444, 0, 0, 0.5], + "8224": [0.19444, 0.69444, 0, 0, 0.44445], + "8225": [0.19444, 0.69444, 0, 0, 0.44445], + "8230": [0, 0.12, 0, 0, 1.172], + "8242": [0, 0.55556, 0, 0, 0.275], + "8407": [0, 0.71444, 0.15382, 0, 0.5], + "8463": [0, 0.68889, 0, 0, 0.54028], + "8465": [0, 0.69444, 0, 0, 0.72222], + "8467": [0, 0.69444, 0, 0.11111, 0.41667], + "8472": [0.19444, 0.43056, 0, 0.11111, 0.63646], + "8476": [0, 0.69444, 0, 0, 0.72222], + "8501": [0, 0.69444, 0, 0, 0.61111], + "8592": [-0.13313, 0.36687, 0, 0, 1.0], + "8593": [0.19444, 0.69444, 0, 0, 0.5], + "8594": [-0.13313, 0.36687, 0, 0, 1.0], + "8595": [0.19444, 0.69444, 0, 0, 0.5], + "8596": [-0.13313, 0.36687, 0, 0, 1.0], + "8597": [0.25, 0.75, 0, 0, 0.5], + "8598": [0.19444, 0.69444, 0, 0, 1.0], + "8599": [0.19444, 0.69444, 0, 0, 1.0], + "8600": [0.19444, 0.69444, 0, 0, 1.0], + "8601": [0.19444, 0.69444, 0, 0, 1.0], + "8614": [0.011, 0.511, 0, 0, 1.0], + "8617": [0.011, 0.511, 0, 0, 1.126], + "8618": [0.011, 0.511, 0, 0, 1.126], + "8636": [-0.13313, 0.36687, 0, 0, 1.0], + "8637": [-0.13313, 0.36687, 0, 0, 1.0], + "8640": [-0.13313, 0.36687, 0, 0, 1.0], + "8641": [-0.13313, 0.36687, 0, 0, 1.0], + "8652": [0.011, 0.671, 0, 0, 1.0], + "8656": [-0.13313, 0.36687, 0, 0, 1.0], + "8657": [0.19444, 0.69444, 0, 0, 0.61111], + "8658": [-0.13313, 0.36687, 0, 0, 1.0], + "8659": [0.19444, 0.69444, 0, 0, 0.61111], + "8660": [-0.13313, 0.36687, 0, 0, 1.0], + "8661": [0.25, 0.75, 0, 0, 0.61111], + "8704": [0, 0.69444, 0, 0, 0.55556], + "8706": [0, 0.69444, 0.05556, 0.08334, 0.5309], + "8707": [0, 0.69444, 0, 0, 0.55556], + "8709": [0.05556, 0.75, 0, 0, 0.5], + "8711": [0, 0.68333, 0, 0, 0.83334], + "8712": [0.0391, 0.5391, 0, 0, 0.66667], + "8715": [0.0391, 0.5391, 0, 0, 0.66667], + "8722": [0.08333, 0.58333, 0, 0, 0.77778], + "8723": [0.08333, 0.58333, 0, 0, 0.77778], + "8725": [0.25, 0.75, 0, 0, 0.5], + "8726": [0.25, 0.75, 0, 0, 0.5], + "8727": [-0.03472, 0.46528, 0, 0, 0.5], + "8728": [-0.05555, 0.44445, 0, 0, 0.5], + "8729": [-0.05555, 0.44445, 0, 0, 0.5], + "8730": [0.2, 0.8, 0, 0, 0.83334], + "8733": [0, 0.43056, 0, 0, 0.77778], + "8734": [0, 0.43056, 0, 0, 1.0], + "8736": [0, 0.69224, 0, 0, 0.72222], + "8739": [0.25, 0.75, 0, 0, 0.27778], + "8741": [0.25, 0.75, 0, 0, 0.5], + "8743": [0, 0.55556, 0, 0, 0.66667], + "8744": [0, 0.55556, 0, 0, 0.66667], + "8745": [0, 0.55556, 0, 0, 0.66667], + "8746": [0, 0.55556, 0, 0, 0.66667], + "8747": [0.19444, 0.69444, 0.11111, 0, 0.41667], + "8764": [-0.13313, 0.36687, 0, 0, 0.77778], + "8768": [0.19444, 0.69444, 0, 0, 0.27778], + "8771": [-0.03625, 0.46375, 0, 0, 0.77778], + "8773": [-0.022, 0.589, 0, 0, 1.0], + "8776": [-0.01688, 0.48312, 0, 0, 0.77778], + "8781": [-0.03625, 0.46375, 0, 0, 0.77778], + "8784": [-0.133, 0.67, 0, 0, 0.778], + "8801": [-0.03625, 0.46375, 0, 0, 0.77778], + "8804": [0.13597, 0.63597, 0, 0, 0.77778], + "8805": [0.13597, 0.63597, 0, 0, 0.77778], + "8810": [0.0391, 0.5391, 0, 0, 1.0], + "8811": [0.0391, 0.5391, 0, 0, 1.0], + "8826": [0.0391, 0.5391, 0, 0, 0.77778], + "8827": [0.0391, 0.5391, 0, 0, 0.77778], + "8834": [0.0391, 0.5391, 0, 0, 0.77778], + "8835": [0.0391, 0.5391, 0, 0, 0.77778], + "8838": [0.13597, 0.63597, 0, 0, 0.77778], + "8839": [0.13597, 0.63597, 0, 0, 0.77778], + "8846": [0, 0.55556, 0, 0, 0.66667], + "8849": [0.13597, 0.63597, 0, 0, 0.77778], + "8850": [0.13597, 0.63597, 0, 0, 0.77778], + "8851": [0, 0.55556, 0, 0, 0.66667], + "8852": [0, 0.55556, 0, 0, 0.66667], + "8853": [0.08333, 0.58333, 0, 0, 0.77778], + "8854": [0.08333, 0.58333, 0, 0, 0.77778], + "8855": [0.08333, 0.58333, 0, 0, 0.77778], + "8856": [0.08333, 0.58333, 0, 0, 0.77778], + "8857": [0.08333, 0.58333, 0, 0, 0.77778], + "8866": [0, 0.69444, 0, 0, 0.61111], + "8867": [0, 0.69444, 0, 0, 0.61111], + "8868": [0, 0.69444, 0, 0, 0.77778], + "8869": [0, 0.69444, 0, 0, 0.77778], + "8872": [0.249, 0.75, 0, 0, 0.867], + "8900": [-0.05555, 0.44445, 0, 0, 0.5], + "8901": [-0.05555, 0.44445, 0, 0, 0.27778], + "8902": [-0.03472, 0.46528, 0, 0, 0.5], + "8904": [0.005, 0.505, 0, 0, 0.9], + "8942": [0.03, 0.9, 0, 0, 0.278], + "8943": [-0.19, 0.31, 0, 0, 1.172], + "8945": [-0.1, 0.82, 0, 0, 1.282], + "8968": [0.25, 0.75, 0, 0, 0.44445], + "8969": [0.25, 0.75, 0, 0, 0.44445], + "8970": [0.25, 0.75, 0, 0, 0.44445], + "8971": [0.25, 0.75, 0, 0, 0.44445], + "8994": [-0.14236, 0.35764, 0, 0, 1.0], + "8995": [-0.14236, 0.35764, 0, 0, 1.0], + "9136": [0.244, 0.744, 0, 0, 0.412], + "9137": [0.244, 0.744, 0, 0, 0.412], + "9651": [0.19444, 0.69444, 0, 0, 0.88889], + "9657": [-0.03472, 0.46528, 0, 0, 0.5], + "9661": [0.19444, 0.69444, 0, 0, 0.88889], + "9667": [-0.03472, 0.46528, 0, 0, 0.5], + "9711": [0.19444, 0.69444, 0, 0, 1.0], + "9824": [0.12963, 0.69444, 0, 0, 0.77778], + "9825": [0.12963, 0.69444, 0, 0, 0.77778], + "9826": [0.12963, 0.69444, 0, 0, 0.77778], + "9827": [0.12963, 0.69444, 0, 0, 0.77778], + "9837": [0, 0.75, 0, 0, 0.38889], + "9838": [0.19444, 0.69444, 0, 0, 0.38889], + "9839": [0.19444, 0.69444, 0, 0, 0.38889], + "10216": [0.25, 0.75, 0, 0, 0.38889], + "10217": [0.25, 0.75, 0, 0, 0.38889], + "10222": [0.244, 0.744, 0, 0, 0.412], + "10223": [0.244, 0.744, 0, 0, 0.412], + "10229": [0.011, 0.511, 0, 0, 1.609], + "10230": [0.011, 0.511, 0, 0, 1.638], + "10231": [0.011, 0.511, 0, 0, 1.859], + "10232": [0.024, 0.525, 0, 0, 1.609], + "10233": [0.024, 0.525, 0, 0, 1.638], + "10234": [0.024, 0.525, 0, 0, 1.858], + "10236": [0.011, 0.511, 0, 0, 1.638], + "10815": [0, 0.68333, 0, 0, 0.75], + "10927": [0.13597, 0.63597, 0, 0, 0.77778], + "10928": [0.13597, 0.63597, 0, 0, 0.77778], + "57376": [0.19444, 0.69444, 0, 0, 0] + }, + "Math-BoldItalic": { + "65": [0, 0.68611, 0, 0, 0.86944], + "66": [0, 0.68611, 0.04835, 0, 0.8664], + "67": [0, 0.68611, 0.06979, 0, 0.81694], + "68": [0, 0.68611, 0.03194, 0, 0.93812], + "69": [0, 0.68611, 0.05451, 0, 0.81007], + "70": [0, 0.68611, 0.15972, 0, 0.68889], + "71": [0, 0.68611, 0, 0, 0.88673], + "72": [0, 0.68611, 0.08229, 0, 0.98229], + "73": [0, 0.68611, 0.07778, 0, 0.51111], + "74": [0, 0.68611, 0.10069, 0, 0.63125], + "75": [0, 0.68611, 0.06979, 0, 0.97118], + "76": [0, 0.68611, 0, 0, 0.75555], + "77": [0, 0.68611, 0.11424, 0, 1.14201], + "78": [0, 0.68611, 0.11424, 0, 0.95034], + "79": [0, 0.68611, 0.03194, 0, 0.83666], + "80": [0, 0.68611, 0.15972, 0, 0.72309], + "81": [0.19444, 0.68611, 0, 0, 0.86861], + "82": [0, 0.68611, 0.00421, 0, 0.87235], + "83": [0, 0.68611, 0.05382, 0, 0.69271], + "84": [0, 0.68611, 0.15972, 0, 0.63663], + "85": [0, 0.68611, 0.11424, 0, 0.80027], + "86": [0, 0.68611, 0.25555, 0, 0.67778], + "87": [0, 0.68611, 0.15972, 0, 1.09305], + "88": [0, 0.68611, 0.07778, 0, 0.94722], + "89": [0, 0.68611, 0.25555, 0, 0.67458], + "90": [0, 0.68611, 0.06979, 0, 0.77257], + "97": [0, 0.44444, 0, 0, 0.63287], + "98": [0, 0.69444, 0, 0, 0.52083], + "99": [0, 0.44444, 0, 0, 0.51342], + "100": [0, 0.69444, 0, 0, 0.60972], + "101": [0, 0.44444, 0, 0, 0.55361], + "102": [0.19444, 0.69444, 0.11042, 0, 0.56806], + "103": [0.19444, 0.44444, 0.03704, 0, 0.5449], + "104": [0, 0.69444, 0, 0, 0.66759], + "105": [0, 0.69326, 0, 0, 0.4048], + "106": [0.19444, 0.69326, 0.0622, 0, 0.47083], + "107": [0, 0.69444, 0.01852, 0, 0.6037], + "108": [0, 0.69444, 0.0088, 0, 0.34815], + "109": [0, 0.44444, 0, 0, 1.0324], + "110": [0, 0.44444, 0, 0, 0.71296], + "111": [0, 0.44444, 0, 0, 0.58472], + "112": [0.19444, 0.44444, 0, 0, 0.60092], + "113": [0.19444, 0.44444, 0.03704, 0, 0.54213], + "114": [0, 0.44444, 0.03194, 0, 0.5287], + "115": [0, 0.44444, 0, 0, 0.53125], + "116": [0, 0.63492, 0, 0, 0.41528], + "117": [0, 0.44444, 0, 0, 0.68102], + "118": [0, 0.44444, 0.03704, 0, 0.56666], + "119": [0, 0.44444, 0.02778, 0, 0.83148], + "120": [0, 0.44444, 0, 0, 0.65903], + "121": [0.19444, 0.44444, 0.03704, 0, 0.59028], + "122": [0, 0.44444, 0.04213, 0, 0.55509], + "915": [0, 0.68611, 0.15972, 0, 0.65694], + "916": [0, 0.68611, 0, 0, 0.95833], + "920": [0, 0.68611, 0.03194, 0, 0.86722], + "923": [0, 0.68611, 0, 0, 0.80555], + "926": [0, 0.68611, 0.07458, 0, 0.84125], + "928": [0, 0.68611, 0.08229, 0, 0.98229], + "931": [0, 0.68611, 0.05451, 0, 0.88507], + "933": [0, 0.68611, 0.15972, 0, 0.67083], + "934": [0, 0.68611, 0, 0, 0.76666], + "936": [0, 0.68611, 0.11653, 0, 0.71402], + "937": [0, 0.68611, 0.04835, 0, 0.8789], + "945": [0, 0.44444, 0, 0, 0.76064], + "946": [0.19444, 0.69444, 0.03403, 0, 0.65972], + "947": [0.19444, 0.44444, 0.06389, 0, 0.59003], + "948": [0, 0.69444, 0.03819, 0, 0.52222], + "949": [0, 0.44444, 0, 0, 0.52882], + "950": [0.19444, 0.69444, 0.06215, 0, 0.50833], + "951": [0.19444, 0.44444, 0.03704, 0, 0.6], + "952": [0, 0.69444, 0.03194, 0, 0.5618], + "953": [0, 0.44444, 0, 0, 0.41204], + "954": [0, 0.44444, 0, 0, 0.66759], + "955": [0, 0.69444, 0, 0, 0.67083], + "956": [0.19444, 0.44444, 0, 0, 0.70787], + "957": [0, 0.44444, 0.06898, 0, 0.57685], + "958": [0.19444, 0.69444, 0.03021, 0, 0.50833], + "959": [0, 0.44444, 0, 0, 0.58472], + "960": [0, 0.44444, 0.03704, 0, 0.68241], + "961": [0.19444, 0.44444, 0, 0, 0.6118], + "962": [0.09722, 0.44444, 0.07917, 0, 0.42361], + "963": [0, 0.44444, 0.03704, 0, 0.68588], + "964": [0, 0.44444, 0.13472, 0, 0.52083], + "965": [0, 0.44444, 0.03704, 0, 0.63055], + "966": [0.19444, 0.44444, 0, 0, 0.74722], + "967": [0.19444, 0.44444, 0, 0, 0.71805], + "968": [0.19444, 0.69444, 0.03704, 0, 0.75833], + "969": [0, 0.44444, 0.03704, 0, 0.71782], + "977": [0, 0.69444, 0, 0, 0.69155], + "981": [0.19444, 0.69444, 0, 0, 0.7125], + "982": [0, 0.44444, 0.03194, 0, 0.975], + "1009": [0.19444, 0.44444, 0, 0, 0.6118], + "1013": [0, 0.44444, 0, 0, 0.48333] + }, + "Math-Italic": { + "65": [0, 0.68333, 0, 0.13889, 0.75], + "66": [0, 0.68333, 0.05017, 0.08334, 0.75851], + "67": [0, 0.68333, 0.07153, 0.08334, 0.71472], + "68": [0, 0.68333, 0.02778, 0.05556, 0.82792], + "69": [0, 0.68333, 0.05764, 0.08334, 0.7382], + "70": [0, 0.68333, 0.13889, 0.08334, 0.64306], + "71": [0, 0.68333, 0, 0.08334, 0.78625], + "72": [0, 0.68333, 0.08125, 0.05556, 0.83125], + "73": [0, 0.68333, 0.07847, 0.11111, 0.43958], + "74": [0, 0.68333, 0.09618, 0.16667, 0.55451], + "75": [0, 0.68333, 0.07153, 0.05556, 0.84931], + "76": [0, 0.68333, 0, 0.02778, 0.68056], + "77": [0, 0.68333, 0.10903, 0.08334, 0.97014], + "78": [0, 0.68333, 0.10903, 0.08334, 0.80347], + "79": [0, 0.68333, 0.02778, 0.08334, 0.76278], + "80": [0, 0.68333, 0.13889, 0.08334, 0.64201], + "81": [0.19444, 0.68333, 0, 0.08334, 0.79056], + "82": [0, 0.68333, 0.00773, 0.08334, 0.75929], + "83": [0, 0.68333, 0.05764, 0.08334, 0.6132], + "84": [0, 0.68333, 0.13889, 0.08334, 0.58438], + "85": [0, 0.68333, 0.10903, 0.02778, 0.68278], + "86": [0, 0.68333, 0.22222, 0, 0.58333], + "87": [0, 0.68333, 0.13889, 0, 0.94445], + "88": [0, 0.68333, 0.07847, 0.08334, 0.82847], + "89": [0, 0.68333, 0.22222, 0, 0.58056], + "90": [0, 0.68333, 0.07153, 0.08334, 0.68264], + "97": [0, 0.43056, 0, 0, 0.52859], + "98": [0, 0.69444, 0, 0, 0.42917], + "99": [0, 0.43056, 0, 0.05556, 0.43276], + "100": [0, 0.69444, 0, 0.16667, 0.52049], + "101": [0, 0.43056, 0, 0.05556, 0.46563], + "102": [0.19444, 0.69444, 0.10764, 0.16667, 0.48959], + "103": [0.19444, 0.43056, 0.03588, 0.02778, 0.47697], + "104": [0, 0.69444, 0, 0, 0.57616], + "105": [0, 0.65952, 0, 0, 0.34451], + "106": [0.19444, 0.65952, 0.05724, 0, 0.41181], + "107": [0, 0.69444, 0.03148, 0, 0.5206], + "108": [0, 0.69444, 0.01968, 0.08334, 0.29838], + "109": [0, 0.43056, 0, 0, 0.87801], + "110": [0, 0.43056, 0, 0, 0.60023], + "111": [0, 0.43056, 0, 0.05556, 0.48472], + "112": [0.19444, 0.43056, 0, 0.08334, 0.50313], + "113": [0.19444, 0.43056, 0.03588, 0.08334, 0.44641], + "114": [0, 0.43056, 0.02778, 0.05556, 0.45116], + "115": [0, 0.43056, 0, 0.05556, 0.46875], + "116": [0, 0.61508, 0, 0.08334, 0.36111], + "117": [0, 0.43056, 0, 0.02778, 0.57246], + "118": [0, 0.43056, 0.03588, 0.02778, 0.48472], + "119": [0, 0.43056, 0.02691, 0.08334, 0.71592], + "120": [0, 0.43056, 0, 0.02778, 0.57153], + "121": [0.19444, 0.43056, 0.03588, 0.05556, 0.49028], + "122": [0, 0.43056, 0.04398, 0.05556, 0.46505], + "915": [0, 0.68333, 0.13889, 0.08334, 0.61528], + "916": [0, 0.68333, 0, 0.16667, 0.83334], + "920": [0, 0.68333, 0.02778, 0.08334, 0.76278], + "923": [0, 0.68333, 0, 0.16667, 0.69445], + "926": [0, 0.68333, 0.07569, 0.08334, 0.74236], + "928": [0, 0.68333, 0.08125, 0.05556, 0.83125], + "931": [0, 0.68333, 0.05764, 0.08334, 0.77986], + "933": [0, 0.68333, 0.13889, 0.05556, 0.58333], + "934": [0, 0.68333, 0, 0.08334, 0.66667], + "936": [0, 0.68333, 0.11, 0.05556, 0.61222], + "937": [0, 0.68333, 0.05017, 0.08334, 0.7724], + "945": [0, 0.43056, 0.0037, 0.02778, 0.6397], + "946": [0.19444, 0.69444, 0.05278, 0.08334, 0.56563], + "947": [0.19444, 0.43056, 0.05556, 0, 0.51773], + "948": [0, 0.69444, 0.03785, 0.05556, 0.44444], + "949": [0, 0.43056, 0, 0.08334, 0.46632], + "950": [0.19444, 0.69444, 0.07378, 0.08334, 0.4375], + "951": [0.19444, 0.43056, 0.03588, 0.05556, 0.49653], + "952": [0, 0.69444, 0.02778, 0.08334, 0.46944], + "953": [0, 0.43056, 0, 0.05556, 0.35394], + "954": [0, 0.43056, 0, 0, 0.57616], + "955": [0, 0.69444, 0, 0, 0.58334], + "956": [0.19444, 0.43056, 0, 0.02778, 0.60255], + "957": [0, 0.43056, 0.06366, 0.02778, 0.49398], + "958": [0.19444, 0.69444, 0.04601, 0.11111, 0.4375], + "959": [0, 0.43056, 0, 0.05556, 0.48472], + "960": [0, 0.43056, 0.03588, 0, 0.57003], + "961": [0.19444, 0.43056, 0, 0.08334, 0.51702], + "962": [0.09722, 0.43056, 0.07986, 0.08334, 0.36285], + "963": [0, 0.43056, 0.03588, 0, 0.57141], + "964": [0, 0.43056, 0.1132, 0.02778, 0.43715], + "965": [0, 0.43056, 0.03588, 0.02778, 0.54028], + "966": [0.19444, 0.43056, 0, 0.08334, 0.65417], + "967": [0.19444, 0.43056, 0, 0.05556, 0.62569], + "968": [0.19444, 0.69444, 0.03588, 0.11111, 0.65139], + "969": [0, 0.43056, 0.03588, 0, 0.62245], + "977": [0, 0.69444, 0, 0.08334, 0.59144], + "981": [0.19444, 0.69444, 0, 0.08334, 0.59583], + "982": [0, 0.43056, 0.02778, 0, 0.82813], + "1009": [0.19444, 0.43056, 0, 0.08334, 0.51702], + "1013": [0, 0.43056, 0, 0.05556, 0.4059] + }, + "Math-Regular": { + "65": [0, 0.68333, 0, 0.13889, 0.75], + "66": [0, 0.68333, 0.05017, 0.08334, 0.75851], + "67": [0, 0.68333, 0.07153, 0.08334, 0.71472], + "68": [0, 0.68333, 0.02778, 0.05556, 0.82792], + "69": [0, 0.68333, 0.05764, 0.08334, 0.7382], + "70": [0, 0.68333, 0.13889, 0.08334, 0.64306], + "71": [0, 0.68333, 0, 0.08334, 0.78625], + "72": [0, 0.68333, 0.08125, 0.05556, 0.83125], + "73": [0, 0.68333, 0.07847, 0.11111, 0.43958], + "74": [0, 0.68333, 0.09618, 0.16667, 0.55451], + "75": [0, 0.68333, 0.07153, 0.05556, 0.84931], + "76": [0, 0.68333, 0, 0.02778, 0.68056], + "77": [0, 0.68333, 0.10903, 0.08334, 0.97014], + "78": [0, 0.68333, 0.10903, 0.08334, 0.80347], + "79": [0, 0.68333, 0.02778, 0.08334, 0.76278], + "80": [0, 0.68333, 0.13889, 0.08334, 0.64201], + "81": [0.19444, 0.68333, 0, 0.08334, 0.79056], + "82": [0, 0.68333, 0.00773, 0.08334, 0.75929], + "83": [0, 0.68333, 0.05764, 0.08334, 0.6132], + "84": [0, 0.68333, 0.13889, 0.08334, 0.58438], + "85": [0, 0.68333, 0.10903, 0.02778, 0.68278], + "86": [0, 0.68333, 0.22222, 0, 0.58333], + "87": [0, 0.68333, 0.13889, 0, 0.94445], + "88": [0, 0.68333, 0.07847, 0.08334, 0.82847], + "89": [0, 0.68333, 0.22222, 0, 0.58056], + "90": [0, 0.68333, 0.07153, 0.08334, 0.68264], + "97": [0, 0.43056, 0, 0, 0.52859], + "98": [0, 0.69444, 0, 0, 0.42917], + "99": [0, 0.43056, 0, 0.05556, 0.43276], + "100": [0, 0.69444, 0, 0.16667, 0.52049], + "101": [0, 0.43056, 0, 0.05556, 0.46563], + "102": [0.19444, 0.69444, 0.10764, 0.16667, 0.48959], + "103": [0.19444, 0.43056, 0.03588, 0.02778, 0.47697], + "104": [0, 0.69444, 0, 0, 0.57616], + "105": [0, 0.65952, 0, 0, 0.34451], + "106": [0.19444, 0.65952, 0.05724, 0, 0.41181], + "107": [0, 0.69444, 0.03148, 0, 0.5206], + "108": [0, 0.69444, 0.01968, 0.08334, 0.29838], + "109": [0, 0.43056, 0, 0, 0.87801], + "110": [0, 0.43056, 0, 0, 0.60023], + "111": [0, 0.43056, 0, 0.05556, 0.48472], + "112": [0.19444, 0.43056, 0, 0.08334, 0.50313], + "113": [0.19444, 0.43056, 0.03588, 0.08334, 0.44641], + "114": [0, 0.43056, 0.02778, 0.05556, 0.45116], + "115": [0, 0.43056, 0, 0.05556, 0.46875], + "116": [0, 0.61508, 0, 0.08334, 0.36111], + "117": [0, 0.43056, 0, 0.02778, 0.57246], + "118": [0, 0.43056, 0.03588, 0.02778, 0.48472], + "119": [0, 0.43056, 0.02691, 0.08334, 0.71592], + "120": [0, 0.43056, 0, 0.02778, 0.57153], + "121": [0.19444, 0.43056, 0.03588, 0.05556, 0.49028], + "122": [0, 0.43056, 0.04398, 0.05556, 0.46505], + "915": [0, 0.68333, 0.13889, 0.08334, 0.61528], + "916": [0, 0.68333, 0, 0.16667, 0.83334], + "920": [0, 0.68333, 0.02778, 0.08334, 0.76278], + "923": [0, 0.68333, 0, 0.16667, 0.69445], + "926": [0, 0.68333, 0.07569, 0.08334, 0.74236], + "928": [0, 0.68333, 0.08125, 0.05556, 0.83125], + "931": [0, 0.68333, 0.05764, 0.08334, 0.77986], + "933": [0, 0.68333, 0.13889, 0.05556, 0.58333], + "934": [0, 0.68333, 0, 0.08334, 0.66667], + "936": [0, 0.68333, 0.11, 0.05556, 0.61222], + "937": [0, 0.68333, 0.05017, 0.08334, 0.7724], + "945": [0, 0.43056, 0.0037, 0.02778, 0.6397], + "946": [0.19444, 0.69444, 0.05278, 0.08334, 0.56563], + "947": [0.19444, 0.43056, 0.05556, 0, 0.51773], + "948": [0, 0.69444, 0.03785, 0.05556, 0.44444], + "949": [0, 0.43056, 0, 0.08334, 0.46632], + "950": [0.19444, 0.69444, 0.07378, 0.08334, 0.4375], + "951": [0.19444, 0.43056, 0.03588, 0.05556, 0.49653], + "952": [0, 0.69444, 0.02778, 0.08334, 0.46944], + "953": [0, 0.43056, 0, 0.05556, 0.35394], + "954": [0, 0.43056, 0, 0, 0.57616], + "955": [0, 0.69444, 0, 0, 0.58334], + "956": [0.19444, 0.43056, 0, 0.02778, 0.60255], + "957": [0, 0.43056, 0.06366, 0.02778, 0.49398], + "958": [0.19444, 0.69444, 0.04601, 0.11111, 0.4375], + "959": [0, 0.43056, 0, 0.05556, 0.48472], + "960": [0, 0.43056, 0.03588, 0, 0.57003], + "961": [0.19444, 0.43056, 0, 0.08334, 0.51702], + "962": [0.09722, 0.43056, 0.07986, 0.08334, 0.36285], + "963": [0, 0.43056, 0.03588, 0, 0.57141], + "964": [0, 0.43056, 0.1132, 0.02778, 0.43715], + "965": [0, 0.43056, 0.03588, 0.02778, 0.54028], + "966": [0.19444, 0.43056, 0, 0.08334, 0.65417], + "967": [0.19444, 0.43056, 0, 0.05556, 0.62569], + "968": [0.19444, 0.69444, 0.03588, 0.11111, 0.65139], + "969": [0, 0.43056, 0.03588, 0, 0.62245], + "977": [0, 0.69444, 0, 0.08334, 0.59144], + "981": [0.19444, 0.69444, 0, 0.08334, 0.59583], + "982": [0, 0.43056, 0.02778, 0, 0.82813], + "1009": [0.19444, 0.43056, 0, 0.08334, 0.51702], + "1013": [0, 0.43056, 0, 0.05556, 0.4059] + }, + "SansSerif-Bold": { + "33": [0, 0.69444, 0, 0, 0.36667], + "34": [0, 0.69444, 0, 0, 0.55834], + "35": [0.19444, 0.69444, 0, 0, 0.91667], + "36": [0.05556, 0.75, 0, 0, 0.55], + "37": [0.05556, 0.75, 0, 0, 1.02912], + "38": [0, 0.69444, 0, 0, 0.83056], + "39": [0, 0.69444, 0, 0, 0.30556], + "40": [0.25, 0.75, 0, 0, 0.42778], + "41": [0.25, 0.75, 0, 0, 0.42778], + "42": [0, 0.75, 0, 0, 0.55], + "43": [0.11667, 0.61667, 0, 0, 0.85556], + "44": [0.10556, 0.13056, 0, 0, 0.30556], + "45": [0, 0.45833, 0, 0, 0.36667], + "46": [0, 0.13056, 0, 0, 0.30556], + "47": [0.25, 0.75, 0, 0, 0.55], + "48": [0, 0.69444, 0, 0, 0.55], + "49": [0, 0.69444, 0, 0, 0.55], + "50": [0, 0.69444, 0, 0, 0.55], + "51": [0, 0.69444, 0, 0, 0.55], + "52": [0, 0.69444, 0, 0, 0.55], + "53": [0, 0.69444, 0, 0, 0.55], + "54": [0, 0.69444, 0, 0, 0.55], + "55": [0, 0.69444, 0, 0, 0.55], + "56": [0, 0.69444, 0, 0, 0.55], + "57": [0, 0.69444, 0, 0, 0.55], + "58": [0, 0.45833, 0, 0, 0.30556], + "59": [0.10556, 0.45833, 0, 0, 0.30556], + "61": [-0.09375, 0.40625, 0, 0, 0.85556], + "63": [0, 0.69444, 0, 0, 0.51945], + "64": [0, 0.69444, 0, 0, 0.73334], + "65": [0, 0.69444, 0, 0, 0.73334], + "66": [0, 0.69444, 0, 0, 0.73334], + "67": [0, 0.69444, 0, 0, 0.70278], + "68": [0, 0.69444, 0, 0, 0.79445], + "69": [0, 0.69444, 0, 0, 0.64167], + "70": [0, 0.69444, 0, 0, 0.61111], + "71": [0, 0.69444, 0, 0, 0.73334], + "72": [0, 0.69444, 0, 0, 0.79445], + "73": [0, 0.69444, 0, 0, 0.33056], + "74": [0, 0.69444, 0, 0, 0.51945], + "75": [0, 0.69444, 0, 0, 0.76389], + "76": [0, 0.69444, 0, 0, 0.58056], + "77": [0, 0.69444, 0, 0, 0.97778], + "78": [0, 0.69444, 0, 0, 0.79445], + "79": [0, 0.69444, 0, 0, 0.79445], + "80": [0, 0.69444, 0, 0, 0.70278], + "81": [0.10556, 0.69444, 0, 0, 0.79445], + "82": [0, 0.69444, 0, 0, 0.70278], + "83": [0, 0.69444, 0, 0, 0.61111], + "84": [0, 0.69444, 0, 0, 0.73334], + "85": [0, 0.69444, 0, 0, 0.76389], + "86": [0, 0.69444, 0.01528, 0, 0.73334], + "87": [0, 0.69444, 0.01528, 0, 1.03889], + "88": [0, 0.69444, 0, 0, 0.73334], + "89": [0, 0.69444, 0.0275, 0, 0.73334], + "90": [0, 0.69444, 0, 0, 0.67223], + "91": [0.25, 0.75, 0, 0, 0.34306], + "93": [0.25, 0.75, 0, 0, 0.34306], + "94": [0, 0.69444, 0, 0, 0.55], + "95": [0.35, 0.10833, 0.03056, 0, 0.55], + "97": [0, 0.45833, 0, 0, 0.525], + "98": [0, 0.69444, 0, 0, 0.56111], + "99": [0, 0.45833, 0, 0, 0.48889], + "100": [0, 0.69444, 0, 0, 0.56111], + "101": [0, 0.45833, 0, 0, 0.51111], + "102": [0, 0.69444, 0.07639, 0, 0.33611], + "103": [0.19444, 0.45833, 0.01528, 0, 0.55], + "104": [0, 0.69444, 0, 0, 0.56111], + "105": [0, 0.69444, 0, 0, 0.25556], + "106": [0.19444, 0.69444, 0, 0, 0.28611], + "107": [0, 0.69444, 0, 0, 0.53056], + "108": [0, 0.69444, 0, 0, 0.25556], + "109": [0, 0.45833, 0, 0, 0.86667], + "110": [0, 0.45833, 0, 0, 0.56111], + "111": [0, 0.45833, 0, 0, 0.55], + "112": [0.19444, 0.45833, 0, 0, 0.56111], + "113": [0.19444, 0.45833, 0, 0, 0.56111], + "114": [0, 0.45833, 0.01528, 0, 0.37222], + "115": [0, 0.45833, 0, 0, 0.42167], + "116": [0, 0.58929, 0, 0, 0.40417], + "117": [0, 0.45833, 0, 0, 0.56111], + "118": [0, 0.45833, 0.01528, 0, 0.5], + "119": [0, 0.45833, 0.01528, 0, 0.74445], + "120": [0, 0.45833, 0, 0, 0.5], + "121": [0.19444, 0.45833, 0.01528, 0, 0.5], + "122": [0, 0.45833, 0, 0, 0.47639], + "126": [0.35, 0.34444, 0, 0, 0.55], + "168": [0, 0.69444, 0, 0, 0.55], + "176": [0, 0.69444, 0, 0, 0.73334], + "180": [0, 0.69444, 0, 0, 0.55], + "184": [0.17014, 0, 0, 0, 0.48889], + "305": [0, 0.45833, 0, 0, 0.25556], + "567": [0.19444, 0.45833, 0, 0, 0.28611], + "710": [0, 0.69444, 0, 0, 0.55], + "711": [0, 0.63542, 0, 0, 0.55], + "713": [0, 0.63778, 0, 0, 0.55], + "728": [0, 0.69444, 0, 0, 0.55], + "729": [0, 0.69444, 0, 0, 0.30556], + "730": [0, 0.69444, 0, 0, 0.73334], + "732": [0, 0.69444, 0, 0, 0.55], + "733": [0, 0.69444, 0, 0, 0.55], + "915": [0, 0.69444, 0, 0, 0.58056], + "916": [0, 0.69444, 0, 0, 0.91667], + "920": [0, 0.69444, 0, 0, 0.85556], + "923": [0, 0.69444, 0, 0, 0.67223], + "926": [0, 0.69444, 0, 0, 0.73334], + "928": [0, 0.69444, 0, 0, 0.79445], + "931": [0, 0.69444, 0, 0, 0.79445], + "933": [0, 0.69444, 0, 0, 0.85556], + "934": [0, 0.69444, 0, 0, 0.79445], + "936": [0, 0.69444, 0, 0, 0.85556], + "937": [0, 0.69444, 0, 0, 0.79445], + "8211": [0, 0.45833, 0.03056, 0, 0.55], + "8212": [0, 0.45833, 0.03056, 0, 1.10001], + "8216": [0, 0.69444, 0, 0, 0.30556], + "8217": [0, 0.69444, 0, 0, 0.30556], + "8220": [0, 0.69444, 0, 0, 0.55834], + "8221": [0, 0.69444, 0, 0, 0.55834] + }, + "SansSerif-Italic": { + "33": [0, 0.69444, 0.05733, 0, 0.31945], + "34": [0, 0.69444, 0.00316, 0, 0.5], + "35": [0.19444, 0.69444, 0.05087, 0, 0.83334], + "36": [0.05556, 0.75, 0.11156, 0, 0.5], + "37": [0.05556, 0.75, 0.03126, 0, 0.83334], + "38": [0, 0.69444, 0.03058, 0, 0.75834], + "39": [0, 0.69444, 0.07816, 0, 0.27778], + "40": [0.25, 0.75, 0.13164, 0, 0.38889], + "41": [0.25, 0.75, 0.02536, 0, 0.38889], + "42": [0, 0.75, 0.11775, 0, 0.5], + "43": [0.08333, 0.58333, 0.02536, 0, 0.77778], + "44": [0.125, 0.08333, 0, 0, 0.27778], + "45": [0, 0.44444, 0.01946, 0, 0.33333], + "46": [0, 0.08333, 0, 0, 0.27778], + "47": [0.25, 0.75, 0.13164, 0, 0.5], + "48": [0, 0.65556, 0.11156, 0, 0.5], + "49": [0, 0.65556, 0.11156, 0, 0.5], + "50": [0, 0.65556, 0.11156, 0, 0.5], + "51": [0, 0.65556, 0.11156, 0, 0.5], + "52": [0, 0.65556, 0.11156, 0, 0.5], + "53": [0, 0.65556, 0.11156, 0, 0.5], + "54": [0, 0.65556, 0.11156, 0, 0.5], + "55": [0, 0.65556, 0.11156, 0, 0.5], + "56": [0, 0.65556, 0.11156, 0, 0.5], + "57": [0, 0.65556, 0.11156, 0, 0.5], + "58": [0, 0.44444, 0.02502, 0, 0.27778], + "59": [0.125, 0.44444, 0.02502, 0, 0.27778], + "61": [-0.13, 0.37, 0.05087, 0, 0.77778], + "63": [0, 0.69444, 0.11809, 0, 0.47222], + "64": [0, 0.69444, 0.07555, 0, 0.66667], + "65": [0, 0.69444, 0, 0, 0.66667], + "66": [0, 0.69444, 0.08293, 0, 0.66667], + "67": [0, 0.69444, 0.11983, 0, 0.63889], + "68": [0, 0.69444, 0.07555, 0, 0.72223], + "69": [0, 0.69444, 0.11983, 0, 0.59722], + "70": [0, 0.69444, 0.13372, 0, 0.56945], + "71": [0, 0.69444, 0.11983, 0, 0.66667], + "72": [0, 0.69444, 0.08094, 0, 0.70834], + "73": [0, 0.69444, 0.13372, 0, 0.27778], + "74": [0, 0.69444, 0.08094, 0, 0.47222], + "75": [0, 0.69444, 0.11983, 0, 0.69445], + "76": [0, 0.69444, 0, 0, 0.54167], + "77": [0, 0.69444, 0.08094, 0, 0.875], + "78": [0, 0.69444, 0.08094, 0, 0.70834], + "79": [0, 0.69444, 0.07555, 0, 0.73611], + "80": [0, 0.69444, 0.08293, 0, 0.63889], + "81": [0.125, 0.69444, 0.07555, 0, 0.73611], + "82": [0, 0.69444, 0.08293, 0, 0.64584], + "83": [0, 0.69444, 0.09205, 0, 0.55556], + "84": [0, 0.69444, 0.13372, 0, 0.68056], + "85": [0, 0.69444, 0.08094, 0, 0.6875], + "86": [0, 0.69444, 0.1615, 0, 0.66667], + "87": [0, 0.69444, 0.1615, 0, 0.94445], + "88": [0, 0.69444, 0.13372, 0, 0.66667], + "89": [0, 0.69444, 0.17261, 0, 0.66667], + "90": [0, 0.69444, 0.11983, 0, 0.61111], + "91": [0.25, 0.75, 0.15942, 0, 0.28889], + "93": [0.25, 0.75, 0.08719, 0, 0.28889], + "94": [0, 0.69444, 0.0799, 0, 0.5], + "95": [0.35, 0.09444, 0.08616, 0, 0.5], + "97": [0, 0.44444, 0.00981, 0, 0.48056], + "98": [0, 0.69444, 0.03057, 0, 0.51667], + "99": [0, 0.44444, 0.08336, 0, 0.44445], + "100": [0, 0.69444, 0.09483, 0, 0.51667], + "101": [0, 0.44444, 0.06778, 0, 0.44445], + "102": [0, 0.69444, 0.21705, 0, 0.30556], + "103": [0.19444, 0.44444, 0.10836, 0, 0.5], + "104": [0, 0.69444, 0.01778, 0, 0.51667], + "105": [0, 0.67937, 0.09718, 0, 0.23889], + "106": [0.19444, 0.67937, 0.09162, 0, 0.26667], + "107": [0, 0.69444, 0.08336, 0, 0.48889], + "108": [0, 0.69444, 0.09483, 0, 0.23889], + "109": [0, 0.44444, 0.01778, 0, 0.79445], + "110": [0, 0.44444, 0.01778, 0, 0.51667], + "111": [0, 0.44444, 0.06613, 0, 0.5], + "112": [0.19444, 0.44444, 0.0389, 0, 0.51667], + "113": [0.19444, 0.44444, 0.04169, 0, 0.51667], + "114": [0, 0.44444, 0.10836, 0, 0.34167], + "115": [0, 0.44444, 0.0778, 0, 0.38333], + "116": [0, 0.57143, 0.07225, 0, 0.36111], + "117": [0, 0.44444, 0.04169, 0, 0.51667], + "118": [0, 0.44444, 0.10836, 0, 0.46111], + "119": [0, 0.44444, 0.10836, 0, 0.68334], + "120": [0, 0.44444, 0.09169, 0, 0.46111], + "121": [0.19444, 0.44444, 0.10836, 0, 0.46111], + "122": [0, 0.44444, 0.08752, 0, 0.43472], + "126": [0.35, 0.32659, 0.08826, 0, 0.5], + "168": [0, 0.67937, 0.06385, 0, 0.5], + "176": [0, 0.69444, 0, 0, 0.73752], + "184": [0.17014, 0, 0, 0, 0.44445], + "305": [0, 0.44444, 0.04169, 0, 0.23889], + "567": [0.19444, 0.44444, 0.04169, 0, 0.26667], + "710": [0, 0.69444, 0.0799, 0, 0.5], + "711": [0, 0.63194, 0.08432, 0, 0.5], + "713": [0, 0.60889, 0.08776, 0, 0.5], + "714": [0, 0.69444, 0.09205, 0, 0.5], + "715": [0, 0.69444, 0, 0, 0.5], + "728": [0, 0.69444, 0.09483, 0, 0.5], + "729": [0, 0.67937, 0.07774, 0, 0.27778], + "730": [0, 0.69444, 0, 0, 0.73752], + "732": [0, 0.67659, 0.08826, 0, 0.5], + "733": [0, 0.69444, 0.09205, 0, 0.5], + "915": [0, 0.69444, 0.13372, 0, 0.54167], + "916": [0, 0.69444, 0, 0, 0.83334], + "920": [0, 0.69444, 0.07555, 0, 0.77778], + "923": [0, 0.69444, 0, 0, 0.61111], + "926": [0, 0.69444, 0.12816, 0, 0.66667], + "928": [0, 0.69444, 0.08094, 0, 0.70834], + "931": [0, 0.69444, 0.11983, 0, 0.72222], + "933": [0, 0.69444, 0.09031, 0, 0.77778], + "934": [0, 0.69444, 0.04603, 0, 0.72222], + "936": [0, 0.69444, 0.09031, 0, 0.77778], + "937": [0, 0.69444, 0.08293, 0, 0.72222], + "8211": [0, 0.44444, 0.08616, 0, 0.5], + "8212": [0, 0.44444, 0.08616, 0, 1.0], + "8216": [0, 0.69444, 0.07816, 0, 0.27778], + "8217": [0, 0.69444, 0.07816, 0, 0.27778], + "8220": [0, 0.69444, 0.14205, 0, 0.5], + "8221": [0, 0.69444, 0.00316, 0, 0.5] + }, + "SansSerif-Regular": { + "33": [0, 0.69444, 0, 0, 0.31945], + "34": [0, 0.69444, 0, 0, 0.5], + "35": [0.19444, 0.69444, 0, 0, 0.83334], + "36": [0.05556, 0.75, 0, 0, 0.5], + "37": [0.05556, 0.75, 0, 0, 0.83334], + "38": [0, 0.69444, 0, 0, 0.75834], + "39": [0, 0.69444, 0, 0, 0.27778], + "40": [0.25, 0.75, 0, 0, 0.38889], + "41": [0.25, 0.75, 0, 0, 0.38889], + "42": [0, 0.75, 0, 0, 0.5], + "43": [0.08333, 0.58333, 0, 0, 0.77778], + "44": [0.125, 0.08333, 0, 0, 0.27778], + "45": [0, 0.44444, 0, 0, 0.33333], + "46": [0, 0.08333, 0, 0, 0.27778], + "47": [0.25, 0.75, 0, 0, 0.5], + "48": [0, 0.65556, 0, 0, 0.5], + "49": [0, 0.65556, 0, 0, 0.5], + "50": [0, 0.65556, 0, 0, 0.5], + "51": [0, 0.65556, 0, 0, 0.5], + "52": [0, 0.65556, 0, 0, 0.5], + "53": [0, 0.65556, 0, 0, 0.5], + "54": [0, 0.65556, 0, 0, 0.5], + "55": [0, 0.65556, 0, 0, 0.5], + "56": [0, 0.65556, 0, 0, 0.5], + "57": [0, 0.65556, 0, 0, 0.5], + "58": [0, 0.44444, 0, 0, 0.27778], + "59": [0.125, 0.44444, 0, 0, 0.27778], + "61": [-0.13, 0.37, 0, 0, 0.77778], + "63": [0, 0.69444, 0, 0, 0.47222], + "64": [0, 0.69444, 0, 0, 0.66667], + "65": [0, 0.69444, 0, 0, 0.66667], + "66": [0, 0.69444, 0, 0, 0.66667], + "67": [0, 0.69444, 0, 0, 0.63889], + "68": [0, 0.69444, 0, 0, 0.72223], + "69": [0, 0.69444, 0, 0, 0.59722], + "70": [0, 0.69444, 0, 0, 0.56945], + "71": [0, 0.69444, 0, 0, 0.66667], + "72": [0, 0.69444, 0, 0, 0.70834], + "73": [0, 0.69444, 0, 0, 0.27778], + "74": [0, 0.69444, 0, 0, 0.47222], + "75": [0, 0.69444, 0, 0, 0.69445], + "76": [0, 0.69444, 0, 0, 0.54167], + "77": [0, 0.69444, 0, 0, 0.875], + "78": [0, 0.69444, 0, 0, 0.70834], + "79": [0, 0.69444, 0, 0, 0.73611], + "80": [0, 0.69444, 0, 0, 0.63889], + "81": [0.125, 0.69444, 0, 0, 0.73611], + "82": [0, 0.69444, 0, 0, 0.64584], + "83": [0, 0.69444, 0, 0, 0.55556], + "84": [0, 0.69444, 0, 0, 0.68056], + "85": [0, 0.69444, 0, 0, 0.6875], + "86": [0, 0.69444, 0.01389, 0, 0.66667], + "87": [0, 0.69444, 0.01389, 0, 0.94445], + "88": [0, 0.69444, 0, 0, 0.66667], + "89": [0, 0.69444, 0.025, 0, 0.66667], + "90": [0, 0.69444, 0, 0, 0.61111], + "91": [0.25, 0.75, 0, 0, 0.28889], + "93": [0.25, 0.75, 0, 0, 0.28889], + "94": [0, 0.69444, 0, 0, 0.5], + "95": [0.35, 0.09444, 0.02778, 0, 0.5], + "97": [0, 0.44444, 0, 0, 0.48056], + "98": [0, 0.69444, 0, 0, 0.51667], + "99": [0, 0.44444, 0, 0, 0.44445], + "100": [0, 0.69444, 0, 0, 0.51667], + "101": [0, 0.44444, 0, 0, 0.44445], + "102": [0, 0.69444, 0.06944, 0, 0.30556], + "103": [0.19444, 0.44444, 0.01389, 0, 0.5], + "104": [0, 0.69444, 0, 0, 0.51667], + "105": [0, 0.67937, 0, 0, 0.23889], + "106": [0.19444, 0.67937, 0, 0, 0.26667], + "107": [0, 0.69444, 0, 0, 0.48889], + "108": [0, 0.69444, 0, 0, 0.23889], + "109": [0, 0.44444, 0, 0, 0.79445], + "110": [0, 0.44444, 0, 0, 0.51667], + "111": [0, 0.44444, 0, 0, 0.5], + "112": [0.19444, 0.44444, 0, 0, 0.51667], + "113": [0.19444, 0.44444, 0, 0, 0.51667], + "114": [0, 0.44444, 0.01389, 0, 0.34167], + "115": [0, 0.44444, 0, 0, 0.38333], + "116": [0, 0.57143, 0, 0, 0.36111], + "117": [0, 0.44444, 0, 0, 0.51667], + "118": [0, 0.44444, 0.01389, 0, 0.46111], + "119": [0, 0.44444, 0.01389, 0, 0.68334], + "120": [0, 0.44444, 0, 0, 0.46111], + "121": [0.19444, 0.44444, 0.01389, 0, 0.46111], + "122": [0, 0.44444, 0, 0, 0.43472], + "126": [0.35, 0.32659, 0, 0, 0.5], + "168": [0, 0.67937, 0, 0, 0.5], + "176": [0, 0.69444, 0, 0, 0.66667], + "184": [0.17014, 0, 0, 0, 0.44445], + "305": [0, 0.44444, 0, 0, 0.23889], + "567": [0.19444, 0.44444, 0, 0, 0.26667], + "710": [0, 0.69444, 0, 0, 0.5], + "711": [0, 0.63194, 0, 0, 0.5], + "713": [0, 0.60889, 0, 0, 0.5], + "714": [0, 0.69444, 0, 0, 0.5], + "715": [0, 0.69444, 0, 0, 0.5], + "728": [0, 0.69444, 0, 0, 0.5], + "729": [0, 0.67937, 0, 0, 0.27778], + "730": [0, 0.69444, 0, 0, 0.66667], + "732": [0, 0.67659, 0, 0, 0.5], + "733": [0, 0.69444, 0, 0, 0.5], + "915": [0, 0.69444, 0, 0, 0.54167], + "916": [0, 0.69444, 0, 0, 0.83334], + "920": [0, 0.69444, 0, 0, 0.77778], + "923": [0, 0.69444, 0, 0, 0.61111], + "926": [0, 0.69444, 0, 0, 0.66667], + "928": [0, 0.69444, 0, 0, 0.70834], + "931": [0, 0.69444, 0, 0, 0.72222], + "933": [0, 0.69444, 0, 0, 0.77778], + "934": [0, 0.69444, 0, 0, 0.72222], + "936": [0, 0.69444, 0, 0, 0.77778], + "937": [0, 0.69444, 0, 0, 0.72222], + "8211": [0, 0.44444, 0.02778, 0, 0.5], + "8212": [0, 0.44444, 0.02778, 0, 1.0], + "8216": [0, 0.69444, 0, 0, 0.27778], + "8217": [0, 0.69444, 0, 0, 0.27778], + "8220": [0, 0.69444, 0, 0, 0.5], + "8221": [0, 0.69444, 0, 0, 0.5] + }, + "Script-Regular": { + "65": [0, 0.7, 0.22925, 0, 0.80253], + "66": [0, 0.7, 0.04087, 0, 0.90757], + "67": [0, 0.7, 0.1689, 0, 0.66619], + "68": [0, 0.7, 0.09371, 0, 0.77443], + "69": [0, 0.7, 0.18583, 0, 0.56162], + "70": [0, 0.7, 0.13634, 0, 0.89544], + "71": [0, 0.7, 0.17322, 0, 0.60961], + "72": [0, 0.7, 0.29694, 0, 0.96919], + "73": [0, 0.7, 0.19189, 0, 0.80907], + "74": [0.27778, 0.7, 0.19189, 0, 1.05159], + "75": [0, 0.7, 0.31259, 0, 0.91364], + "76": [0, 0.7, 0.19189, 0, 0.87373], + "77": [0, 0.7, 0.15981, 0, 1.08031], + "78": [0, 0.7, 0.3525, 0, 0.9015], + "79": [0, 0.7, 0.08078, 0, 0.73787], + "80": [0, 0.7, 0.08078, 0, 1.01262], + "81": [0, 0.7, 0.03305, 0, 0.88282], + "82": [0, 0.7, 0.06259, 0, 0.85], + "83": [0, 0.7, 0.19189, 0, 0.86767], + "84": [0, 0.7, 0.29087, 0, 0.74697], + "85": [0, 0.7, 0.25815, 0, 0.79996], + "86": [0, 0.7, 0.27523, 0, 0.62204], + "87": [0, 0.7, 0.27523, 0, 0.80532], + "88": [0, 0.7, 0.26006, 0, 0.94445], + "89": [0, 0.7, 0.2939, 0, 0.70961], + "90": [0, 0.7, 0.24037, 0, 0.8212] + }, + "Size1-Regular": { + "40": [0.35001, 0.85, 0, 0, 0.45834], + "41": [0.35001, 0.85, 0, 0, 0.45834], + "47": [0.35001, 0.85, 0, 0, 0.57778], + "91": [0.35001, 0.85, 0, 0, 0.41667], + "92": [0.35001, 0.85, 0, 0, 0.57778], + "93": [0.35001, 0.85, 0, 0, 0.41667], + "123": [0.35001, 0.85, 0, 0, 0.58334], + "125": [0.35001, 0.85, 0, 0, 0.58334], + "710": [0, 0.72222, 0, 0, 0.55556], + "732": [0, 0.72222, 0, 0, 0.55556], + "770": [0, 0.72222, 0, 0, 0.55556], + "771": [0, 0.72222, 0, 0, 0.55556], + "8214": [-0.00099, 0.601, 0, 0, 0.77778], + "8593": [1e-05, 0.6, 0, 0, 0.66667], + "8595": [1e-05, 0.6, 0, 0, 0.66667], + "8657": [1e-05, 0.6, 0, 0, 0.77778], + "8659": [1e-05, 0.6, 0, 0, 0.77778], + "8719": [0.25001, 0.75, 0, 0, 0.94445], + "8720": [0.25001, 0.75, 0, 0, 0.94445], + "8721": [0.25001, 0.75, 0, 0, 1.05556], + "8730": [0.35001, 0.85, 0, 0, 1.0], + "8739": [-0.00599, 0.606, 0, 0, 0.33333], + "8741": [-0.00599, 0.606, 0, 0, 0.55556], + "8747": [0.30612, 0.805, 0.19445, 0, 0.47222], + "8748": [0.306, 0.805, 0.19445, 0, 0.47222], + "8749": [0.306, 0.805, 0.19445, 0, 0.47222], + "8750": [0.30612, 0.805, 0.19445, 0, 0.47222], + "8896": [0.25001, 0.75, 0, 0, 0.83334], + "8897": [0.25001, 0.75, 0, 0, 0.83334], + "8898": [0.25001, 0.75, 0, 0, 0.83334], + "8899": [0.25001, 0.75, 0, 0, 0.83334], + "8968": [0.35001, 0.85, 0, 0, 0.47222], + "8969": [0.35001, 0.85, 0, 0, 0.47222], + "8970": [0.35001, 0.85, 0, 0, 0.47222], + "8971": [0.35001, 0.85, 0, 0, 0.47222], + "9168": [-0.00099, 0.601, 0, 0, 0.66667], + "10216": [0.35001, 0.85, 0, 0, 0.47222], + "10217": [0.35001, 0.85, 0, 0, 0.47222], + "10752": [0.25001, 0.75, 0, 0, 1.11111], + "10753": [0.25001, 0.75, 0, 0, 1.11111], + "10754": [0.25001, 0.75, 0, 0, 1.11111], + "10756": [0.25001, 0.75, 0, 0, 0.83334], + "10758": [0.25001, 0.75, 0, 0, 0.83334] + }, + "Size2-Regular": { + "40": [0.65002, 1.15, 0, 0, 0.59722], + "41": [0.65002, 1.15, 0, 0, 0.59722], + "47": [0.65002, 1.15, 0, 0, 0.81111], + "91": [0.65002, 1.15, 0, 0, 0.47222], + "92": [0.65002, 1.15, 0, 0, 0.81111], + "93": [0.65002, 1.15, 0, 0, 0.47222], + "123": [0.65002, 1.15, 0, 0, 0.66667], + "125": [0.65002, 1.15, 0, 0, 0.66667], + "710": [0, 0.75, 0, 0, 1.0], + "732": [0, 0.75, 0, 0, 1.0], + "770": [0, 0.75, 0, 0, 1.0], + "771": [0, 0.75, 0, 0, 1.0], + "8719": [0.55001, 1.05, 0, 0, 1.27778], + "8720": [0.55001, 1.05, 0, 0, 1.27778], + "8721": [0.55001, 1.05, 0, 0, 1.44445], + "8730": [0.65002, 1.15, 0, 0, 1.0], + "8747": [0.86225, 1.36, 0.44445, 0, 0.55556], + "8748": [0.862, 1.36, 0.44445, 0, 0.55556], + "8749": [0.862, 1.36, 0.44445, 0, 0.55556], + "8750": [0.86225, 1.36, 0.44445, 0, 0.55556], + "8896": [0.55001, 1.05, 0, 0, 1.11111], + "8897": [0.55001, 1.05, 0, 0, 1.11111], + "8898": [0.55001, 1.05, 0, 0, 1.11111], + "8899": [0.55001, 1.05, 0, 0, 1.11111], + "8968": [0.65002, 1.15, 0, 0, 0.52778], + "8969": [0.65002, 1.15, 0, 0, 0.52778], + "8970": [0.65002, 1.15, 0, 0, 0.52778], + "8971": [0.65002, 1.15, 0, 0, 0.52778], + "10216": [0.65002, 1.15, 0, 0, 0.61111], + "10217": [0.65002, 1.15, 0, 0, 0.61111], + "10752": [0.55001, 1.05, 0, 0, 1.51112], + "10753": [0.55001, 1.05, 0, 0, 1.51112], + "10754": [0.55001, 1.05, 0, 0, 1.51112], + "10756": [0.55001, 1.05, 0, 0, 1.11111], + "10758": [0.55001, 1.05, 0, 0, 1.11111] + }, + "Size3-Regular": { + "40": [0.95003, 1.45, 0, 0, 0.73611], + "41": [0.95003, 1.45, 0, 0, 0.73611], + "47": [0.95003, 1.45, 0, 0, 1.04445], + "91": [0.95003, 1.45, 0, 0, 0.52778], + "92": [0.95003, 1.45, 0, 0, 1.04445], + "93": [0.95003, 1.45, 0, 0, 0.52778], + "123": [0.95003, 1.45, 0, 0, 0.75], + "125": [0.95003, 1.45, 0, 0, 0.75], + "710": [0, 0.75, 0, 0, 1.44445], + "732": [0, 0.75, 0, 0, 1.44445], + "770": [0, 0.75, 0, 0, 1.44445], + "771": [0, 0.75, 0, 0, 1.44445], + "8730": [0.95003, 1.45, 0, 0, 1.0], + "8968": [0.95003, 1.45, 0, 0, 0.58334], + "8969": [0.95003, 1.45, 0, 0, 0.58334], + "8970": [0.95003, 1.45, 0, 0, 0.58334], + "8971": [0.95003, 1.45, 0, 0, 0.58334], + "10216": [0.95003, 1.45, 0, 0, 0.75], + "10217": [0.95003, 1.45, 0, 0, 0.75] + }, + "Size4-Regular": { + "40": [1.25003, 1.75, 0, 0, 0.79167], + "41": [1.25003, 1.75, 0, 0, 0.79167], + "47": [1.25003, 1.75, 0, 0, 1.27778], + "91": [1.25003, 1.75, 0, 0, 0.58334], + "92": [1.25003, 1.75, 0, 0, 1.27778], + "93": [1.25003, 1.75, 0, 0, 0.58334], + "123": [1.25003, 1.75, 0, 0, 0.80556], + "125": [1.25003, 1.75, 0, 0, 0.80556], + "710": [0, 0.825, 0, 0, 1.8889], + "732": [0, 0.825, 0, 0, 1.8889], + "770": [0, 0.825, 0, 0, 1.8889], + "771": [0, 0.825, 0, 0, 1.8889], + "8730": [1.25003, 1.75, 0, 0, 1.0], + "8968": [1.25003, 1.75, 0, 0, 0.63889], + "8969": [1.25003, 1.75, 0, 0, 0.63889], + "8970": [1.25003, 1.75, 0, 0, 0.63889], + "8971": [1.25003, 1.75, 0, 0, 0.63889], + "9115": [0.64502, 1.155, 0, 0, 0.875], + "9116": [1e-05, 0.6, 0, 0, 0.875], + "9117": [0.64502, 1.155, 0, 0, 0.875], + "9118": [0.64502, 1.155, 0, 0, 0.875], + "9119": [1e-05, 0.6, 0, 0, 0.875], + "9120": [0.64502, 1.155, 0, 0, 0.875], + "9121": [0.64502, 1.155, 0, 0, 0.66667], + "9122": [-0.00099, 0.601, 0, 0, 0.66667], + "9123": [0.64502, 1.155, 0, 0, 0.66667], + "9124": [0.64502, 1.155, 0, 0, 0.66667], + "9125": [-0.00099, 0.601, 0, 0, 0.66667], + "9126": [0.64502, 1.155, 0, 0, 0.66667], + "9127": [1e-05, 0.9, 0, 0, 0.88889], + "9128": [0.65002, 1.15, 0, 0, 0.88889], + "9129": [0.90001, 0, 0, 0, 0.88889], + "9130": [0, 0.3, 0, 0, 0.88889], + "9131": [1e-05, 0.9, 0, 0, 0.88889], + "9132": [0.65002, 1.15, 0, 0, 0.88889], + "9133": [0.90001, 0, 0, 0, 0.88889], + "9143": [0.88502, 0.915, 0, 0, 1.05556], + "10216": [1.25003, 1.75, 0, 0, 0.80556], + "10217": [1.25003, 1.75, 0, 0, 0.80556], + "57344": [-0.00499, 0.605, 0, 0, 1.05556], + "57345": [-0.00499, 0.605, 0, 0, 1.05556], + "57680": [0, 0.12, 0, 0, 0.45], + "57681": [0, 0.12, 0, 0, 0.45], + "57682": [0, 0.12, 0, 0, 0.45], + "57683": [0, 0.12, 0, 0, 0.45] + }, + "Typewriter-Regular": { + "32": [0, 0, 0, 0, 0.525], + "33": [0, 0.61111, 0, 0, 0.525], + "34": [0, 0.61111, 0, 0, 0.525], + "35": [0, 0.61111, 0, 0, 0.525], + "36": [0.08333, 0.69444, 0, 0, 0.525], + "37": [0.08333, 0.69444, 0, 0, 0.525], + "38": [0, 0.61111, 0, 0, 0.525], + "39": [0, 0.61111, 0, 0, 0.525], + "40": [0.08333, 0.69444, 0, 0, 0.525], + "41": [0.08333, 0.69444, 0, 0, 0.525], + "42": [0, 0.52083, 0, 0, 0.525], + "43": [-0.08056, 0.53055, 0, 0, 0.525], + "44": [0.13889, 0.125, 0, 0, 0.525], + "45": [-0.08056, 0.53055, 0, 0, 0.525], + "46": [0, 0.125, 0, 0, 0.525], + "47": [0.08333, 0.69444, 0, 0, 0.525], + "48": [0, 0.61111, 0, 0, 0.525], + "49": [0, 0.61111, 0, 0, 0.525], + "50": [0, 0.61111, 0, 0, 0.525], + "51": [0, 0.61111, 0, 0, 0.525], + "52": [0, 0.61111, 0, 0, 0.525], + "53": [0, 0.61111, 0, 0, 0.525], + "54": [0, 0.61111, 0, 0, 0.525], + "55": [0, 0.61111, 0, 0, 0.525], + "56": [0, 0.61111, 0, 0, 0.525], + "57": [0, 0.61111, 0, 0, 0.525], + "58": [0, 0.43056, 0, 0, 0.525], + "59": [0.13889, 0.43056, 0, 0, 0.525], + "60": [-0.05556, 0.55556, 0, 0, 0.525], + "61": [-0.19549, 0.41562, 0, 0, 0.525], + "62": [-0.05556, 0.55556, 0, 0, 0.525], + "63": [0, 0.61111, 0, 0, 0.525], + "64": [0, 0.61111, 0, 0, 0.525], + "65": [0, 0.61111, 0, 0, 0.525], + "66": [0, 0.61111, 0, 0, 0.525], + "67": [0, 0.61111, 0, 0, 0.525], + "68": [0, 0.61111, 0, 0, 0.525], + "69": [0, 0.61111, 0, 0, 0.525], + "70": [0, 0.61111, 0, 0, 0.525], + "71": [0, 0.61111, 0, 0, 0.525], + "72": [0, 0.61111, 0, 0, 0.525], + "73": [0, 0.61111, 0, 0, 0.525], + "74": [0, 0.61111, 0, 0, 0.525], + "75": [0, 0.61111, 0, 0, 0.525], + "76": [0, 0.61111, 0, 0, 0.525], + "77": [0, 0.61111, 0, 0, 0.525], + "78": [0, 0.61111, 0, 0, 0.525], + "79": [0, 0.61111, 0, 0, 0.525], + "80": [0, 0.61111, 0, 0, 0.525], + "81": [0.13889, 0.61111, 0, 0, 0.525], + "82": [0, 0.61111, 0, 0, 0.525], + "83": [0, 0.61111, 0, 0, 0.525], + "84": [0, 0.61111, 0, 0, 0.525], + "85": [0, 0.61111, 0, 0, 0.525], + "86": [0, 0.61111, 0, 0, 0.525], + "87": [0, 0.61111, 0, 0, 0.525], + "88": [0, 0.61111, 0, 0, 0.525], + "89": [0, 0.61111, 0, 0, 0.525], + "90": [0, 0.61111, 0, 0, 0.525], + "91": [0.08333, 0.69444, 0, 0, 0.525], + "92": [0.08333, 0.69444, 0, 0, 0.525], + "93": [0.08333, 0.69444, 0, 0, 0.525], + "94": [0, 0.61111, 0, 0, 0.525], + "95": [0.09514, 0, 0, 0, 0.525], + "96": [0, 0.61111, 0, 0, 0.525], + "97": [0, 0.43056, 0, 0, 0.525], + "98": [0, 0.61111, 0, 0, 0.525], + "99": [0, 0.43056, 0, 0, 0.525], + "100": [0, 0.61111, 0, 0, 0.525], + "101": [0, 0.43056, 0, 0, 0.525], + "102": [0, 0.61111, 0, 0, 0.525], + "103": [0.22222, 0.43056, 0, 0, 0.525], + "104": [0, 0.61111, 0, 0, 0.525], + "105": [0, 0.61111, 0, 0, 0.525], + "106": [0.22222, 0.61111, 0, 0, 0.525], + "107": [0, 0.61111, 0, 0, 0.525], + "108": [0, 0.61111, 0, 0, 0.525], + "109": [0, 0.43056, 0, 0, 0.525], + "110": [0, 0.43056, 0, 0, 0.525], + "111": [0, 0.43056, 0, 0, 0.525], + "112": [0.22222, 0.43056, 0, 0, 0.525], + "113": [0.22222, 0.43056, 0, 0, 0.525], + "114": [0, 0.43056, 0, 0, 0.525], + "115": [0, 0.43056, 0, 0, 0.525], + "116": [0, 0.55358, 0, 0, 0.525], + "117": [0, 0.43056, 0, 0, 0.525], + "118": [0, 0.43056, 0, 0, 0.525], + "119": [0, 0.43056, 0, 0, 0.525], + "120": [0, 0.43056, 0, 0, 0.525], + "121": [0.22222, 0.43056, 0, 0, 0.525], + "122": [0, 0.43056, 0, 0, 0.525], + "123": [0.08333, 0.69444, 0, 0, 0.525], + "124": [0.08333, 0.69444, 0, 0, 0.525], + "125": [0.08333, 0.69444, 0, 0, 0.525], + "126": [0, 0.61111, 0, 0, 0.525], + "127": [0, 0.61111, 0, 0, 0.525], + "160": [0, 0, 0, 0, 0.525], + "176": [0, 0.61111, 0, 0, 0.525], + "184": [0.19445, 0, 0, 0, 0.525], + "305": [0, 0.43056, 0, 0, 0.525], + "567": [0.22222, 0.43056, 0, 0, 0.525], + "711": [0, 0.56597, 0, 0, 0.525], + "713": [0, 0.56555, 0, 0, 0.525], + "714": [0, 0.61111, 0, 0, 0.525], + "715": [0, 0.61111, 0, 0, 0.525], + "728": [0, 0.61111, 0, 0, 0.525], + "730": [0, 0.61111, 0, 0, 0.525], + "770": [0, 0.61111, 0, 0, 0.525], + "771": [0, 0.61111, 0, 0, 0.525], + "776": [0, 0.61111, 0, 0, 0.525], + "915": [0, 0.61111, 0, 0, 0.525], + "916": [0, 0.61111, 0, 0, 0.525], + "920": [0, 0.61111, 0, 0, 0.525], + "923": [0, 0.61111, 0, 0, 0.525], + "926": [0, 0.61111, 0, 0, 0.525], + "928": [0, 0.61111, 0, 0, 0.525], + "931": [0, 0.61111, 0, 0, 0.525], + "933": [0, 0.61111, 0, 0, 0.525], + "934": [0, 0.61111, 0, 0, 0.525], + "936": [0, 0.61111, 0, 0, 0.525], + "937": [0, 0.61111, 0, 0, 0.525], + "8216": [0, 0.61111, 0, 0, 0.525], + "8217": [0, 0.61111, 0, 0, 0.525], + "8242": [0, 0.61111, 0, 0, 0.525], + "9251": [0.11111, 0.21944, 0, 0, 0.525] + } +}); +// CONCATENATED MODULE: ./src/fontMetrics.js + + +/** + * This file contains metrics regarding fonts and individual symbols. The sigma + * and xi variables, as well as the metricMap map contain data extracted from + * TeX, TeX font metrics, and the TTF files. These data are then exposed via the + * `metrics` variable and the getCharacterMetrics function. + */ +// In TeX, there are actually three sets of dimensions, one for each of +// textstyle (size index 5 and higher: >=9pt), scriptstyle (size index 3 and 4: +// 7-8pt), and scriptscriptstyle (size index 1 and 2: 5-6pt). These are +// provided in the the arrays below, in that order. +// +// The font metrics are stored in fonts cmsy10, cmsy7, and cmsy5 respsectively. +// This was determined by running the following script: +// +// latex -interaction=nonstopmode \ +// '\documentclass{article}\usepackage{amsmath}\begin{document}' \ +// '$a$ \expandafter\show\the\textfont2' \ +// '\expandafter\show\the\scriptfont2' \ +// '\expandafter\show\the\scriptscriptfont2' \ +// '\stop' +// +// The metrics themselves were retreived using the following commands: +// +// tftopl cmsy10 +// tftopl cmsy7 +// tftopl cmsy5 +// +// The output of each of these commands is quite lengthy. The only part we +// care about is the FONTDIMEN section. Each value is measured in EMs. +var sigmasAndXis = { + slant: [0.250, 0.250, 0.250], + // sigma1 + space: [0.000, 0.000, 0.000], + // sigma2 + stretch: [0.000, 0.000, 0.000], + // sigma3 + shrink: [0.000, 0.000, 0.000], + // sigma4 + xHeight: [0.431, 0.431, 0.431], + // sigma5 + quad: [1.000, 1.171, 1.472], + // sigma6 + extraSpace: [0.000, 0.000, 0.000], + // sigma7 + num1: [0.677, 0.732, 0.925], + // sigma8 + num2: [0.394, 0.384, 0.387], + // sigma9 + num3: [0.444, 0.471, 0.504], + // sigma10 + denom1: [0.686, 0.752, 1.025], + // sigma11 + denom2: [0.345, 0.344, 0.532], + // sigma12 + sup1: [0.413, 0.503, 0.504], + // sigma13 + sup2: [0.363, 0.431, 0.404], + // sigma14 + sup3: [0.289, 0.286, 0.294], + // sigma15 + sub1: [0.150, 0.143, 0.200], + // sigma16 + sub2: [0.247, 0.286, 0.400], + // sigma17 + supDrop: [0.386, 0.353, 0.494], + // sigma18 + subDrop: [0.050, 0.071, 0.100], + // sigma19 + delim1: [2.390, 1.700, 1.980], + // sigma20 + delim2: [1.010, 1.157, 1.420], + // sigma21 + axisHeight: [0.250, 0.250, 0.250], + // sigma22 + // These font metrics are extracted from TeX by using tftopl on cmex10.tfm; + // they correspond to the font parameters of the extension fonts (family 3). + // See the TeXbook, page 441. In AMSTeX, the extension fonts scale; to + // match cmex7, we'd use cmex7.tfm values for script and scriptscript + // values. + defaultRuleThickness: [0.04, 0.049, 0.049], + // xi8; cmex7: 0.049 + bigOpSpacing1: [0.111, 0.111, 0.111], + // xi9 + bigOpSpacing2: [0.166, 0.166, 0.166], + // xi10 + bigOpSpacing3: [0.2, 0.2, 0.2], + // xi11 + bigOpSpacing4: [0.6, 0.611, 0.611], + // xi12; cmex7: 0.611 + bigOpSpacing5: [0.1, 0.143, 0.143], + // xi13; cmex7: 0.143 + // The \sqrt rule width is taken from the height of the surd character. + // Since we use the same font at all sizes, this thickness doesn't scale. + sqrtRuleThickness: [0.04, 0.04, 0.04], + // This value determines how large a pt is, for metrics which are defined + // in terms of pts. + // This value is also used in katex.less; if you change it make sure the + // values match. + ptPerEm: [10.0, 10.0, 10.0], + // The space between adjacent `|` columns in an array definition. From + // `\showthe\doublerulesep` in LaTeX. Equals 2.0 / ptPerEm. + doubleRuleSep: [0.2, 0.2, 0.2], + // The width of separator lines in {array} environments. From + // `\showthe\arrayrulewidth` in LaTeX. Equals 0.4 / ptPerEm. + arrayRuleWidth: [0.04, 0.04, 0.04], + // Two values from LaTeX source2e: + fboxsep: [0.3, 0.3, 0.3], + // 3 pt / ptPerEm + fboxrule: [0.04, 0.04, 0.04] // 0.4 pt / ptPerEm + +}; // This map contains a mapping from font name and character code to character +// metrics, including height, depth, italic correction, and skew (kern from the +// character to the corresponding \skewchar) +// This map is generated via `make metrics`. It should not be changed manually. + + // These are very rough approximations. We default to Times New Roman which +// should have Latin-1 and Cyrillic characters, but may not depending on the +// operating system. The metrics do not account for extra height from the +// accents. In the case of Cyrillic characters which have both ascenders and +// descenders we prefer approximations with ascenders, primarily to prevent +// the fraction bar or root line from intersecting the glyph. +// TODO(kevinb) allow union of multiple glyph metrics for better accuracy. + +var extraCharacterMap = { + // Latin-1 + 'Å': 'A', + 'Ç': 'C', + 'Ð': 'D', + 'Þ': 'o', + 'å': 'a', + 'ç': 'c', + 'ð': 'd', + 'þ': 'o', + // Cyrillic + 'А': 'A', + 'Б': 'B', + 'В': 'B', + 'Г': 'F', + 'Д': 'A', + 'Е': 'E', + 'Ж': 'K', + 'З': '3', + 'И': 'N', + 'Й': 'N', + 'К': 'K', + 'Л': 'N', + 'М': 'M', + 'Н': 'H', + 'О': 'O', + 'П': 'N', + 'Р': 'P', + 'С': 'C', + 'Т': 'T', + 'У': 'y', + 'Ф': 'O', + 'Х': 'X', + 'Ц': 'U', + 'Ч': 'h', + 'Ш': 'W', + 'Щ': 'W', + 'Ъ': 'B', + 'Ы': 'X', + 'Ь': 'B', + 'Э': '3', + 'Ю': 'X', + 'Я': 'R', + 'а': 'a', + 'б': 'b', + 'в': 'a', + 'г': 'r', + 'д': 'y', + 'е': 'e', + 'ж': 'm', + 'з': 'e', + 'и': 'n', + 'й': 'n', + 'к': 'n', + 'л': 'n', + 'м': 'm', + 'н': 'n', + 'о': 'o', + 'п': 'n', + 'р': 'p', + 'с': 'c', + 'т': 'o', + 'у': 'y', + 'ф': 'b', + 'х': 'x', + 'ц': 'n', + 'ч': 'n', + 'ш': 'w', + 'щ': 'w', + 'ъ': 'a', + 'ы': 'm', + 'ь': 'a', + 'э': 'e', + 'ю': 'm', + 'я': 'r' +}; + +/** + * This function adds new font metrics to default metricMap + * It can also override existing metrics + */ +function setFontMetrics(fontName, metrics) { + fontMetricsData[fontName] = metrics; +} +/** + * This function is a convenience function for looking up information in the + * metricMap table. It takes a character as a string, and a font. + * + * Note: the `width` property may be undefined if fontMetricsData.js wasn't + * built using `Make extended_metrics`. + */ + +function getCharacterMetrics(character, font, mode) { + if (!fontMetricsData[font]) { + throw new Error("Font metrics not found for font: " + font + "."); + } + + var ch = character.charCodeAt(0); + var metrics = fontMetricsData[font][ch]; + + if (!metrics && character[0] in extraCharacterMap) { + ch = extraCharacterMap[character[0]].charCodeAt(0); + metrics = fontMetricsData[font][ch]; + } + + if (!metrics && mode === 'text') { + // We don't typically have font metrics for Asian scripts. + // But since we support them in text mode, we need to return + // some sort of metrics. + // So if the character is in a script we support but we + // don't have metrics for it, just use the metrics for + // the Latin capital letter M. This is close enough because + // we (currently) only care about the height of the glpyh + // not its width. + if (supportedCodepoint(ch)) { + metrics = fontMetricsData[font][77]; // 77 is the charcode for 'M' + } + } + + if (metrics) { + return { + depth: metrics[0], + height: metrics[1], + italic: metrics[2], + skew: metrics[3], + width: metrics[4] + }; + } +} +var fontMetricsBySizeIndex = {}; +/** + * Get the font metrics for a given size. + */ + +function getGlobalMetrics(size) { + var sizeIndex; + + if (size >= 5) { + sizeIndex = 0; + } else if (size >= 3) { + sizeIndex = 1; + } else { + sizeIndex = 2; + } + + if (!fontMetricsBySizeIndex[sizeIndex]) { + var metrics = fontMetricsBySizeIndex[sizeIndex] = { + cssEmPerMu: sigmasAndXis.quad[sizeIndex] / 18 + }; + + for (var key in sigmasAndXis) { + if (sigmasAndXis.hasOwnProperty(key)) { + metrics[key] = sigmasAndXis[key][sizeIndex]; + } + } + } + + return fontMetricsBySizeIndex[sizeIndex]; +} +// CONCATENATED MODULE: ./src/symbols.js +/** + * This file holds a list of all no-argument functions and single-character + * symbols (like 'a' or ';'). + * + * For each of the symbols, there are three properties they can have: + * - font (required): the font to be used for this symbol. Either "main" (the + normal font), or "ams" (the ams fonts). + * - group (required): the ParseNode group type the symbol should have (i.e. + "textord", "mathord", etc). + See https://github.com/KaTeX/KaTeX/wiki/Examining-TeX#group-types + * - replace: the character that this symbol or function should be + * replaced with (i.e. "\phi" has a replace value of "\u03d5", the phi + * character in the main font). + * + * The outermost map in the table indicates what mode the symbols should be + * accepted in (e.g. "math" or "text"). + */ +// Some of these have a "-token" suffix since these are also used as `ParseNode` +// types for raw text tokens, and we want to avoid conflicts with higher-level +// `ParseNode` types. These `ParseNode`s are constructed within `Parser` by +// looking up the `symbols` map. +var ATOMS = { + "bin": 1, + "close": 1, + "inner": 1, + "open": 1, + "punct": 1, + "rel": 1 +}; +var NON_ATOMS = { + "accent-token": 1, + "mathord": 1, + "op-token": 1, + "spacing": 1, + "textord": 1 +}; +var symbols = { + "math": {}, + "text": {} +}; +/* harmony default export */ var src_symbols = (symbols); +/** `acceptUnicodeChar = true` is only applicable if `replace` is set. */ + +function defineSymbol(mode, font, group, replace, name, acceptUnicodeChar) { + symbols[mode][name] = { + font: font, + group: group, + replace: replace + }; + + if (acceptUnicodeChar && replace) { + symbols[mode][replace] = symbols[mode][name]; + } +} // Some abbreviations for commonly used strings. +// This helps minify the code, and also spotting typos using jshint. +// modes: + +var symbols_math = "math"; +var symbols_text = "text"; // fonts: + +var main = "main"; +var ams = "ams"; // groups: + +var symbols_accent = "accent-token"; +var bin = "bin"; +var symbols_close = "close"; +var symbols_inner = "inner"; +var mathord = "mathord"; +var op = "op-token"; +var symbols_open = "open"; +var punct = "punct"; +var rel = "rel"; +var symbols_spacing = "spacing"; +var symbols_textord = "textord"; // Now comes the symbol table +// Relation Symbols + +defineSymbol(symbols_math, main, rel, "\u2261", "\\equiv", true); +defineSymbol(symbols_math, main, rel, "\u227A", "\\prec", true); +defineSymbol(symbols_math, main, rel, "\u227B", "\\succ", true); +defineSymbol(symbols_math, main, rel, "\u223C", "\\sim", true); +defineSymbol(symbols_math, main, rel, "\u22A5", "\\perp"); +defineSymbol(symbols_math, main, rel, "\u2AAF", "\\preceq", true); +defineSymbol(symbols_math, main, rel, "\u2AB0", "\\succeq", true); +defineSymbol(symbols_math, main, rel, "\u2243", "\\simeq", true); +defineSymbol(symbols_math, main, rel, "\u2223", "\\mid", true); +defineSymbol(symbols_math, main, rel, "\u226A", "\\ll", true); +defineSymbol(symbols_math, main, rel, "\u226B", "\\gg", true); +defineSymbol(symbols_math, main, rel, "\u224D", "\\asymp", true); +defineSymbol(symbols_math, main, rel, "\u2225", "\\parallel"); +defineSymbol(symbols_math, main, rel, "\u22C8", "\\bowtie", true); +defineSymbol(symbols_math, main, rel, "\u2323", "\\smile", true); +defineSymbol(symbols_math, main, rel, "\u2291", "\\sqsubseteq", true); +defineSymbol(symbols_math, main, rel, "\u2292", "\\sqsupseteq", true); +defineSymbol(symbols_math, main, rel, "\u2250", "\\doteq", true); +defineSymbol(symbols_math, main, rel, "\u2322", "\\frown", true); +defineSymbol(symbols_math, main, rel, "\u220B", "\\ni", true); +defineSymbol(symbols_math, main, rel, "\u221D", "\\propto", true); +defineSymbol(symbols_math, main, rel, "\u22A2", "\\vdash", true); +defineSymbol(symbols_math, main, rel, "\u22A3", "\\dashv", true); +defineSymbol(symbols_math, main, rel, "\u220B", "\\owns"); // Punctuation + +defineSymbol(symbols_math, main, punct, ".", "\\ldotp"); +defineSymbol(symbols_math, main, punct, "\u22C5", "\\cdotp"); // Misc Symbols + +defineSymbol(symbols_math, main, symbols_textord, "#", "\\#"); +defineSymbol(symbols_text, main, symbols_textord, "#", "\\#"); +defineSymbol(symbols_math, main, symbols_textord, "&", "\\&"); +defineSymbol(symbols_text, main, symbols_textord, "&", "\\&"); +defineSymbol(symbols_math, main, symbols_textord, "\u2135", "\\aleph", true); +defineSymbol(symbols_math, main, symbols_textord, "\u2200", "\\forall", true); +defineSymbol(symbols_math, main, symbols_textord, "\u210F", "\\hbar", true); +defineSymbol(symbols_math, main, symbols_textord, "\u2203", "\\exists", true); +defineSymbol(symbols_math, main, symbols_textord, "\u2207", "\\nabla", true); +defineSymbol(symbols_math, main, symbols_textord, "\u266D", "\\flat", true); +defineSymbol(symbols_math, main, symbols_textord, "\u2113", "\\ell", true); +defineSymbol(symbols_math, main, symbols_textord, "\u266E", "\\natural", true); +defineSymbol(symbols_math, main, symbols_textord, "\u2663", "\\clubsuit", true); +defineSymbol(symbols_math, main, symbols_textord, "\u2118", "\\wp", true); +defineSymbol(symbols_math, main, symbols_textord, "\u266F", "\\sharp", true); +defineSymbol(symbols_math, main, symbols_textord, "\u2662", "\\diamondsuit", true); +defineSymbol(symbols_math, main, symbols_textord, "\u211C", "\\Re", true); +defineSymbol(symbols_math, main, symbols_textord, "\u2661", "\\heartsuit", true); +defineSymbol(symbols_math, main, symbols_textord, "\u2111", "\\Im", true); +defineSymbol(symbols_math, main, symbols_textord, "\u2660", "\\spadesuit", true); +defineSymbol(symbols_text, main, symbols_textord, "\xA7", "\\S", true); +defineSymbol(symbols_text, main, symbols_textord, "\xB6", "\\P", true); // Math and Text + +defineSymbol(symbols_math, main, symbols_textord, "\u2020", "\\dag"); +defineSymbol(symbols_text, main, symbols_textord, "\u2020", "\\dag"); +defineSymbol(symbols_text, main, symbols_textord, "\u2020", "\\textdagger"); +defineSymbol(symbols_math, main, symbols_textord, "\u2021", "\\ddag"); +defineSymbol(symbols_text, main, symbols_textord, "\u2021", "\\ddag"); +defineSymbol(symbols_text, main, symbols_textord, "\u2021", "\\textdaggerdbl"); // Large Delimiters + +defineSymbol(symbols_math, main, symbols_close, "\u23B1", "\\rmoustache", true); +defineSymbol(symbols_math, main, symbols_open, "\u23B0", "\\lmoustache", true); +defineSymbol(symbols_math, main, symbols_close, "\u27EF", "\\rgroup", true); +defineSymbol(symbols_math, main, symbols_open, "\u27EE", "\\lgroup", true); // Binary Operators + +defineSymbol(symbols_math, main, bin, "\u2213", "\\mp", true); +defineSymbol(symbols_math, main, bin, "\u2296", "\\ominus", true); +defineSymbol(symbols_math, main, bin, "\u228E", "\\uplus", true); +defineSymbol(symbols_math, main, bin, "\u2293", "\\sqcap", true); +defineSymbol(symbols_math, main, bin, "\u2217", "\\ast"); +defineSymbol(symbols_math, main, bin, "\u2294", "\\sqcup", true); +defineSymbol(symbols_math, main, bin, "\u25EF", "\\bigcirc"); +defineSymbol(symbols_math, main, bin, "\u2219", "\\bullet"); +defineSymbol(symbols_math, main, bin, "\u2021", "\\ddagger"); +defineSymbol(symbols_math, main, bin, "\u2240", "\\wr", true); +defineSymbol(symbols_math, main, bin, "\u2A3F", "\\amalg"); +defineSymbol(symbols_math, main, bin, "&", "\\And"); // from amsmath +// Arrow Symbols + +defineSymbol(symbols_math, main, rel, "\u27F5", "\\longleftarrow", true); +defineSymbol(symbols_math, main, rel, "\u21D0", "\\Leftarrow", true); +defineSymbol(symbols_math, main, rel, "\u27F8", "\\Longleftarrow", true); +defineSymbol(symbols_math, main, rel, "\u27F6", "\\longrightarrow", true); +defineSymbol(symbols_math, main, rel, "\u21D2", "\\Rightarrow", true); +defineSymbol(symbols_math, main, rel, "\u27F9", "\\Longrightarrow", true); +defineSymbol(symbols_math, main, rel, "\u2194", "\\leftrightarrow", true); +defineSymbol(symbols_math, main, rel, "\u27F7", "\\longleftrightarrow", true); +defineSymbol(symbols_math, main, rel, "\u21D4", "\\Leftrightarrow", true); +defineSymbol(symbols_math, main, rel, "\u27FA", "\\Longleftrightarrow", true); +defineSymbol(symbols_math, main, rel, "\u21A6", "\\mapsto", true); +defineSymbol(symbols_math, main, rel, "\u27FC", "\\longmapsto", true); +defineSymbol(symbols_math, main, rel, "\u2197", "\\nearrow", true); +defineSymbol(symbols_math, main, rel, "\u21A9", "\\hookleftarrow", true); +defineSymbol(symbols_math, main, rel, "\u21AA", "\\hookrightarrow", true); +defineSymbol(symbols_math, main, rel, "\u2198", "\\searrow", true); +defineSymbol(symbols_math, main, rel, "\u21BC", "\\leftharpoonup", true); +defineSymbol(symbols_math, main, rel, "\u21C0", "\\rightharpoonup", true); +defineSymbol(symbols_math, main, rel, "\u2199", "\\swarrow", true); +defineSymbol(symbols_math, main, rel, "\u21BD", "\\leftharpoondown", true); +defineSymbol(symbols_math, main, rel, "\u21C1", "\\rightharpoondown", true); +defineSymbol(symbols_math, main, rel, "\u2196", "\\nwarrow", true); +defineSymbol(symbols_math, main, rel, "\u21CC", "\\rightleftharpoons", true); // AMS Negated Binary Relations + +defineSymbol(symbols_math, ams, rel, "\u226E", "\\nless", true); // Symbol names preceeded by "@" each have a corresponding macro. + +defineSymbol(symbols_math, ams, rel, "\uE010", "\\@nleqslant"); +defineSymbol(symbols_math, ams, rel, "\uE011", "\\@nleqq"); +defineSymbol(symbols_math, ams, rel, "\u2A87", "\\lneq", true); +defineSymbol(symbols_math, ams, rel, "\u2268", "\\lneqq", true); +defineSymbol(symbols_math, ams, rel, "\uE00C", "\\@lvertneqq"); +defineSymbol(symbols_math, ams, rel, "\u22E6", "\\lnsim", true); +defineSymbol(symbols_math, ams, rel, "\u2A89", "\\lnapprox", true); +defineSymbol(symbols_math, ams, rel, "\u2280", "\\nprec", true); // unicode-math maps \u22e0 to \npreccurlyeq. We'll use the AMS synonym. + +defineSymbol(symbols_math, ams, rel, "\u22E0", "\\npreceq", true); +defineSymbol(symbols_math, ams, rel, "\u22E8", "\\precnsim", true); +defineSymbol(symbols_math, ams, rel, "\u2AB9", "\\precnapprox", true); +defineSymbol(symbols_math, ams, rel, "\u2241", "\\nsim", true); +defineSymbol(symbols_math, ams, rel, "\uE006", "\\@nshortmid"); +defineSymbol(symbols_math, ams, rel, "\u2224", "\\nmid", true); +defineSymbol(symbols_math, ams, rel, "\u22AC", "\\nvdash", true); +defineSymbol(symbols_math, ams, rel, "\u22AD", "\\nvDash", true); +defineSymbol(symbols_math, ams, rel, "\u22EA", "\\ntriangleleft"); +defineSymbol(symbols_math, ams, rel, "\u22EC", "\\ntrianglelefteq", true); +defineSymbol(symbols_math, ams, rel, "\u228A", "\\subsetneq", true); +defineSymbol(symbols_math, ams, rel, "\uE01A", "\\@varsubsetneq"); +defineSymbol(symbols_math, ams, rel, "\u2ACB", "\\subsetneqq", true); +defineSymbol(symbols_math, ams, rel, "\uE017", "\\@varsubsetneqq"); +defineSymbol(symbols_math, ams, rel, "\u226F", "\\ngtr", true); +defineSymbol(symbols_math, ams, rel, "\uE00F", "\\@ngeqslant"); +defineSymbol(symbols_math, ams, rel, "\uE00E", "\\@ngeqq"); +defineSymbol(symbols_math, ams, rel, "\u2A88", "\\gneq", true); +defineSymbol(symbols_math, ams, rel, "\u2269", "\\gneqq", true); +defineSymbol(symbols_math, ams, rel, "\uE00D", "\\@gvertneqq"); +defineSymbol(symbols_math, ams, rel, "\u22E7", "\\gnsim", true); +defineSymbol(symbols_math, ams, rel, "\u2A8A", "\\gnapprox", true); +defineSymbol(symbols_math, ams, rel, "\u2281", "\\nsucc", true); // unicode-math maps \u22e1 to \nsucccurlyeq. We'll use the AMS synonym. + +defineSymbol(symbols_math, ams, rel, "\u22E1", "\\nsucceq", true); +defineSymbol(symbols_math, ams, rel, "\u22E9", "\\succnsim", true); +defineSymbol(symbols_math, ams, rel, "\u2ABA", "\\succnapprox", true); // unicode-math maps \u2246 to \simneqq. We'll use the AMS synonym. + +defineSymbol(symbols_math, ams, rel, "\u2246", "\\ncong", true); +defineSymbol(symbols_math, ams, rel, "\uE007", "\\@nshortparallel"); +defineSymbol(symbols_math, ams, rel, "\u2226", "\\nparallel", true); +defineSymbol(symbols_math, ams, rel, "\u22AF", "\\nVDash", true); +defineSymbol(symbols_math, ams, rel, "\u22EB", "\\ntriangleright"); +defineSymbol(symbols_math, ams, rel, "\u22ED", "\\ntrianglerighteq", true); +defineSymbol(symbols_math, ams, rel, "\uE018", "\\@nsupseteqq"); +defineSymbol(symbols_math, ams, rel, "\u228B", "\\supsetneq", true); +defineSymbol(symbols_math, ams, rel, "\uE01B", "\\@varsupsetneq"); +defineSymbol(symbols_math, ams, rel, "\u2ACC", "\\supsetneqq", true); +defineSymbol(symbols_math, ams, rel, "\uE019", "\\@varsupsetneqq"); +defineSymbol(symbols_math, ams, rel, "\u22AE", "\\nVdash", true); +defineSymbol(symbols_math, ams, rel, "\u2AB5", "\\precneqq", true); +defineSymbol(symbols_math, ams, rel, "\u2AB6", "\\succneqq", true); +defineSymbol(symbols_math, ams, rel, "\uE016", "\\@nsubseteqq"); +defineSymbol(symbols_math, ams, bin, "\u22B4", "\\unlhd"); +defineSymbol(symbols_math, ams, bin, "\u22B5", "\\unrhd"); // AMS Negated Arrows + +defineSymbol(symbols_math, ams, rel, "\u219A", "\\nleftarrow", true); +defineSymbol(symbols_math, ams, rel, "\u219B", "\\nrightarrow", true); +defineSymbol(symbols_math, ams, rel, "\u21CD", "\\nLeftarrow", true); +defineSymbol(symbols_math, ams, rel, "\u21CF", "\\nRightarrow", true); +defineSymbol(symbols_math, ams, rel, "\u21AE", "\\nleftrightarrow", true); +defineSymbol(symbols_math, ams, rel, "\u21CE", "\\nLeftrightarrow", true); // AMS Misc + +defineSymbol(symbols_math, ams, rel, "\u25B3", "\\vartriangle"); +defineSymbol(symbols_math, ams, symbols_textord, "\u210F", "\\hslash"); +defineSymbol(symbols_math, ams, symbols_textord, "\u25BD", "\\triangledown"); +defineSymbol(symbols_math, ams, symbols_textord, "\u25CA", "\\lozenge"); +defineSymbol(symbols_math, ams, symbols_textord, "\u24C8", "\\circledS"); +defineSymbol(symbols_math, ams, symbols_textord, "\xAE", "\\circledR"); +defineSymbol(symbols_text, ams, symbols_textord, "\xAE", "\\circledR"); +defineSymbol(symbols_math, ams, symbols_textord, "\u2221", "\\measuredangle", true); +defineSymbol(symbols_math, ams, symbols_textord, "\u2204", "\\nexists"); +defineSymbol(symbols_math, ams, symbols_textord, "\u2127", "\\mho"); +defineSymbol(symbols_math, ams, symbols_textord, "\u2132", "\\Finv", true); +defineSymbol(symbols_math, ams, symbols_textord, "\u2141", "\\Game", true); +defineSymbol(symbols_math, ams, symbols_textord, "\u2035", "\\backprime"); +defineSymbol(symbols_math, ams, symbols_textord, "\u25B2", "\\blacktriangle"); +defineSymbol(symbols_math, ams, symbols_textord, "\u25BC", "\\blacktriangledown"); +defineSymbol(symbols_math, ams, symbols_textord, "\u25A0", "\\blacksquare"); +defineSymbol(symbols_math, ams, symbols_textord, "\u29EB", "\\blacklozenge"); +defineSymbol(symbols_math, ams, symbols_textord, "\u2605", "\\bigstar"); +defineSymbol(symbols_math, ams, symbols_textord, "\u2222", "\\sphericalangle", true); +defineSymbol(symbols_math, ams, symbols_textord, "\u2201", "\\complement", true); // unicode-math maps U+F0 (ð) to \matheth. We map to AMS function \eth + +defineSymbol(symbols_math, ams, symbols_textord, "\xF0", "\\eth", true); +defineSymbol(symbols_math, ams, symbols_textord, "\u2571", "\\diagup"); +defineSymbol(symbols_math, ams, symbols_textord, "\u2572", "\\diagdown"); +defineSymbol(symbols_math, ams, symbols_textord, "\u25A1", "\\square"); +defineSymbol(symbols_math, ams, symbols_textord, "\u25A1", "\\Box"); +defineSymbol(symbols_math, ams, symbols_textord, "\u25CA", "\\Diamond"); // unicode-math maps U+A5 to \mathyen. We map to AMS function \yen + +defineSymbol(symbols_math, ams, symbols_textord, "\xA5", "\\yen", true); +defineSymbol(symbols_text, ams, symbols_textord, "\xA5", "\\yen", true); +defineSymbol(symbols_math, ams, symbols_textord, "\u2713", "\\checkmark", true); +defineSymbol(symbols_text, ams, symbols_textord, "\u2713", "\\checkmark"); // AMS Hebrew + +defineSymbol(symbols_math, ams, symbols_textord, "\u2136", "\\beth", true); +defineSymbol(symbols_math, ams, symbols_textord, "\u2138", "\\daleth", true); +defineSymbol(symbols_math, ams, symbols_textord, "\u2137", "\\gimel", true); // AMS Greek + +defineSymbol(symbols_math, ams, symbols_textord, "\u03DD", "\\digamma", true); +defineSymbol(symbols_math, ams, symbols_textord, "\u03F0", "\\varkappa"); // AMS Delimiters + +defineSymbol(symbols_math, ams, symbols_open, "\u250C", "\\ulcorner", true); +defineSymbol(symbols_math, ams, symbols_close, "\u2510", "\\urcorner", true); +defineSymbol(symbols_math, ams, symbols_open, "\u2514", "\\llcorner", true); +defineSymbol(symbols_math, ams, symbols_close, "\u2518", "\\lrcorner", true); // AMS Binary Relations + +defineSymbol(symbols_math, ams, rel, "\u2266", "\\leqq", true); +defineSymbol(symbols_math, ams, rel, "\u2A7D", "\\leqslant", true); +defineSymbol(symbols_math, ams, rel, "\u2A95", "\\eqslantless", true); +defineSymbol(symbols_math, ams, rel, "\u2272", "\\lesssim", true); +defineSymbol(symbols_math, ams, rel, "\u2A85", "\\lessapprox", true); +defineSymbol(symbols_math, ams, rel, "\u224A", "\\approxeq", true); +defineSymbol(symbols_math, ams, bin, "\u22D6", "\\lessdot"); +defineSymbol(symbols_math, ams, rel, "\u22D8", "\\lll", true); +defineSymbol(symbols_math, ams, rel, "\u2276", "\\lessgtr", true); +defineSymbol(symbols_math, ams, rel, "\u22DA", "\\lesseqgtr", true); +defineSymbol(symbols_math, ams, rel, "\u2A8B", "\\lesseqqgtr", true); +defineSymbol(symbols_math, ams, rel, "\u2251", "\\doteqdot"); +defineSymbol(symbols_math, ams, rel, "\u2253", "\\risingdotseq", true); +defineSymbol(symbols_math, ams, rel, "\u2252", "\\fallingdotseq", true); +defineSymbol(symbols_math, ams, rel, "\u223D", "\\backsim", true); +defineSymbol(symbols_math, ams, rel, "\u22CD", "\\backsimeq", true); +defineSymbol(symbols_math, ams, rel, "\u2AC5", "\\subseteqq", true); +defineSymbol(symbols_math, ams, rel, "\u22D0", "\\Subset", true); +defineSymbol(symbols_math, ams, rel, "\u228F", "\\sqsubset", true); +defineSymbol(symbols_math, ams, rel, "\u227C", "\\preccurlyeq", true); +defineSymbol(symbols_math, ams, rel, "\u22DE", "\\curlyeqprec", true); +defineSymbol(symbols_math, ams, rel, "\u227E", "\\precsim", true); +defineSymbol(symbols_math, ams, rel, "\u2AB7", "\\precapprox", true); +defineSymbol(symbols_math, ams, rel, "\u22B2", "\\vartriangleleft"); +defineSymbol(symbols_math, ams, rel, "\u22B4", "\\trianglelefteq"); +defineSymbol(symbols_math, ams, rel, "\u22A8", "\\vDash", true); +defineSymbol(symbols_math, ams, rel, "\u22AA", "\\Vvdash", true); +defineSymbol(symbols_math, ams, rel, "\u2323", "\\smallsmile"); +defineSymbol(symbols_math, ams, rel, "\u2322", "\\smallfrown"); +defineSymbol(symbols_math, ams, rel, "\u224F", "\\bumpeq", true); +defineSymbol(symbols_math, ams, rel, "\u224E", "\\Bumpeq", true); +defineSymbol(symbols_math, ams, rel, "\u2267", "\\geqq", true); +defineSymbol(symbols_math, ams, rel, "\u2A7E", "\\geqslant", true); +defineSymbol(symbols_math, ams, rel, "\u2A96", "\\eqslantgtr", true); +defineSymbol(symbols_math, ams, rel, "\u2273", "\\gtrsim", true); +defineSymbol(symbols_math, ams, rel, "\u2A86", "\\gtrapprox", true); +defineSymbol(symbols_math, ams, bin, "\u22D7", "\\gtrdot"); +defineSymbol(symbols_math, ams, rel, "\u22D9", "\\ggg", true); +defineSymbol(symbols_math, ams, rel, "\u2277", "\\gtrless", true); +defineSymbol(symbols_math, ams, rel, "\u22DB", "\\gtreqless", true); +defineSymbol(symbols_math, ams, rel, "\u2A8C", "\\gtreqqless", true); +defineSymbol(symbols_math, ams, rel, "\u2256", "\\eqcirc", true); +defineSymbol(symbols_math, ams, rel, "\u2257", "\\circeq", true); +defineSymbol(symbols_math, ams, rel, "\u225C", "\\triangleq", true); +defineSymbol(symbols_math, ams, rel, "\u223C", "\\thicksim"); +defineSymbol(symbols_math, ams, rel, "\u2248", "\\thickapprox"); +defineSymbol(symbols_math, ams, rel, "\u2AC6", "\\supseteqq", true); +defineSymbol(symbols_math, ams, rel, "\u22D1", "\\Supset", true); +defineSymbol(symbols_math, ams, rel, "\u2290", "\\sqsupset", true); +defineSymbol(symbols_math, ams, rel, "\u227D", "\\succcurlyeq", true); +defineSymbol(symbols_math, ams, rel, "\u22DF", "\\curlyeqsucc", true); +defineSymbol(symbols_math, ams, rel, "\u227F", "\\succsim", true); +defineSymbol(symbols_math, ams, rel, "\u2AB8", "\\succapprox", true); +defineSymbol(symbols_math, ams, rel, "\u22B3", "\\vartriangleright"); +defineSymbol(symbols_math, ams, rel, "\u22B5", "\\trianglerighteq"); +defineSymbol(symbols_math, ams, rel, "\u22A9", "\\Vdash", true); +defineSymbol(symbols_math, ams, rel, "\u2223", "\\shortmid"); +defineSymbol(symbols_math, ams, rel, "\u2225", "\\shortparallel"); +defineSymbol(symbols_math, ams, rel, "\u226C", "\\between", true); +defineSymbol(symbols_math, ams, rel, "\u22D4", "\\pitchfork", true); +defineSymbol(symbols_math, ams, rel, "\u221D", "\\varpropto"); +defineSymbol(symbols_math, ams, rel, "\u25C0", "\\blacktriangleleft"); // unicode-math says that \therefore is a mathord atom. +// We kept the amssymb atom type, which is rel. + +defineSymbol(symbols_math, ams, rel, "\u2234", "\\therefore", true); +defineSymbol(symbols_math, ams, rel, "\u220D", "\\backepsilon"); +defineSymbol(symbols_math, ams, rel, "\u25B6", "\\blacktriangleright"); // unicode-math says that \because is a mathord atom. +// We kept the amssymb atom type, which is rel. + +defineSymbol(symbols_math, ams, rel, "\u2235", "\\because", true); +defineSymbol(symbols_math, ams, rel, "\u22D8", "\\llless"); +defineSymbol(symbols_math, ams, rel, "\u22D9", "\\gggtr"); +defineSymbol(symbols_math, ams, bin, "\u22B2", "\\lhd"); +defineSymbol(symbols_math, ams, bin, "\u22B3", "\\rhd"); +defineSymbol(symbols_math, ams, rel, "\u2242", "\\eqsim", true); +defineSymbol(symbols_math, main, rel, "\u22C8", "\\Join"); +defineSymbol(symbols_math, ams, rel, "\u2251", "\\Doteq", true); // AMS Binary Operators + +defineSymbol(symbols_math, ams, bin, "\u2214", "\\dotplus", true); +defineSymbol(symbols_math, ams, bin, "\u2216", "\\smallsetminus"); +defineSymbol(symbols_math, ams, bin, "\u22D2", "\\Cap", true); +defineSymbol(symbols_math, ams, bin, "\u22D3", "\\Cup", true); +defineSymbol(symbols_math, ams, bin, "\u2A5E", "\\doublebarwedge", true); +defineSymbol(symbols_math, ams, bin, "\u229F", "\\boxminus", true); +defineSymbol(symbols_math, ams, bin, "\u229E", "\\boxplus", true); +defineSymbol(symbols_math, ams, bin, "\u22C7", "\\divideontimes", true); +defineSymbol(symbols_math, ams, bin, "\u22C9", "\\ltimes", true); +defineSymbol(symbols_math, ams, bin, "\u22CA", "\\rtimes", true); +defineSymbol(symbols_math, ams, bin, "\u22CB", "\\leftthreetimes", true); +defineSymbol(symbols_math, ams, bin, "\u22CC", "\\rightthreetimes", true); +defineSymbol(symbols_math, ams, bin, "\u22CF", "\\curlywedge", true); +defineSymbol(symbols_math, ams, bin, "\u22CE", "\\curlyvee", true); +defineSymbol(symbols_math, ams, bin, "\u229D", "\\circleddash", true); +defineSymbol(symbols_math, ams, bin, "\u229B", "\\circledast", true); +defineSymbol(symbols_math, ams, bin, "\u22C5", "\\centerdot"); +defineSymbol(symbols_math, ams, bin, "\u22BA", "\\intercal", true); +defineSymbol(symbols_math, ams, bin, "\u22D2", "\\doublecap"); +defineSymbol(symbols_math, ams, bin, "\u22D3", "\\doublecup"); +defineSymbol(symbols_math, ams, bin, "\u22A0", "\\boxtimes", true); // AMS Arrows +// Note: unicode-math maps \u21e2 to their own function \rightdasharrow. +// We'll map it to AMS function \dashrightarrow. It produces the same atom. + +defineSymbol(symbols_math, ams, rel, "\u21E2", "\\dashrightarrow", true); // unicode-math maps \u21e0 to \leftdasharrow. We'll use the AMS synonym. + +defineSymbol(symbols_math, ams, rel, "\u21E0", "\\dashleftarrow", true); +defineSymbol(symbols_math, ams, rel, "\u21C7", "\\leftleftarrows", true); +defineSymbol(symbols_math, ams, rel, "\u21C6", "\\leftrightarrows", true); +defineSymbol(symbols_math, ams, rel, "\u21DA", "\\Lleftarrow", true); +defineSymbol(symbols_math, ams, rel, "\u219E", "\\twoheadleftarrow", true); +defineSymbol(symbols_math, ams, rel, "\u21A2", "\\leftarrowtail", true); +defineSymbol(symbols_math, ams, rel, "\u21AB", "\\looparrowleft", true); +defineSymbol(symbols_math, ams, rel, "\u21CB", "\\leftrightharpoons", true); +defineSymbol(symbols_math, ams, rel, "\u21B6", "\\curvearrowleft", true); // unicode-math maps \u21ba to \acwopencirclearrow. We'll use the AMS synonym. + +defineSymbol(symbols_math, ams, rel, "\u21BA", "\\circlearrowleft", true); +defineSymbol(symbols_math, ams, rel, "\u21B0", "\\Lsh", true); +defineSymbol(symbols_math, ams, rel, "\u21C8", "\\upuparrows", true); +defineSymbol(symbols_math, ams, rel, "\u21BF", "\\upharpoonleft", true); +defineSymbol(symbols_math, ams, rel, "\u21C3", "\\downharpoonleft", true); +defineSymbol(symbols_math, ams, rel, "\u22B8", "\\multimap", true); +defineSymbol(symbols_math, ams, rel, "\u21AD", "\\leftrightsquigarrow", true); +defineSymbol(symbols_math, ams, rel, "\u21C9", "\\rightrightarrows", true); +defineSymbol(symbols_math, ams, rel, "\u21C4", "\\rightleftarrows", true); +defineSymbol(symbols_math, ams, rel, "\u21A0", "\\twoheadrightarrow", true); +defineSymbol(symbols_math, ams, rel, "\u21A3", "\\rightarrowtail", true); +defineSymbol(symbols_math, ams, rel, "\u21AC", "\\looparrowright", true); +defineSymbol(symbols_math, ams, rel, "\u21B7", "\\curvearrowright", true); // unicode-math maps \u21bb to \cwopencirclearrow. We'll use the AMS synonym. + +defineSymbol(symbols_math, ams, rel, "\u21BB", "\\circlearrowright", true); +defineSymbol(symbols_math, ams, rel, "\u21B1", "\\Rsh", true); +defineSymbol(symbols_math, ams, rel, "\u21CA", "\\downdownarrows", true); +defineSymbol(symbols_math, ams, rel, "\u21BE", "\\upharpoonright", true); +defineSymbol(symbols_math, ams, rel, "\u21C2", "\\downharpoonright", true); +defineSymbol(symbols_math, ams, rel, "\u21DD", "\\rightsquigarrow", true); +defineSymbol(symbols_math, ams, rel, "\u21DD", "\\leadsto"); +defineSymbol(symbols_math, ams, rel, "\u21DB", "\\Rrightarrow", true); +defineSymbol(symbols_math, ams, rel, "\u21BE", "\\restriction"); +defineSymbol(symbols_math, main, symbols_textord, "\u2018", "`"); +defineSymbol(symbols_math, main, symbols_textord, "$", "\\$"); +defineSymbol(symbols_text, main, symbols_textord, "$", "\\$"); +defineSymbol(symbols_text, main, symbols_textord, "$", "\\textdollar"); +defineSymbol(symbols_math, main, symbols_textord, "%", "\\%"); +defineSymbol(symbols_text, main, symbols_textord, "%", "\\%"); +defineSymbol(symbols_math, main, symbols_textord, "_", "\\_"); +defineSymbol(symbols_text, main, symbols_textord, "_", "\\_"); +defineSymbol(symbols_text, main, symbols_textord, "_", "\\textunderscore"); +defineSymbol(symbols_math, main, symbols_textord, "\u2220", "\\angle", true); +defineSymbol(symbols_math, main, symbols_textord, "\u221E", "\\infty", true); +defineSymbol(symbols_math, main, symbols_textord, "\u2032", "\\prime"); +defineSymbol(symbols_math, main, symbols_textord, "\u25B3", "\\triangle"); +defineSymbol(symbols_math, main, symbols_textord, "\u0393", "\\Gamma", true); +defineSymbol(symbols_math, main, symbols_textord, "\u0394", "\\Delta", true); +defineSymbol(symbols_math, main, symbols_textord, "\u0398", "\\Theta", true); +defineSymbol(symbols_math, main, symbols_textord, "\u039B", "\\Lambda", true); +defineSymbol(symbols_math, main, symbols_textord, "\u039E", "\\Xi", true); +defineSymbol(symbols_math, main, symbols_textord, "\u03A0", "\\Pi", true); +defineSymbol(symbols_math, main, symbols_textord, "\u03A3", "\\Sigma", true); +defineSymbol(symbols_math, main, symbols_textord, "\u03A5", "\\Upsilon", true); +defineSymbol(symbols_math, main, symbols_textord, "\u03A6", "\\Phi", true); +defineSymbol(symbols_math, main, symbols_textord, "\u03A8", "\\Psi", true); +defineSymbol(symbols_math, main, symbols_textord, "\u03A9", "\\Omega", true); +defineSymbol(symbols_math, main, symbols_textord, "A", "\u0391"); +defineSymbol(symbols_math, main, symbols_textord, "B", "\u0392"); +defineSymbol(symbols_math, main, symbols_textord, "E", "\u0395"); +defineSymbol(symbols_math, main, symbols_textord, "Z", "\u0396"); +defineSymbol(symbols_math, main, symbols_textord, "H", "\u0397"); +defineSymbol(symbols_math, main, symbols_textord, "I", "\u0399"); +defineSymbol(symbols_math, main, symbols_textord, "K", "\u039A"); +defineSymbol(symbols_math, main, symbols_textord, "M", "\u039C"); +defineSymbol(symbols_math, main, symbols_textord, "N", "\u039D"); +defineSymbol(symbols_math, main, symbols_textord, "O", "\u039F"); +defineSymbol(symbols_math, main, symbols_textord, "P", "\u03A1"); +defineSymbol(symbols_math, main, symbols_textord, "T", "\u03A4"); +defineSymbol(symbols_math, main, symbols_textord, "X", "\u03A7"); +defineSymbol(symbols_math, main, symbols_textord, "\xAC", "\\neg", true); +defineSymbol(symbols_math, main, symbols_textord, "\xAC", "\\lnot"); +defineSymbol(symbols_math, main, symbols_textord, "\u22A4", "\\top"); +defineSymbol(symbols_math, main, symbols_textord, "\u22A5", "\\bot"); +defineSymbol(symbols_math, main, symbols_textord, "\u2205", "\\emptyset"); +defineSymbol(symbols_math, ams, symbols_textord, "\u2205", "\\varnothing"); +defineSymbol(symbols_math, main, mathord, "\u03B1", "\\alpha", true); +defineSymbol(symbols_math, main, mathord, "\u03B2", "\\beta", true); +defineSymbol(symbols_math, main, mathord, "\u03B3", "\\gamma", true); +defineSymbol(symbols_math, main, mathord, "\u03B4", "\\delta", true); +defineSymbol(symbols_math, main, mathord, "\u03F5", "\\epsilon", true); +defineSymbol(symbols_math, main, mathord, "\u03B6", "\\zeta", true); +defineSymbol(symbols_math, main, mathord, "\u03B7", "\\eta", true); +defineSymbol(symbols_math, main, mathord, "\u03B8", "\\theta", true); +defineSymbol(symbols_math, main, mathord, "\u03B9", "\\iota", true); +defineSymbol(symbols_math, main, mathord, "\u03BA", "\\kappa", true); +defineSymbol(symbols_math, main, mathord, "\u03BB", "\\lambda", true); +defineSymbol(symbols_math, main, mathord, "\u03BC", "\\mu", true); +defineSymbol(symbols_math, main, mathord, "\u03BD", "\\nu", true); +defineSymbol(symbols_math, main, mathord, "\u03BE", "\\xi", true); +defineSymbol(symbols_math, main, mathord, "\u03BF", "\\omicron", true); +defineSymbol(symbols_math, main, mathord, "\u03C0", "\\pi", true); +defineSymbol(symbols_math, main, mathord, "\u03C1", "\\rho", true); +defineSymbol(symbols_math, main, mathord, "\u03C3", "\\sigma", true); +defineSymbol(symbols_math, main, mathord, "\u03C4", "\\tau", true); +defineSymbol(symbols_math, main, mathord, "\u03C5", "\\upsilon", true); +defineSymbol(symbols_math, main, mathord, "\u03D5", "\\phi", true); +defineSymbol(symbols_math, main, mathord, "\u03C7", "\\chi", true); +defineSymbol(symbols_math, main, mathord, "\u03C8", "\\psi", true); +defineSymbol(symbols_math, main, mathord, "\u03C9", "\\omega", true); +defineSymbol(symbols_math, main, mathord, "\u03B5", "\\varepsilon", true); +defineSymbol(symbols_math, main, mathord, "\u03D1", "\\vartheta", true); +defineSymbol(symbols_math, main, mathord, "\u03D6", "\\varpi", true); +defineSymbol(symbols_math, main, mathord, "\u03F1", "\\varrho", true); +defineSymbol(symbols_math, main, mathord, "\u03C2", "\\varsigma", true); +defineSymbol(symbols_math, main, mathord, "\u03C6", "\\varphi", true); +defineSymbol(symbols_math, main, bin, "\u2217", "*"); +defineSymbol(symbols_math, main, bin, "+", "+"); +defineSymbol(symbols_math, main, bin, "\u2212", "-"); +defineSymbol(symbols_math, main, bin, "\u22C5", "\\cdot", true); +defineSymbol(symbols_math, main, bin, "\u2218", "\\circ"); +defineSymbol(symbols_math, main, bin, "\xF7", "\\div", true); +defineSymbol(symbols_math, main, bin, "\xB1", "\\pm", true); +defineSymbol(symbols_math, main, bin, "\xD7", "\\times", true); +defineSymbol(symbols_math, main, bin, "\u2229", "\\cap", true); +defineSymbol(symbols_math, main, bin, "\u222A", "\\cup", true); +defineSymbol(symbols_math, main, bin, "\u2216", "\\setminus"); +defineSymbol(symbols_math, main, bin, "\u2227", "\\land"); +defineSymbol(symbols_math, main, bin, "\u2228", "\\lor"); +defineSymbol(symbols_math, main, bin, "\u2227", "\\wedge", true); +defineSymbol(symbols_math, main, bin, "\u2228", "\\vee", true); +defineSymbol(symbols_math, main, symbols_textord, "\u221A", "\\surd"); +defineSymbol(symbols_math, main, symbols_open, "(", "("); +defineSymbol(symbols_math, main, symbols_open, "[", "["); +defineSymbol(symbols_math, main, symbols_open, "\u27E8", "\\langle", true); +defineSymbol(symbols_math, main, symbols_open, "\u2223", "\\lvert"); +defineSymbol(symbols_math, main, symbols_open, "\u2225", "\\lVert"); +defineSymbol(symbols_math, main, symbols_close, ")", ")"); +defineSymbol(symbols_math, main, symbols_close, "]", "]"); +defineSymbol(symbols_math, main, symbols_close, "?", "?"); +defineSymbol(symbols_math, main, symbols_close, "!", "!"); +defineSymbol(symbols_math, main, symbols_close, "\u27E9", "\\rangle", true); +defineSymbol(symbols_math, main, symbols_close, "\u2223", "\\rvert"); +defineSymbol(symbols_math, main, symbols_close, "\u2225", "\\rVert"); +defineSymbol(symbols_math, main, rel, "=", "="); +defineSymbol(symbols_math, main, rel, "<", "<"); +defineSymbol(symbols_math, main, rel, ">", ">"); +defineSymbol(symbols_math, main, rel, ":", ":"); +defineSymbol(symbols_math, main, rel, "\u2248", "\\approx", true); +defineSymbol(symbols_math, main, rel, "\u2245", "\\cong", true); +defineSymbol(symbols_math, main, rel, "\u2265", "\\ge"); +defineSymbol(symbols_math, main, rel, "\u2265", "\\geq", true); +defineSymbol(symbols_math, main, rel, "\u2190", "\\gets"); +defineSymbol(symbols_math, main, rel, ">", "\\gt"); +defineSymbol(symbols_math, main, rel, "\u2208", "\\in", true); +defineSymbol(symbols_math, main, rel, "\uE020", "\\@not"); +defineSymbol(symbols_math, main, rel, "\u2282", "\\subset", true); +defineSymbol(symbols_math, main, rel, "\u2283", "\\supset", true); +defineSymbol(symbols_math, main, rel, "\u2286", "\\subseteq", true); +defineSymbol(symbols_math, main, rel, "\u2287", "\\supseteq", true); +defineSymbol(symbols_math, ams, rel, "\u2288", "\\nsubseteq", true); +defineSymbol(symbols_math, ams, rel, "\u2289", "\\nsupseteq", true); +defineSymbol(symbols_math, main, rel, "\u22A8", "\\models"); +defineSymbol(symbols_math, main, rel, "\u2190", "\\leftarrow", true); +defineSymbol(symbols_math, main, rel, "\u2264", "\\le"); +defineSymbol(symbols_math, main, rel, "\u2264", "\\leq", true); +defineSymbol(symbols_math, main, rel, "<", "\\lt"); +defineSymbol(symbols_math, main, rel, "\u2192", "\\rightarrow", true); +defineSymbol(symbols_math, main, rel, "\u2192", "\\to"); +defineSymbol(symbols_math, ams, rel, "\u2271", "\\ngeq", true); +defineSymbol(symbols_math, ams, rel, "\u2270", "\\nleq", true); +defineSymbol(symbols_math, main, symbols_spacing, "\xA0", "\\ "); +defineSymbol(symbols_math, main, symbols_spacing, "\xA0", "~"); +defineSymbol(symbols_math, main, symbols_spacing, "\xA0", "\\space"); // Ref: LaTeX Source 2e: \DeclareRobustCommand{\nobreakspace}{% + +defineSymbol(symbols_math, main, symbols_spacing, "\xA0", "\\nobreakspace"); +defineSymbol(symbols_text, main, symbols_spacing, "\xA0", "\\ "); +defineSymbol(symbols_text, main, symbols_spacing, "\xA0", "~"); +defineSymbol(symbols_text, main, symbols_spacing, "\xA0", "\\space"); +defineSymbol(symbols_text, main, symbols_spacing, "\xA0", "\\nobreakspace"); +defineSymbol(symbols_math, main, symbols_spacing, null, "\\nobreak"); +defineSymbol(symbols_math, main, symbols_spacing, null, "\\allowbreak"); +defineSymbol(symbols_math, main, punct, ",", ","); +defineSymbol(symbols_math, main, punct, ";", ";"); +defineSymbol(symbols_math, ams, bin, "\u22BC", "\\barwedge", true); +defineSymbol(symbols_math, ams, bin, "\u22BB", "\\veebar", true); +defineSymbol(symbols_math, main, bin, "\u2299", "\\odot", true); +defineSymbol(symbols_math, main, bin, "\u2295", "\\oplus", true); +defineSymbol(symbols_math, main, bin, "\u2297", "\\otimes", true); +defineSymbol(symbols_math, main, symbols_textord, "\u2202", "\\partial", true); +defineSymbol(symbols_math, main, bin, "\u2298", "\\oslash", true); +defineSymbol(symbols_math, ams, bin, "\u229A", "\\circledcirc", true); +defineSymbol(symbols_math, ams, bin, "\u22A1", "\\boxdot", true); +defineSymbol(symbols_math, main, bin, "\u25B3", "\\bigtriangleup"); +defineSymbol(symbols_math, main, bin, "\u25BD", "\\bigtriangledown"); +defineSymbol(symbols_math, main, bin, "\u2020", "\\dagger"); +defineSymbol(symbols_math, main, bin, "\u22C4", "\\diamond"); +defineSymbol(symbols_math, main, bin, "\u22C6", "\\star"); +defineSymbol(symbols_math, main, bin, "\u25C3", "\\triangleleft"); +defineSymbol(symbols_math, main, bin, "\u25B9", "\\triangleright"); +defineSymbol(symbols_math, main, symbols_open, "{", "\\{"); +defineSymbol(symbols_text, main, symbols_textord, "{", "\\{"); +defineSymbol(symbols_text, main, symbols_textord, "{", "\\textbraceleft"); +defineSymbol(symbols_math, main, symbols_close, "}", "\\}"); +defineSymbol(symbols_text, main, symbols_textord, "}", "\\}"); +defineSymbol(symbols_text, main, symbols_textord, "}", "\\textbraceright"); +defineSymbol(symbols_math, main, symbols_open, "{", "\\lbrace"); +defineSymbol(symbols_math, main, symbols_close, "}", "\\rbrace"); +defineSymbol(symbols_math, main, symbols_open, "[", "\\lbrack"); +defineSymbol(symbols_text, main, symbols_textord, "[", "\\lbrack"); +defineSymbol(symbols_math, main, symbols_close, "]", "\\rbrack"); +defineSymbol(symbols_text, main, symbols_textord, "]", "\\rbrack"); +defineSymbol(symbols_math, main, symbols_open, "(", "\\lparen"); +defineSymbol(symbols_math, main, symbols_close, ")", "\\rparen"); +defineSymbol(symbols_text, main, symbols_textord, "<", "\\textless"); // in T1 fontenc + +defineSymbol(symbols_text, main, symbols_textord, ">", "\\textgreater"); // in T1 fontenc + +defineSymbol(symbols_math, main, symbols_open, "\u230A", "\\lfloor", true); +defineSymbol(symbols_math, main, symbols_close, "\u230B", "\\rfloor", true); +defineSymbol(symbols_math, main, symbols_open, "\u2308", "\\lceil", true); +defineSymbol(symbols_math, main, symbols_close, "\u2309", "\\rceil", true); +defineSymbol(symbols_math, main, symbols_textord, "\\", "\\backslash"); +defineSymbol(symbols_math, main, symbols_textord, "\u2223", "|"); +defineSymbol(symbols_math, main, symbols_textord, "\u2223", "\\vert"); +defineSymbol(symbols_text, main, symbols_textord, "|", "\\textbar"); // in T1 fontenc + +defineSymbol(symbols_math, main, symbols_textord, "\u2225", "\\|"); +defineSymbol(symbols_math, main, symbols_textord, "\u2225", "\\Vert"); +defineSymbol(symbols_text, main, symbols_textord, "\u2225", "\\textbardbl"); +defineSymbol(symbols_text, main, symbols_textord, "~", "\\textasciitilde"); +defineSymbol(symbols_text, main, symbols_textord, "\\", "\\textbackslash"); +defineSymbol(symbols_text, main, symbols_textord, "^", "\\textasciicircum"); +defineSymbol(symbols_math, main, rel, "\u2191", "\\uparrow", true); +defineSymbol(symbols_math, main, rel, "\u21D1", "\\Uparrow", true); +defineSymbol(symbols_math, main, rel, "\u2193", "\\downarrow", true); +defineSymbol(symbols_math, main, rel, "\u21D3", "\\Downarrow", true); +defineSymbol(symbols_math, main, rel, "\u2195", "\\updownarrow", true); +defineSymbol(symbols_math, main, rel, "\u21D5", "\\Updownarrow", true); +defineSymbol(symbols_math, main, op, "\u2210", "\\coprod"); +defineSymbol(symbols_math, main, op, "\u22C1", "\\bigvee"); +defineSymbol(symbols_math, main, op, "\u22C0", "\\bigwedge"); +defineSymbol(symbols_math, main, op, "\u2A04", "\\biguplus"); +defineSymbol(symbols_math, main, op, "\u22C2", "\\bigcap"); +defineSymbol(symbols_math, main, op, "\u22C3", "\\bigcup"); +defineSymbol(symbols_math, main, op, "\u222B", "\\int"); +defineSymbol(symbols_math, main, op, "\u222B", "\\intop"); +defineSymbol(symbols_math, main, op, "\u222C", "\\iint"); +defineSymbol(symbols_math, main, op, "\u222D", "\\iiint"); +defineSymbol(symbols_math, main, op, "\u220F", "\\prod"); +defineSymbol(symbols_math, main, op, "\u2211", "\\sum"); +defineSymbol(symbols_math, main, op, "\u2A02", "\\bigotimes"); +defineSymbol(symbols_math, main, op, "\u2A01", "\\bigoplus"); +defineSymbol(symbols_math, main, op, "\u2A00", "\\bigodot"); +defineSymbol(symbols_math, main, op, "\u222E", "\\oint"); +defineSymbol(symbols_math, main, op, "\u222F", "\\oiint"); +defineSymbol(symbols_math, main, op, "\u2230", "\\oiiint"); +defineSymbol(symbols_math, main, op, "\u2A06", "\\bigsqcup"); +defineSymbol(symbols_math, main, op, "\u222B", "\\smallint"); +defineSymbol(symbols_text, main, symbols_inner, "\u2026", "\\textellipsis"); +defineSymbol(symbols_math, main, symbols_inner, "\u2026", "\\mathellipsis"); +defineSymbol(symbols_text, main, symbols_inner, "\u2026", "\\ldots", true); +defineSymbol(symbols_math, main, symbols_inner, "\u2026", "\\ldots", true); +defineSymbol(symbols_math, main, symbols_inner, "\u22EF", "\\@cdots", true); +defineSymbol(symbols_math, main, symbols_inner, "\u22F1", "\\ddots", true); +defineSymbol(symbols_math, main, symbols_textord, "\u22EE", "\\varvdots"); // \vdots is a macro + +defineSymbol(symbols_math, main, symbols_accent, "\u02CA", "\\acute"); +defineSymbol(symbols_math, main, symbols_accent, "\u02CB", "\\grave"); +defineSymbol(symbols_math, main, symbols_accent, "\xA8", "\\ddot"); +defineSymbol(symbols_math, main, symbols_accent, "~", "\\tilde"); +defineSymbol(symbols_math, main, symbols_accent, "\u02C9", "\\bar"); +defineSymbol(symbols_math, main, symbols_accent, "\u02D8", "\\breve"); +defineSymbol(symbols_math, main, symbols_accent, "\u02C7", "\\check"); +defineSymbol(symbols_math, main, symbols_accent, "^", "\\hat"); +defineSymbol(symbols_math, main, symbols_accent, "\u20D7", "\\vec"); +defineSymbol(symbols_math, main, symbols_accent, "\u02D9", "\\dot"); +defineSymbol(symbols_math, main, symbols_accent, "\u02DA", "\\mathring"); +defineSymbol(symbols_math, main, mathord, "\u0131", "\\imath", true); +defineSymbol(symbols_math, main, mathord, "\u0237", "\\jmath", true); +defineSymbol(symbols_text, main, symbols_textord, "\u0131", "\\i", true); +defineSymbol(symbols_text, main, symbols_textord, "\u0237", "\\j", true); +defineSymbol(symbols_text, main, symbols_textord, "\xDF", "\\ss", true); +defineSymbol(symbols_text, main, symbols_textord, "\xE6", "\\ae", true); +defineSymbol(symbols_text, main, symbols_textord, "\xE6", "\\ae", true); +defineSymbol(symbols_text, main, symbols_textord, "\u0153", "\\oe", true); +defineSymbol(symbols_text, main, symbols_textord, "\xF8", "\\o", true); +defineSymbol(symbols_text, main, symbols_textord, "\xC6", "\\AE", true); +defineSymbol(symbols_text, main, symbols_textord, "\u0152", "\\OE", true); +defineSymbol(symbols_text, main, symbols_textord, "\xD8", "\\O", true); +defineSymbol(symbols_text, main, symbols_accent, "\u02CA", "\\'"); // acute + +defineSymbol(symbols_text, main, symbols_accent, "\u02CB", "\\`"); // grave + +defineSymbol(symbols_text, main, symbols_accent, "\u02C6", "\\^"); // circumflex + +defineSymbol(symbols_text, main, symbols_accent, "\u02DC", "\\~"); // tilde + +defineSymbol(symbols_text, main, symbols_accent, "\u02C9", "\\="); // macron + +defineSymbol(symbols_text, main, symbols_accent, "\u02D8", "\\u"); // breve + +defineSymbol(symbols_text, main, symbols_accent, "\u02D9", "\\."); // dot above + +defineSymbol(symbols_text, main, symbols_accent, "\u02DA", "\\r"); // ring above + +defineSymbol(symbols_text, main, symbols_accent, "\u02C7", "\\v"); // caron + +defineSymbol(symbols_text, main, symbols_accent, "\xA8", '\\"'); // diaresis + +defineSymbol(symbols_text, main, symbols_accent, "\u02DD", "\\H"); // double acute + +defineSymbol(symbols_text, main, symbols_accent, "\u25EF", "\\textcircled"); // \bigcirc glyph +// These ligatures are detected and created in Parser.js's `formLigatures`. + +var ligatures = { + "--": true, + "---": true, + "``": true, + "''": true +}; +defineSymbol(symbols_text, main, symbols_textord, "\u2013", "--"); +defineSymbol(symbols_text, main, symbols_textord, "\u2013", "\\textendash"); +defineSymbol(symbols_text, main, symbols_textord, "\u2014", "---"); +defineSymbol(symbols_text, main, symbols_textord, "\u2014", "\\textemdash"); +defineSymbol(symbols_text, main, symbols_textord, "\u2018", "`"); +defineSymbol(symbols_text, main, symbols_textord, "\u2018", "\\textquoteleft"); +defineSymbol(symbols_text, main, symbols_textord, "\u2019", "'"); +defineSymbol(symbols_text, main, symbols_textord, "\u2019", "\\textquoteright"); +defineSymbol(symbols_text, main, symbols_textord, "\u201C", "``"); +defineSymbol(symbols_text, main, symbols_textord, "\u201C", "\\textquotedblleft"); +defineSymbol(symbols_text, main, symbols_textord, "\u201D", "''"); +defineSymbol(symbols_text, main, symbols_textord, "\u201D", "\\textquotedblright"); // \degree from gensymb package + +defineSymbol(symbols_math, main, symbols_textord, "\xB0", "\\degree", true); +defineSymbol(symbols_text, main, symbols_textord, "\xB0", "\\degree"); // \textdegree from inputenc package + +defineSymbol(symbols_text, main, symbols_textord, "\xB0", "\\textdegree", true); // TODO: In LaTeX, \pounds can generate a different character in text and math +// mode, but among our fonts, only Main-Italic defines this character "163". + +defineSymbol(symbols_math, main, mathord, "\xA3", "\\pounds"); +defineSymbol(symbols_math, main, mathord, "\xA3", "\\mathsterling", true); +defineSymbol(symbols_text, main, mathord, "\xA3", "\\pounds"); +defineSymbol(symbols_text, main, mathord, "\xA3", "\\textsterling", true); +defineSymbol(symbols_math, ams, symbols_textord, "\u2720", "\\maltese"); +defineSymbol(symbols_text, ams, symbols_textord, "\u2720", "\\maltese"); +defineSymbol(symbols_text, main, symbols_spacing, "\xA0", "\\ "); +defineSymbol(symbols_text, main, symbols_spacing, "\xA0", " "); +defineSymbol(symbols_text, main, symbols_spacing, "\xA0", "~"); // There are lots of symbols which are the same, so we add them in afterwards. +// All of these are textords in math mode + +var mathTextSymbols = "0123456789/@.\""; + +for (var symbols_i = 0; symbols_i < mathTextSymbols.length; symbols_i++) { + var symbols_ch = mathTextSymbols.charAt(symbols_i); + defineSymbol(symbols_math, main, symbols_textord, symbols_ch, symbols_ch); +} // All of these are textords in text mode + + +var textSymbols = "0123456789!@*()-=+[]<>|\";:?/.,"; + +for (var src_symbols_i = 0; src_symbols_i < textSymbols.length; src_symbols_i++) { + var _ch = textSymbols.charAt(src_symbols_i); + + defineSymbol(symbols_text, main, symbols_textord, _ch, _ch); +} // All of these are textords in text mode, and mathords in math mode + + +var letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +for (var symbols_i2 = 0; symbols_i2 < letters.length; symbols_i2++) { + var _ch2 = letters.charAt(symbols_i2); + + defineSymbol(symbols_math, main, mathord, _ch2, _ch2); + defineSymbol(symbols_text, main, symbols_textord, _ch2, _ch2); +} // Blackboard bold and script letters in Unicode range + + +defineSymbol(symbols_math, ams, symbols_textord, "C", "\u2102"); // blackboard bold + +defineSymbol(symbols_text, ams, symbols_textord, "C", "\u2102"); +defineSymbol(symbols_math, ams, symbols_textord, "H", "\u210D"); +defineSymbol(symbols_text, ams, symbols_textord, "H", "\u210D"); +defineSymbol(symbols_math, ams, symbols_textord, "N", "\u2115"); +defineSymbol(symbols_text, ams, symbols_textord, "N", "\u2115"); +defineSymbol(symbols_math, ams, symbols_textord, "P", "\u2119"); +defineSymbol(symbols_text, ams, symbols_textord, "P", "\u2119"); +defineSymbol(symbols_math, ams, symbols_textord, "Q", "\u211A"); +defineSymbol(symbols_text, ams, symbols_textord, "Q", "\u211A"); +defineSymbol(symbols_math, ams, symbols_textord, "R", "\u211D"); +defineSymbol(symbols_text, ams, symbols_textord, "R", "\u211D"); +defineSymbol(symbols_math, ams, symbols_textord, "Z", "\u2124"); +defineSymbol(symbols_text, ams, symbols_textord, "Z", "\u2124"); +defineSymbol(symbols_math, main, mathord, "h", "\u210E"); // italic h, Planck constant + +defineSymbol(symbols_text, main, mathord, "h", "\u210E"); // The next loop loads wide (surrogate pair) characters. +// We support some letters in the Unicode range U+1D400 to U+1D7FF, +// Mathematical Alphanumeric Symbols. +// Some editors do not deal well with wide characters. So don't write the +// string into this file. Instead, create the string from the surrogate pair. + +var symbols_wideChar = ""; + +for (var symbols_i3 = 0; symbols_i3 < letters.length; symbols_i3++) { + var _ch3 = letters.charAt(symbols_i3); // The hex numbers in the next line are a surrogate pair. + // 0xD835 is the high surrogate for all letters in the range we support. + // 0xDC00 is the low surrogate for bold A. + + + symbols_wideChar = String.fromCharCode(0xD835, 0xDC00 + symbols_i3); // A-Z a-z bold + + defineSymbol(symbols_math, main, mathord, _ch3, symbols_wideChar); + defineSymbol(symbols_text, main, symbols_textord, _ch3, symbols_wideChar); + symbols_wideChar = String.fromCharCode(0xD835, 0xDC34 + symbols_i3); // A-Z a-z italic + + defineSymbol(symbols_math, main, mathord, _ch3, symbols_wideChar); + defineSymbol(symbols_text, main, symbols_textord, _ch3, symbols_wideChar); + symbols_wideChar = String.fromCharCode(0xD835, 0xDC68 + symbols_i3); // A-Z a-z bold italic + + defineSymbol(symbols_math, main, mathord, _ch3, symbols_wideChar); + defineSymbol(symbols_text, main, symbols_textord, _ch3, symbols_wideChar); + symbols_wideChar = String.fromCharCode(0xD835, 0xDD04 + symbols_i3); // A-Z a-z Fractur + + defineSymbol(symbols_math, main, mathord, _ch3, symbols_wideChar); + defineSymbol(symbols_text, main, symbols_textord, _ch3, symbols_wideChar); + symbols_wideChar = String.fromCharCode(0xD835, 0xDDA0 + symbols_i3); // A-Z a-z sans-serif + + defineSymbol(symbols_math, main, mathord, _ch3, symbols_wideChar); + defineSymbol(symbols_text, main, symbols_textord, _ch3, symbols_wideChar); + symbols_wideChar = String.fromCharCode(0xD835, 0xDDD4 + symbols_i3); // A-Z a-z sans bold + + defineSymbol(symbols_math, main, mathord, _ch3, symbols_wideChar); + defineSymbol(symbols_text, main, symbols_textord, _ch3, symbols_wideChar); + symbols_wideChar = String.fromCharCode(0xD835, 0xDE08 + symbols_i3); // A-Z a-z sans italic + + defineSymbol(symbols_math, main, mathord, _ch3, symbols_wideChar); + defineSymbol(symbols_text, main, symbols_textord, _ch3, symbols_wideChar); + symbols_wideChar = String.fromCharCode(0xD835, 0xDE70 + symbols_i3); // A-Z a-z monospace + + defineSymbol(symbols_math, main, mathord, _ch3, symbols_wideChar); + defineSymbol(symbols_text, main, symbols_textord, _ch3, symbols_wideChar); + + if (symbols_i3 < 26) { + // KaTeX fonts have only capital letters for blackboard bold and script. + // See exception for k below. + symbols_wideChar = String.fromCharCode(0xD835, 0xDD38 + symbols_i3); // A-Z double struck + + defineSymbol(symbols_math, main, mathord, _ch3, symbols_wideChar); + defineSymbol(symbols_text, main, symbols_textord, _ch3, symbols_wideChar); + symbols_wideChar = String.fromCharCode(0xD835, 0xDC9C + symbols_i3); // A-Z script + + defineSymbol(symbols_math, main, mathord, _ch3, symbols_wideChar); + defineSymbol(symbols_text, main, symbols_textord, _ch3, symbols_wideChar); + } // TODO: Add bold script when it is supported by a KaTeX font. + +} // "k" is the only double struck lower case letter in the KaTeX fonts. + + +symbols_wideChar = String.fromCharCode(0xD835, 0xDD5C); // k double struck + +defineSymbol(symbols_math, main, mathord, "k", symbols_wideChar); +defineSymbol(symbols_text, main, symbols_textord, "k", symbols_wideChar); // Next, some wide character numerals + +for (var symbols_i4 = 0; symbols_i4 < 10; symbols_i4++) { + var _ch4 = symbols_i4.toString(); + + symbols_wideChar = String.fromCharCode(0xD835, 0xDFCE + symbols_i4); // 0-9 bold + + defineSymbol(symbols_math, main, mathord, _ch4, symbols_wideChar); + defineSymbol(symbols_text, main, symbols_textord, _ch4, symbols_wideChar); + symbols_wideChar = String.fromCharCode(0xD835, 0xDFE2 + symbols_i4); // 0-9 sans serif + + defineSymbol(symbols_math, main, mathord, _ch4, symbols_wideChar); + defineSymbol(symbols_text, main, symbols_textord, _ch4, symbols_wideChar); + symbols_wideChar = String.fromCharCode(0xD835, 0xDFEC + symbols_i4); // 0-9 bold sans + + defineSymbol(symbols_math, main, mathord, _ch4, symbols_wideChar); + defineSymbol(symbols_text, main, symbols_textord, _ch4, symbols_wideChar); + symbols_wideChar = String.fromCharCode(0xD835, 0xDFF6 + symbols_i4); // 0-9 monospace + + defineSymbol(symbols_math, main, mathord, _ch4, symbols_wideChar); + defineSymbol(symbols_text, main, symbols_textord, _ch4, symbols_wideChar); +} // We add these Latin-1 letters as symbols for backwards-compatibility, +// but they are not actually in the font, nor are they supported by the +// Unicode accent mechanism, so they fall back to Times font and look ugly. +// TODO(edemaine): Fix this. + + +var extraLatin = "ÇÐÞçþ"; + +for (var _i5 = 0; _i5 < extraLatin.length; _i5++) { + var _ch5 = extraLatin.charAt(_i5); + + defineSymbol(symbols_math, main, mathord, _ch5, _ch5); + defineSymbol(symbols_text, main, symbols_textord, _ch5, _ch5); +} + +defineSymbol(symbols_text, main, symbols_textord, "ð", "ð"); // Unicode versions of existing characters + +defineSymbol(symbols_text, main, symbols_textord, "\u2013", "–"); +defineSymbol(symbols_text, main, symbols_textord, "\u2014", "—"); +defineSymbol(symbols_text, main, symbols_textord, "\u2018", "‘"); +defineSymbol(symbols_text, main, symbols_textord, "\u2019", "’"); +defineSymbol(symbols_text, main, symbols_textord, "\u201C", "“"); +defineSymbol(symbols_text, main, symbols_textord, "\u201D", "”"); +// CONCATENATED MODULE: ./src/wide-character.js +/** + * This file provides support for Unicode range U+1D400 to U+1D7FF, + * Mathematical Alphanumeric Symbols. + * + * Function wideCharacterFont takes a wide character as input and returns + * the font information necessary to render it properly. + */ + +/** + * Data below is from https://www.unicode.org/charts/PDF/U1D400.pdf + * That document sorts characters into groups by font type, say bold or italic. + * + * In the arrays below, each subarray consists three elements: + * * The CSS class of that group when in math mode. + * * The CSS class of that group when in text mode. + * * The font name, so that KaTeX can get font metrics. + */ + +var wideLatinLetterData = [["mathbf", "textbf", "Main-Bold"], // A-Z bold upright +["mathbf", "textbf", "Main-Bold"], // a-z bold upright +["mathdefault", "textit", "Math-Italic"], // A-Z italic +["mathdefault", "textit", "Math-Italic"], // a-z italic +["boldsymbol", "boldsymbol", "Main-BoldItalic"], // A-Z bold italic +["boldsymbol", "boldsymbol", "Main-BoldItalic"], // a-z bold italic +// Map fancy A-Z letters to script, not calligraphic. +// This aligns with unicode-math and math fonts (except Cambria Math). +["mathscr", "textscr", "Script-Regular"], // A-Z script +["", "", ""], // a-z script. No font +["", "", ""], // A-Z bold script. No font +["", "", ""], // a-z bold script. No font +["mathfrak", "textfrak", "Fraktur-Regular"], // A-Z Fraktur +["mathfrak", "textfrak", "Fraktur-Regular"], // a-z Fraktur +["mathbb", "textbb", "AMS-Regular"], // A-Z double-struck +["mathbb", "textbb", "AMS-Regular"], // k double-struck +["", "", ""], // A-Z bold Fraktur No font metrics +["", "", ""], // a-z bold Fraktur. No font. +["mathsf", "textsf", "SansSerif-Regular"], // A-Z sans-serif +["mathsf", "textsf", "SansSerif-Regular"], // a-z sans-serif +["mathboldsf", "textboldsf", "SansSerif-Bold"], // A-Z bold sans-serif +["mathboldsf", "textboldsf", "SansSerif-Bold"], // a-z bold sans-serif +["mathitsf", "textitsf", "SansSerif-Italic"], // A-Z italic sans-serif +["mathitsf", "textitsf", "SansSerif-Italic"], // a-z italic sans-serif +["", "", ""], // A-Z bold italic sans. No font +["", "", ""], // a-z bold italic sans. No font +["mathtt", "texttt", "Typewriter-Regular"], // A-Z monospace +["mathtt", "texttt", "Typewriter-Regular"]]; +var wideNumeralData = [["mathbf", "textbf", "Main-Bold"], // 0-9 bold +["", "", ""], // 0-9 double-struck. No KaTeX font. +["mathsf", "textsf", "SansSerif-Regular"], // 0-9 sans-serif +["mathboldsf", "textboldsf", "SansSerif-Bold"], // 0-9 bold sans-serif +["mathtt", "texttt", "Typewriter-Regular"]]; +var wide_character_wideCharacterFont = function wideCharacterFont(wideChar, mode) { + // IE doesn't support codePointAt(). So work with the surrogate pair. + var H = wideChar.charCodeAt(0); // high surrogate + + var L = wideChar.charCodeAt(1); // low surrogate + + var codePoint = (H - 0xD800) * 0x400 + (L - 0xDC00) + 0x10000; + var j = mode === "math" ? 0 : 1; // column index for CSS class. + + if (0x1D400 <= codePoint && codePoint < 0x1D6A4) { + // wideLatinLetterData contains exactly 26 chars on each row. + // So we can calculate the relevant row. No traverse necessary. + var i = Math.floor((codePoint - 0x1D400) / 26); + return [wideLatinLetterData[i][2], wideLatinLetterData[i][j]]; + } else if (0x1D7CE <= codePoint && codePoint <= 0x1D7FF) { + // Numerals, ten per row. + var _i = Math.floor((codePoint - 0x1D7CE) / 10); + + return [wideNumeralData[_i][2], wideNumeralData[_i][j]]; + } else if (codePoint === 0x1D6A5 || codePoint === 0x1D6A6) { + // dotless i or j + return [wideLatinLetterData[0][2], wideLatinLetterData[0][j]]; + } else if (0x1D6A6 < codePoint && codePoint < 0x1D7CE) { + // Greek letters. Not supported, yet. + return ["", ""]; + } else { + // We don't support any wide characters outside 1D400–1D7FF. + throw new src_ParseError("Unsupported character: " + wideChar); + } +}; +// CONCATENATED MODULE: ./src/Options.js +/** + * This file contains information about the options that the Parser carries + * around with it while parsing. Data is held in an `Options` object, and when + * recursing, a new `Options` object can be created with the `.with*` and + * `.reset` functions. + */ + +var sizeStyleMap = [// Each element contains [textsize, scriptsize, scriptscriptsize]. +// The size mappings are taken from TeX with \normalsize=10pt. +[1, 1, 1], // size1: [5, 5, 5] \tiny +[2, 1, 1], // size2: [6, 5, 5] +[3, 1, 1], // size3: [7, 5, 5] \scriptsize +[4, 2, 1], // size4: [8, 6, 5] \footnotesize +[5, 2, 1], // size5: [9, 6, 5] \small +[6, 3, 1], // size6: [10, 7, 5] \normalsize +[7, 4, 2], // size7: [12, 8, 6] \large +[8, 6, 3], // size8: [14.4, 10, 7] \Large +[9, 7, 6], // size9: [17.28, 12, 10] \LARGE +[10, 8, 7], // size10: [20.74, 14.4, 12] \huge +[11, 10, 9]]; +var sizeMultipliers = [// fontMetrics.js:getGlobalMetrics also uses size indexes, so if +// you change size indexes, change that function. +0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.2, 1.44, 1.728, 2.074, 2.488]; + +var sizeAtStyle = function sizeAtStyle(size, style) { + return style.size < 2 ? size : sizeStyleMap[size - 1][style.size - 1]; +}; // In these types, "" (empty string) means "no change". + + +/** + * This is the main options class. It contains the current style, size, color, + * and font. + * + * Options objects should not be modified. To create a new Options with + * different properties, call a `.having*` method. + */ +var Options_Options = +/*#__PURE__*/ +function () { + // A font family applies to a group of fonts (i.e. SansSerif), while a font + // represents a specific font (i.e. SansSerif Bold). + // See: https://tex.stackexchange.com/questions/22350/difference-between-textrm-and-mathrm + + /** + * The base size index. + */ + function Options(data) { + this.style = void 0; + this.color = void 0; + this.size = void 0; + this.textSize = void 0; + this.phantom = void 0; + this.font = void 0; + this.fontFamily = void 0; + this.fontWeight = void 0; + this.fontShape = void 0; + this.sizeMultiplier = void 0; + this.maxSize = void 0; + this.minRuleThickness = void 0; + this._fontMetrics = void 0; + this.style = data.style; + this.color = data.color; + this.size = data.size || Options.BASESIZE; + this.textSize = data.textSize || this.size; + this.phantom = !!data.phantom; + this.font = data.font || ""; + this.fontFamily = data.fontFamily || ""; + this.fontWeight = data.fontWeight || ''; + this.fontShape = data.fontShape || ''; + this.sizeMultiplier = sizeMultipliers[this.size - 1]; + this.maxSize = data.maxSize; + this.minRuleThickness = data.minRuleThickness; + this._fontMetrics = undefined; + } + /** + * Returns a new options object with the same properties as "this". Properties + * from "extension" will be copied to the new options object. + */ + + + var _proto = Options.prototype; + + _proto.extend = function extend(extension) { + var data = { + style: this.style, + size: this.size, + textSize: this.textSize, + color: this.color, + phantom: this.phantom, + font: this.font, + fontFamily: this.fontFamily, + fontWeight: this.fontWeight, + fontShape: this.fontShape, + maxSize: this.maxSize, + minRuleThickness: this.minRuleThickness + }; + + for (var key in extension) { + if (extension.hasOwnProperty(key)) { + data[key] = extension[key]; + } + } + + return new Options(data); + } + /** + * Return an options object with the given style. If `this.style === style`, + * returns `this`. + */ + ; + + _proto.havingStyle = function havingStyle(style) { + if (this.style === style) { + return this; + } else { + return this.extend({ + style: style, + size: sizeAtStyle(this.textSize, style) + }); + } + } + /** + * Return an options object with a cramped version of the current style. If + * the current style is cramped, returns `this`. + */ + ; + + _proto.havingCrampedStyle = function havingCrampedStyle() { + return this.havingStyle(this.style.cramp()); + } + /** + * Return an options object with the given size and in at least `\textstyle`. + * Returns `this` if appropriate. + */ + ; + + _proto.havingSize = function havingSize(size) { + if (this.size === size && this.textSize === size) { + return this; + } else { + return this.extend({ + style: this.style.text(), + size: size, + textSize: size, + sizeMultiplier: sizeMultipliers[size - 1] + }); + } + } + /** + * Like `this.havingSize(BASESIZE).havingStyle(style)`. If `style` is omitted, + * changes to at least `\textstyle`. + */ + ; + + _proto.havingBaseStyle = function havingBaseStyle(style) { + style = style || this.style.text(); + var wantSize = sizeAtStyle(Options.BASESIZE, style); + + if (this.size === wantSize && this.textSize === Options.BASESIZE && this.style === style) { + return this; + } else { + return this.extend({ + style: style, + size: wantSize + }); + } + } + /** + * Remove the effect of sizing changes such as \Huge. + * Keep the effect of the current style, such as \scriptstyle. + */ + ; + + _proto.havingBaseSizing = function havingBaseSizing() { + var size; + + switch (this.style.id) { + case 4: + case 5: + size = 3; // normalsize in scriptstyle + + break; + + case 6: + case 7: + size = 1; // normalsize in scriptscriptstyle + + break; + + default: + size = 6; + // normalsize in textstyle or displaystyle + } + + return this.extend({ + style: this.style.text(), + size: size + }); + } + /** + * Create a new options object with the given color. + */ + ; + + _proto.withColor = function withColor(color) { + return this.extend({ + color: color + }); + } + /** + * Create a new options object with "phantom" set to true. + */ + ; + + _proto.withPhantom = function withPhantom() { + return this.extend({ + phantom: true + }); + } + /** + * Creates a new options object with the given math font or old text font. + * @type {[type]} + */ + ; + + _proto.withFont = function withFont(font) { + return this.extend({ + font: font + }); + } + /** + * Create a new options objects with the given fontFamily. + */ + ; + + _proto.withTextFontFamily = function withTextFontFamily(fontFamily) { + return this.extend({ + fontFamily: fontFamily, + font: "" + }); + } + /** + * Creates a new options object with the given font weight + */ + ; + + _proto.withTextFontWeight = function withTextFontWeight(fontWeight) { + return this.extend({ + fontWeight: fontWeight, + font: "" + }); + } + /** + * Creates a new options object with the given font weight + */ + ; + + _proto.withTextFontShape = function withTextFontShape(fontShape) { + return this.extend({ + fontShape: fontShape, + font: "" + }); + } + /** + * Return the CSS sizing classes required to switch from enclosing options + * `oldOptions` to `this`. Returns an array of classes. + */ + ; + + _proto.sizingClasses = function sizingClasses(oldOptions) { + if (oldOptions.size !== this.size) { + return ["sizing", "reset-size" + oldOptions.size, "size" + this.size]; + } else { + return []; + } + } + /** + * Return the CSS sizing classes required to switch to the base size. Like + * `this.havingSize(BASESIZE).sizingClasses(this)`. + */ + ; + + _proto.baseSizingClasses = function baseSizingClasses() { + if (this.size !== Options.BASESIZE) { + return ["sizing", "reset-size" + this.size, "size" + Options.BASESIZE]; + } else { + return []; + } + } + /** + * Return the font metrics for this size. + */ + ; + + _proto.fontMetrics = function fontMetrics() { + if (!this._fontMetrics) { + this._fontMetrics = getGlobalMetrics(this.size); + } + + return this._fontMetrics; + } + /** + * Gets the CSS color of the current options object + */ + ; + + _proto.getColor = function getColor() { + if (this.phantom) { + return "transparent"; + } else { + return this.color; + } + }; + + return Options; +}(); + +Options_Options.BASESIZE = 6; +/* harmony default export */ var src_Options = (Options_Options); +// CONCATENATED MODULE: ./src/units.js +/** + * This file does conversion between units. In particular, it provides + * calculateSize to convert other units into ems. + */ + + // This table gives the number of TeX pts in one of each *absolute* TeX unit. +// Thus, multiplying a length by this number converts the length from units +// into pts. Dividing the result by ptPerEm gives the number of ems +// *assuming* a font size of ptPerEm (normal size, normal style). + +var ptPerUnit = { + // https://en.wikibooks.org/wiki/LaTeX/Lengths and + // https://tex.stackexchange.com/a/8263 + "pt": 1, + // TeX point + "mm": 7227 / 2540, + // millimeter + "cm": 7227 / 254, + // centimeter + "in": 72.27, + // inch + "bp": 803 / 800, + // big (PostScript) points + "pc": 12, + // pica + "dd": 1238 / 1157, + // didot + "cc": 14856 / 1157, + // cicero (12 didot) + "nd": 685 / 642, + // new didot + "nc": 1370 / 107, + // new cicero (12 new didot) + "sp": 1 / 65536, + // scaled point (TeX's internal smallest unit) + // https://tex.stackexchange.com/a/41371 + "px": 803 / 800 // \pdfpxdimen defaults to 1 bp in pdfTeX and LuaTeX + +}; // Dictionary of relative units, for fast validity testing. + +var relativeUnit = { + "ex": true, + "em": true, + "mu": true +}; + +/** + * Determine whether the specified unit (either a string defining the unit + * or a "size" parse node containing a unit field) is valid. + */ +var validUnit = function validUnit(unit) { + if (typeof unit !== "string") { + unit = unit.unit; + } + + return unit in ptPerUnit || unit in relativeUnit || unit === "ex"; +}; +/* + * Convert a "size" parse node (with numeric "number" and string "unit" fields, + * as parsed by functions.js argType "size") into a CSS em value for the + * current style/scale. `options` gives the current options. + */ + +var units_calculateSize = function calculateSize(sizeValue, options) { + var scale; + + if (sizeValue.unit in ptPerUnit) { + // Absolute units + scale = ptPerUnit[sizeValue.unit] // Convert unit to pt + / options.fontMetrics().ptPerEm // Convert pt to CSS em + / options.sizeMultiplier; // Unscale to make absolute units + } else if (sizeValue.unit === "mu") { + // `mu` units scale with scriptstyle/scriptscriptstyle. + scale = options.fontMetrics().cssEmPerMu; + } else { + // Other relative units always refer to the *textstyle* font + // in the current size. + var unitOptions; + + if (options.style.isTight()) { + // isTight() means current style is script/scriptscript. + unitOptions = options.havingStyle(options.style.text()); + } else { + unitOptions = options; + } // TODO: In TeX these units are relative to the quad of the current + // *text* font, e.g. cmr10. KaTeX instead uses values from the + // comparably-sized *Computer Modern symbol* font. At 10pt, these + // match. At 7pt and 5pt, they differ: cmr7=1.138894, cmsy7=1.170641; + // cmr5=1.361133, cmsy5=1.472241. Consider $\scriptsize a\kern1emb$. + // TeX \showlists shows a kern of 1.13889 * fontsize; + // KaTeX shows a kern of 1.171 * fontsize. + + + if (sizeValue.unit === "ex") { + scale = unitOptions.fontMetrics().xHeight; + } else if (sizeValue.unit === "em") { + scale = unitOptions.fontMetrics().quad; + } else { + throw new src_ParseError("Invalid unit: '" + sizeValue.unit + "'"); + } + + if (unitOptions !== options) { + scale *= unitOptions.sizeMultiplier / options.sizeMultiplier; + } + } + + return Math.min(sizeValue.number * scale, options.maxSize); +}; +// CONCATENATED MODULE: ./src/buildCommon.js +/* eslint no-console:0 */ + +/** + * This module contains general functions that can be used for building + * different kinds of domTree nodes in a consistent manner. + */ + + + + + + + +// The following have to be loaded from Main-Italic font, using class mathit +var mathitLetters = ["\\imath", "ı", // dotless i +"\\jmath", "ȷ", // dotless j +"\\pounds", "\\mathsterling", "\\textsterling", "£"]; +/** + * Looks up the given symbol in fontMetrics, after applying any symbol + * replacements defined in symbol.js + */ + +var buildCommon_lookupSymbol = function lookupSymbol(value, // TODO(#963): Use a union type for this. +fontName, mode) { + // Replace the value with its replaced value from symbol.js + if (src_symbols[mode][value] && src_symbols[mode][value].replace) { + value = src_symbols[mode][value].replace; + } + + return { + value: value, + metrics: getCharacterMetrics(value, fontName, mode) + }; +}; +/** + * Makes a symbolNode after translation via the list of symbols in symbols.js. + * Correctly pulls out metrics for the character, and optionally takes a list of + * classes to be attached to the node. + * + * TODO: make argument order closer to makeSpan + * TODO: add a separate argument for math class (e.g. `mop`, `mbin`), which + * should if present come first in `classes`. + * TODO(#953): Make `options` mandatory and always pass it in. + */ + + +var buildCommon_makeSymbol = function makeSymbol(value, fontName, mode, options, classes) { + var lookup = buildCommon_lookupSymbol(value, fontName, mode); + var metrics = lookup.metrics; + value = lookup.value; + var symbolNode; + + if (metrics) { + var italic = metrics.italic; + + if (mode === "text" || options && options.font === "mathit") { + italic = 0; + } + + symbolNode = new domTree_SymbolNode(value, metrics.height, metrics.depth, italic, metrics.skew, metrics.width, classes); + } else { + // TODO(emily): Figure out a good way to only print this in development + typeof console !== "undefined" && console.warn("No character metrics " + ("for '" + value + "' in style '" + fontName + "' and mode '" + mode + "'")); + symbolNode = new domTree_SymbolNode(value, 0, 0, 0, 0, 0, classes); + } + + if (options) { + symbolNode.maxFontSize = options.sizeMultiplier; + + if (options.style.isTight()) { + symbolNode.classes.push("mtight"); + } + + var color = options.getColor(); + + if (color) { + symbolNode.style.color = color; + } + } + + return symbolNode; +}; +/** + * Makes a symbol in Main-Regular or AMS-Regular. + * Used for rel, bin, open, close, inner, and punct. + */ + + +var buildCommon_mathsym = function mathsym(value, mode, options, classes) { + if (classes === void 0) { + classes = []; + } + + // Decide what font to render the symbol in by its entry in the symbols + // table. + // Have a special case for when the value = \ because the \ is used as a + // textord in unsupported command errors but cannot be parsed as a regular + // text ordinal and is therefore not present as a symbol in the symbols + // table for text, as well as a special case for boldsymbol because it + // can be used for bold + and - + if (options.font === "boldsymbol" && buildCommon_lookupSymbol(value, "Main-Bold", mode).metrics) { + return buildCommon_makeSymbol(value, "Main-Bold", mode, options, classes.concat(["mathbf"])); + } else if (value === "\\" || src_symbols[mode][value].font === "main") { + return buildCommon_makeSymbol(value, "Main-Regular", mode, options, classes); + } else { + return buildCommon_makeSymbol(value, "AMS-Regular", mode, options, classes.concat(["amsrm"])); + } +}; +/** + * Determines which of the two font names (Main-Italic and Math-Italic) and + * corresponding style tags (maindefault or mathit) to use for default math font, + * depending on the symbol. + */ + + +var buildCommon_mathdefault = function mathdefault(value, mode, options, classes) { + if (/[0-9]/.test(value.charAt(0)) || // glyphs for \imath and \jmath do not exist in Math-Italic so we + // need to use Main-Italic instead + utils.contains(mathitLetters, value)) { + return { + fontName: "Main-Italic", + fontClass: "mathit" + }; + } else { + return { + fontName: "Math-Italic", + fontClass: "mathdefault" + }; + } +}; +/** + * Determines which of the font names (Main-Italic, Math-Italic, and Caligraphic) + * and corresponding style tags (mathit, mathdefault, or mathcal) to use for font + * "mathnormal", depending on the symbol. Use this function instead of fontMap for + * font "mathnormal". + */ + + +var buildCommon_mathnormal = function mathnormal(value, mode, options, classes) { + if (utils.contains(mathitLetters, value)) { + return { + fontName: "Main-Italic", + fontClass: "mathit" + }; + } else if (/[0-9]/.test(value.charAt(0))) { + return { + fontName: "Caligraphic-Regular", + fontClass: "mathcal" + }; + } else { + return { + fontName: "Math-Italic", + fontClass: "mathdefault" + }; + } +}; +/** + * Determines which of the two font names (Main-Bold and Math-BoldItalic) and + * corresponding style tags (mathbf or boldsymbol) to use for font "boldsymbol", + * depending on the symbol. Use this function instead of fontMap for font + * "boldsymbol". + */ + + +var boldsymbol = function boldsymbol(value, mode, options, classes) { + if (buildCommon_lookupSymbol(value, "Math-BoldItalic", mode).metrics) { + return { + fontName: "Math-BoldItalic", + fontClass: "boldsymbol" + }; + } else { + // Some glyphs do not exist in Math-BoldItalic so we need to use + // Main-Bold instead. + return { + fontName: "Main-Bold", + fontClass: "mathbf" + }; + } +}; +/** + * Makes either a mathord or textord in the correct font and color. + */ + + +var buildCommon_makeOrd = function makeOrd(group, options, type) { + var mode = group.mode; + var text = group.text; + var classes = ["mord"]; // Math mode or Old font (i.e. \rm) + + var isFont = mode === "math" || mode === "text" && options.font; + var fontOrFamily = isFont ? options.font : options.fontFamily; + + if (text.charCodeAt(0) === 0xD835) { + // surrogate pairs get special treatment + var _wideCharacterFont = wide_character_wideCharacterFont(text, mode), + wideFontName = _wideCharacterFont[0], + wideFontClass = _wideCharacterFont[1]; + + return buildCommon_makeSymbol(text, wideFontName, mode, options, classes.concat(wideFontClass)); + } else if (fontOrFamily) { + var fontName; + var fontClasses; + + if (fontOrFamily === "boldsymbol" || fontOrFamily === "mathnormal") { + var fontData = fontOrFamily === "boldsymbol" ? boldsymbol(text, mode, options, classes) : buildCommon_mathnormal(text, mode, options, classes); + fontName = fontData.fontName; + fontClasses = [fontData.fontClass]; + } else if (utils.contains(mathitLetters, text)) { + fontName = "Main-Italic"; + fontClasses = ["mathit"]; + } else if (isFont) { + fontName = fontMap[fontOrFamily].fontName; + fontClasses = [fontOrFamily]; + } else { + fontName = retrieveTextFontName(fontOrFamily, options.fontWeight, options.fontShape); + fontClasses = [fontOrFamily, options.fontWeight, options.fontShape]; + } + + if (buildCommon_lookupSymbol(text, fontName, mode).metrics) { + return buildCommon_makeSymbol(text, fontName, mode, options, classes.concat(fontClasses)); + } else if (ligatures.hasOwnProperty(text) && fontName.substr(0, 10) === "Typewriter") { + // Deconstruct ligatures in monospace fonts (\texttt, \tt). + var parts = []; + + for (var i = 0; i < text.length; i++) { + parts.push(buildCommon_makeSymbol(text[i], fontName, mode, options, classes.concat(fontClasses))); + } + + return buildCommon_makeFragment(parts); + } + } // Makes a symbol in the default font for mathords and textords. + + + if (type === "mathord") { + var fontLookup = buildCommon_mathdefault(text, mode, options, classes); + return buildCommon_makeSymbol(text, fontLookup.fontName, mode, options, classes.concat([fontLookup.fontClass])); + } else if (type === "textord") { + var font = src_symbols[mode][text] && src_symbols[mode][text].font; + + if (font === "ams") { + var _fontName = retrieveTextFontName("amsrm", options.fontWeight, options.fontShape); + + return buildCommon_makeSymbol(text, _fontName, mode, options, classes.concat("amsrm", options.fontWeight, options.fontShape)); + } else if (font === "main" || !font) { + var _fontName2 = retrieveTextFontName("textrm", options.fontWeight, options.fontShape); + + return buildCommon_makeSymbol(text, _fontName2, mode, options, classes.concat(options.fontWeight, options.fontShape)); + } else { + // fonts added by plugins + var _fontName3 = retrieveTextFontName(font, options.fontWeight, options.fontShape); // We add font name as a css class + + + return buildCommon_makeSymbol(text, _fontName3, mode, options, classes.concat(_fontName3, options.fontWeight, options.fontShape)); + } + } else { + throw new Error("unexpected type: " + type + " in makeOrd"); + } +}; +/** + * Returns true if subsequent symbolNodes have the same classes, skew, maxFont, + * and styles. + */ + + +var buildCommon_canCombine = function canCombine(prev, next) { + if (createClass(prev.classes) !== createClass(next.classes) || prev.skew !== next.skew || prev.maxFontSize !== next.maxFontSize) { + return false; + } + + for (var style in prev.style) { + if (prev.style.hasOwnProperty(style) && prev.style[style] !== next.style[style]) { + return false; + } + } + + for (var _style in next.style) { + if (next.style.hasOwnProperty(_style) && prev.style[_style] !== next.style[_style]) { + return false; + } + } + + return true; +}; +/** + * Combine consequetive domTree.symbolNodes into a single symbolNode. + * Note: this function mutates the argument. + */ + + +var buildCommon_tryCombineChars = function tryCombineChars(chars) { + for (var i = 0; i < chars.length - 1; i++) { + var prev = chars[i]; + var next = chars[i + 1]; + + if (prev instanceof domTree_SymbolNode && next instanceof domTree_SymbolNode && buildCommon_canCombine(prev, next)) { + prev.text += next.text; + prev.height = Math.max(prev.height, next.height); + prev.depth = Math.max(prev.depth, next.depth); // Use the last character's italic correction since we use + // it to add padding to the right of the span created from + // the combined characters. + + prev.italic = next.italic; + chars.splice(i + 1, 1); + i--; + } + } + + return chars; +}; +/** + * Calculate the height, depth, and maxFontSize of an element based on its + * children. + */ + + +var sizeElementFromChildren = function sizeElementFromChildren(elem) { + var height = 0; + var depth = 0; + var maxFontSize = 0; + + for (var i = 0; i < elem.children.length; i++) { + var child = elem.children[i]; + + if (child.height > height) { + height = child.height; + } + + if (child.depth > depth) { + depth = child.depth; + } + + if (child.maxFontSize > maxFontSize) { + maxFontSize = child.maxFontSize; + } + } + + elem.height = height; + elem.depth = depth; + elem.maxFontSize = maxFontSize; +}; +/** + * Makes a span with the given list of classes, list of children, and options. + * + * TODO(#953): Ensure that `options` is always provided (currently some call + * sites don't pass it) and make the type below mandatory. + * TODO: add a separate argument for math class (e.g. `mop`, `mbin`), which + * should if present come first in `classes`. + */ + + +var buildCommon_makeSpan = function makeSpan(classes, children, options, style) { + var span = new domTree_Span(classes, children, options, style); + sizeElementFromChildren(span); + return span; +}; // SVG one is simpler -- doesn't require height, depth, max-font setting. +// This is also a separate method for typesafety. + + +var buildCommon_makeSvgSpan = function makeSvgSpan(classes, children, options, style) { + return new domTree_Span(classes, children, options, style); +}; + +var makeLineSpan = function makeLineSpan(className, options, thickness) { + var line = buildCommon_makeSpan([className], [], options); + line.height = Math.max(thickness || options.fontMetrics().defaultRuleThickness, options.minRuleThickness); + line.style.borderBottomWidth = line.height + "em"; + line.maxFontSize = 1.0; + return line; +}; +/** + * Makes an anchor with the given href, list of classes, list of children, + * and options. + */ + + +var buildCommon_makeAnchor = function makeAnchor(href, classes, children, options) { + var anchor = new domTree_Anchor(href, classes, children, options); + sizeElementFromChildren(anchor); + return anchor; +}; +/** + * Makes a document fragment with the given list of children. + */ + + +var buildCommon_makeFragment = function makeFragment(children) { + var fragment = new tree_DocumentFragment(children); + sizeElementFromChildren(fragment); + return fragment; +}; +/** + * Wraps group in a span if it's a document fragment, allowing to apply classes + * and styles + */ + + +var buildCommon_wrapFragment = function wrapFragment(group, options) { + if (group instanceof tree_DocumentFragment) { + return buildCommon_makeSpan([], [group], options); + } + + return group; +}; // These are exact object types to catch typos in the names of the optional fields. + + +// Computes the updated `children` list and the overall depth. +// +// This helper function for makeVList makes it easier to enforce type safety by +// allowing early exits (returns) in the logic. +var getVListChildrenAndDepth = function getVListChildrenAndDepth(params) { + if (params.positionType === "individualShift") { + var oldChildren = params.children; + var children = [oldChildren[0]]; // Add in kerns to the list of params.children to get each element to be + // shifted to the correct specified shift + + var _depth = -oldChildren[0].shift - oldChildren[0].elem.depth; + + var currPos = _depth; + + for (var i = 1; i < oldChildren.length; i++) { + var diff = -oldChildren[i].shift - currPos - oldChildren[i].elem.depth; + var size = diff - (oldChildren[i - 1].elem.height + oldChildren[i - 1].elem.depth); + currPos = currPos + diff; + children.push({ + type: "kern", + size: size + }); + children.push(oldChildren[i]); + } + + return { + children: children, + depth: _depth + }; + } + + var depth; + + if (params.positionType === "top") { + // We always start at the bottom, so calculate the bottom by adding up + // all the sizes + var bottom = params.positionData; + + for (var _i = 0; _i < params.children.length; _i++) { + var child = params.children[_i]; + bottom -= child.type === "kern" ? child.size : child.elem.height + child.elem.depth; + } + + depth = bottom; + } else if (params.positionType === "bottom") { + depth = -params.positionData; + } else { + var firstChild = params.children[0]; + + if (firstChild.type !== "elem") { + throw new Error('First child must have type "elem".'); + } + + if (params.positionType === "shift") { + depth = -firstChild.elem.depth - params.positionData; + } else if (params.positionType === "firstBaseline") { + depth = -firstChild.elem.depth; + } else { + throw new Error("Invalid positionType " + params.positionType + "."); + } + } + + return { + children: params.children, + depth: depth + }; +}; +/** + * Makes a vertical list by stacking elements and kerns on top of each other. + * Allows for many different ways of specifying the positioning method. + * + * See VListParam documentation above. + */ + + +var buildCommon_makeVList = function makeVList(params, options) { + var _getVListChildrenAndD = getVListChildrenAndDepth(params), + children = _getVListChildrenAndD.children, + depth = _getVListChildrenAndD.depth; // Create a strut that is taller than any list item. The strut is added to + // each item, where it will determine the item's baseline. Since it has + // `overflow:hidden`, the strut's top edge will sit on the item's line box's + // top edge and the strut's bottom edge will sit on the item's baseline, + // with no additional line-height spacing. This allows the item baseline to + // be positioned precisely without worrying about font ascent and + // line-height. + + + var pstrutSize = 0; + + for (var i = 0; i < children.length; i++) { + var child = children[i]; + + if (child.type === "elem") { + var elem = child.elem; + pstrutSize = Math.max(pstrutSize, elem.maxFontSize, elem.height); + } + } + + pstrutSize += 2; + var pstrut = buildCommon_makeSpan(["pstrut"], []); + pstrut.style.height = pstrutSize + "em"; // Create a new list of actual children at the correct offsets + + var realChildren = []; + var minPos = depth; + var maxPos = depth; + var currPos = depth; + + for (var _i2 = 0; _i2 < children.length; _i2++) { + var _child = children[_i2]; + + if (_child.type === "kern") { + currPos += _child.size; + } else { + var _elem = _child.elem; + var classes = _child.wrapperClasses || []; + var style = _child.wrapperStyle || {}; + var childWrap = buildCommon_makeSpan(classes, [pstrut, _elem], undefined, style); + childWrap.style.top = -pstrutSize - currPos - _elem.depth + "em"; + + if (_child.marginLeft) { + childWrap.style.marginLeft = _child.marginLeft; + } + + if (_child.marginRight) { + childWrap.style.marginRight = _child.marginRight; + } + + realChildren.push(childWrap); + currPos += _elem.height + _elem.depth; + } + + minPos = Math.min(minPos, currPos); + maxPos = Math.max(maxPos, currPos); + } // The vlist contents go in a table-cell with `vertical-align:bottom`. + // This cell's bottom edge will determine the containing table's baseline + // without overly expanding the containing line-box. + + + var vlist = buildCommon_makeSpan(["vlist"], realChildren); + vlist.style.height = maxPos + "em"; // A second row is used if necessary to represent the vlist's depth. + + var rows; + + if (minPos < 0) { + // We will define depth in an empty span with display: table-cell. + // It should render with the height that we define. But Chrome, in + // contenteditable mode only, treats that span as if it contains some + // text content. And that min-height over-rides our desired height. + // So we put another empty span inside the depth strut span. + var emptySpan = buildCommon_makeSpan([], []); + var depthStrut = buildCommon_makeSpan(["vlist"], [emptySpan]); + depthStrut.style.height = -minPos + "em"; // Safari wants the first row to have inline content; otherwise it + // puts the bottom of the *second* row on the baseline. + + var topStrut = buildCommon_makeSpan(["vlist-s"], [new domTree_SymbolNode("\u200B")]); + rows = [buildCommon_makeSpan(["vlist-r"], [vlist, topStrut]), buildCommon_makeSpan(["vlist-r"], [depthStrut])]; + } else { + rows = [buildCommon_makeSpan(["vlist-r"], [vlist])]; + } + + var vtable = buildCommon_makeSpan(["vlist-t"], rows); + + if (rows.length === 2) { + vtable.classes.push("vlist-t2"); + } + + vtable.height = maxPos; + vtable.depth = -minPos; + return vtable; +}; // Glue is a concept from TeX which is a flexible space between elements in +// either a vertical or horizontal list. In KaTeX, at least for now, it's +// static space between elements in a horizontal layout. + + +var buildCommon_makeGlue = function makeGlue(measurement, options) { + // Make an empty span for the space + var rule = buildCommon_makeSpan(["mspace"], [], options); + var size = units_calculateSize(measurement, options); + rule.style.marginRight = size + "em"; + return rule; +}; // Takes font options, and returns the appropriate fontLookup name + + +var retrieveTextFontName = function retrieveTextFontName(fontFamily, fontWeight, fontShape) { + var baseFontName = ""; + + switch (fontFamily) { + case "amsrm": + baseFontName = "AMS"; + break; + + case "textrm": + baseFontName = "Main"; + break; + + case "textsf": + baseFontName = "SansSerif"; + break; + + case "texttt": + baseFontName = "Typewriter"; + break; + + default: + baseFontName = fontFamily; + // use fonts added by a plugin + } + + var fontStylesName; + + if (fontWeight === "textbf" && fontShape === "textit") { + fontStylesName = "BoldItalic"; + } else if (fontWeight === "textbf") { + fontStylesName = "Bold"; + } else if (fontWeight === "textit") { + fontStylesName = "Italic"; + } else { + fontStylesName = "Regular"; + } + + return baseFontName + "-" + fontStylesName; +}; +/** + * Maps TeX font commands to objects containing: + * - variant: string used for "mathvariant" attribute in buildMathML.js + * - fontName: the "style" parameter to fontMetrics.getCharacterMetrics + */ +// A map between tex font commands an MathML mathvariant attribute values + + +var fontMap = { + // styles + "mathbf": { + variant: "bold", + fontName: "Main-Bold" + }, + "mathrm": { + variant: "normal", + fontName: "Main-Regular" + }, + "textit": { + variant: "italic", + fontName: "Main-Italic" + }, + "mathit": { + variant: "italic", + fontName: "Main-Italic" + }, + // Default math font, "mathnormal" and "boldsymbol" are missing because they + // require the use of several fonts: Main-Italic and Math-Italic for default + // math font, Main-Italic, Math-Italic, Caligraphic for "mathnormal", and + // Math-BoldItalic and Main-Bold for "boldsymbol". This is handled by a + // special case in makeOrd which ends up calling mathdefault, mathnormal, + // and boldsymbol. + // families + "mathbb": { + variant: "double-struck", + fontName: "AMS-Regular" + }, + "mathcal": { + variant: "script", + fontName: "Caligraphic-Regular" + }, + "mathfrak": { + variant: "fraktur", + fontName: "Fraktur-Regular" + }, + "mathscr": { + variant: "script", + fontName: "Script-Regular" + }, + "mathsf": { + variant: "sans-serif", + fontName: "SansSerif-Regular" + }, + "mathtt": { + variant: "monospace", + fontName: "Typewriter-Regular" + } +}; +var svgData = { + // path, width, height + vec: ["vec", 0.471, 0.714], + // values from the font glyph + oiintSize1: ["oiintSize1", 0.957, 0.499], + // oval to overlay the integrand + oiintSize2: ["oiintSize2", 1.472, 0.659], + oiiintSize1: ["oiiintSize1", 1.304, 0.499], + oiiintSize2: ["oiiintSize2", 1.98, 0.659] +}; + +var buildCommon_staticSvg = function staticSvg(value, options) { + // Create a span with inline SVG for the element. + var _svgData$value = svgData[value], + pathName = _svgData$value[0], + width = _svgData$value[1], + height = _svgData$value[2]; + var path = new domTree_PathNode(pathName); + var svgNode = new SvgNode([path], { + "width": width + "em", + "height": height + "em", + // Override CSS rule `.katex svg { width: 100% }` + "style": "width:" + width + "em", + "viewBox": "0 0 " + 1000 * width + " " + 1000 * height, + "preserveAspectRatio": "xMinYMin" + }); + var span = buildCommon_makeSvgSpan(["overlay"], [svgNode], options); + span.height = height; + span.style.height = height + "em"; + span.style.width = width + "em"; + return span; +}; + +/* harmony default export */ var buildCommon = ({ + fontMap: fontMap, + makeSymbol: buildCommon_makeSymbol, + mathsym: buildCommon_mathsym, + makeSpan: buildCommon_makeSpan, + makeSvgSpan: buildCommon_makeSvgSpan, + makeLineSpan: makeLineSpan, + makeAnchor: buildCommon_makeAnchor, + makeFragment: buildCommon_makeFragment, + wrapFragment: buildCommon_wrapFragment, + makeVList: buildCommon_makeVList, + makeOrd: buildCommon_makeOrd, + makeGlue: buildCommon_makeGlue, + staticSvg: buildCommon_staticSvg, + svgData: svgData, + tryCombineChars: buildCommon_tryCombineChars +}); +// CONCATENATED MODULE: ./src/parseNode.js + + +/** + * Asserts that the node is of the given type and returns it with stricter + * typing. Throws if the node's type does not match. + */ +function assertNodeType(node, type) { + var typedNode = checkNodeType(node, type); + + if (!typedNode) { + throw new Error("Expected node of type " + type + ", but got " + (node ? "node of type " + node.type : String(node))); + } // $FlowFixMe: Unsure why. + + + return typedNode; +} +/** + * Returns the node more strictly typed iff it is of the given type. Otherwise, + * returns null. + */ + +function checkNodeType(node, type) { + if (node && node.type === type) { + // The definition of ParseNode doesn't communicate to flow that + // `type: TYPE` (as that's not explicitly mentioned anywhere), though that + // happens to be true for all our value types. + // $FlowFixMe + return node; + } + + return null; +} +/** + * Asserts that the node is of the given type and returns it with stricter + * typing. Throws if the node's type does not match. + */ + +function assertAtomFamily(node, family) { + var typedNode = checkAtomFamily(node, family); + + if (!typedNode) { + throw new Error("Expected node of type \"atom\" and family \"" + family + "\", but got " + (node ? node.type === "atom" ? "atom of family " + node.family : "node of type " + node.type : String(node))); + } + + return typedNode; +} +/** + * Returns the node more strictly typed iff it is of the given type. Otherwise, + * returns null. + */ + +function checkAtomFamily(node, family) { + return node && node.type === "atom" && node.family === family ? node : null; +} +/** + * Returns the node more strictly typed iff it is of the given type. Otherwise, + * returns null. + */ + +function assertSymbolNodeType(node) { + var typedNode = checkSymbolNodeType(node); + + if (!typedNode) { + throw new Error("Expected node of symbol group type, but got " + (node ? "node of type " + node.type : String(node))); + } + + return typedNode; +} +/** + * Returns the node more strictly typed iff it is of the given type. Otherwise, + * returns null. + */ + +function checkSymbolNodeType(node) { + if (node && (node.type === "atom" || NON_ATOMS.hasOwnProperty(node.type))) { + // $FlowFixMe + return node; + } + + return null; +} +// CONCATENATED MODULE: ./src/spacingData.js +/** + * Describes spaces between different classes of atoms. + */ +var thinspace = { + number: 3, + unit: "mu" +}; +var mediumspace = { + number: 4, + unit: "mu" +}; +var thickspace = { + number: 5, + unit: "mu" +}; // Making the type below exact with all optional fields doesn't work due to +// - https://github.com/facebook/flow/issues/4582 +// - https://github.com/facebook/flow/issues/5688 +// However, since *all* fields are optional, $Shape<> works as suggested in 5688 +// above. + +// Spacing relationships for display and text styles +var spacings = { + mord: { + mop: thinspace, + mbin: mediumspace, + mrel: thickspace, + minner: thinspace + }, + mop: { + mord: thinspace, + mop: thinspace, + mrel: thickspace, + minner: thinspace + }, + mbin: { + mord: mediumspace, + mop: mediumspace, + mopen: mediumspace, + minner: mediumspace + }, + mrel: { + mord: thickspace, + mop: thickspace, + mopen: thickspace, + minner: thickspace + }, + mopen: {}, + mclose: { + mop: thinspace, + mbin: mediumspace, + mrel: thickspace, + minner: thinspace + }, + mpunct: { + mord: thinspace, + mop: thinspace, + mrel: thickspace, + mopen: thinspace, + mclose: thinspace, + mpunct: thinspace, + minner: thinspace + }, + minner: { + mord: thinspace, + mop: thinspace, + mbin: mediumspace, + mrel: thickspace, + mopen: thinspace, + mpunct: thinspace, + minner: thinspace + } +}; // Spacing relationships for script and scriptscript styles + +var tightSpacings = { + mord: { + mop: thinspace + }, + mop: { + mord: thinspace, + mop: thinspace + }, + mbin: {}, + mrel: {}, + mopen: {}, + mclose: { + mop: thinspace + }, + mpunct: {}, + minner: { + mop: thinspace + } +}; +// CONCATENATED MODULE: ./src/defineFunction.js + + +/** + * All registered functions. + * `functions.js` just exports this same dictionary again and makes it public. + * `Parser.js` requires this dictionary. + */ +var _functions = {}; +/** + * All HTML builders. Should be only used in the `define*` and the `build*ML` + * functions. + */ + +var _htmlGroupBuilders = {}; +/** + * All MathML builders. Should be only used in the `define*` and the `build*ML` + * functions. + */ + +var _mathmlGroupBuilders = {}; +function defineFunction(_ref) { + var type = _ref.type, + names = _ref.names, + props = _ref.props, + handler = _ref.handler, + htmlBuilder = _ref.htmlBuilder, + mathmlBuilder = _ref.mathmlBuilder; + // Set default values of functions + var data = { + type: type, + numArgs: props.numArgs, + argTypes: props.argTypes, + greediness: props.greediness === undefined ? 1 : props.greediness, + allowedInText: !!props.allowedInText, + allowedInMath: props.allowedInMath === undefined ? true : props.allowedInMath, + numOptionalArgs: props.numOptionalArgs || 0, + infix: !!props.infix, + handler: handler + }; + + for (var i = 0; i < names.length; ++i) { + _functions[names[i]] = data; + } + + if (type) { + if (htmlBuilder) { + _htmlGroupBuilders[type] = htmlBuilder; + } + + if (mathmlBuilder) { + _mathmlGroupBuilders[type] = mathmlBuilder; + } + } +} +/** + * Use this to register only the HTML and MathML builders for a function (e.g. + * if the function's ParseNode is generated in Parser.js rather than via a + * stand-alone handler provided to `defineFunction`). + */ + +function defineFunctionBuilders(_ref2) { + var type = _ref2.type, + htmlBuilder = _ref2.htmlBuilder, + mathmlBuilder = _ref2.mathmlBuilder; + defineFunction({ + type: type, + names: [], + props: { + numArgs: 0 + }, + handler: function handler() { + throw new Error('Should never be called.'); + }, + htmlBuilder: htmlBuilder, + mathmlBuilder: mathmlBuilder + }); +} // Since the corresponding buildHTML/buildMathML function expects a +// list of elements, we normalize for different kinds of arguments + +var defineFunction_ordargument = function ordargument(arg) { + var node = checkNodeType(arg, "ordgroup"); + return node ? node.body : [arg]; +}; +// CONCATENATED MODULE: ./src/buildHTML.js +/** + * This file does the main work of building a domTree structure from a parse + * tree. The entry point is the `buildHTML` function, which takes a parse tree. + * Then, the buildExpression, buildGroup, and various groupBuilders functions + * are called, to produce a final HTML tree. + */ + + + + + + + + + +var buildHTML_makeSpan = buildCommon.makeSpan; // Binary atoms (first class `mbin`) change into ordinary atoms (`mord`) +// depending on their surroundings. See TeXbook pg. 442-446, Rules 5 and 6, +// and the text before Rule 19. + +var binLeftCanceller = ["leftmost", "mbin", "mopen", "mrel", "mop", "mpunct"]; +var binRightCanceller = ["rightmost", "mrel", "mclose", "mpunct"]; +var styleMap = { + "display": src_Style.DISPLAY, + "text": src_Style.TEXT, + "script": src_Style.SCRIPT, + "scriptscript": src_Style.SCRIPTSCRIPT +}; +var DomEnum = { + mord: "mord", + mop: "mop", + mbin: "mbin", + mrel: "mrel", + mopen: "mopen", + mclose: "mclose", + mpunct: "mpunct", + minner: "minner" +}; + +/** + * Take a list of nodes, build them in order, and return a list of the built + * nodes. documentFragments are flattened into their contents, so the + * returned list contains no fragments. `isRealGroup` is true if `expression` + * is a real group (no atoms will be added on either side), as opposed to + * a partial group (e.g. one created by \color). `surrounding` is an array + * consisting type of nodes that will be added to the left and right. + */ +var buildHTML_buildExpression = function buildExpression(expression, options, isRealGroup, surrounding) { + if (surrounding === void 0) { + surrounding = [null, null]; + } + + // Parse expressions into `groups`. + var groups = []; + + for (var i = 0; i < expression.length; i++) { + var output = buildHTML_buildGroup(expression[i], options); + + if (output instanceof tree_DocumentFragment) { + var children = output.children; + groups.push.apply(groups, children); + } else { + groups.push(output); + } + } // If `expression` is a partial group, let the parent handle spacings + // to avoid processing groups multiple times. + + + if (!isRealGroup) { + return groups; + } + + var glueOptions = options; + + if (expression.length === 1) { + var node = checkNodeType(expression[0], "sizing") || checkNodeType(expression[0], "styling"); + + if (!node) {// No match. + } else if (node.type === "sizing") { + glueOptions = options.havingSize(node.size); + } else if (node.type === "styling") { + glueOptions = options.havingStyle(styleMap[node.style]); + } + } // Dummy spans for determining spacings between surrounding atoms. + // If `expression` has no atoms on the left or right, class "leftmost" + // or "rightmost", respectively, is used to indicate it. + + + var dummyPrev = buildHTML_makeSpan([surrounding[0] || "leftmost"], [], options); + var dummyNext = buildHTML_makeSpan([surrounding[1] || "rightmost"], [], options); // TODO: These code assumes that a node's math class is the first element + // of its `classes` array. A later cleanup should ensure this, for + // instance by changing the signature of `makeSpan`. + // Before determining what spaces to insert, perform bin cancellation. + // Binary operators change to ordinary symbols in some contexts. + + traverseNonSpaceNodes(groups, function (node, prev) { + var prevType = prev.classes[0]; + var type = node.classes[0]; + + if (prevType === "mbin" && utils.contains(binRightCanceller, type)) { + prev.classes[0] = "mord"; + } else if (type === "mbin" && utils.contains(binLeftCanceller, prevType)) { + node.classes[0] = "mord"; + } + }, { + node: dummyPrev + }, dummyNext); + traverseNonSpaceNodes(groups, function (node, prev) { + var prevType = getTypeOfDomTree(prev); + var type = getTypeOfDomTree(node); // 'mtight' indicates that the node is script or scriptscript style. + + var space = prevType && type ? node.hasClass("mtight") ? tightSpacings[prevType][type] : spacings[prevType][type] : null; + + if (space) { + // Insert glue (spacing) after the `prev`. + return buildCommon.makeGlue(space, glueOptions); + } + }, { + node: dummyPrev + }, dummyNext); + return groups; +}; // Depth-first traverse non-space `nodes`, calling `callback` with the current and +// previous node as arguments, optionally returning a node to insert after the +// previous node. `prev` is an object with the previous node and `insertAfter` +// function to insert after it. `next` is a node that will be added to the right. +// Used for bin cancellation and inserting spacings. + +var traverseNonSpaceNodes = function traverseNonSpaceNodes(nodes, callback, prev, next) { + if (next) { + // temporarily append the right node, if exists + nodes.push(next); + } + + var i = 0; + + for (; i < nodes.length; i++) { + var node = nodes[i]; + var partialGroup = buildHTML_checkPartialGroup(node); + + if (partialGroup) { + // Recursive DFS + // $FlowFixMe: make nodes a $ReadOnlyArray by returning a new array + traverseNonSpaceNodes(partialGroup.children, callback, prev); + continue; + } // Ignore explicit spaces (e.g., \;, \,) when determining what implicit + // spacing should go between atoms of different classes + + + if (node.classes[0] === "mspace") { + continue; + } + + var result = callback(node, prev.node); + + if (result) { + if (prev.insertAfter) { + prev.insertAfter(result); + } else { + // insert at front + nodes.unshift(result); + i++; + } + } + + prev.node = node; + + prev.insertAfter = function (index) { + return function (n) { + nodes.splice(index + 1, 0, n); + i++; + }; + }(i); + } + + if (next) { + nodes.pop(); + } +}; // Check if given node is a partial group, i.e., does not affect spacing around. + + +var buildHTML_checkPartialGroup = function checkPartialGroup(node) { + if (node instanceof tree_DocumentFragment || node instanceof domTree_Anchor) { + return node; + } + + return null; +}; // Return the outermost node of a domTree. + + +var getOutermostNode = function getOutermostNode(node, side) { + var partialGroup = buildHTML_checkPartialGroup(node); + + if (partialGroup) { + var children = partialGroup.children; + + if (children.length) { + if (side === "right") { + return getOutermostNode(children[children.length - 1], "right"); + } else if (side === "left") { + return getOutermostNode(children[0], "left"); + } + } + } + + return node; +}; // Return math atom class (mclass) of a domTree. +// If `side` is given, it will get the type of the outermost node at given side. + + +var getTypeOfDomTree = function getTypeOfDomTree(node, side) { + if (!node) { + return null; + } + + if (side) { + node = getOutermostNode(node, side); + } // This makes a lot of assumptions as to where the type of atom + // appears. We should do a better job of enforcing this. + + + return DomEnum[node.classes[0]] || null; +}; +var makeNullDelimiter = function makeNullDelimiter(options, classes) { + var moreClasses = ["nulldelimiter"].concat(options.baseSizingClasses()); + return buildHTML_makeSpan(classes.concat(moreClasses)); +}; +/** + * buildGroup is the function that takes a group and calls the correct groupType + * function for it. It also handles the interaction of size and style changes + * between parents and children. + */ + +var buildHTML_buildGroup = function buildGroup(group, options, baseOptions) { + if (!group) { + return buildHTML_makeSpan(); + } + + if (_htmlGroupBuilders[group.type]) { + // Call the groupBuilders function + var groupNode = _htmlGroupBuilders[group.type](group, options); // If the size changed between the parent and the current group, account + // for that size difference. + + if (baseOptions && options.size !== baseOptions.size) { + groupNode = buildHTML_makeSpan(options.sizingClasses(baseOptions), [groupNode], options); + var multiplier = options.sizeMultiplier / baseOptions.sizeMultiplier; + groupNode.height *= multiplier; + groupNode.depth *= multiplier; + } + + return groupNode; + } else { + throw new src_ParseError("Got group of unknown type: '" + group.type + "'"); + } +}; +/** + * Combine an array of HTML DOM nodes (e.g., the output of `buildExpression`) + * into an unbreakable HTML node of class .base, with proper struts to + * guarantee correct vertical extent. `buildHTML` calls this repeatedly to + * make up the entire expression as a sequence of unbreakable units. + */ + +function buildHTMLUnbreakable(children, options) { + // Compute height and depth of this chunk. + var body = buildHTML_makeSpan(["base"], children, options); // Add strut, which ensures that the top of the HTML element falls at + // the height of the expression, and the bottom of the HTML element + // falls at the depth of the expression. + // We used to have separate top and bottom struts, where the bottom strut + // would like to use `vertical-align: top`, but in IE 9 this lowers the + // baseline of the box to the bottom of this strut (instead of staying in + // the normal place) so we use an absolute value for vertical-align instead. + + var strut = buildHTML_makeSpan(["strut"]); + strut.style.height = body.height + body.depth + "em"; + strut.style.verticalAlign = -body.depth + "em"; + body.children.unshift(strut); + return body; +} +/** + * Take an entire parse tree, and build it into an appropriate set of HTML + * nodes. + */ + + +function buildHTML(tree, options) { + // Strip off outer tag wrapper for processing below. + var tag = null; + + if (tree.length === 1 && tree[0].type === "tag") { + tag = tree[0].tag; + tree = tree[0].body; + } // Build the expression contained in the tree + + + var expression = buildHTML_buildExpression(tree, options, true); + var children = []; // Create one base node for each chunk between potential line breaks. + // The TeXBook [p.173] says "A formula will be broken only after a + // relation symbol like $=$ or $<$ or $\rightarrow$, or after a binary + // operation symbol like $+$ or $-$ or $\times$, where the relation or + // binary operation is on the ``outer level'' of the formula (i.e., not + // enclosed in {...} and not part of an \over construction)." + + var parts = []; + + for (var i = 0; i < expression.length; i++) { + parts.push(expression[i]); + + if (expression[i].hasClass("mbin") || expression[i].hasClass("mrel") || expression[i].hasClass("allowbreak")) { + // Put any post-operator glue on same line as operator. + // Watch for \nobreak along the way, and stop at \newline. + var nobreak = false; + + while (i < expression.length - 1 && expression[i + 1].hasClass("mspace") && !expression[i + 1].hasClass("newline")) { + i++; + parts.push(expression[i]); + + if (expression[i].hasClass("nobreak")) { + nobreak = true; + } + } // Don't allow break if \nobreak among the post-operator glue. + + + if (!nobreak) { + children.push(buildHTMLUnbreakable(parts, options)); + parts = []; + } + } else if (expression[i].hasClass("newline")) { + // Write the line except the newline + parts.pop(); + + if (parts.length > 0) { + children.push(buildHTMLUnbreakable(parts, options)); + parts = []; + } // Put the newline at the top level + + + children.push(expression[i]); + } + } + + if (parts.length > 0) { + children.push(buildHTMLUnbreakable(parts, options)); + } // Now, if there was a tag, build it too and append it as a final child. + + + var tagChild; + + if (tag) { + tagChild = buildHTMLUnbreakable(buildHTML_buildExpression(tag, options, true)); + tagChild.classes = ["tag"]; + children.push(tagChild); + } + + var htmlNode = buildHTML_makeSpan(["katex-html"], children); + htmlNode.setAttribute("aria-hidden", "true"); // Adjust the strut of the tag to be the maximum height of all children + // (the height of the enclosing htmlNode) for proper vertical alignment. + + if (tagChild) { + var strut = tagChild.children[0]; + strut.style.height = htmlNode.height + htmlNode.depth + "em"; + strut.style.verticalAlign = -htmlNode.depth + "em"; + } + + return htmlNode; +} +// CONCATENATED MODULE: ./src/mathMLTree.js +/** + * These objects store data about MathML nodes. This is the MathML equivalent + * of the types in domTree.js. Since MathML handles its own rendering, and + * since we're mainly using MathML to improve accessibility, we don't manage + * any of the styling state that the plain DOM nodes do. + * + * The `toNode` and `toMarkup` functions work simlarly to how they do in + * domTree.js, creating namespaced DOM nodes and HTML text markup respectively. + */ + + +function newDocumentFragment(children) { + return new tree_DocumentFragment(children); +} +/** + * This node represents a general purpose MathML node of any type. The + * constructor requires the type of node to create (for example, `"mo"` or + * `"mspace"`, corresponding to `` and `` tags). + */ + +var mathMLTree_MathNode = +/*#__PURE__*/ +function () { + function MathNode(type, children) { + this.type = void 0; + this.attributes = void 0; + this.children = void 0; + this.type = type; + this.attributes = {}; + this.children = children || []; + } + /** + * Sets an attribute on a MathML node. MathML depends on attributes to convey a + * semantic content, so this is used heavily. + */ + + + var _proto = MathNode.prototype; + + _proto.setAttribute = function setAttribute(name, value) { + this.attributes[name] = value; + } + /** + * Gets an attribute on a MathML node. + */ + ; + + _proto.getAttribute = function getAttribute(name) { + return this.attributes[name]; + } + /** + * Converts the math node into a MathML-namespaced DOM element. + */ + ; + + _proto.toNode = function toNode() { + var node = document.createElementNS("http://www.w3.org/1998/Math/MathML", this.type); + + for (var attr in this.attributes) { + if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) { + node.setAttribute(attr, this.attributes[attr]); + } + } + + for (var i = 0; i < this.children.length; i++) { + node.appendChild(this.children[i].toNode()); + } + + return node; + } + /** + * Converts the math node into an HTML markup string. + */ + ; + + _proto.toMarkup = function toMarkup() { + var markup = "<" + this.type; // Add the attributes + + for (var attr in this.attributes) { + if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) { + markup += " " + attr + "=\""; + markup += utils.escape(this.attributes[attr]); + markup += "\""; + } + } + + markup += ">"; + + for (var i = 0; i < this.children.length; i++) { + markup += this.children[i].toMarkup(); + } + + markup += ""; + return markup; + } + /** + * Converts the math node into a string, similar to innerText, but escaped. + */ + ; + + _proto.toText = function toText() { + return this.children.map(function (child) { + return child.toText(); + }).join(""); + }; + + return MathNode; +}(); +/** + * This node represents a piece of text. + */ + +var mathMLTree_TextNode = +/*#__PURE__*/ +function () { + function TextNode(text) { + this.text = void 0; + this.text = text; + } + /** + * Converts the text node into a DOM text node. + */ + + + var _proto2 = TextNode.prototype; + + _proto2.toNode = function toNode() { + return document.createTextNode(this.text); + } + /** + * Converts the text node into escaped HTML markup + * (representing the text itself). + */ + ; + + _proto2.toMarkup = function toMarkup() { + return utils.escape(this.toText()); + } + /** + * Converts the text node into a string + * (representing the text iteself). + */ + ; + + _proto2.toText = function toText() { + return this.text; + }; + + return TextNode; +}(); +/** + * This node represents a space, but may render as or as text, + * depending on the width. + */ + +var SpaceNode = +/*#__PURE__*/ +function () { + /** + * Create a Space node with width given in CSS ems. + */ + function SpaceNode(width) { + this.width = void 0; + this.character = void 0; + this.width = width; // See https://www.w3.org/TR/2000/WD-MathML2-20000328/chapter6.html + // for a table of space-like characters. We use Unicode + // representations instead of &LongNames; as it's not clear how to + // make the latter via document.createTextNode. + + if (width >= 0.05555 && width <= 0.05556) { + this.character = "\u200A"; //   + } else if (width >= 0.1666 && width <= 0.1667) { + this.character = "\u2009"; //   + } else if (width >= 0.2222 && width <= 0.2223) { + this.character = "\u2005"; //   + } else if (width >= 0.2777 && width <= 0.2778) { + this.character = "\u2005\u200A"; //    + } else if (width >= -0.05556 && width <= -0.05555) { + this.character = "\u200A\u2063"; // ​ + } else if (width >= -0.1667 && width <= -0.1666) { + this.character = "\u2009\u2063"; // ​ + } else if (width >= -0.2223 && width <= -0.2222) { + this.character = "\u205F\u2063"; // ​ + } else if (width >= -0.2778 && width <= -0.2777) { + this.character = "\u2005\u2063"; // ​ + } else { + this.character = null; + } + } + /** + * Converts the math node into a MathML-namespaced DOM element. + */ + + + var _proto3 = SpaceNode.prototype; + + _proto3.toNode = function toNode() { + if (this.character) { + return document.createTextNode(this.character); + } else { + var node = document.createElementNS("http://www.w3.org/1998/Math/MathML", "mspace"); + node.setAttribute("width", this.width + "em"); + return node; + } + } + /** + * Converts the math node into an HTML markup string. + */ + ; + + _proto3.toMarkup = function toMarkup() { + if (this.character) { + return "" + this.character + ""; + } else { + return ""; + } + } + /** + * Converts the math node into a string, similar to innerText. + */ + ; + + _proto3.toText = function toText() { + if (this.character) { + return this.character; + } else { + return " "; + } + }; + + return SpaceNode; +}(); + +/* harmony default export */ var mathMLTree = ({ + MathNode: mathMLTree_MathNode, + TextNode: mathMLTree_TextNode, + SpaceNode: SpaceNode, + newDocumentFragment: newDocumentFragment +}); +// CONCATENATED MODULE: ./src/buildMathML.js +/** + * This file converts a parse tree into a cooresponding MathML tree. The main + * entry point is the `buildMathML` function, which takes a parse tree from the + * parser. + */ + + + + + + + + + +/** + * Takes a symbol and converts it into a MathML text node after performing + * optional replacement from symbols.js. + */ +var buildMathML_makeText = function makeText(text, mode, options) { + if (src_symbols[mode][text] && src_symbols[mode][text].replace && text.charCodeAt(0) !== 0xD835 && !(ligatures.hasOwnProperty(text) && options && (options.fontFamily && options.fontFamily.substr(4, 2) === "tt" || options.font && options.font.substr(4, 2) === "tt"))) { + text = src_symbols[mode][text].replace; + } + + return new mathMLTree.TextNode(text); +}; +/** + * Wrap the given array of nodes in an node if needed, i.e., + * unless the array has length 1. Always returns a single node. + */ + +var buildMathML_makeRow = function makeRow(body) { + if (body.length === 1) { + return body[0]; + } else { + return new mathMLTree.MathNode("mrow", body); + } +}; +/** + * Returns the math variant as a string or null if none is required. + */ + +var buildMathML_getVariant = function getVariant(group, options) { + // Handle \text... font specifiers as best we can. + // MathML has a limited list of allowable mathvariant specifiers; see + // https://www.w3.org/TR/MathML3/chapter3.html#presm.commatt + if (options.fontFamily === "texttt") { + return "monospace"; + } else if (options.fontFamily === "textsf") { + if (options.fontShape === "textit" && options.fontWeight === "textbf") { + return "sans-serif-bold-italic"; + } else if (options.fontShape === "textit") { + return "sans-serif-italic"; + } else if (options.fontWeight === "textbf") { + return "bold-sans-serif"; + } else { + return "sans-serif"; + } + } else if (options.fontShape === "textit" && options.fontWeight === "textbf") { + return "bold-italic"; + } else if (options.fontShape === "textit") { + return "italic"; + } else if (options.fontWeight === "textbf") { + return "bold"; + } + + var font = options.font; + + if (!font || font === "mathnormal") { + return null; + } + + var mode = group.mode; + + if (font === "mathit") { + return "italic"; + } else if (font === "boldsymbol") { + return "bold-italic"; + } else if (font === "mathbf") { + return "bold"; + } else if (font === "mathbb") { + return "double-struck"; + } else if (font === "mathfrak") { + return "fraktur"; + } else if (font === "mathscr" || font === "mathcal") { + // MathML makes no distinction between script and caligrahpic + return "script"; + } else if (font === "mathsf") { + return "sans-serif"; + } else if (font === "mathtt") { + return "monospace"; + } + + var text = group.text; + + if (utils.contains(["\\imath", "\\jmath"], text)) { + return null; + } + + if (src_symbols[mode][text] && src_symbols[mode][text].replace) { + text = src_symbols[mode][text].replace; + } + + var fontName = buildCommon.fontMap[font].fontName; + + if (getCharacterMetrics(text, fontName, mode)) { + return buildCommon.fontMap[font].variant; + } + + return null; +}; +/** + * Takes a list of nodes, builds them, and returns a list of the generated + * MathML nodes. Also combine consecutive outputs into a single + * tag. + */ + +var buildMathML_buildExpression = function buildExpression(expression, options, isOrdgroup) { + if (expression.length === 1) { + var group = buildMathML_buildGroup(expression[0], options); + + if (isOrdgroup && group instanceof mathMLTree_MathNode && group.type === "mo") { + // When TeX writers want to suppress spacing on an operator, + // they often put the operator by itself inside braces. + group.setAttribute("lspace", "0em"); + group.setAttribute("rspace", "0em"); + } + + return [group]; + } + + var groups = []; + var lastGroup; + + for (var i = 0; i < expression.length; i++) { + var _group = buildMathML_buildGroup(expression[i], options); + + if (_group instanceof mathMLTree_MathNode && lastGroup instanceof mathMLTree_MathNode) { + // Concatenate adjacent s + if (_group.type === 'mtext' && lastGroup.type === 'mtext' && _group.getAttribute('mathvariant') === lastGroup.getAttribute('mathvariant')) { + var _lastGroup$children; + + (_lastGroup$children = lastGroup.children).push.apply(_lastGroup$children, _group.children); + + continue; // Concatenate adjacent s + } else if (_group.type === 'mn' && lastGroup.type === 'mn') { + var _lastGroup$children2; + + (_lastGroup$children2 = lastGroup.children).push.apply(_lastGroup$children2, _group.children); + + continue; // Concatenate ... followed by . + } else if (_group.type === 'mi' && _group.children.length === 1 && lastGroup.type === 'mn') { + var child = _group.children[0]; + + if (child instanceof mathMLTree_TextNode && child.text === '.') { + var _lastGroup$children3; + + (_lastGroup$children3 = lastGroup.children).push.apply(_lastGroup$children3, _group.children); + + continue; + } + } else if (lastGroup.type === 'mi' && lastGroup.children.length === 1) { + var lastChild = lastGroup.children[0]; + + if (lastChild instanceof mathMLTree_TextNode && lastChild.text === "\u0338" && (_group.type === 'mo' || _group.type === 'mi' || _group.type === 'mn')) { + var _child = _group.children[0]; + + if (_child instanceof mathMLTree_TextNode && _child.text.length > 0) { + // Overlay with combining character long solidus + _child.text = _child.text.slice(0, 1) + "\u0338" + _child.text.slice(1); + groups.pop(); + } + } + } + } + + groups.push(_group); + lastGroup = _group; + } + + return groups; +}; +/** + * Equivalent to buildExpression, but wraps the elements in an + * if there's more than one. Returns a single node instead of an array. + */ + +var buildExpressionRow = function buildExpressionRow(expression, options, isOrdgroup) { + return buildMathML_makeRow(buildMathML_buildExpression(expression, options, isOrdgroup)); +}; +/** + * Takes a group from the parser and calls the appropriate groupBuilders function + * on it to produce a MathML node. + */ + +var buildMathML_buildGroup = function buildGroup(group, options) { + if (!group) { + return new mathMLTree.MathNode("mrow"); + } + + if (_mathmlGroupBuilders[group.type]) { + // Call the groupBuilders function + var result = _mathmlGroupBuilders[group.type](group, options); + return result; + } else { + throw new src_ParseError("Got group of unknown type: '" + group.type + "'"); + } +}; +/** + * Takes a full parse tree and settings and builds a MathML representation of + * it. In particular, we put the elements from building the parse tree into a + * tag so we can also include that TeX source as an annotation. + * + * Note that we actually return a domTree element with a `` inside it so + * we can do appropriate styling. + */ + +function buildMathML(tree, texExpression, options, forMathmlOnly) { + var expression = buildMathML_buildExpression(tree, options); // Wrap up the expression in an mrow so it is presented in the semantics + // tag correctly, unless it's a single or . + + var wrapper; + + if (expression.length === 1 && expression[0] instanceof mathMLTree_MathNode && utils.contains(["mrow", "mtable"], expression[0].type)) { + wrapper = expression[0]; + } else { + wrapper = new mathMLTree.MathNode("mrow", expression); + } // Build a TeX annotation of the source + + + var annotation = new mathMLTree.MathNode("annotation", [new mathMLTree.TextNode(texExpression)]); + annotation.setAttribute("encoding", "application/x-tex"); + var semantics = new mathMLTree.MathNode("semantics", [wrapper, annotation]); + var math = new mathMLTree.MathNode("math", [semantics]); + math.setAttribute("xmlns", "http://www.w3.org/1998/Math/MathML"); // You can't style nodes, so we wrap the node in a span. + // NOTE: The span class is not typed to have nodes as children, and + // we don't want to make the children type more generic since the children + // of span are expected to have more fields in `buildHtml` contexts. + + var wrapperClass = forMathmlOnly ? "katex" : "katex-mathml"; // $FlowFixMe + + return buildCommon.makeSpan([wrapperClass], [math]); +} +// CONCATENATED MODULE: ./src/buildTree.js + + + + + + + +var buildTree_optionsFromSettings = function optionsFromSettings(settings) { + return new src_Options({ + style: settings.displayMode ? src_Style.DISPLAY : src_Style.TEXT, + maxSize: settings.maxSize, + minRuleThickness: settings.minRuleThickness + }); +}; + +var buildTree_displayWrap = function displayWrap(node, settings) { + if (settings.displayMode) { + var classes = ["katex-display"]; + + if (settings.leqno) { + classes.push("leqno"); + } + + if (settings.fleqn) { + classes.push("fleqn"); + } + + node = buildCommon.makeSpan(classes, [node]); + } + + return node; +}; + +var buildTree_buildTree = function buildTree(tree, expression, settings) { + var options = buildTree_optionsFromSettings(settings); + var katexNode; + + if (settings.output === "mathml") { + return buildMathML(tree, expression, options, true); + } else if (settings.output === "html") { + var htmlNode = buildHTML(tree, options); + katexNode = buildCommon.makeSpan(["katex"], [htmlNode]); + } else { + var mathMLNode = buildMathML(tree, expression, options, false); + + var _htmlNode = buildHTML(tree, options); + + katexNode = buildCommon.makeSpan(["katex"], [mathMLNode, _htmlNode]); + } + + return buildTree_displayWrap(katexNode, settings); +}; +var buildTree_buildHTMLTree = function buildHTMLTree(tree, expression, settings) { + var options = buildTree_optionsFromSettings(settings); + var htmlNode = buildHTML(tree, options); + var katexNode = buildCommon.makeSpan(["katex"], [htmlNode]); + return buildTree_displayWrap(katexNode, settings); +}; +/* harmony default export */ var src_buildTree = (buildTree_buildTree); +// CONCATENATED MODULE: ./src/stretchy.js +/** + * This file provides support to buildMathML.js and buildHTML.js + * for stretchy wide elements rendered from SVG files + * and other CSS trickery. + */ + + + + +var stretchyCodePoint = { + widehat: "^", + widecheck: "ˇ", + widetilde: "~", + utilde: "~", + overleftarrow: "\u2190", + underleftarrow: "\u2190", + xleftarrow: "\u2190", + overrightarrow: "\u2192", + underrightarrow: "\u2192", + xrightarrow: "\u2192", + underbrace: "\u23DF", + overbrace: "\u23DE", + overgroup: "\u23E0", + undergroup: "\u23E1", + overleftrightarrow: "\u2194", + underleftrightarrow: "\u2194", + xleftrightarrow: "\u2194", + Overrightarrow: "\u21D2", + xRightarrow: "\u21D2", + overleftharpoon: "\u21BC", + xleftharpoonup: "\u21BC", + overrightharpoon: "\u21C0", + xrightharpoonup: "\u21C0", + xLeftarrow: "\u21D0", + xLeftrightarrow: "\u21D4", + xhookleftarrow: "\u21A9", + xhookrightarrow: "\u21AA", + xmapsto: "\u21A6", + xrightharpoondown: "\u21C1", + xleftharpoondown: "\u21BD", + xrightleftharpoons: "\u21CC", + xleftrightharpoons: "\u21CB", + xtwoheadleftarrow: "\u219E", + xtwoheadrightarrow: "\u21A0", + xlongequal: "=", + xtofrom: "\u21C4", + xrightleftarrows: "\u21C4", + xrightequilibrium: "\u21CC", + // Not a perfect match. + xleftequilibrium: "\u21CB" // None better available. + +}; + +var stretchy_mathMLnode = function mathMLnode(label) { + var node = new mathMLTree.MathNode("mo", [new mathMLTree.TextNode(stretchyCodePoint[label.substr(1)])]); + node.setAttribute("stretchy", "true"); + return node; +}; // Many of the KaTeX SVG images have been adapted from glyphs in KaTeX fonts. +// Copyright (c) 2009-2010, Design Science, Inc. () +// Copyright (c) 2014-2017 Khan Academy () +// Licensed under the SIL Open Font License, Version 1.1. +// See \nhttp://scripts.sil.org/OFL +// Very Long SVGs +// Many of the KaTeX stretchy wide elements use a long SVG image and an +// overflow: hidden tactic to achieve a stretchy image while avoiding +// distortion of arrowheads or brace corners. +// The SVG typically contains a very long (400 em) arrow. +// The SVG is in a container span that has overflow: hidden, so the span +// acts like a window that exposes only part of the SVG. +// The SVG always has a longer, thinner aspect ratio than the container span. +// After the SVG fills 100% of the height of the container span, +// there is a long arrow shaft left over. That left-over shaft is not shown. +// Instead, it is sliced off because the span's CSS has overflow: hidden. +// Thus, the reader sees an arrow that matches the subject matter width +// without distortion. +// Some functions, such as \cancel, need to vary their aspect ratio. These +// functions do not get the overflow SVG treatment. +// Second Brush Stroke +// Low resolution monitors struggle to display images in fine detail. +// So browsers apply anti-aliasing. A long straight arrow shaft therefore +// will sometimes appear as if it has a blurred edge. +// To mitigate this, these SVG files contain a second "brush-stroke" on the +// arrow shafts. That is, a second long thin rectangular SVG path has been +// written directly on top of each arrow shaft. This reinforcement causes +// some of the screen pixels to display as black instead of the anti-aliased +// gray pixel that a single path would generate. So we get arrow shafts +// whose edges appear to be sharper. +// In the katexImagesData object just below, the dimensions all +// correspond to path geometry inside the relevant SVG. +// For example, \overrightarrow uses the same arrowhead as glyph U+2192 +// from the KaTeX Main font. The scaling factor is 1000. +// That is, inside the font, that arrowhead is 522 units tall, which +// corresponds to 0.522 em inside the document. + + +var katexImagesData = { + // path(s), minWidth, height, align + overrightarrow: [["rightarrow"], 0.888, 522, "xMaxYMin"], + overleftarrow: [["leftarrow"], 0.888, 522, "xMinYMin"], + underrightarrow: [["rightarrow"], 0.888, 522, "xMaxYMin"], + underleftarrow: [["leftarrow"], 0.888, 522, "xMinYMin"], + xrightarrow: [["rightarrow"], 1.469, 522, "xMaxYMin"], + xleftarrow: [["leftarrow"], 1.469, 522, "xMinYMin"], + Overrightarrow: [["doublerightarrow"], 0.888, 560, "xMaxYMin"], + xRightarrow: [["doublerightarrow"], 1.526, 560, "xMaxYMin"], + xLeftarrow: [["doubleleftarrow"], 1.526, 560, "xMinYMin"], + overleftharpoon: [["leftharpoon"], 0.888, 522, "xMinYMin"], + xleftharpoonup: [["leftharpoon"], 0.888, 522, "xMinYMin"], + xleftharpoondown: [["leftharpoondown"], 0.888, 522, "xMinYMin"], + overrightharpoon: [["rightharpoon"], 0.888, 522, "xMaxYMin"], + xrightharpoonup: [["rightharpoon"], 0.888, 522, "xMaxYMin"], + xrightharpoondown: [["rightharpoondown"], 0.888, 522, "xMaxYMin"], + xlongequal: [["longequal"], 0.888, 334, "xMinYMin"], + xtwoheadleftarrow: [["twoheadleftarrow"], 0.888, 334, "xMinYMin"], + xtwoheadrightarrow: [["twoheadrightarrow"], 0.888, 334, "xMaxYMin"], + overleftrightarrow: [["leftarrow", "rightarrow"], 0.888, 522], + overbrace: [["leftbrace", "midbrace", "rightbrace"], 1.6, 548], + underbrace: [["leftbraceunder", "midbraceunder", "rightbraceunder"], 1.6, 548], + underleftrightarrow: [["leftarrow", "rightarrow"], 0.888, 522], + xleftrightarrow: [["leftarrow", "rightarrow"], 1.75, 522], + xLeftrightarrow: [["doubleleftarrow", "doublerightarrow"], 1.75, 560], + xrightleftharpoons: [["leftharpoondownplus", "rightharpoonplus"], 1.75, 716], + xleftrightharpoons: [["leftharpoonplus", "rightharpoondownplus"], 1.75, 716], + xhookleftarrow: [["leftarrow", "righthook"], 1.08, 522], + xhookrightarrow: [["lefthook", "rightarrow"], 1.08, 522], + overlinesegment: [["leftlinesegment", "rightlinesegment"], 0.888, 522], + underlinesegment: [["leftlinesegment", "rightlinesegment"], 0.888, 522], + overgroup: [["leftgroup", "rightgroup"], 0.888, 342], + undergroup: [["leftgroupunder", "rightgroupunder"], 0.888, 342], + xmapsto: [["leftmapsto", "rightarrow"], 1.5, 522], + xtofrom: [["leftToFrom", "rightToFrom"], 1.75, 528], + // The next three arrows are from the mhchem package. + // In mhchem.sty, min-length is 2.0em. But these arrows might appear in the + // document as \xrightarrow or \xrightleftharpoons. Those have + // min-length = 1.75em, so we set min-length on these next three to match. + xrightleftarrows: [["baraboveleftarrow", "rightarrowabovebar"], 1.75, 901], + xrightequilibrium: [["baraboveshortleftharpoon", "rightharpoonaboveshortbar"], 1.75, 716], + xleftequilibrium: [["shortbaraboveleftharpoon", "shortrightharpoonabovebar"], 1.75, 716] +}; + +var groupLength = function groupLength(arg) { + if (arg.type === "ordgroup") { + return arg.body.length; + } else { + return 1; + } +}; + +var stretchy_svgSpan = function svgSpan(group, options) { + // Create a span with inline SVG for the element. + function buildSvgSpan_() { + var viewBoxWidth = 400000; // default + + var label = group.label.substr(1); + + if (utils.contains(["widehat", "widecheck", "widetilde", "utilde"], label)) { + // Each type in the `if` statement corresponds to one of the ParseNode + // types below. This narrowing is required to access `grp.base`. + var grp = group; // There are four SVG images available for each function. + // Choose a taller image when there are more characters. + + var numChars = groupLength(grp.base); + var viewBoxHeight; + var pathName; + + var _height; + + if (numChars > 5) { + if (label === "widehat" || label === "widecheck") { + viewBoxHeight = 420; + viewBoxWidth = 2364; + _height = 0.42; + pathName = label + "4"; + } else { + viewBoxHeight = 312; + viewBoxWidth = 2340; + _height = 0.34; + pathName = "tilde4"; + } + } else { + var imgIndex = [1, 1, 2, 2, 3, 3][numChars]; + + if (label === "widehat" || label === "widecheck") { + viewBoxWidth = [0, 1062, 2364, 2364, 2364][imgIndex]; + viewBoxHeight = [0, 239, 300, 360, 420][imgIndex]; + _height = [0, 0.24, 0.3, 0.3, 0.36, 0.42][imgIndex]; + pathName = label + imgIndex; + } else { + viewBoxWidth = [0, 600, 1033, 2339, 2340][imgIndex]; + viewBoxHeight = [0, 260, 286, 306, 312][imgIndex]; + _height = [0, 0.26, 0.286, 0.3, 0.306, 0.34][imgIndex]; + pathName = "tilde" + imgIndex; + } + } + + var path = new domTree_PathNode(pathName); + var svgNode = new SvgNode([path], { + "width": "100%", + "height": _height + "em", + "viewBox": "0 0 " + viewBoxWidth + " " + viewBoxHeight, + "preserveAspectRatio": "none" + }); + return { + span: buildCommon.makeSvgSpan([], [svgNode], options), + minWidth: 0, + height: _height + }; + } else { + var spans = []; + var data = katexImagesData[label]; + var paths = data[0], + _minWidth = data[1], + _viewBoxHeight = data[2]; + + var _height2 = _viewBoxHeight / 1000; + + var numSvgChildren = paths.length; + var widthClasses; + var aligns; + + if (numSvgChildren === 1) { + // $FlowFixMe: All these cases must be of the 4-tuple type. + var align1 = data[3]; + widthClasses = ["hide-tail"]; + aligns = [align1]; + } else if (numSvgChildren === 2) { + widthClasses = ["halfarrow-left", "halfarrow-right"]; + aligns = ["xMinYMin", "xMaxYMin"]; + } else if (numSvgChildren === 3) { + widthClasses = ["brace-left", "brace-center", "brace-right"]; + aligns = ["xMinYMin", "xMidYMin", "xMaxYMin"]; + } else { + throw new Error("Correct katexImagesData or update code here to support\n " + numSvgChildren + " children."); + } + + for (var i = 0; i < numSvgChildren; i++) { + var _path = new domTree_PathNode(paths[i]); + + var _svgNode = new SvgNode([_path], { + "width": "400em", + "height": _height2 + "em", + "viewBox": "0 0 " + viewBoxWidth + " " + _viewBoxHeight, + "preserveAspectRatio": aligns[i] + " slice" + }); + + var _span = buildCommon.makeSvgSpan([widthClasses[i]], [_svgNode], options); + + if (numSvgChildren === 1) { + return { + span: _span, + minWidth: _minWidth, + height: _height2 + }; + } else { + _span.style.height = _height2 + "em"; + spans.push(_span); + } + } + + return { + span: buildCommon.makeSpan(["stretchy"], spans, options), + minWidth: _minWidth, + height: _height2 + }; + } + } // buildSvgSpan_() + + + var _buildSvgSpan_ = buildSvgSpan_(), + span = _buildSvgSpan_.span, + minWidth = _buildSvgSpan_.minWidth, + height = _buildSvgSpan_.height; // Note that we are returning span.depth = 0. + // Any adjustments relative to the baseline must be done in buildHTML. + + + span.height = height; + span.style.height = height + "em"; + + if (minWidth > 0) { + span.style.minWidth = minWidth + "em"; + } + + return span; +}; + +var stretchy_encloseSpan = function encloseSpan(inner, label, pad, options) { + // Return an image span for \cancel, \bcancel, \xcancel, or \fbox + var img; + var totalHeight = inner.height + inner.depth + 2 * pad; + + if (/fbox|color/.test(label)) { + img = buildCommon.makeSpan(["stretchy", label], [], options); + + if (label === "fbox") { + var color = options.color && options.getColor(); + + if (color) { + img.style.borderColor = color; + } + } + } else { + // \cancel, \bcancel, or \xcancel + // Since \cancel's SVG is inline and it omits the viewBox attribute, + // its stroke-width will not vary with span area. + var lines = []; + + if (/^[bx]cancel$/.test(label)) { + lines.push(new LineNode({ + "x1": "0", + "y1": "0", + "x2": "100%", + "y2": "100%", + "stroke-width": "0.046em" + })); + } + + if (/^x?cancel$/.test(label)) { + lines.push(new LineNode({ + "x1": "0", + "y1": "100%", + "x2": "100%", + "y2": "0", + "stroke-width": "0.046em" + })); + } + + var svgNode = new SvgNode(lines, { + "width": "100%", + "height": totalHeight + "em" + }); + img = buildCommon.makeSvgSpan([], [svgNode], options); + } + + img.height = totalHeight; + img.style.height = totalHeight + "em"; + return img; +}; + +/* harmony default export */ var stretchy = ({ + encloseSpan: stretchy_encloseSpan, + mathMLnode: stretchy_mathMLnode, + svgSpan: stretchy_svgSpan +}); +// CONCATENATED MODULE: ./src/functions/accent.js + + + + + + + + + +// NOTE: Unlike most `htmlBuilder`s, this one handles not only "accent", but +var accent_htmlBuilder = function htmlBuilder(grp, options) { + // Accents are handled in the TeXbook pg. 443, rule 12. + var base; + var group; + var supSub = checkNodeType(grp, "supsub"); + var supSubGroup; + + if (supSub) { + // If our base is a character box, and we have superscripts and + // subscripts, the supsub will defer to us. In particular, we want + // to attach the superscripts and subscripts to the inner body (so + // that the position of the superscripts and subscripts won't be + // affected by the height of the accent). We accomplish this by + // sticking the base of the accent into the base of the supsub, and + // rendering that, while keeping track of where the accent is. + // The real accent group is the base of the supsub group + group = assertNodeType(supSub.base, "accent"); // The character box is the base of the accent group + + base = group.base; // Stick the character box into the base of the supsub group + + supSub.base = base; // Rerender the supsub group with its new base, and store that + // result. + + supSubGroup = assertSpan(buildHTML_buildGroup(supSub, options)); // reset original base + + supSub.base = group; + } else { + group = assertNodeType(grp, "accent"); + base = group.base; + } // Build the base group + + + var body = buildHTML_buildGroup(base, options.havingCrampedStyle()); // Does the accent need to shift for the skew of a character? + + var mustShift = group.isShifty && utils.isCharacterBox(base); // Calculate the skew of the accent. This is based on the line "If the + // nucleus is not a single character, let s = 0; otherwise set s to the + // kern amount for the nucleus followed by the \skewchar of its font." + // Note that our skew metrics are just the kern between each character + // and the skewchar. + + var skew = 0; + + if (mustShift) { + // If the base is a character box, then we want the skew of the + // innermost character. To do that, we find the innermost character: + var baseChar = utils.getBaseElem(base); // Then, we render its group to get the symbol inside it + + var baseGroup = buildHTML_buildGroup(baseChar, options.havingCrampedStyle()); // Finally, we pull the skew off of the symbol. + + skew = assertSymbolDomNode(baseGroup).skew; // Note that we now throw away baseGroup, because the layers we + // removed with getBaseElem might contain things like \color which + // we can't get rid of. + // TODO(emily): Find a better way to get the skew + } // calculate the amount of space between the body and the accent + + + var clearance = Math.min(body.height, options.fontMetrics().xHeight); // Build the accent + + var accentBody; + + if (!group.isStretchy) { + var accent; + var width; + + if (group.label === "\\vec") { + // Before version 0.9, \vec used the combining font glyph U+20D7. + // But browsers, especially Safari, are not consistent in how they + // render combining characters when not preceded by a character. + // So now we use an SVG. + // If Safari reforms, we should consider reverting to the glyph. + accent = buildCommon.staticSvg("vec", options); + width = buildCommon.svgData.vec[1]; + } else { + accent = buildCommon.makeOrd({ + mode: group.mode, + text: group.label + }, options, "textord"); + accent = assertSymbolDomNode(accent); // Remove the italic correction of the accent, because it only serves to + // shift the accent over to a place we don't want. + + accent.italic = 0; + width = accent.width; + } + + accentBody = buildCommon.makeSpan(["accent-body"], [accent]); // "Full" accents expand the width of the resulting symbol to be + // at least the width of the accent, and overlap directly onto the + // character without any vertical offset. + + var accentFull = group.label === "\\textcircled"; + + if (accentFull) { + accentBody.classes.push('accent-full'); + clearance = body.height; + } // Shift the accent over by the skew. + + + var left = skew; // CSS defines `.katex .accent .accent-body:not(.accent-full) { width: 0 }` + // so that the accent doesn't contribute to the bounding box. + // We need to shift the character by its width (effectively half + // its width) to compensate. + + if (!accentFull) { + left -= width / 2; + } + + accentBody.style.left = left + "em"; // \textcircled uses the \bigcirc glyph, so it needs some + // vertical adjustment to match LaTeX. + + if (group.label === "\\textcircled") { + accentBody.style.top = ".2em"; + } + + accentBody = buildCommon.makeVList({ + positionType: "firstBaseline", + children: [{ + type: "elem", + elem: body + }, { + type: "kern", + size: -clearance + }, { + type: "elem", + elem: accentBody + }] + }, options); + } else { + accentBody = stretchy.svgSpan(group, options); + accentBody = buildCommon.makeVList({ + positionType: "firstBaseline", + children: [{ + type: "elem", + elem: body + }, { + type: "elem", + elem: accentBody, + wrapperClasses: ["svg-align"], + wrapperStyle: skew > 0 ? { + width: "calc(100% - " + 2 * skew + "em)", + marginLeft: 2 * skew + "em" + } : undefined + }] + }, options); + } + + var accentWrap = buildCommon.makeSpan(["mord", "accent"], [accentBody], options); + + if (supSubGroup) { + // Here, we replace the "base" child of the supsub with our newly + // generated accent. + supSubGroup.children[0] = accentWrap; // Since we don't rerun the height calculation after replacing the + // accent, we manually recalculate height. + + supSubGroup.height = Math.max(accentWrap.height, supSubGroup.height); // Accents should always be ords, even when their innards are not. + + supSubGroup.classes[0] = "mord"; + return supSubGroup; + } else { + return accentWrap; + } +}; + +var accent_mathmlBuilder = function mathmlBuilder(group, options) { + var accentNode = group.isStretchy ? stretchy.mathMLnode(group.label) : new mathMLTree.MathNode("mo", [buildMathML_makeText(group.label, group.mode)]); + var node = new mathMLTree.MathNode("mover", [buildMathML_buildGroup(group.base, options), accentNode]); + node.setAttribute("accent", "true"); + return node; +}; + +var NON_STRETCHY_ACCENT_REGEX = new RegExp(["\\acute", "\\grave", "\\ddot", "\\tilde", "\\bar", "\\breve", "\\check", "\\hat", "\\vec", "\\dot", "\\mathring"].map(function (accent) { + return "\\" + accent; +}).join("|")); // Accents + +defineFunction({ + type: "accent", + names: ["\\acute", "\\grave", "\\ddot", "\\tilde", "\\bar", "\\breve", "\\check", "\\hat", "\\vec", "\\dot", "\\mathring", "\\widecheck", "\\widehat", "\\widetilde", "\\overrightarrow", "\\overleftarrow", "\\Overrightarrow", "\\overleftrightarrow", "\\overgroup", "\\overlinesegment", "\\overleftharpoon", "\\overrightharpoon"], + props: { + numArgs: 1 + }, + handler: function handler(context, args) { + var base = args[0]; + var isStretchy = !NON_STRETCHY_ACCENT_REGEX.test(context.funcName); + var isShifty = !isStretchy || context.funcName === "\\widehat" || context.funcName === "\\widetilde" || context.funcName === "\\widecheck"; + return { + type: "accent", + mode: context.parser.mode, + label: context.funcName, + isStretchy: isStretchy, + isShifty: isShifty, + base: base + }; + }, + htmlBuilder: accent_htmlBuilder, + mathmlBuilder: accent_mathmlBuilder +}); // Text-mode accents + +defineFunction({ + type: "accent", + names: ["\\'", "\\`", "\\^", "\\~", "\\=", "\\u", "\\.", '\\"', "\\r", "\\H", "\\v", "\\textcircled"], + props: { + numArgs: 1, + allowedInText: true, + allowedInMath: false + }, + handler: function handler(context, args) { + var base = args[0]; + return { + type: "accent", + mode: context.parser.mode, + label: context.funcName, + isStretchy: false, + isShifty: true, + base: base + }; + }, + htmlBuilder: accent_htmlBuilder, + mathmlBuilder: accent_mathmlBuilder +}); +// CONCATENATED MODULE: ./src/functions/accentunder.js +// Horizontal overlap functions + + + + + + +defineFunction({ + type: "accentUnder", + names: ["\\underleftarrow", "\\underrightarrow", "\\underleftrightarrow", "\\undergroup", "\\underlinesegment", "\\utilde"], + props: { + numArgs: 1 + }, + handler: function handler(_ref, args) { + var parser = _ref.parser, + funcName = _ref.funcName; + var base = args[0]; + return { + type: "accentUnder", + mode: parser.mode, + label: funcName, + base: base + }; + }, + htmlBuilder: function htmlBuilder(group, options) { + // Treat under accents much like underlines. + var innerGroup = buildHTML_buildGroup(group.base, options); + var accentBody = stretchy.svgSpan(group, options); + var kern = group.label === "\\utilde" ? 0.12 : 0; // Generate the vlist, with the appropriate kerns + + var vlist = buildCommon.makeVList({ + positionType: "bottom", + positionData: accentBody.height + kern, + children: [{ + type: "elem", + elem: accentBody, + wrapperClasses: ["svg-align"] + }, { + type: "kern", + size: kern + }, { + type: "elem", + elem: innerGroup + }] + }, options); + return buildCommon.makeSpan(["mord", "accentunder"], [vlist], options); + }, + mathmlBuilder: function mathmlBuilder(group, options) { + var accentNode = stretchy.mathMLnode(group.label); + var node = new mathMLTree.MathNode("munder", [buildMathML_buildGroup(group.base, options), accentNode]); + node.setAttribute("accentunder", "true"); + return node; + } +}); +// CONCATENATED MODULE: ./src/functions/arrow.js + + + + + + + +// Helper function +var arrow_paddedNode = function paddedNode(group) { + var node = new mathMLTree.MathNode("mpadded", group ? [group] : []); + node.setAttribute("width", "+0.6em"); + node.setAttribute("lspace", "0.3em"); + return node; +}; // Stretchy arrows with an optional argument + + +defineFunction({ + type: "xArrow", + names: ["\\xleftarrow", "\\xrightarrow", "\\xLeftarrow", "\\xRightarrow", "\\xleftrightarrow", "\\xLeftrightarrow", "\\xhookleftarrow", "\\xhookrightarrow", "\\xmapsto", "\\xrightharpoondown", "\\xrightharpoonup", "\\xleftharpoondown", "\\xleftharpoonup", "\\xrightleftharpoons", "\\xleftrightharpoons", "\\xlongequal", "\\xtwoheadrightarrow", "\\xtwoheadleftarrow", "\\xtofrom", // The next 3 functions are here to support the mhchem extension. + // Direct use of these functions is discouraged and may break someday. + "\\xrightleftarrows", "\\xrightequilibrium", "\\xleftequilibrium"], + props: { + numArgs: 1, + numOptionalArgs: 1 + }, + handler: function handler(_ref, args, optArgs) { + var parser = _ref.parser, + funcName = _ref.funcName; + return { + type: "xArrow", + mode: parser.mode, + label: funcName, + body: args[0], + below: optArgs[0] + }; + }, + // Flow is unable to correctly infer the type of `group`, even though it's + // unamibiguously determined from the passed-in `type` above. + htmlBuilder: function htmlBuilder(group, options) { + var style = options.style; // Build the argument groups in the appropriate style. + // Ref: amsmath.dtx: \hbox{$\scriptstyle\mkern#3mu{#6}\mkern#4mu$}% + // Some groups can return document fragments. Handle those by wrapping + // them in a span. + + var newOptions = options.havingStyle(style.sup()); + var upperGroup = buildCommon.wrapFragment(buildHTML_buildGroup(group.body, newOptions, options), options); + upperGroup.classes.push("x-arrow-pad"); + var lowerGroup; + + if (group.below) { + // Build the lower group + newOptions = options.havingStyle(style.sub()); + lowerGroup = buildCommon.wrapFragment(buildHTML_buildGroup(group.below, newOptions, options), options); + lowerGroup.classes.push("x-arrow-pad"); + } + + var arrowBody = stretchy.svgSpan(group, options); // Re shift: Note that stretchy.svgSpan returned arrowBody.depth = 0. + // The point we want on the math axis is at 0.5 * arrowBody.height. + + var arrowShift = -options.fontMetrics().axisHeight + 0.5 * arrowBody.height; // 2 mu kern. Ref: amsmath.dtx: #7\if0#2\else\mkern#2mu\fi + + var upperShift = -options.fontMetrics().axisHeight - 0.5 * arrowBody.height - 0.111; // 0.111 em = 2 mu + + if (upperGroup.depth > 0.25 || group.label === "\\xleftequilibrium") { + upperShift -= upperGroup.depth; // shift up if depth encroaches + } // Generate the vlist + + + var vlist; + + if (lowerGroup) { + var lowerShift = -options.fontMetrics().axisHeight + lowerGroup.height + 0.5 * arrowBody.height + 0.111; + vlist = buildCommon.makeVList({ + positionType: "individualShift", + children: [{ + type: "elem", + elem: upperGroup, + shift: upperShift + }, { + type: "elem", + elem: arrowBody, + shift: arrowShift + }, { + type: "elem", + elem: lowerGroup, + shift: lowerShift + }] + }, options); + } else { + vlist = buildCommon.makeVList({ + positionType: "individualShift", + children: [{ + type: "elem", + elem: upperGroup, + shift: upperShift + }, { + type: "elem", + elem: arrowBody, + shift: arrowShift + }] + }, options); + } // $FlowFixMe: Replace this with passing "svg-align" into makeVList. + + + vlist.children[0].children[0].children[1].classes.push("svg-align"); + return buildCommon.makeSpan(["mrel", "x-arrow"], [vlist], options); + }, + mathmlBuilder: function mathmlBuilder(group, options) { + var arrowNode = stretchy.mathMLnode(group.label); + var node; + + if (group.body) { + var upperNode = arrow_paddedNode(buildMathML_buildGroup(group.body, options)); + + if (group.below) { + var lowerNode = arrow_paddedNode(buildMathML_buildGroup(group.below, options)); + node = new mathMLTree.MathNode("munderover", [arrowNode, lowerNode, upperNode]); + } else { + node = new mathMLTree.MathNode("mover", [arrowNode, upperNode]); + } + } else if (group.below) { + var _lowerNode = arrow_paddedNode(buildMathML_buildGroup(group.below, options)); + + node = new mathMLTree.MathNode("munder", [arrowNode, _lowerNode]); + } else { + // This should never happen. + // Parser.js throws an error if there is no argument. + node = arrow_paddedNode(); + node = new mathMLTree.MathNode("mover", [arrowNode, node]); + } + + return node; + } +}); +// CONCATENATED MODULE: ./src/functions/char.js + + + // \@char is an internal function that takes a grouped decimal argument like +// {123} and converts into symbol with code 123. It is used by the *macro* +// \char defined in macros.js. + +defineFunction({ + type: "textord", + names: ["\\@char"], + props: { + numArgs: 1, + allowedInText: true + }, + handler: function handler(_ref, args) { + var parser = _ref.parser; + var arg = assertNodeType(args[0], "ordgroup"); + var group = arg.body; + var number = ""; + + for (var i = 0; i < group.length; i++) { + var node = assertNodeType(group[i], "textord"); + number += node.text; + } + + var code = parseInt(number); + + if (isNaN(code)) { + throw new src_ParseError("\\@char has non-numeric argument " + number); + } + + return { + type: "textord", + mode: parser.mode, + text: String.fromCharCode(code) + }; + } +}); +// CONCATENATED MODULE: ./src/functions/color.js + + + + + + + +var color_htmlBuilder = function htmlBuilder(group, options) { + var elements = buildHTML_buildExpression(group.body, options.withColor(group.color), false); // \color isn't supposed to affect the type of the elements it contains. + // To accomplish this, we wrap the results in a fragment, so the inner + // elements will be able to directly interact with their neighbors. For + // example, `\color{red}{2 +} 3` has the same spacing as `2 + 3` + + return buildCommon.makeFragment(elements); +}; + +var color_mathmlBuilder = function mathmlBuilder(group, options) { + var inner = buildMathML_buildExpression(group.body, options.withColor(group.color)); + var node = new mathMLTree.MathNode("mstyle", inner); + node.setAttribute("mathcolor", group.color); + return node; +}; + +defineFunction({ + type: "color", + names: ["\\textcolor"], + props: { + numArgs: 2, + allowedInText: true, + greediness: 3, + argTypes: ["color", "original"] + }, + handler: function handler(_ref, args) { + var parser = _ref.parser; + var color = assertNodeType(args[0], "color-token").color; + var body = args[1]; + return { + type: "color", + mode: parser.mode, + color: color, + body: defineFunction_ordargument(body) + }; + }, + htmlBuilder: color_htmlBuilder, + mathmlBuilder: color_mathmlBuilder +}); +defineFunction({ + type: "color", + names: ["\\color"], + props: { + numArgs: 1, + allowedInText: true, + greediness: 3, + argTypes: ["color"] + }, + handler: function handler(_ref2, args) { + var parser = _ref2.parser, + breakOnTokenText = _ref2.breakOnTokenText; + var color = assertNodeType(args[0], "color-token").color; // Set macro \current@color in current namespace to store the current + // color, mimicking the behavior of color.sty. + // This is currently used just to correctly color a \right + // that follows a \color command. + + parser.gullet.macros.set("\\current@color", color); // Parse out the implicit body that should be colored. + + var body = parser.parseExpression(true, breakOnTokenText); + return { + type: "color", + mode: parser.mode, + color: color, + body: body + }; + }, + htmlBuilder: color_htmlBuilder, + mathmlBuilder: color_mathmlBuilder +}); +// CONCATENATED MODULE: ./src/functions/cr.js +// Row breaks within tabular environments, and line breaks at top level + + + + + + // \\ is a macro mapping to either \cr or \newline. Because they have the +// same signature, we implement them as one megafunction, with newRow +// indicating whether we're in the \cr case, and newLine indicating whether +// to break the line in the \newline case. + +defineFunction({ + type: "cr", + names: ["\\cr", "\\newline"], + props: { + numArgs: 0, + numOptionalArgs: 1, + argTypes: ["size"], + allowedInText: true + }, + handler: function handler(_ref, args, optArgs) { + var parser = _ref.parser, + funcName = _ref.funcName; + var size = optArgs[0]; + var newRow = funcName === "\\cr"; + var newLine = false; + + if (!newRow) { + if (parser.settings.displayMode && parser.settings.useStrictBehavior("newLineInDisplayMode", "In LaTeX, \\\\ or \\newline " + "does nothing in display mode")) { + newLine = false; + } else { + newLine = true; + } + } + + return { + type: "cr", + mode: parser.mode, + newLine: newLine, + newRow: newRow, + size: size && assertNodeType(size, "size").value + }; + }, + // The following builders are called only at the top level, + // not within tabular/array environments. + htmlBuilder: function htmlBuilder(group, options) { + if (group.newRow) { + throw new src_ParseError("\\cr valid only within a tabular/array environment"); + } + + var span = buildCommon.makeSpan(["mspace"], [], options); + + if (group.newLine) { + span.classes.push("newline"); + + if (group.size) { + span.style.marginTop = units_calculateSize(group.size, options) + "em"; + } + } + + return span; + }, + mathmlBuilder: function mathmlBuilder(group, options) { + var node = new mathMLTree.MathNode("mspace"); + + if (group.newLine) { + node.setAttribute("linebreak", "newline"); + + if (group.size) { + node.setAttribute("height", units_calculateSize(group.size, options) + "em"); + } + } + + return node; + } +}); +// CONCATENATED MODULE: ./src/delimiter.js +/** + * This file deals with creating delimiters of various sizes. The TeXbook + * discusses these routines on page 441-442, in the "Another subroutine sets box + * x to a specified variable delimiter" paragraph. + * + * There are three main routines here. `makeSmallDelim` makes a delimiter in the + * normal font, but in either text, script, or scriptscript style. + * `makeLargeDelim` makes a delimiter in textstyle, but in one of the Size1, + * Size2, Size3, or Size4 fonts. `makeStackedDelim` makes a delimiter out of + * smaller pieces that are stacked on top of one another. + * + * The functions take a parameter `center`, which determines if the delimiter + * should be centered around the axis. + * + * Then, there are three exposed functions. `sizedDelim` makes a delimiter in + * one of the given sizes. This is used for things like `\bigl`. + * `customSizedDelim` makes a delimiter with a given total height+depth. It is + * called in places like `\sqrt`. `leftRightDelim` makes an appropriate + * delimiter which surrounds an expression of a given height an depth. It is + * used in `\left` and `\right`. + */ + + + + + + + + + +/** + * Get the metrics for a given symbol and font, after transformation (i.e. + * after following replacement from symbols.js) + */ +var delimiter_getMetrics = function getMetrics(symbol, font, mode) { + var replace = src_symbols.math[symbol] && src_symbols.math[symbol].replace; + var metrics = getCharacterMetrics(replace || symbol, font, mode); + + if (!metrics) { + throw new Error("Unsupported symbol " + symbol + " and font size " + font + "."); + } + + return metrics; +}; +/** + * Puts a delimiter span in a given style, and adds appropriate height, depth, + * and maxFontSizes. + */ + + +var delimiter_styleWrap = function styleWrap(delim, toStyle, options, classes) { + var newOptions = options.havingBaseStyle(toStyle); + var span = buildCommon.makeSpan(classes.concat(newOptions.sizingClasses(options)), [delim], options); + var delimSizeMultiplier = newOptions.sizeMultiplier / options.sizeMultiplier; + span.height *= delimSizeMultiplier; + span.depth *= delimSizeMultiplier; + span.maxFontSize = newOptions.sizeMultiplier; + return span; +}; + +var centerSpan = function centerSpan(span, options, style) { + var newOptions = options.havingBaseStyle(style); + var shift = (1 - options.sizeMultiplier / newOptions.sizeMultiplier) * options.fontMetrics().axisHeight; + span.classes.push("delimcenter"); + span.style.top = shift + "em"; + span.height -= shift; + span.depth += shift; +}; +/** + * Makes a small delimiter. This is a delimiter that comes in the Main-Regular + * font, but is restyled to either be in textstyle, scriptstyle, or + * scriptscriptstyle. + */ + + +var delimiter_makeSmallDelim = function makeSmallDelim(delim, style, center, options, mode, classes) { + var text = buildCommon.makeSymbol(delim, "Main-Regular", mode, options); + var span = delimiter_styleWrap(text, style, options, classes); + + if (center) { + centerSpan(span, options, style); + } + + return span; +}; +/** + * Builds a symbol in the given font size (note size is an integer) + */ + + +var delimiter_mathrmSize = function mathrmSize(value, size, mode, options) { + return buildCommon.makeSymbol(value, "Size" + size + "-Regular", mode, options); +}; +/** + * Makes a large delimiter. This is a delimiter that comes in the Size1, Size2, + * Size3, or Size4 fonts. It is always rendered in textstyle. + */ + + +var delimiter_makeLargeDelim = function makeLargeDelim(delim, size, center, options, mode, classes) { + var inner = delimiter_mathrmSize(delim, size, mode, options); + var span = delimiter_styleWrap(buildCommon.makeSpan(["delimsizing", "size" + size], [inner], options), src_Style.TEXT, options, classes); + + if (center) { + centerSpan(span, options, src_Style.TEXT); + } + + return span; +}; +/** + * Make an inner span with the given offset and in the given font. This is used + * in `makeStackedDelim` to make the stacking pieces for the delimiter. + */ + + +var delimiter_makeInner = function makeInner(symbol, font, mode) { + var sizeClass; // Apply the correct CSS class to choose the right font. + + if (font === "Size1-Regular") { + sizeClass = "delim-size1"; + } else + /* if (font === "Size4-Regular") */ + { + sizeClass = "delim-size4"; + } + + var inner = buildCommon.makeSpan(["delimsizinginner", sizeClass], [buildCommon.makeSpan([], [buildCommon.makeSymbol(symbol, font, mode)])]); // Since this will be passed into `makeVList` in the end, wrap the element + // in the appropriate tag that VList uses. + + return { + type: "elem", + elem: inner + }; +}; // Helper for makeStackedDelim + + +var lap = { + type: "kern", + size: -0.005 +}; +/** + * Make a stacked delimiter out of a given delimiter, with the total height at + * least `heightTotal`. This routine is mentioned on page 442 of the TeXbook. + */ + +var delimiter_makeStackedDelim = function makeStackedDelim(delim, heightTotal, center, options, mode, classes) { + // There are four parts, the top, an optional middle, a repeated part, and a + // bottom. + var top; + var middle; + var repeat; + var bottom; + top = repeat = bottom = delim; + middle = null; // Also keep track of what font the delimiters are in + + var font = "Size1-Regular"; // We set the parts and font based on the symbol. Note that we use + // '\u23d0' instead of '|' and '\u2016' instead of '\\|' for the + // repeats of the arrows + + if (delim === "\\uparrow") { + repeat = bottom = "\u23D0"; + } else if (delim === "\\Uparrow") { + repeat = bottom = "\u2016"; + } else if (delim === "\\downarrow") { + top = repeat = "\u23D0"; + } else if (delim === "\\Downarrow") { + top = repeat = "\u2016"; + } else if (delim === "\\updownarrow") { + top = "\\uparrow"; + repeat = "\u23D0"; + bottom = "\\downarrow"; + } else if (delim === "\\Updownarrow") { + top = "\\Uparrow"; + repeat = "\u2016"; + bottom = "\\Downarrow"; + } else if (delim === "[" || delim === "\\lbrack") { + top = "\u23A1"; + repeat = "\u23A2"; + bottom = "\u23A3"; + font = "Size4-Regular"; + } else if (delim === "]" || delim === "\\rbrack") { + top = "\u23A4"; + repeat = "\u23A5"; + bottom = "\u23A6"; + font = "Size4-Regular"; + } else if (delim === "\\lfloor" || delim === "\u230A") { + repeat = top = "\u23A2"; + bottom = "\u23A3"; + font = "Size4-Regular"; + } else if (delim === "\\lceil" || delim === "\u2308") { + top = "\u23A1"; + repeat = bottom = "\u23A2"; + font = "Size4-Regular"; + } else if (delim === "\\rfloor" || delim === "\u230B") { + repeat = top = "\u23A5"; + bottom = "\u23A6"; + font = "Size4-Regular"; + } else if (delim === "\\rceil" || delim === "\u2309") { + top = "\u23A4"; + repeat = bottom = "\u23A5"; + font = "Size4-Regular"; + } else if (delim === "(" || delim === "\\lparen") { + top = "\u239B"; + repeat = "\u239C"; + bottom = "\u239D"; + font = "Size4-Regular"; + } else if (delim === ")" || delim === "\\rparen") { + top = "\u239E"; + repeat = "\u239F"; + bottom = "\u23A0"; + font = "Size4-Regular"; + } else if (delim === "\\{" || delim === "\\lbrace") { + top = "\u23A7"; + middle = "\u23A8"; + bottom = "\u23A9"; + repeat = "\u23AA"; + font = "Size4-Regular"; + } else if (delim === "\\}" || delim === "\\rbrace") { + top = "\u23AB"; + middle = "\u23AC"; + bottom = "\u23AD"; + repeat = "\u23AA"; + font = "Size4-Regular"; + } else if (delim === "\\lgroup" || delim === "\u27EE") { + top = "\u23A7"; + bottom = "\u23A9"; + repeat = "\u23AA"; + font = "Size4-Regular"; + } else if (delim === "\\rgroup" || delim === "\u27EF") { + top = "\u23AB"; + bottom = "\u23AD"; + repeat = "\u23AA"; + font = "Size4-Regular"; + } else if (delim === "\\lmoustache" || delim === "\u23B0") { + top = "\u23A7"; + bottom = "\u23AD"; + repeat = "\u23AA"; + font = "Size4-Regular"; + } else if (delim === "\\rmoustache" || delim === "\u23B1") { + top = "\u23AB"; + bottom = "\u23A9"; + repeat = "\u23AA"; + font = "Size4-Regular"; + } // Get the metrics of the four sections + + + var topMetrics = delimiter_getMetrics(top, font, mode); + var topHeightTotal = topMetrics.height + topMetrics.depth; + var repeatMetrics = delimiter_getMetrics(repeat, font, mode); + var repeatHeightTotal = repeatMetrics.height + repeatMetrics.depth; + var bottomMetrics = delimiter_getMetrics(bottom, font, mode); + var bottomHeightTotal = bottomMetrics.height + bottomMetrics.depth; + var middleHeightTotal = 0; + var middleFactor = 1; + + if (middle !== null) { + var middleMetrics = delimiter_getMetrics(middle, font, mode); + middleHeightTotal = middleMetrics.height + middleMetrics.depth; + middleFactor = 2; // repeat symmetrically above and below middle + } // Calcuate the minimal height that the delimiter can have. + // It is at least the size of the top, bottom, and optional middle combined. + + + var minHeight = topHeightTotal + bottomHeightTotal + middleHeightTotal; // Compute the number of copies of the repeat symbol we will need + + var repeatCount = Math.max(0, Math.ceil((heightTotal - minHeight) / (middleFactor * repeatHeightTotal))); // Compute the total height of the delimiter including all the symbols + + var realHeightTotal = minHeight + repeatCount * middleFactor * repeatHeightTotal; // The center of the delimiter is placed at the center of the axis. Note + // that in this context, "center" means that the delimiter should be + // centered around the axis in the current style, while normally it is + // centered around the axis in textstyle. + + var axisHeight = options.fontMetrics().axisHeight; + + if (center) { + axisHeight *= options.sizeMultiplier; + } // Calculate the depth + + + var depth = realHeightTotal / 2 - axisHeight; // This function differs from the TeX procedure in one way. + // We shift each repeat element downwards by 0.005em, to prevent a gap + // due to browser floating point rounding error. + // Then, at the last element-to element joint, we add one extra repeat + // element to cover the gap created by the shifts. + // Find the shift needed to align the upper end of the extra element at a point + // 0.005em above the lower end of the top element. + + var shiftOfExtraElement = (repeatCount + 1) * 0.005 - repeatHeightTotal; // Now, we start building the pieces that will go into the vlist + // Keep a list of the inner pieces + + var inners = []; // Add the bottom symbol + + inners.push(delimiter_makeInner(bottom, font, mode)); + + if (middle === null) { + // Add that many symbols + for (var i = 0; i < repeatCount; i++) { + inners.push(lap); // overlap + + inners.push(delimiter_makeInner(repeat, font, mode)); + } + } else { + // When there is a middle bit, we need the middle part and two repeated + // sections + for (var _i = 0; _i < repeatCount; _i++) { + inners.push(lap); + inners.push(delimiter_makeInner(repeat, font, mode)); + } // Insert one extra repeat element. + + + inners.push({ + type: "kern", + size: shiftOfExtraElement + }); + inners.push(delimiter_makeInner(repeat, font, mode)); + inners.push(lap); // Now insert the middle of the brace. + + inners.push(delimiter_makeInner(middle, font, mode)); + + for (var _i2 = 0; _i2 < repeatCount; _i2++) { + inners.push(lap); + inners.push(delimiter_makeInner(repeat, font, mode)); + } + } // To cover the gap create by the overlaps, insert one more repeat element, + // at a position that juts 0.005 above the bottom of the top element. + + + inners.push({ + type: "kern", + size: shiftOfExtraElement + }); + inners.push(delimiter_makeInner(repeat, font, mode)); + inners.push(lap); // Add the top symbol + + inners.push(delimiter_makeInner(top, font, mode)); // Finally, build the vlist + + var newOptions = options.havingBaseStyle(src_Style.TEXT); + var inner = buildCommon.makeVList({ + positionType: "bottom", + positionData: depth, + children: inners + }, newOptions); + return delimiter_styleWrap(buildCommon.makeSpan(["delimsizing", "mult"], [inner], newOptions), src_Style.TEXT, options, classes); +}; // All surds have 0.08em padding above the viniculum inside the SVG. +// That keeps browser span height rounding error from pinching the line. + + +var vbPad = 80; // padding above the surd, measured inside the viewBox. + +var emPad = 0.08; // padding, in ems, measured in the document. + +var delimiter_sqrtSvg = function sqrtSvg(sqrtName, height, viewBoxHeight, extraViniculum, options) { + var path = sqrtPath(sqrtName, extraViniculum, viewBoxHeight); + var pathNode = new domTree_PathNode(sqrtName, path); + var svg = new SvgNode([pathNode], { + // Note: 1000:1 ratio of viewBox to document em width. + "width": "400em", + "height": height + "em", + "viewBox": "0 0 400000 " + viewBoxHeight, + "preserveAspectRatio": "xMinYMin slice" + }); + return buildCommon.makeSvgSpan(["hide-tail"], [svg], options); +}; +/** + * Make a sqrt image of the given height, + */ + + +var makeSqrtImage = function makeSqrtImage(height, options) { + // Define a newOptions that removes the effect of size changes such as \Huge. + // We don't pick different a height surd for \Huge. For it, we scale up. + var newOptions = options.havingBaseSizing(); // Pick the desired surd glyph from a sequence of surds. + + var delim = traverseSequence("\\surd", height * newOptions.sizeMultiplier, stackLargeDelimiterSequence, newOptions); + var sizeMultiplier = newOptions.sizeMultiplier; // default + // The standard sqrt SVGs each have a 0.04em thick viniculum. + // If Settings.minRuleThickness is larger than that, we add extraViniculum. + + var extraViniculum = Math.max(0, options.minRuleThickness - options.fontMetrics().sqrtRuleThickness); // Create a span containing an SVG image of a sqrt symbol. + + var span; + var spanHeight = 0; + var texHeight = 0; + var viewBoxHeight = 0; + var advanceWidth; // We create viewBoxes with 80 units of "padding" above each surd. + // Then browser rounding error on the parent span height will not + // encroach on the ink of the viniculum. But that padding is not + // included in the TeX-like `height` used for calculation of + // vertical alignment. So texHeight = span.height < span.style.height. + + if (delim.type === "small") { + // Get an SVG that is derived from glyph U+221A in font KaTeX-Main. + // 1000 unit normal glyph height. + viewBoxHeight = 1000 + 1000 * extraViniculum + vbPad; + + if (height < 1.0) { + sizeMultiplier = 1.0; // mimic a \textfont radical + } else if (height < 1.4) { + sizeMultiplier = 0.7; // mimic a \scriptfont radical + } + + spanHeight = (1.0 + extraViniculum + emPad) / sizeMultiplier; + texHeight = (1.00 + extraViniculum) / sizeMultiplier; + span = delimiter_sqrtSvg("sqrtMain", spanHeight, viewBoxHeight, extraViniculum, options); + span.style.minWidth = "0.853em"; + advanceWidth = 0.833 / sizeMultiplier; // from the font. + } else if (delim.type === "large") { + // These SVGs come from fonts: KaTeX_Size1, _Size2, etc. + viewBoxHeight = (1000 + vbPad) * sizeToMaxHeight[delim.size]; + texHeight = (sizeToMaxHeight[delim.size] + extraViniculum) / sizeMultiplier; + spanHeight = (sizeToMaxHeight[delim.size] + extraViniculum + emPad) / sizeMultiplier; + span = delimiter_sqrtSvg("sqrtSize" + delim.size, spanHeight, viewBoxHeight, extraViniculum, options); + span.style.minWidth = "1.02em"; + advanceWidth = 1.0 / sizeMultiplier; // 1.0 from the font. + } else { + // Tall sqrt. In TeX, this would be stacked using multiple glyphs. + // We'll use a single SVG to accomplish the same thing. + spanHeight = height + extraViniculum + emPad; + texHeight = height + extraViniculum; + viewBoxHeight = Math.floor(1000 * height + extraViniculum) + vbPad; + span = delimiter_sqrtSvg("sqrtTall", spanHeight, viewBoxHeight, extraViniculum, options); + span.style.minWidth = "0.742em"; + advanceWidth = 1.056; + } + + span.height = texHeight; + span.style.height = spanHeight + "em"; + return { + span: span, + advanceWidth: advanceWidth, + // Calculate the actual line width. + // This actually should depend on the chosen font -- e.g. \boldmath + // should use the thicker surd symbols from e.g. KaTeX_Main-Bold, and + // have thicker rules. + ruleWidth: (options.fontMetrics().sqrtRuleThickness + extraViniculum) * sizeMultiplier + }; +}; // There are three kinds of delimiters, delimiters that stack when they become +// too large + + +var stackLargeDelimiters = ["(", "\\lparen", ")", "\\rparen", "[", "\\lbrack", "]", "\\rbrack", "\\{", "\\lbrace", "\\}", "\\rbrace", "\\lfloor", "\\rfloor", "\u230A", "\u230B", "\\lceil", "\\rceil", "\u2308", "\u2309", "\\surd"]; // delimiters that always stack + +var stackAlwaysDelimiters = ["\\uparrow", "\\downarrow", "\\updownarrow", "\\Uparrow", "\\Downarrow", "\\Updownarrow", "|", "\\|", "\\vert", "\\Vert", "\\lvert", "\\rvert", "\\lVert", "\\rVert", "\\lgroup", "\\rgroup", "\u27EE", "\u27EF", "\\lmoustache", "\\rmoustache", "\u23B0", "\u23B1"]; // and delimiters that never stack + +var stackNeverDelimiters = ["<", ">", "\\langle", "\\rangle", "/", "\\backslash", "\\lt", "\\gt"]; // Metrics of the different sizes. Found by looking at TeX's output of +// $\bigl| // \Bigl| \biggl| \Biggl| \showlists$ +// Used to create stacked delimiters of appropriate sizes in makeSizedDelim. + +var sizeToMaxHeight = [0, 1.2, 1.8, 2.4, 3.0]; +/** + * Used to create a delimiter of a specific size, where `size` is 1, 2, 3, or 4. + */ + +var delimiter_makeSizedDelim = function makeSizedDelim(delim, size, options, mode, classes) { + // < and > turn into \langle and \rangle in delimiters + if (delim === "<" || delim === "\\lt" || delim === "\u27E8") { + delim = "\\langle"; + } else if (delim === ">" || delim === "\\gt" || delim === "\u27E9") { + delim = "\\rangle"; + } // Sized delimiters are never centered. + + + if (utils.contains(stackLargeDelimiters, delim) || utils.contains(stackNeverDelimiters, delim)) { + return delimiter_makeLargeDelim(delim, size, false, options, mode, classes); + } else if (utils.contains(stackAlwaysDelimiters, delim)) { + return delimiter_makeStackedDelim(delim, sizeToMaxHeight[size], false, options, mode, classes); + } else { + throw new src_ParseError("Illegal delimiter: '" + delim + "'"); + } +}; +/** + * There are three different sequences of delimiter sizes that the delimiters + * follow depending on the kind of delimiter. This is used when creating custom + * sized delimiters to decide whether to create a small, large, or stacked + * delimiter. + * + * In real TeX, these sequences aren't explicitly defined, but are instead + * defined inside the font metrics. Since there are only three sequences that + * are possible for the delimiters that TeX defines, it is easier to just encode + * them explicitly here. + */ + + +// Delimiters that never stack try small delimiters and large delimiters only +var stackNeverDelimiterSequence = [{ + type: "small", + style: src_Style.SCRIPTSCRIPT +}, { + type: "small", + style: src_Style.SCRIPT +}, { + type: "small", + style: src_Style.TEXT +}, { + type: "large", + size: 1 +}, { + type: "large", + size: 2 +}, { + type: "large", + size: 3 +}, { + type: "large", + size: 4 +}]; // Delimiters that always stack try the small delimiters first, then stack + +var stackAlwaysDelimiterSequence = [{ + type: "small", + style: src_Style.SCRIPTSCRIPT +}, { + type: "small", + style: src_Style.SCRIPT +}, { + type: "small", + style: src_Style.TEXT +}, { + type: "stack" +}]; // Delimiters that stack when large try the small and then large delimiters, and +// stack afterwards + +var stackLargeDelimiterSequence = [{ + type: "small", + style: src_Style.SCRIPTSCRIPT +}, { + type: "small", + style: src_Style.SCRIPT +}, { + type: "small", + style: src_Style.TEXT +}, { + type: "large", + size: 1 +}, { + type: "large", + size: 2 +}, { + type: "large", + size: 3 +}, { + type: "large", + size: 4 +}, { + type: "stack" +}]; +/** + * Get the font used in a delimiter based on what kind of delimiter it is. + * TODO(#963) Use more specific font family return type once that is introduced. + */ + +var delimTypeToFont = function delimTypeToFont(type) { + if (type.type === "small") { + return "Main-Regular"; + } else if (type.type === "large") { + return "Size" + type.size + "-Regular"; + } else if (type.type === "stack") { + return "Size4-Regular"; + } else { + throw new Error("Add support for delim type '" + type.type + "' here."); + } +}; +/** + * Traverse a sequence of types of delimiters to decide what kind of delimiter + * should be used to create a delimiter of the given height+depth. + */ + + +var traverseSequence = function traverseSequence(delim, height, sequence, options) { + // Here, we choose the index we should start at in the sequences. In smaller + // sizes (which correspond to larger numbers in style.size) we start earlier + // in the sequence. Thus, scriptscript starts at index 3-3=0, script starts + // at index 3-2=1, text starts at 3-1=2, and display starts at min(2,3-0)=2 + var start = Math.min(2, 3 - options.style.size); + + for (var i = start; i < sequence.length; i++) { + if (sequence[i].type === "stack") { + // This is always the last delimiter, so we just break the loop now. + break; + } + + var metrics = delimiter_getMetrics(delim, delimTypeToFont(sequence[i]), "math"); + var heightDepth = metrics.height + metrics.depth; // Small delimiters are scaled down versions of the same font, so we + // account for the style change size. + + if (sequence[i].type === "small") { + var newOptions = options.havingBaseStyle(sequence[i].style); + heightDepth *= newOptions.sizeMultiplier; + } // Check if the delimiter at this size works for the given height. + + + if (heightDepth > height) { + return sequence[i]; + } + } // If we reached the end of the sequence, return the last sequence element. + + + return sequence[sequence.length - 1]; +}; +/** + * Make a delimiter of a given height+depth, with optional centering. Here, we + * traverse the sequences, and create a delimiter that the sequence tells us to. + */ + + +var delimiter_makeCustomSizedDelim = function makeCustomSizedDelim(delim, height, center, options, mode, classes) { + if (delim === "<" || delim === "\\lt" || delim === "\u27E8") { + delim = "\\langle"; + } else if (delim === ">" || delim === "\\gt" || delim === "\u27E9") { + delim = "\\rangle"; + } // Decide what sequence to use + + + var sequence; + + if (utils.contains(stackNeverDelimiters, delim)) { + sequence = stackNeverDelimiterSequence; + } else if (utils.contains(stackLargeDelimiters, delim)) { + sequence = stackLargeDelimiterSequence; + } else { + sequence = stackAlwaysDelimiterSequence; + } // Look through the sequence + + + var delimType = traverseSequence(delim, height, sequence, options); // Get the delimiter from font glyphs. + // Depending on the sequence element we decided on, call the + // appropriate function. + + if (delimType.type === "small") { + return delimiter_makeSmallDelim(delim, delimType.style, center, options, mode, classes); + } else if (delimType.type === "large") { + return delimiter_makeLargeDelim(delim, delimType.size, center, options, mode, classes); + } else + /* if (delimType.type === "stack") */ + { + return delimiter_makeStackedDelim(delim, height, center, options, mode, classes); + } +}; +/** + * Make a delimiter for use with `\left` and `\right`, given a height and depth + * of an expression that the delimiters surround. + */ + + +var makeLeftRightDelim = function makeLeftRightDelim(delim, height, depth, options, mode, classes) { + // We always center \left/\right delimiters, so the axis is always shifted + var axisHeight = options.fontMetrics().axisHeight * options.sizeMultiplier; // Taken from TeX source, tex.web, function make_left_right + + var delimiterFactor = 901; + var delimiterExtend = 5.0 / options.fontMetrics().ptPerEm; + var maxDistFromAxis = Math.max(height - axisHeight, depth + axisHeight); + var totalHeight = Math.max( // In real TeX, calculations are done using integral values which are + // 65536 per pt, or 655360 per em. So, the division here truncates in + // TeX but doesn't here, producing different results. If we wanted to + // exactly match TeX's calculation, we could do + // Math.floor(655360 * maxDistFromAxis / 500) * + // delimiterFactor / 655360 + // (To see the difference, compare + // x^{x^{\left(\rule{0.1em}{0.68em}\right)}} + // in TeX and KaTeX) + maxDistFromAxis / 500 * delimiterFactor, 2 * maxDistFromAxis - delimiterExtend); // Finally, we defer to `makeCustomSizedDelim` with our calculated total + // height + + return delimiter_makeCustomSizedDelim(delim, totalHeight, true, options, mode, classes); +}; + +/* harmony default export */ var delimiter = ({ + sqrtImage: makeSqrtImage, + sizedDelim: delimiter_makeSizedDelim, + customSizedDelim: delimiter_makeCustomSizedDelim, + leftRightDelim: makeLeftRightDelim +}); +// CONCATENATED MODULE: ./src/functions/delimsizing.js + + + + + + + + + +// Extra data needed for the delimiter handler down below +var delimiterSizes = { + "\\bigl": { + mclass: "mopen", + size: 1 + }, + "\\Bigl": { + mclass: "mopen", + size: 2 + }, + "\\biggl": { + mclass: "mopen", + size: 3 + }, + "\\Biggl": { + mclass: "mopen", + size: 4 + }, + "\\bigr": { + mclass: "mclose", + size: 1 + }, + "\\Bigr": { + mclass: "mclose", + size: 2 + }, + "\\biggr": { + mclass: "mclose", + size: 3 + }, + "\\Biggr": { + mclass: "mclose", + size: 4 + }, + "\\bigm": { + mclass: "mrel", + size: 1 + }, + "\\Bigm": { + mclass: "mrel", + size: 2 + }, + "\\biggm": { + mclass: "mrel", + size: 3 + }, + "\\Biggm": { + mclass: "mrel", + size: 4 + }, + "\\big": { + mclass: "mord", + size: 1 + }, + "\\Big": { + mclass: "mord", + size: 2 + }, + "\\bigg": { + mclass: "mord", + size: 3 + }, + "\\Bigg": { + mclass: "mord", + size: 4 + } +}; +var delimiters = ["(", "\\lparen", ")", "\\rparen", "[", "\\lbrack", "]", "\\rbrack", "\\{", "\\lbrace", "\\}", "\\rbrace", "\\lfloor", "\\rfloor", "\u230A", "\u230B", "\\lceil", "\\rceil", "\u2308", "\u2309", "<", ">", "\\langle", "\u27E8", "\\rangle", "\u27E9", "\\lt", "\\gt", "\\lvert", "\\rvert", "\\lVert", "\\rVert", "\\lgroup", "\\rgroup", "\u27EE", "\u27EF", "\\lmoustache", "\\rmoustache", "\u23B0", "\u23B1", "/", "\\backslash", "|", "\\vert", "\\|", "\\Vert", "\\uparrow", "\\Uparrow", "\\downarrow", "\\Downarrow", "\\updownarrow", "\\Updownarrow", "."]; + +// Delimiter functions +function checkDelimiter(delim, context) { + var symDelim = checkSymbolNodeType(delim); + + if (symDelim && utils.contains(delimiters, symDelim.text)) { + return symDelim; + } else { + throw new src_ParseError("Invalid delimiter: '" + (symDelim ? symDelim.text : JSON.stringify(delim)) + "' after '" + context.funcName + "'", delim); + } +} + +defineFunction({ + type: "delimsizing", + names: ["\\bigl", "\\Bigl", "\\biggl", "\\Biggl", "\\bigr", "\\Bigr", "\\biggr", "\\Biggr", "\\bigm", "\\Bigm", "\\biggm", "\\Biggm", "\\big", "\\Big", "\\bigg", "\\Bigg"], + props: { + numArgs: 1 + }, + handler: function handler(context, args) { + var delim = checkDelimiter(args[0], context); + return { + type: "delimsizing", + mode: context.parser.mode, + size: delimiterSizes[context.funcName].size, + mclass: delimiterSizes[context.funcName].mclass, + delim: delim.text + }; + }, + htmlBuilder: function htmlBuilder(group, options) { + if (group.delim === ".") { + // Empty delimiters still count as elements, even though they don't + // show anything. + return buildCommon.makeSpan([group.mclass]); + } // Use delimiter.sizedDelim to generate the delimiter. + + + return delimiter.sizedDelim(group.delim, group.size, options, group.mode, [group.mclass]); + }, + mathmlBuilder: function mathmlBuilder(group) { + var children = []; + + if (group.delim !== ".") { + children.push(buildMathML_makeText(group.delim, group.mode)); + } + + var node = new mathMLTree.MathNode("mo", children); + + if (group.mclass === "mopen" || group.mclass === "mclose") { + // Only some of the delimsizing functions act as fences, and they + // return "mopen" or "mclose" mclass. + node.setAttribute("fence", "true"); + } else { + // Explicitly disable fencing if it's not a fence, to override the + // defaults. + node.setAttribute("fence", "false"); + } + + return node; + } +}); + +function assertParsed(group) { + if (!group.body) { + throw new Error("Bug: The leftright ParseNode wasn't fully parsed."); + } +} + +defineFunction({ + type: "leftright-right", + names: ["\\right"], + props: { + numArgs: 1 + }, + handler: function handler(context, args) { + // \left case below triggers parsing of \right in + // `const right = parser.parseFunction();` + // uses this return value. + var color = context.parser.gullet.macros.get("\\current@color"); + + if (color && typeof color !== "string") { + throw new src_ParseError("\\current@color set to non-string in \\right"); + } + + return { + type: "leftright-right", + mode: context.parser.mode, + delim: checkDelimiter(args[0], context).text, + color: color // undefined if not set via \color + + }; + } +}); +defineFunction({ + type: "leftright", + names: ["\\left"], + props: { + numArgs: 1 + }, + handler: function handler(context, args) { + var delim = checkDelimiter(args[0], context); + var parser = context.parser; // Parse out the implicit body + + ++parser.leftrightDepth; // parseExpression stops before '\\right' + + var body = parser.parseExpression(false); + --parser.leftrightDepth; // Check the next token + + parser.expect("\\right", false); + var right = assertNodeType(parser.parseFunction(), "leftright-right"); + return { + type: "leftright", + mode: parser.mode, + body: body, + left: delim.text, + right: right.delim, + rightColor: right.color + }; + }, + htmlBuilder: function htmlBuilder(group, options) { + assertParsed(group); // Build the inner expression + + var inner = buildHTML_buildExpression(group.body, options, true, ["mopen", "mclose"]); + var innerHeight = 0; + var innerDepth = 0; + var hadMiddle = false; // Calculate its height and depth + + for (var i = 0; i < inner.length; i++) { + // Property `isMiddle` not defined on `span`. See comment in + // "middle"'s htmlBuilder. + // $FlowFixMe + if (inner[i].isMiddle) { + hadMiddle = true; + } else { + innerHeight = Math.max(inner[i].height, innerHeight); + innerDepth = Math.max(inner[i].depth, innerDepth); + } + } // The size of delimiters is the same, regardless of what style we are + // in. Thus, to correctly calculate the size of delimiter we need around + // a group, we scale down the inner size based on the size. + + + innerHeight *= options.sizeMultiplier; + innerDepth *= options.sizeMultiplier; + var leftDelim; + + if (group.left === ".") { + // Empty delimiters in \left and \right make null delimiter spaces. + leftDelim = makeNullDelimiter(options, ["mopen"]); + } else { + // Otherwise, use leftRightDelim to generate the correct sized + // delimiter. + leftDelim = delimiter.leftRightDelim(group.left, innerHeight, innerDepth, options, group.mode, ["mopen"]); + } // Add it to the beginning of the expression + + + inner.unshift(leftDelim); // Handle middle delimiters + + if (hadMiddle) { + for (var _i = 1; _i < inner.length; _i++) { + var middleDelim = inner[_i]; // Property `isMiddle` not defined on `span`. See comment in + // "middle"'s htmlBuilder. + // $FlowFixMe + + var isMiddle = middleDelim.isMiddle; + + if (isMiddle) { + // Apply the options that were active when \middle was called + inner[_i] = delimiter.leftRightDelim(isMiddle.delim, innerHeight, innerDepth, isMiddle.options, group.mode, []); + } + } + } + + var rightDelim; // Same for the right delimiter, but using color specified by \color + + if (group.right === ".") { + rightDelim = makeNullDelimiter(options, ["mclose"]); + } else { + var colorOptions = group.rightColor ? options.withColor(group.rightColor) : options; + rightDelim = delimiter.leftRightDelim(group.right, innerHeight, innerDepth, colorOptions, group.mode, ["mclose"]); + } // Add it to the end of the expression. + + + inner.push(rightDelim); + return buildCommon.makeSpan(["minner"], inner, options); + }, + mathmlBuilder: function mathmlBuilder(group, options) { + assertParsed(group); + var inner = buildMathML_buildExpression(group.body, options); + + if (group.left !== ".") { + var leftNode = new mathMLTree.MathNode("mo", [buildMathML_makeText(group.left, group.mode)]); + leftNode.setAttribute("fence", "true"); + inner.unshift(leftNode); + } + + if (group.right !== ".") { + var rightNode = new mathMLTree.MathNode("mo", [buildMathML_makeText(group.right, group.mode)]); + rightNode.setAttribute("fence", "true"); + + if (group.rightColor) { + rightNode.setAttribute("mathcolor", group.rightColor); + } + + inner.push(rightNode); + } + + return buildMathML_makeRow(inner); + } +}); +defineFunction({ + type: "middle", + names: ["\\middle"], + props: { + numArgs: 1 + }, + handler: function handler(context, args) { + var delim = checkDelimiter(args[0], context); + + if (!context.parser.leftrightDepth) { + throw new src_ParseError("\\middle without preceding \\left", delim); + } + + return { + type: "middle", + mode: context.parser.mode, + delim: delim.text + }; + }, + htmlBuilder: function htmlBuilder(group, options) { + var middleDelim; + + if (group.delim === ".") { + middleDelim = makeNullDelimiter(options, []); + } else { + middleDelim = delimiter.sizedDelim(group.delim, 1, options, group.mode, []); + var isMiddle = { + delim: group.delim, + options: options + }; // Property `isMiddle` not defined on `span`. It is only used in + // this file above. + // TODO: Fix this violation of the `span` type and possibly rename + // things since `isMiddle` sounds like a boolean, but is a struct. + // $FlowFixMe + + middleDelim.isMiddle = isMiddle; + } + + return middleDelim; + }, + mathmlBuilder: function mathmlBuilder(group, options) { + // A Firefox \middle will strech a character vertically only if it + // is in the fence part of the operator dictionary at: + // https://www.w3.org/TR/MathML3/appendixc.html. + // So we need to avoid U+2223 and use plain "|" instead. + var textNode = group.delim === "\\vert" || group.delim === "|" ? buildMathML_makeText("|", "text") : buildMathML_makeText(group.delim, group.mode); + var middleNode = new mathMLTree.MathNode("mo", [textNode]); + middleNode.setAttribute("fence", "true"); // MathML gives 5/18em spacing to each element. + // \middle should get delimiter spacing instead. + + middleNode.setAttribute("lspace", "0.05em"); + middleNode.setAttribute("rspace", "0.05em"); + return middleNode; + } +}); +// CONCATENATED MODULE: ./src/functions/enclose.js + + + + + + + + + +var enclose_htmlBuilder = function htmlBuilder(group, options) { + // \cancel, \bcancel, \xcancel, \sout, \fbox, \colorbox, \fcolorbox + // Some groups can return document fragments. Handle those by wrapping + // them in a span. + var inner = buildCommon.wrapFragment(buildHTML_buildGroup(group.body, options), options); + var label = group.label.substr(1); + var scale = options.sizeMultiplier; + var img; + var imgShift = 0; // In the LaTeX cancel package, line geometry is slightly different + // depending on whether the subject is wider than it is tall, or vice versa. + // We don't know the width of a group, so as a proxy, we test if + // the subject is a single character. This captures most of the + // subjects that should get the "tall" treatment. + + var isSingleChar = utils.isCharacterBox(group.body); + + if (label === "sout") { + img = buildCommon.makeSpan(["stretchy", "sout"]); + img.height = options.fontMetrics().defaultRuleThickness / scale; + imgShift = -0.5 * options.fontMetrics().xHeight; + } else { + // Add horizontal padding + if (/cancel/.test(label)) { + if (!isSingleChar) { + inner.classes.push("cancel-pad"); + } + } else { + inner.classes.push("boxpad"); + } // Add vertical padding + + + var vertPad = 0; + var ruleThickness = 0; // ref: cancel package: \advance\totalheight2\p@ % "+2" + + if (/box/.test(label)) { + ruleThickness = Math.max(options.fontMetrics().fboxrule, // default + options.minRuleThickness // User override. + ); + vertPad = options.fontMetrics().fboxsep + (label === "colorbox" ? 0 : ruleThickness); + } else { + vertPad = isSingleChar ? 0.2 : 0; + } + + img = stretchy.encloseSpan(inner, label, vertPad, options); + + if (/fbox|boxed|fcolorbox/.test(label)) { + img.style.borderStyle = "solid"; + img.style.borderWidth = ruleThickness + "em"; + } + + imgShift = inner.depth + vertPad; + + if (group.backgroundColor) { + img.style.backgroundColor = group.backgroundColor; + + if (group.borderColor) { + img.style.borderColor = group.borderColor; + } + } + } + + var vlist; + + if (group.backgroundColor) { + vlist = buildCommon.makeVList({ + positionType: "individualShift", + children: [// Put the color background behind inner; + { + type: "elem", + elem: img, + shift: imgShift + }, { + type: "elem", + elem: inner, + shift: 0 + }] + }, options); + } else { + vlist = buildCommon.makeVList({ + positionType: "individualShift", + children: [// Write the \cancel stroke on top of inner. + { + type: "elem", + elem: inner, + shift: 0 + }, { + type: "elem", + elem: img, + shift: imgShift, + wrapperClasses: /cancel/.test(label) ? ["svg-align"] : [] + }] + }, options); + } + + if (/cancel/.test(label)) { + // The cancel package documentation says that cancel lines add their height + // to the expression, but tests show that isn't how it actually works. + vlist.height = inner.height; + vlist.depth = inner.depth; + } + + if (/cancel/.test(label) && !isSingleChar) { + // cancel does not create horiz space for its line extension. + return buildCommon.makeSpan(["mord", "cancel-lap"], [vlist], options); + } else { + return buildCommon.makeSpan(["mord"], [vlist], options); + } +}; + +var enclose_mathmlBuilder = function mathmlBuilder(group, options) { + var fboxsep = 0; + var node = new mathMLTree.MathNode(group.label.indexOf("colorbox") > -1 ? "mpadded" : "menclose", [buildMathML_buildGroup(group.body, options)]); + + switch (group.label) { + case "\\cancel": + node.setAttribute("notation", "updiagonalstrike"); + break; + + case "\\bcancel": + node.setAttribute("notation", "downdiagonalstrike"); + break; + + case "\\sout": + node.setAttribute("notation", "horizontalstrike"); + break; + + case "\\fbox": + node.setAttribute("notation", "box"); + break; + + case "\\fcolorbox": + case "\\colorbox": + // doesn't have a good notation option. So use + // instead. Set some attributes that come included with . + fboxsep = options.fontMetrics().fboxsep * options.fontMetrics().ptPerEm; + node.setAttribute("width", "+" + 2 * fboxsep + "pt"); + node.setAttribute("height", "+" + 2 * fboxsep + "pt"); + node.setAttribute("lspace", fboxsep + "pt"); // + + node.setAttribute("voffset", fboxsep + "pt"); + + if (group.label === "\\fcolorbox") { + var thk = Math.max(options.fontMetrics().fboxrule, // default + options.minRuleThickness // user override + ); + node.setAttribute("style", "border: " + thk + "em solid " + String(group.borderColor)); + } + + break; + + case "\\xcancel": + node.setAttribute("notation", "updiagonalstrike downdiagonalstrike"); + break; + } + + if (group.backgroundColor) { + node.setAttribute("mathbackground", group.backgroundColor); + } + + return node; +}; + +defineFunction({ + type: "enclose", + names: ["\\colorbox"], + props: { + numArgs: 2, + allowedInText: true, + greediness: 3, + argTypes: ["color", "text"] + }, + handler: function handler(_ref, args, optArgs) { + var parser = _ref.parser, + funcName = _ref.funcName; + var color = assertNodeType(args[0], "color-token").color; + var body = args[1]; + return { + type: "enclose", + mode: parser.mode, + label: funcName, + backgroundColor: color, + body: body + }; + }, + htmlBuilder: enclose_htmlBuilder, + mathmlBuilder: enclose_mathmlBuilder +}); +defineFunction({ + type: "enclose", + names: ["\\fcolorbox"], + props: { + numArgs: 3, + allowedInText: true, + greediness: 3, + argTypes: ["color", "color", "text"] + }, + handler: function handler(_ref2, args, optArgs) { + var parser = _ref2.parser, + funcName = _ref2.funcName; + var borderColor = assertNodeType(args[0], "color-token").color; + var backgroundColor = assertNodeType(args[1], "color-token").color; + var body = args[2]; + return { + type: "enclose", + mode: parser.mode, + label: funcName, + backgroundColor: backgroundColor, + borderColor: borderColor, + body: body + }; + }, + htmlBuilder: enclose_htmlBuilder, + mathmlBuilder: enclose_mathmlBuilder +}); +defineFunction({ + type: "enclose", + names: ["\\fbox"], + props: { + numArgs: 1, + argTypes: ["hbox"], + allowedInText: true + }, + handler: function handler(_ref3, args) { + var parser = _ref3.parser; + return { + type: "enclose", + mode: parser.mode, + label: "\\fbox", + body: args[0] + }; + } +}); +defineFunction({ + type: "enclose", + names: ["\\cancel", "\\bcancel", "\\xcancel", "\\sout"], + props: { + numArgs: 1 + }, + handler: function handler(_ref4, args, optArgs) { + var parser = _ref4.parser, + funcName = _ref4.funcName; + var body = args[0]; + return { + type: "enclose", + mode: parser.mode, + label: funcName, + body: body + }; + }, + htmlBuilder: enclose_htmlBuilder, + mathmlBuilder: enclose_mathmlBuilder +}); +// CONCATENATED MODULE: ./src/defineEnvironment.js + + +/** + * All registered environments. + * `environments.js` exports this same dictionary again and makes it public. + * `Parser.js` requires this dictionary via `environments.js`. + */ +var _environments = {}; +function defineEnvironment(_ref) { + var type = _ref.type, + names = _ref.names, + props = _ref.props, + handler = _ref.handler, + htmlBuilder = _ref.htmlBuilder, + mathmlBuilder = _ref.mathmlBuilder; + // Set default values of environments. + var data = { + type: type, + numArgs: props.numArgs || 0, + greediness: 1, + allowedInText: false, + numOptionalArgs: 0, + handler: handler + }; + + for (var i = 0; i < names.length; ++i) { + // TODO: The value type of _environments should be a type union of all + // possible `EnvSpec<>` possibilities instead of `EnvSpec<*>`, which is + // an existential type. + // $FlowFixMe + _environments[names[i]] = data; + } + + if (htmlBuilder) { + _htmlGroupBuilders[type] = htmlBuilder; + } + + if (mathmlBuilder) { + _mathmlGroupBuilders[type] = mathmlBuilder; + } +} +// CONCATENATED MODULE: ./src/environments/array.js + + + + + + + + + + + + + +function getHLines(parser) { + // Return an array. The array length = number of hlines. + // Each element in the array tells if the line is dashed. + var hlineInfo = []; + parser.consumeSpaces(); + var nxt = parser.fetch().text; + + while (nxt === "\\hline" || nxt === "\\hdashline") { + parser.consume(); + hlineInfo.push(nxt === "\\hdashline"); + parser.consumeSpaces(); + nxt = parser.fetch().text; + } + + return hlineInfo; +} +/** + * Parse the body of the environment, with rows delimited by \\ and + * columns delimited by &, and create a nested list in row-major order + * with one group per cell. If given an optional argument style + * ("text", "display", etc.), then each cell is cast into that style. + */ + + +function parseArray(parser, _ref, style) { + var hskipBeforeAndAfter = _ref.hskipBeforeAndAfter, + addJot = _ref.addJot, + cols = _ref.cols, + arraystretch = _ref.arraystretch, + colSeparationType = _ref.colSeparationType; + // Parse body of array with \\ temporarily mapped to \cr + parser.gullet.beginGroup(); + parser.gullet.macros.set("\\\\", "\\cr"); // Get current arraystretch if it's not set by the environment + + if (!arraystretch) { + var stretch = parser.gullet.expandMacroAsText("\\arraystretch"); + + if (stretch == null) { + // Default \arraystretch from lttab.dtx + arraystretch = 1; + } else { + arraystretch = parseFloat(stretch); + + if (!arraystretch || arraystretch < 0) { + throw new src_ParseError("Invalid \\arraystretch: " + stretch); + } + } + } // Start group for first cell + + + parser.gullet.beginGroup(); + var row = []; + var body = [row]; + var rowGaps = []; + var hLinesBeforeRow = []; // Test for \hline at the top of the array. + + hLinesBeforeRow.push(getHLines(parser)); + + while (true) { + // eslint-disable-line no-constant-condition + // Parse each cell in its own group (namespace) + var cell = parser.parseExpression(false, "\\cr"); + parser.gullet.endGroup(); + parser.gullet.beginGroup(); + cell = { + type: "ordgroup", + mode: parser.mode, + body: cell + }; + + if (style) { + cell = { + type: "styling", + mode: parser.mode, + style: style, + body: [cell] + }; + } + + row.push(cell); + var next = parser.fetch().text; + + if (next === "&") { + parser.consume(); + } else if (next === "\\end") { + // Arrays terminate newlines with `\crcr` which consumes a `\cr` if + // the last line is empty. + // NOTE: Currently, `cell` is the last item added into `row`. + if (row.length === 1 && cell.type === "styling" && cell.body[0].body.length === 0) { + body.pop(); + } + + if (hLinesBeforeRow.length < body.length + 1) { + hLinesBeforeRow.push([]); + } + + break; + } else if (next === "\\cr") { + var cr = assertNodeType(parser.parseFunction(), "cr"); + rowGaps.push(cr.size); // check for \hline(s) following the row separator + + hLinesBeforeRow.push(getHLines(parser)); + row = []; + body.push(row); + } else { + throw new src_ParseError("Expected & or \\\\ or \\cr or \\end", parser.nextToken); + } + } // End cell group + + + parser.gullet.endGroup(); // End array group defining \\ + + parser.gullet.endGroup(); + return { + type: "array", + mode: parser.mode, + addJot: addJot, + arraystretch: arraystretch, + body: body, + cols: cols, + rowGaps: rowGaps, + hskipBeforeAndAfter: hskipBeforeAndAfter, + hLinesBeforeRow: hLinesBeforeRow, + colSeparationType: colSeparationType + }; +} // Decides on a style for cells in an array according to whether the given +// environment name starts with the letter 'd'. + + +function dCellStyle(envName) { + if (envName.substr(0, 1) === "d") { + return "display"; + } else { + return "text"; + } +} + +var array_htmlBuilder = function htmlBuilder(group, options) { + var r; + var c; + var nr = group.body.length; + var hLinesBeforeRow = group.hLinesBeforeRow; + var nc = 0; + var body = new Array(nr); + var hlines = []; + var ruleThickness = Math.max( // From LaTeX \showthe\arrayrulewidth. Equals 0.04 em. + options.fontMetrics().arrayRuleWidth, options.minRuleThickness // User override. + ); // Horizontal spacing + + var pt = 1 / options.fontMetrics().ptPerEm; + var arraycolsep = 5 * pt; // default value, i.e. \arraycolsep in article.cls + + if (group.colSeparationType && group.colSeparationType === "small") { + // We're in a {smallmatrix}. Default column space is \thickspace, + // i.e. 5/18em = 0.2778em, per amsmath.dtx for {smallmatrix}. + // But that needs adjustment because LaTeX applies \scriptstyle to the + // entire array, including the colspace, but this function applies + // \scriptstyle only inside each element. + var localMultiplier = options.havingStyle(src_Style.SCRIPT).sizeMultiplier; + arraycolsep = 0.2778 * (localMultiplier / options.sizeMultiplier); + } // Vertical spacing + + + var baselineskip = 12 * pt; // see size10.clo + // Default \jot from ltmath.dtx + // TODO(edemaine): allow overriding \jot via \setlength (#687) + + var jot = 3 * pt; + var arrayskip = group.arraystretch * baselineskip; + var arstrutHeight = 0.7 * arrayskip; // \strutbox in ltfsstrc.dtx and + + var arstrutDepth = 0.3 * arrayskip; // \@arstrutbox in lttab.dtx + + var totalHeight = 0; // Set a position for \hline(s) at the top of the array, if any. + + function setHLinePos(hlinesInGap) { + for (var i = 0; i < hlinesInGap.length; ++i) { + if (i > 0) { + totalHeight += 0.25; + } + + hlines.push({ + pos: totalHeight, + isDashed: hlinesInGap[i] + }); + } + } + + setHLinePos(hLinesBeforeRow[0]); + + for (r = 0; r < group.body.length; ++r) { + var inrow = group.body[r]; + var height = arstrutHeight; // \@array adds an \@arstrut + + var depth = arstrutDepth; // to each tow (via the template) + + if (nc < inrow.length) { + nc = inrow.length; + } + + var outrow = new Array(inrow.length); + + for (c = 0; c < inrow.length; ++c) { + var elt = buildHTML_buildGroup(inrow[c], options); + + if (depth < elt.depth) { + depth = elt.depth; + } + + if (height < elt.height) { + height = elt.height; + } + + outrow[c] = elt; + } + + var rowGap = group.rowGaps[r]; + var gap = 0; + + if (rowGap) { + gap = units_calculateSize(rowGap, options); + + if (gap > 0) { + // \@argarraycr + gap += arstrutDepth; + + if (depth < gap) { + depth = gap; // \@xargarraycr + } + + gap = 0; + } + } // In AMS multiline environments such as aligned and gathered, rows + // correspond to lines that have additional \jot added to the + // \baselineskip via \openup. + + + if (group.addJot) { + depth += jot; + } + + outrow.height = height; + outrow.depth = depth; + totalHeight += height; + outrow.pos = totalHeight; + totalHeight += depth + gap; // \@yargarraycr + + body[r] = outrow; // Set a position for \hline(s), if any. + + setHLinePos(hLinesBeforeRow[r + 1]); + } + + var offset = totalHeight / 2 + options.fontMetrics().axisHeight; + var colDescriptions = group.cols || []; + var cols = []; + var colSep; + var colDescrNum; + + for (c = 0, colDescrNum = 0; // Continue while either there are more columns or more column + // descriptions, so trailing separators don't get lost. + c < nc || colDescrNum < colDescriptions.length; ++c, ++colDescrNum) { + var colDescr = colDescriptions[colDescrNum] || {}; + var firstSeparator = true; + + while (colDescr.type === "separator") { + // If there is more than one separator in a row, add a space + // between them. + if (!firstSeparator) { + colSep = buildCommon.makeSpan(["arraycolsep"], []); + colSep.style.width = options.fontMetrics().doubleRuleSep + "em"; + cols.push(colSep); + } + + if (colDescr.separator === "|" || colDescr.separator === ":") { + var lineType = colDescr.separator === "|" ? "solid" : "dashed"; + var separator = buildCommon.makeSpan(["vertical-separator"], [], options); + separator.style.height = totalHeight + "em"; + separator.style.borderRightWidth = ruleThickness + "em"; + separator.style.borderRightStyle = lineType; + separator.style.margin = "0 -" + ruleThickness / 2 + "em"; + separator.style.verticalAlign = -(totalHeight - offset) + "em"; + cols.push(separator); + } else { + throw new src_ParseError("Invalid separator type: " + colDescr.separator); + } + + colDescrNum++; + colDescr = colDescriptions[colDescrNum] || {}; + firstSeparator = false; + } + + if (c >= nc) { + continue; + } + + var sepwidth = void 0; + + if (c > 0 || group.hskipBeforeAndAfter) { + sepwidth = utils.deflt(colDescr.pregap, arraycolsep); + + if (sepwidth !== 0) { + colSep = buildCommon.makeSpan(["arraycolsep"], []); + colSep.style.width = sepwidth + "em"; + cols.push(colSep); + } + } + + var col = []; + + for (r = 0; r < nr; ++r) { + var row = body[r]; + var elem = row[c]; + + if (!elem) { + continue; + } + + var shift = row.pos - offset; + elem.depth = row.depth; + elem.height = row.height; + col.push({ + type: "elem", + elem: elem, + shift: shift + }); + } + + col = buildCommon.makeVList({ + positionType: "individualShift", + children: col + }, options); + col = buildCommon.makeSpan(["col-align-" + (colDescr.align || "c")], [col]); + cols.push(col); + + if (c < nc - 1 || group.hskipBeforeAndAfter) { + sepwidth = utils.deflt(colDescr.postgap, arraycolsep); + + if (sepwidth !== 0) { + colSep = buildCommon.makeSpan(["arraycolsep"], []); + colSep.style.width = sepwidth + "em"; + cols.push(colSep); + } + } + } + + body = buildCommon.makeSpan(["mtable"], cols); // Add \hline(s), if any. + + if (hlines.length > 0) { + var line = buildCommon.makeLineSpan("hline", options, ruleThickness); + var dashes = buildCommon.makeLineSpan("hdashline", options, ruleThickness); + var vListElems = [{ + type: "elem", + elem: body, + shift: 0 + }]; + + while (hlines.length > 0) { + var hline = hlines.pop(); + var lineShift = hline.pos - offset; + + if (hline.isDashed) { + vListElems.push({ + type: "elem", + elem: dashes, + shift: lineShift + }); + } else { + vListElems.push({ + type: "elem", + elem: line, + shift: lineShift + }); + } + } + + body = buildCommon.makeVList({ + positionType: "individualShift", + children: vListElems + }, options); + } + + return buildCommon.makeSpan(["mord"], [body], options); +}; + +var alignMap = { + c: "center ", + l: "left ", + r: "right " +}; + +var array_mathmlBuilder = function mathmlBuilder(group, options) { + var table = new mathMLTree.MathNode("mtable", group.body.map(function (row) { + return new mathMLTree.MathNode("mtr", row.map(function (cell) { + return new mathMLTree.MathNode("mtd", [buildMathML_buildGroup(cell, options)]); + })); + })); // Set column alignment, row spacing, column spacing, and + // array lines by setting attributes on the table element. + // Set the row spacing. In MathML, we specify a gap distance. + // We do not use rowGap[] because MathML automatically increases + // cell height with the height/depth of the element content. + // LaTeX \arraystretch multiplies the row baseline-to-baseline distance. + // We simulate this by adding (arraystretch - 1)em to the gap. This + // does a reasonable job of adjusting arrays containing 1 em tall content. + // The 0.16 and 0.09 values are found emprically. They produce an array + // similar to LaTeX and in which content does not interfere with \hines. + + var gap = group.arraystretch === 0.5 ? 0.1 // {smallmatrix}, {subarray} + : 0.16 + group.arraystretch - 1 + (group.addJot ? 0.09 : 0); + table.setAttribute("rowspacing", gap + "em"); // MathML table lines go only between cells. + // To place a line on an edge we'll use , if necessary. + + var menclose = ""; + var align = ""; + + if (group.cols) { + // Find column alignment, column spacing, and vertical lines. + var cols = group.cols; + var columnLines = ""; + var prevTypeWasAlign = false; + var iStart = 0; + var iEnd = cols.length; + + if (cols[0].type === "separator") { + menclose += "top "; + iStart = 1; + } + + if (cols[cols.length - 1].type === "separator") { + menclose += "bottom "; + iEnd -= 1; + } + + for (var i = iStart; i < iEnd; i++) { + if (cols[i].type === "align") { + align += alignMap[cols[i].align]; + + if (prevTypeWasAlign) { + columnLines += "none "; + } + + prevTypeWasAlign = true; + } else if (cols[i].type === "separator") { + // MathML accepts only single lines between cells. + // So we read only the first of consecutive separators. + if (prevTypeWasAlign) { + columnLines += cols[i].separator === "|" ? "solid " : "dashed "; + prevTypeWasAlign = false; + } + } + } + + table.setAttribute("columnalign", align.trim()); + + if (/[sd]/.test(columnLines)) { + table.setAttribute("columnlines", columnLines.trim()); + } + } // Set column spacing. + + + if (group.colSeparationType === "align") { + var _cols = group.cols || []; + + var spacing = ""; + + for (var _i = 1; _i < _cols.length; _i++) { + spacing += _i % 2 ? "0em " : "1em "; + } + + table.setAttribute("columnspacing", spacing.trim()); + } else if (group.colSeparationType === "alignat") { + table.setAttribute("columnspacing", "0em"); + } else if (group.colSeparationType === "small") { + table.setAttribute("columnspacing", "0.2778em"); + } else { + table.setAttribute("columnspacing", "1em"); + } // Address \hline and \hdashline + + + var rowLines = ""; + var hlines = group.hLinesBeforeRow; + menclose += hlines[0].length > 0 ? "left " : ""; + menclose += hlines[hlines.length - 1].length > 0 ? "right " : ""; + + for (var _i2 = 1; _i2 < hlines.length - 1; _i2++) { + rowLines += hlines[_i2].length === 0 ? "none " // MathML accepts only a single line between rows. Read one element. + : hlines[_i2][0] ? "dashed " : "solid "; + } + + if (/[sd]/.test(rowLines)) { + table.setAttribute("rowlines", rowLines.trim()); + } + + if (menclose !== "") { + table = new mathMLTree.MathNode("menclose", [table]); + table.setAttribute("notation", menclose.trim()); + } + + if (group.arraystretch && group.arraystretch < 1) { + // A small array. Wrap in scriptstyle so row gap is not too large. + table = new mathMLTree.MathNode("mstyle", [table]); + table.setAttribute("scriptlevel", "1"); + } + + return table; +}; // Convenience function for aligned and alignedat environments. + + +var array_alignedHandler = function alignedHandler(context, args) { + var cols = []; + var res = parseArray(context.parser, { + cols: cols, + addJot: true + }, "display"); // Determining number of columns. + // 1. If the first argument is given, we use it as a number of columns, + // and makes sure that each row doesn't exceed that number. + // 2. Otherwise, just count number of columns = maximum number + // of cells in each row ("aligned" mode -- isAligned will be true). + // + // At the same time, prepend empty group {} at beginning of every second + // cell in each row (starting with second cell) so that operators become + // binary. This behavior is implemented in amsmath's \start@aligned. + + var numMaths; + var numCols = 0; + var emptyGroup = { + type: "ordgroup", + mode: context.mode, + body: [] + }; + var ordgroup = checkNodeType(args[0], "ordgroup"); + + if (ordgroup) { + var arg0 = ""; + + for (var i = 0; i < ordgroup.body.length; i++) { + var textord = assertNodeType(ordgroup.body[i], "textord"); + arg0 += textord.text; + } + + numMaths = Number(arg0); + numCols = numMaths * 2; + } + + var isAligned = !numCols; + res.body.forEach(function (row) { + for (var _i3 = 1; _i3 < row.length; _i3 += 2) { + // Modify ordgroup node within styling node + var styling = assertNodeType(row[_i3], "styling"); + + var _ordgroup = assertNodeType(styling.body[0], "ordgroup"); + + _ordgroup.body.unshift(emptyGroup); + } + + if (!isAligned) { + // Case 1 + var curMaths = row.length / 2; + + if (numMaths < curMaths) { + throw new src_ParseError("Too many math in a row: " + ("expected " + numMaths + ", but got " + curMaths), row[0]); + } + } else if (numCols < row.length) { + // Case 2 + numCols = row.length; + } + }); // Adjusting alignment. + // In aligned mode, we add one \qquad between columns; + // otherwise we add nothing. + + for (var _i4 = 0; _i4 < numCols; ++_i4) { + var align = "r"; + var pregap = 0; + + if (_i4 % 2 === 1) { + align = "l"; + } else if (_i4 > 0 && isAligned) { + // "aligned" mode. + pregap = 1; // add one \quad + } + + cols[_i4] = { + type: "align", + align: align, + pregap: pregap, + postgap: 0 + }; + } + + res.colSeparationType = isAligned ? "align" : "alignat"; + return res; +}; // Arrays are part of LaTeX, defined in lttab.dtx so its documentation +// is part of the source2e.pdf file of LaTeX2e source documentation. +// {darray} is an {array} environment where cells are set in \displaystyle, +// as defined in nccmath.sty. + + +defineEnvironment({ + type: "array", + names: ["array", "darray"], + props: { + numArgs: 1 + }, + handler: function handler(context, args) { + // Since no types are specified above, the two possibilities are + // - The argument is wrapped in {} or [], in which case Parser's + // parseGroup() returns an "ordgroup" wrapping some symbol node. + // - The argument is a bare symbol node. + var symNode = checkSymbolNodeType(args[0]); + var colalign = symNode ? [args[0]] : assertNodeType(args[0], "ordgroup").body; + var cols = colalign.map(function (nde) { + var node = assertSymbolNodeType(nde); + var ca = node.text; + + if ("lcr".indexOf(ca) !== -1) { + return { + type: "align", + align: ca + }; + } else if (ca === "|") { + return { + type: "separator", + separator: "|" + }; + } else if (ca === ":") { + return { + type: "separator", + separator: ":" + }; + } + + throw new src_ParseError("Unknown column alignment: " + ca, nde); + }); + var res = { + cols: cols, + hskipBeforeAndAfter: true // \@preamble in lttab.dtx + + }; + return parseArray(context.parser, res, dCellStyle(context.envName)); + }, + htmlBuilder: array_htmlBuilder, + mathmlBuilder: array_mathmlBuilder +}); // The matrix environments of amsmath builds on the array environment +// of LaTeX, which is discussed above. + +defineEnvironment({ + type: "array", + names: ["matrix", "pmatrix", "bmatrix", "Bmatrix", "vmatrix", "Vmatrix"], + props: { + numArgs: 0 + }, + handler: function handler(context) { + var delimiters = { + "matrix": null, + "pmatrix": ["(", ")"], + "bmatrix": ["[", "]"], + "Bmatrix": ["\\{", "\\}"], + "vmatrix": ["|", "|"], + "Vmatrix": ["\\Vert", "\\Vert"] + }[context.envName]; // \hskip -\arraycolsep in amsmath + + var payload = { + hskipBeforeAndAfter: false + }; + var res = parseArray(context.parser, payload, dCellStyle(context.envName)); + return delimiters ? { + type: "leftright", + mode: context.mode, + body: [res], + left: delimiters[0], + right: delimiters[1], + rightColor: undefined // \right uninfluenced by \color in array + + } : res; + }, + htmlBuilder: array_htmlBuilder, + mathmlBuilder: array_mathmlBuilder +}); +defineEnvironment({ + type: "array", + names: ["smallmatrix"], + props: { + numArgs: 0 + }, + handler: function handler(context) { + var payload = { + arraystretch: 0.5 + }; + var res = parseArray(context.parser, payload, "script"); + res.colSeparationType = "small"; + return res; + }, + htmlBuilder: array_htmlBuilder, + mathmlBuilder: array_mathmlBuilder +}); +defineEnvironment({ + type: "array", + names: ["subarray"], + props: { + numArgs: 1 + }, + handler: function handler(context, args) { + // Parsing of {subarray} is similar to {array} + var symNode = checkSymbolNodeType(args[0]); + var colalign = symNode ? [args[0]] : assertNodeType(args[0], "ordgroup").body; + var cols = colalign.map(function (nde) { + var node = assertSymbolNodeType(nde); + var ca = node.text; // {subarray} only recognizes "l" & "c" + + if ("lc".indexOf(ca) !== -1) { + return { + type: "align", + align: ca + }; + } + + throw new src_ParseError("Unknown column alignment: " + ca, nde); + }); + + if (cols.length > 1) { + throw new src_ParseError("{subarray} can contain only one column"); + } + + var res = { + cols: cols, + hskipBeforeAndAfter: false, + arraystretch: 0.5 + }; + res = parseArray(context.parser, res, "script"); + + if (res.body[0].length > 1) { + throw new src_ParseError("{subarray} can contain only one column"); + } + + return res; + }, + htmlBuilder: array_htmlBuilder, + mathmlBuilder: array_mathmlBuilder +}); // A cases environment (in amsmath.sty) is almost equivalent to +// \def\arraystretch{1.2}% +// \left\{\begin{array}{@{}l@{\quad}l@{}} … \end{array}\right. +// {dcases} is a {cases} environment where cells are set in \displaystyle, +// as defined in mathtools.sty. + +defineEnvironment({ + type: "array", + names: ["cases", "dcases"], + props: { + numArgs: 0 + }, + handler: function handler(context) { + var payload = { + arraystretch: 1.2, + cols: [{ + type: "align", + align: "l", + pregap: 0, + // TODO(kevinb) get the current style. + // For now we use the metrics for TEXT style which is what we were + // doing before. Before attempting to get the current style we + // should look at TeX's behavior especially for \over and matrices. + postgap: 1.0 + /* 1em quad */ + + }, { + type: "align", + align: "l", + pregap: 0, + postgap: 0 + }] + }; + var res = parseArray(context.parser, payload, dCellStyle(context.envName)); + return { + type: "leftright", + mode: context.mode, + body: [res], + left: "\\{", + right: ".", + rightColor: undefined + }; + }, + htmlBuilder: array_htmlBuilder, + mathmlBuilder: array_mathmlBuilder +}); // An aligned environment is like the align* environment +// except it operates within math mode. +// Note that we assume \nomallineskiplimit to be zero, +// so that \strut@ is the same as \strut. + +defineEnvironment({ + type: "array", + names: ["aligned"], + props: { + numArgs: 0 + }, + handler: array_alignedHandler, + htmlBuilder: array_htmlBuilder, + mathmlBuilder: array_mathmlBuilder +}); // A gathered environment is like an array environment with one centered +// column, but where rows are considered lines so get \jot line spacing +// and contents are set in \displaystyle. + +defineEnvironment({ + type: "array", + names: ["gathered"], + props: { + numArgs: 0 + }, + handler: function handler(context) { + var res = { + cols: [{ + type: "align", + align: "c" + }], + addJot: true + }; + return parseArray(context.parser, res, "display"); + }, + htmlBuilder: array_htmlBuilder, + mathmlBuilder: array_mathmlBuilder +}); // alignat environment is like an align environment, but one must explicitly +// specify maximum number of columns in each row, and can adjust spacing between +// each columns. + +defineEnvironment({ + type: "array", + names: ["alignedat"], + // One for numbered and for unnumbered; + // but, KaTeX doesn't supports math numbering yet, + // they make no difference for now. + props: { + numArgs: 1 + }, + handler: array_alignedHandler, + htmlBuilder: array_htmlBuilder, + mathmlBuilder: array_mathmlBuilder +}); // Catch \hline outside array environment + +defineFunction({ + type: "text", + // Doesn't matter what this is. + names: ["\\hline", "\\hdashline"], + props: { + numArgs: 0, + allowedInText: true, + allowedInMath: true + }, + handler: function handler(context, args) { + throw new src_ParseError(context.funcName + " valid only within array environment"); + } +}); +// CONCATENATED MODULE: ./src/environments.js + +var environments = _environments; +/* harmony default export */ var src_environments = (environments); // All environment definitions should be imported below + + +// CONCATENATED MODULE: ./src/functions/environment.js + + + + // Environment delimiters. HTML/MathML rendering is defined in the corresponding +// defineEnvironment definitions. +// $FlowFixMe, "environment" handler returns an environment ParseNode + +defineFunction({ + type: "environment", + names: ["\\begin", "\\end"], + props: { + numArgs: 1, + argTypes: ["text"] + }, + handler: function handler(_ref, args) { + var parser = _ref.parser, + funcName = _ref.funcName; + var nameGroup = args[0]; + + if (nameGroup.type !== "ordgroup") { + throw new src_ParseError("Invalid environment name", nameGroup); + } + + var envName = ""; + + for (var i = 0; i < nameGroup.body.length; ++i) { + envName += assertNodeType(nameGroup.body[i], "textord").text; + } + + if (funcName === "\\begin") { + // begin...end is similar to left...right + if (!src_environments.hasOwnProperty(envName)) { + throw new src_ParseError("No such environment: " + envName, nameGroup); + } // Build the environment object. Arguments and other information will + // be made available to the begin and end methods using properties. + + + var env = src_environments[envName]; + + var _parser$parseArgument = parser.parseArguments("\\begin{" + envName + "}", env), + _args = _parser$parseArgument.args, + optArgs = _parser$parseArgument.optArgs; + + var context = { + mode: parser.mode, + envName: envName, + parser: parser + }; + var result = env.handler(context, _args, optArgs); + parser.expect("\\end", false); + var endNameToken = parser.nextToken; + var end = assertNodeType(parser.parseFunction(), "environment"); + + if (end.name !== envName) { + throw new src_ParseError("Mismatch: \\begin{" + envName + "} matched by \\end{" + end.name + "}", endNameToken); + } + + return result; + } + + return { + type: "environment", + mode: parser.mode, + name: envName, + nameGroup: nameGroup + }; + } +}); +// CONCATENATED MODULE: ./src/functions/mclass.js + + + + + + +var mclass_makeSpan = buildCommon.makeSpan; + +function mclass_htmlBuilder(group, options) { + var elements = buildHTML_buildExpression(group.body, options, true); + return mclass_makeSpan([group.mclass], elements, options); +} + +function mclass_mathmlBuilder(group, options) { + var node; + var inner = buildMathML_buildExpression(group.body, options); + + if (group.mclass === "minner") { + return mathMLTree.newDocumentFragment(inner); + } else if (group.mclass === "mord") { + if (group.isCharacterBox) { + node = inner[0]; + node.type = "mi"; + } else { + node = new mathMLTree.MathNode("mi", inner); + } + } else { + if (group.isCharacterBox) { + node = inner[0]; + node.type = "mo"; + } else { + node = new mathMLTree.MathNode("mo", inner); + } // Set spacing based on what is the most likely adjacent atom type. + // See TeXbook p170. + + + if (group.mclass === "mbin") { + node.attributes.lspace = "0.22em"; // medium space + + node.attributes.rspace = "0.22em"; + } else if (group.mclass === "mpunct") { + node.attributes.lspace = "0em"; + node.attributes.rspace = "0.17em"; // thinspace + } else if (group.mclass === "mopen" || group.mclass === "mclose") { + node.attributes.lspace = "0em"; + node.attributes.rspace = "0em"; + } // MathML default space is 5/18 em, so needs no action. + // Ref: https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mo + + } + + return node; +} // Math class commands except \mathop + + +defineFunction({ + type: "mclass", + names: ["\\mathord", "\\mathbin", "\\mathrel", "\\mathopen", "\\mathclose", "\\mathpunct", "\\mathinner"], + props: { + numArgs: 1 + }, + handler: function handler(_ref, args) { + var parser = _ref.parser, + funcName = _ref.funcName; + var body = args[0]; + return { + type: "mclass", + mode: parser.mode, + mclass: "m" + funcName.substr(5), + // TODO(kevinb): don't prefix with 'm' + body: defineFunction_ordargument(body), + isCharacterBox: utils.isCharacterBox(body) + }; + }, + htmlBuilder: mclass_htmlBuilder, + mathmlBuilder: mclass_mathmlBuilder +}); +var binrelClass = function binrelClass(arg) { + // \binrel@ spacing varies with (bin|rel|ord) of the atom in the argument. + // (by rendering separately and with {}s before and after, and measuring + // the change in spacing). We'll do roughly the same by detecting the + // atom type directly. + var atom = arg.type === "ordgroup" && arg.body.length ? arg.body[0] : arg; + + if (atom.type === "atom" && (atom.family === "bin" || atom.family === "rel")) { + return "m" + atom.family; + } else { + return "mord"; + } +}; // \@binrel{x}{y} renders like y but as mbin/mrel/mord if x is mbin/mrel/mord. +// This is equivalent to \binrel@{x}\binrel@@{y} in AMSTeX. + +defineFunction({ + type: "mclass", + names: ["\\@binrel"], + props: { + numArgs: 2 + }, + handler: function handler(_ref2, args) { + var parser = _ref2.parser; + return { + type: "mclass", + mode: parser.mode, + mclass: binrelClass(args[0]), + body: [args[1]], + isCharacterBox: utils.isCharacterBox(args[1]) + }; + } +}); // Build a relation or stacked op by placing one symbol on top of another + +defineFunction({ + type: "mclass", + names: ["\\stackrel", "\\overset", "\\underset"], + props: { + numArgs: 2 + }, + handler: function handler(_ref3, args) { + var parser = _ref3.parser, + funcName = _ref3.funcName; + var baseArg = args[1]; + var shiftedArg = args[0]; + var mclass; + + if (funcName !== "\\stackrel") { + // LaTeX applies \binrel spacing to \overset and \underset. + mclass = binrelClass(baseArg); + } else { + mclass = "mrel"; // for \stackrel + } + + var baseOp = { + type: "op", + mode: baseArg.mode, + limits: true, + alwaysHandleSupSub: true, + parentIsSupSub: false, + symbol: false, + suppressBaseShift: funcName !== "\\stackrel", + body: defineFunction_ordargument(baseArg) + }; + var supsub = { + type: "supsub", + mode: shiftedArg.mode, + base: baseOp, + sup: funcName === "\\underset" ? null : shiftedArg, + sub: funcName === "\\underset" ? shiftedArg : null + }; + return { + type: "mclass", + mode: parser.mode, + mclass: mclass, + body: [supsub], + isCharacterBox: utils.isCharacterBox(supsub) + }; + }, + htmlBuilder: mclass_htmlBuilder, + mathmlBuilder: mclass_mathmlBuilder +}); +// CONCATENATED MODULE: ./src/functions/font.js +// TODO(kevinb): implement \\sl and \\sc + + + + + + +var font_htmlBuilder = function htmlBuilder(group, options) { + var font = group.font; + var newOptions = options.withFont(font); + return buildHTML_buildGroup(group.body, newOptions); +}; + +var font_mathmlBuilder = function mathmlBuilder(group, options) { + var font = group.font; + var newOptions = options.withFont(font); + return buildMathML_buildGroup(group.body, newOptions); +}; + +var fontAliases = { + "\\Bbb": "\\mathbb", + "\\bold": "\\mathbf", + "\\frak": "\\mathfrak", + "\\bm": "\\boldsymbol" +}; +defineFunction({ + type: "font", + names: [// styles, except \boldsymbol defined below + "\\mathrm", "\\mathit", "\\mathbf", "\\mathnormal", // families + "\\mathbb", "\\mathcal", "\\mathfrak", "\\mathscr", "\\mathsf", "\\mathtt", // aliases, except \bm defined below + "\\Bbb", "\\bold", "\\frak"], + props: { + numArgs: 1, + greediness: 2 + }, + handler: function handler(_ref, args) { + var parser = _ref.parser, + funcName = _ref.funcName; + var body = args[0]; + var func = funcName; + + if (func in fontAliases) { + func = fontAliases[func]; + } + + return { + type: "font", + mode: parser.mode, + font: func.slice(1), + body: body + }; + }, + htmlBuilder: font_htmlBuilder, + mathmlBuilder: font_mathmlBuilder +}); +defineFunction({ + type: "mclass", + names: ["\\boldsymbol", "\\bm"], + props: { + numArgs: 1, + greediness: 2 + }, + handler: function handler(_ref2, args) { + var parser = _ref2.parser; + var body = args[0]; + var isCharacterBox = utils.isCharacterBox(body); // amsbsy.sty's \boldsymbol uses \binrel spacing to inherit the + // argument's bin|rel|ord status + + return { + type: "mclass", + mode: parser.mode, + mclass: binrelClass(body), + body: [{ + type: "font", + mode: parser.mode, + font: "boldsymbol", + body: body + }], + isCharacterBox: isCharacterBox + }; + } +}); // Old font changing functions + +defineFunction({ + type: "font", + names: ["\\rm", "\\sf", "\\tt", "\\bf", "\\it"], + props: { + numArgs: 0, + allowedInText: true + }, + handler: function handler(_ref3, args) { + var parser = _ref3.parser, + funcName = _ref3.funcName, + breakOnTokenText = _ref3.breakOnTokenText; + var mode = parser.mode; + var body = parser.parseExpression(true, breakOnTokenText); + var style = "math" + funcName.slice(1); + return { + type: "font", + mode: mode, + font: style, + body: { + type: "ordgroup", + mode: parser.mode, + body: body + } + }; + }, + htmlBuilder: font_htmlBuilder, + mathmlBuilder: font_mathmlBuilder +}); +// CONCATENATED MODULE: ./src/functions/genfrac.js + + + + + + + + + + + +var genfrac_adjustStyle = function adjustStyle(size, originalStyle) { + // Figure out what style this fraction should be in based on the + // function used + var style = originalStyle; + + if (size === "display") { + // Get display style as a default. + // If incoming style is sub/sup, use style.text() to get correct size. + style = style.id >= src_Style.SCRIPT.id ? style.text() : src_Style.DISPLAY; + } else if (size === "text" && style.size === src_Style.DISPLAY.size) { + // We're in a \tfrac but incoming style is displaystyle, so: + style = src_Style.TEXT; + } else if (size === "script") { + style = src_Style.SCRIPT; + } else if (size === "scriptscript") { + style = src_Style.SCRIPTSCRIPT; + } + + return style; +}; + +var genfrac_htmlBuilder = function htmlBuilder(group, options) { + // Fractions are handled in the TeXbook on pages 444-445, rules 15(a-e). + var style = genfrac_adjustStyle(group.size, options.style); + var nstyle = style.fracNum(); + var dstyle = style.fracDen(); + var newOptions; + newOptions = options.havingStyle(nstyle); + var numerm = buildHTML_buildGroup(group.numer, newOptions, options); + + if (group.continued) { + // \cfrac inserts a \strut into the numerator. + // Get \strut dimensions from TeXbook page 353. + var hStrut = 8.5 / options.fontMetrics().ptPerEm; + var dStrut = 3.5 / options.fontMetrics().ptPerEm; + numerm.height = numerm.height < hStrut ? hStrut : numerm.height; + numerm.depth = numerm.depth < dStrut ? dStrut : numerm.depth; + } + + newOptions = options.havingStyle(dstyle); + var denomm = buildHTML_buildGroup(group.denom, newOptions, options); + var rule; + var ruleWidth; + var ruleSpacing; + + if (group.hasBarLine) { + if (group.barSize) { + ruleWidth = units_calculateSize(group.barSize, options); + rule = buildCommon.makeLineSpan("frac-line", options, ruleWidth); + } else { + rule = buildCommon.makeLineSpan("frac-line", options); + } + + ruleWidth = rule.height; + ruleSpacing = rule.height; + } else { + rule = null; + ruleWidth = 0; + ruleSpacing = options.fontMetrics().defaultRuleThickness; + } // Rule 15b + + + var numShift; + var clearance; + var denomShift; + + if (style.size === src_Style.DISPLAY.size || group.size === "display") { + numShift = options.fontMetrics().num1; + + if (ruleWidth > 0) { + clearance = 3 * ruleSpacing; + } else { + clearance = 7 * ruleSpacing; + } + + denomShift = options.fontMetrics().denom1; + } else { + if (ruleWidth > 0) { + numShift = options.fontMetrics().num2; + clearance = ruleSpacing; + } else { + numShift = options.fontMetrics().num3; + clearance = 3 * ruleSpacing; + } + + denomShift = options.fontMetrics().denom2; + } + + var frac; + + if (!rule) { + // Rule 15c + var candidateClearance = numShift - numerm.depth - (denomm.height - denomShift); + + if (candidateClearance < clearance) { + numShift += 0.5 * (clearance - candidateClearance); + denomShift += 0.5 * (clearance - candidateClearance); + } + + frac = buildCommon.makeVList({ + positionType: "individualShift", + children: [{ + type: "elem", + elem: denomm, + shift: denomShift + }, { + type: "elem", + elem: numerm, + shift: -numShift + }] + }, options); + } else { + // Rule 15d + var axisHeight = options.fontMetrics().axisHeight; + + if (numShift - numerm.depth - (axisHeight + 0.5 * ruleWidth) < clearance) { + numShift += clearance - (numShift - numerm.depth - (axisHeight + 0.5 * ruleWidth)); + } + + if (axisHeight - 0.5 * ruleWidth - (denomm.height - denomShift) < clearance) { + denomShift += clearance - (axisHeight - 0.5 * ruleWidth - (denomm.height - denomShift)); + } + + var midShift = -(axisHeight - 0.5 * ruleWidth); + frac = buildCommon.makeVList({ + positionType: "individualShift", + children: [{ + type: "elem", + elem: denomm, + shift: denomShift + }, { + type: "elem", + elem: rule, + shift: midShift + }, { + type: "elem", + elem: numerm, + shift: -numShift + }] + }, options); + } // Since we manually change the style sometimes (with \dfrac or \tfrac), + // account for the possible size change here. + + + newOptions = options.havingStyle(style); + frac.height *= newOptions.sizeMultiplier / options.sizeMultiplier; + frac.depth *= newOptions.sizeMultiplier / options.sizeMultiplier; // Rule 15e + + var delimSize; + + if (style.size === src_Style.DISPLAY.size) { + delimSize = options.fontMetrics().delim1; + } else { + delimSize = options.fontMetrics().delim2; + } + + var leftDelim; + var rightDelim; + + if (group.leftDelim == null) { + leftDelim = makeNullDelimiter(options, ["mopen"]); + } else { + leftDelim = delimiter.customSizedDelim(group.leftDelim, delimSize, true, options.havingStyle(style), group.mode, ["mopen"]); + } + + if (group.continued) { + rightDelim = buildCommon.makeSpan([]); // zero width for \cfrac + } else if (group.rightDelim == null) { + rightDelim = makeNullDelimiter(options, ["mclose"]); + } else { + rightDelim = delimiter.customSizedDelim(group.rightDelim, delimSize, true, options.havingStyle(style), group.mode, ["mclose"]); + } + + return buildCommon.makeSpan(["mord"].concat(newOptions.sizingClasses(options)), [leftDelim, buildCommon.makeSpan(["mfrac"], [frac]), rightDelim], options); +}; + +var genfrac_mathmlBuilder = function mathmlBuilder(group, options) { + var node = new mathMLTree.MathNode("mfrac", [buildMathML_buildGroup(group.numer, options), buildMathML_buildGroup(group.denom, options)]); + + if (!group.hasBarLine) { + node.setAttribute("linethickness", "0px"); + } else if (group.barSize) { + var ruleWidth = units_calculateSize(group.barSize, options); + node.setAttribute("linethickness", ruleWidth + "em"); + } + + var style = genfrac_adjustStyle(group.size, options.style); + + if (style.size !== options.style.size) { + node = new mathMLTree.MathNode("mstyle", [node]); + var isDisplay = style.size === src_Style.DISPLAY.size ? "true" : "false"; + node.setAttribute("displaystyle", isDisplay); + node.setAttribute("scriptlevel", "0"); + } + + if (group.leftDelim != null || group.rightDelim != null) { + var withDelims = []; + + if (group.leftDelim != null) { + var leftOp = new mathMLTree.MathNode("mo", [new mathMLTree.TextNode(group.leftDelim.replace("\\", ""))]); + leftOp.setAttribute("fence", "true"); + withDelims.push(leftOp); + } + + withDelims.push(node); + + if (group.rightDelim != null) { + var rightOp = new mathMLTree.MathNode("mo", [new mathMLTree.TextNode(group.rightDelim.replace("\\", ""))]); + rightOp.setAttribute("fence", "true"); + withDelims.push(rightOp); + } + + return buildMathML_makeRow(withDelims); + } + + return node; +}; + +defineFunction({ + type: "genfrac", + names: ["\\cfrac", "\\dfrac", "\\frac", "\\tfrac", "\\dbinom", "\\binom", "\\tbinom", "\\\\atopfrac", // can’t be entered directly + "\\\\bracefrac", "\\\\brackfrac"], + props: { + numArgs: 2, + greediness: 2 + }, + handler: function handler(_ref, args) { + var parser = _ref.parser, + funcName = _ref.funcName; + var numer = args[0]; + var denom = args[1]; + var hasBarLine; + var leftDelim = null; + var rightDelim = null; + var size = "auto"; + + switch (funcName) { + case "\\cfrac": + case "\\dfrac": + case "\\frac": + case "\\tfrac": + hasBarLine = true; + break; + + case "\\\\atopfrac": + hasBarLine = false; + break; + + case "\\dbinom": + case "\\binom": + case "\\tbinom": + hasBarLine = false; + leftDelim = "("; + rightDelim = ")"; + break; + + case "\\\\bracefrac": + hasBarLine = false; + leftDelim = "\\{"; + rightDelim = "\\}"; + break; + + case "\\\\brackfrac": + hasBarLine = false; + leftDelim = "["; + rightDelim = "]"; + break; + + default: + throw new Error("Unrecognized genfrac command"); + } + + switch (funcName) { + case "\\cfrac": + case "\\dfrac": + case "\\dbinom": + size = "display"; + break; + + case "\\tfrac": + case "\\tbinom": + size = "text"; + break; + } + + return { + type: "genfrac", + mode: parser.mode, + continued: funcName === "\\cfrac", + numer: numer, + denom: denom, + hasBarLine: hasBarLine, + leftDelim: leftDelim, + rightDelim: rightDelim, + size: size, + barSize: null + }; + }, + htmlBuilder: genfrac_htmlBuilder, + mathmlBuilder: genfrac_mathmlBuilder +}); // Infix generalized fractions -- these are not rendered directly, but replaced +// immediately by one of the variants above. + +defineFunction({ + type: "infix", + names: ["\\over", "\\choose", "\\atop", "\\brace", "\\brack"], + props: { + numArgs: 0, + infix: true + }, + handler: function handler(_ref2) { + var parser = _ref2.parser, + funcName = _ref2.funcName, + token = _ref2.token; + var replaceWith; + + switch (funcName) { + case "\\over": + replaceWith = "\\frac"; + break; + + case "\\choose": + replaceWith = "\\binom"; + break; + + case "\\atop": + replaceWith = "\\\\atopfrac"; + break; + + case "\\brace": + replaceWith = "\\\\bracefrac"; + break; + + case "\\brack": + replaceWith = "\\\\brackfrac"; + break; + + default: + throw new Error("Unrecognized infix genfrac command"); + } + + return { + type: "infix", + mode: parser.mode, + replaceWith: replaceWith, + token: token + }; + } +}); +var stylArray = ["display", "text", "script", "scriptscript"]; + +var delimFromValue = function delimFromValue(delimString) { + var delim = null; + + if (delimString.length > 0) { + delim = delimString; + delim = delim === "." ? null : delim; + } + + return delim; +}; + +defineFunction({ + type: "genfrac", + names: ["\\genfrac"], + props: { + numArgs: 6, + greediness: 6, + argTypes: ["math", "math", "size", "text", "math", "math"] + }, + handler: function handler(_ref3, args) { + var parser = _ref3.parser; + var numer = args[4]; + var denom = args[5]; // Look into the parse nodes to get the desired delimiters. + + var leftNode = checkNodeType(args[0], "atom"); + + if (leftNode) { + leftNode = assertAtomFamily(args[0], "open"); + } + + var leftDelim = leftNode ? delimFromValue(leftNode.text) : null; + var rightNode = checkNodeType(args[1], "atom"); + + if (rightNode) { + rightNode = assertAtomFamily(args[1], "close"); + } + + var rightDelim = rightNode ? delimFromValue(rightNode.text) : null; + var barNode = assertNodeType(args[2], "size"); + var hasBarLine; + var barSize = null; + + if (barNode.isBlank) { + // \genfrac acts differently than \above. + // \genfrac treats an empty size group as a signal to use a + // standard bar size. \above would see size = 0 and omit the bar. + hasBarLine = true; + } else { + barSize = barNode.value; + hasBarLine = barSize.number > 0; + } // Find out if we want displaystyle, textstyle, etc. + + + var size = "auto"; + var styl = checkNodeType(args[3], "ordgroup"); + + if (styl) { + if (styl.body.length > 0) { + var textOrd = assertNodeType(styl.body[0], "textord"); + size = stylArray[Number(textOrd.text)]; + } + } else { + styl = assertNodeType(args[3], "textord"); + size = stylArray[Number(styl.text)]; + } + + return { + type: "genfrac", + mode: parser.mode, + numer: numer, + denom: denom, + continued: false, + hasBarLine: hasBarLine, + barSize: barSize, + leftDelim: leftDelim, + rightDelim: rightDelim, + size: size + }; + }, + htmlBuilder: genfrac_htmlBuilder, + mathmlBuilder: genfrac_mathmlBuilder +}); // \above is an infix fraction that also defines a fraction bar size. + +defineFunction({ + type: "infix", + names: ["\\above"], + props: { + numArgs: 1, + argTypes: ["size"], + infix: true + }, + handler: function handler(_ref4, args) { + var parser = _ref4.parser, + funcName = _ref4.funcName, + token = _ref4.token; + return { + type: "infix", + mode: parser.mode, + replaceWith: "\\\\abovefrac", + size: assertNodeType(args[0], "size").value, + token: token + }; + } +}); +defineFunction({ + type: "genfrac", + names: ["\\\\abovefrac"], + props: { + numArgs: 3, + argTypes: ["math", "size", "math"] + }, + handler: function handler(_ref5, args) { + var parser = _ref5.parser, + funcName = _ref5.funcName; + var numer = args[0]; + var barSize = assert(assertNodeType(args[1], "infix").size); + var denom = args[2]; + var hasBarLine = barSize.number > 0; + return { + type: "genfrac", + mode: parser.mode, + numer: numer, + denom: denom, + continued: false, + hasBarLine: hasBarLine, + barSize: barSize, + leftDelim: null, + rightDelim: null, + size: "auto" + }; + }, + htmlBuilder: genfrac_htmlBuilder, + mathmlBuilder: genfrac_mathmlBuilder +}); +// CONCATENATED MODULE: ./src/functions/horizBrace.js + + + + + + + + +// NOTE: Unlike most `htmlBuilder`s, this one handles not only "horizBrace", but +var horizBrace_htmlBuilder = function htmlBuilder(grp, options) { + var style = options.style; // Pull out the `ParseNode<"horizBrace">` if `grp` is a "supsub" node. + + var supSubGroup; + var group; + var supSub = checkNodeType(grp, "supsub"); + + if (supSub) { + // Ref: LaTeX source2e: }}}}\limits} + // i.e. LaTeX treats the brace similar to an op and passes it + // with \limits, so we need to assign supsub style. + supSubGroup = supSub.sup ? buildHTML_buildGroup(supSub.sup, options.havingStyle(style.sup()), options) : buildHTML_buildGroup(supSub.sub, options.havingStyle(style.sub()), options); + group = assertNodeType(supSub.base, "horizBrace"); + } else { + group = assertNodeType(grp, "horizBrace"); + } // Build the base group + + + var body = buildHTML_buildGroup(group.base, options.havingBaseStyle(src_Style.DISPLAY)); // Create the stretchy element + + var braceBody = stretchy.svgSpan(group, options); // Generate the vlist, with the appropriate kerns ┏━━━━━━━━┓ + // This first vlist contains the content and the brace: equation + + var vlist; + + if (group.isOver) { + vlist = buildCommon.makeVList({ + positionType: "firstBaseline", + children: [{ + type: "elem", + elem: body + }, { + type: "kern", + size: 0.1 + }, { + type: "elem", + elem: braceBody + }] + }, options); // $FlowFixMe: Replace this with passing "svg-align" into makeVList. + + vlist.children[0].children[0].children[1].classes.push("svg-align"); + } else { + vlist = buildCommon.makeVList({ + positionType: "bottom", + positionData: body.depth + 0.1 + braceBody.height, + children: [{ + type: "elem", + elem: braceBody + }, { + type: "kern", + size: 0.1 + }, { + type: "elem", + elem: body + }] + }, options); // $FlowFixMe: Replace this with passing "svg-align" into makeVList. + + vlist.children[0].children[0].children[0].classes.push("svg-align"); + } + + if (supSubGroup) { + // To write the supsub, wrap the first vlist in another vlist: + // They can't all go in the same vlist, because the note might be + // wider than the equation. We want the equation to control the + // brace width. + // note long note long note + // ┏━━━━━━━━┓ or ┏━━━┓ not ┏━━━━━━━━━┓ + // equation eqn eqn + var vSpan = buildCommon.makeSpan(["mord", group.isOver ? "mover" : "munder"], [vlist], options); + + if (group.isOver) { + vlist = buildCommon.makeVList({ + positionType: "firstBaseline", + children: [{ + type: "elem", + elem: vSpan + }, { + type: "kern", + size: 0.2 + }, { + type: "elem", + elem: supSubGroup + }] + }, options); + } else { + vlist = buildCommon.makeVList({ + positionType: "bottom", + positionData: vSpan.depth + 0.2 + supSubGroup.height + supSubGroup.depth, + children: [{ + type: "elem", + elem: supSubGroup + }, { + type: "kern", + size: 0.2 + }, { + type: "elem", + elem: vSpan + }] + }, options); + } + } + + return buildCommon.makeSpan(["mord", group.isOver ? "mover" : "munder"], [vlist], options); +}; + +var horizBrace_mathmlBuilder = function mathmlBuilder(group, options) { + var accentNode = stretchy.mathMLnode(group.label); + return new mathMLTree.MathNode(group.isOver ? "mover" : "munder", [buildMathML_buildGroup(group.base, options), accentNode]); +}; // Horizontal stretchy braces + + +defineFunction({ + type: "horizBrace", + names: ["\\overbrace", "\\underbrace"], + props: { + numArgs: 1 + }, + handler: function handler(_ref, args) { + var parser = _ref.parser, + funcName = _ref.funcName; + return { + type: "horizBrace", + mode: parser.mode, + label: funcName, + isOver: /^\\over/.test(funcName), + base: args[0] + }; + }, + htmlBuilder: horizBrace_htmlBuilder, + mathmlBuilder: horizBrace_mathmlBuilder +}); +// CONCATENATED MODULE: ./src/functions/href.js + + + + + + +defineFunction({ + type: "href", + names: ["\\href"], + props: { + numArgs: 2, + argTypes: ["url", "original"], + allowedInText: true + }, + handler: function handler(_ref, args) { + var parser = _ref.parser; + var body = args[1]; + var href = assertNodeType(args[0], "url").url; + + if (!parser.settings.isTrusted({ + command: "\\href", + url: href + })) { + return parser.formatUnsupportedCmd("\\href"); + } + + return { + type: "href", + mode: parser.mode, + href: href, + body: defineFunction_ordargument(body) + }; + }, + htmlBuilder: function htmlBuilder(group, options) { + var elements = buildHTML_buildExpression(group.body, options, false); + return buildCommon.makeAnchor(group.href, [], elements, options); + }, + mathmlBuilder: function mathmlBuilder(group, options) { + var math = buildExpressionRow(group.body, options); + + if (!(math instanceof mathMLTree_MathNode)) { + math = new mathMLTree_MathNode("mrow", [math]); + } + + math.setAttribute("href", group.href); + return math; + } +}); +defineFunction({ + type: "href", + names: ["\\url"], + props: { + numArgs: 1, + argTypes: ["url"], + allowedInText: true + }, + handler: function handler(_ref2, args) { + var parser = _ref2.parser; + var href = assertNodeType(args[0], "url").url; + + if (!parser.settings.isTrusted({ + command: "\\url", + url: href + })) { + return parser.formatUnsupportedCmd("\\url"); + } + + var chars = []; + + for (var i = 0; i < href.length; i++) { + var c = href[i]; + + if (c === "~") { + c = "\\textasciitilde"; + } + + chars.push({ + type: "textord", + mode: "text", + text: c + }); + } + + var body = { + type: "text", + mode: parser.mode, + font: "\\texttt", + body: chars + }; + return { + type: "href", + mode: parser.mode, + href: href, + body: defineFunction_ordargument(body) + }; + } +}); +// CONCATENATED MODULE: ./src/functions/htmlmathml.js + + + + +defineFunction({ + type: "htmlmathml", + names: ["\\html@mathml"], + props: { + numArgs: 2, + allowedInText: true + }, + handler: function handler(_ref, args) { + var parser = _ref.parser; + return { + type: "htmlmathml", + mode: parser.mode, + html: defineFunction_ordargument(args[0]), + mathml: defineFunction_ordargument(args[1]) + }; + }, + htmlBuilder: function htmlBuilder(group, options) { + var elements = buildHTML_buildExpression(group.html, options, false); + return buildCommon.makeFragment(elements); + }, + mathmlBuilder: function mathmlBuilder(group, options) { + return buildExpressionRow(group.mathml, options); + } +}); +// CONCATENATED MODULE: ./src/functions/includegraphics.js + + + + + + + +var includegraphics_sizeData = function sizeData(str) { + if (/^[-+]? *(\d+(\.\d*)?|\.\d+)$/.test(str)) { + // str is a number with no unit specified. + // default unit is bp, per graphix package. + return { + number: +str, + unit: "bp" + }; + } else { + var match = /([-+]?) *(\d+(?:\.\d*)?|\.\d+) *([a-z]{2})/.exec(str); + + if (!match) { + throw new src_ParseError("Invalid size: '" + str + "' in \\includegraphics"); + } + + var data = { + number: +(match[1] + match[2]), + // sign + magnitude, cast to number + unit: match[3] + }; + + if (!validUnit(data)) { + throw new src_ParseError("Invalid unit: '" + data.unit + "' in \\includegraphics."); + } + + return data; + } +}; + +defineFunction({ + type: "includegraphics", + names: ["\\includegraphics"], + props: { + numArgs: 1, + numOptionalArgs: 1, + argTypes: ["raw", "url"], + allowedInText: false + }, + handler: function handler(_ref, args, optArgs) { + var parser = _ref.parser; + var width = { + number: 0, + unit: "em" + }; + var height = { + number: 0.9, + unit: "em" + }; // sorta character sized. + + var totalheight = { + number: 0, + unit: "em" + }; + var alt = ""; + + if (optArgs[0]) { + var attributeStr = assertNodeType(optArgs[0], "raw").string; // Parser.js does not parse key/value pairs. We get a string. + + var attributes = attributeStr.split(","); + + for (var i = 0; i < attributes.length; i++) { + var keyVal = attributes[i].split("="); + + if (keyVal.length === 2) { + var str = keyVal[1].trim(); + + switch (keyVal[0].trim()) { + case "alt": + alt = str; + break; + + case "width": + width = includegraphics_sizeData(str); + break; + + case "height": + height = includegraphics_sizeData(str); + break; + + case "totalheight": + totalheight = includegraphics_sizeData(str); + break; + + default: + throw new src_ParseError("Invalid key: '" + keyVal[0] + "' in \\includegraphics."); + } + } + } + } + + var src = assertNodeType(args[0], "url").url; + + if (alt === "") { + // No alt given. Use the file name. Strip away the path. + alt = src; + alt = alt.replace(/^.*[\\/]/, ''); + alt = alt.substring(0, alt.lastIndexOf('.')); + } + + if (!parser.settings.isTrusted({ + command: "\\includegraphics", + url: src + })) { + return parser.formatUnsupportedCmd("\\includegraphics"); + } + + return { + type: "includegraphics", + mode: parser.mode, + alt: alt, + width: width, + height: height, + totalheight: totalheight, + src: src + }; + }, + htmlBuilder: function htmlBuilder(group, options) { + var height = units_calculateSize(group.height, options); + var depth = 0; + + if (group.totalheight.number > 0) { + depth = units_calculateSize(group.totalheight, options) - height; + depth = Number(depth.toFixed(2)); + } + + var width = 0; + + if (group.width.number > 0) { + width = units_calculateSize(group.width, options); + } + + var style = { + height: height + depth + "em" + }; + + if (width > 0) { + style.width = width + "em"; + } + + if (depth > 0) { + style.verticalAlign = -depth + "em"; + } + + var node = new domTree_Img(group.src, group.alt, style); + node.height = height; + node.depth = depth; + return node; + }, + mathmlBuilder: function mathmlBuilder(group, options) { + var node = new mathMLTree.MathNode("mglyph", []); + node.setAttribute("alt", group.alt); + var height = units_calculateSize(group.height, options); + var depth = 0; + + if (group.totalheight.number > 0) { + depth = units_calculateSize(group.totalheight, options) - height; + depth = depth.toFixed(2); + node.setAttribute("valign", "-" + depth + "em"); + } + + node.setAttribute("height", height + depth + "em"); + + if (group.width.number > 0) { + var width = units_calculateSize(group.width, options); + node.setAttribute("width", width + "em"); + } + + node.setAttribute("src", group.src); + return node; + } +}); +// CONCATENATED MODULE: ./src/functions/kern.js +// Horizontal spacing commands + + + + + // TODO: \hskip and \mskip should support plus and minus in lengths + +defineFunction({ + type: "kern", + names: ["\\kern", "\\mkern", "\\hskip", "\\mskip"], + props: { + numArgs: 1, + argTypes: ["size"], + allowedInText: true + }, + handler: function handler(_ref, args) { + var parser = _ref.parser, + funcName = _ref.funcName; + var size = assertNodeType(args[0], "size"); + + if (parser.settings.strict) { + var mathFunction = funcName[1] === 'm'; // \mkern, \mskip + + var muUnit = size.value.unit === 'mu'; + + if (mathFunction) { + if (!muUnit) { + parser.settings.reportNonstrict("mathVsTextUnits", "LaTeX's " + funcName + " supports only mu units, " + ("not " + size.value.unit + " units")); + } + + if (parser.mode !== "math") { + parser.settings.reportNonstrict("mathVsTextUnits", "LaTeX's " + funcName + " works only in math mode"); + } + } else { + // !mathFunction + if (muUnit) { + parser.settings.reportNonstrict("mathVsTextUnits", "LaTeX's " + funcName + " doesn't support mu units"); + } + } + } + + return { + type: "kern", + mode: parser.mode, + dimension: size.value + }; + }, + htmlBuilder: function htmlBuilder(group, options) { + return buildCommon.makeGlue(group.dimension, options); + }, + mathmlBuilder: function mathmlBuilder(group, options) { + var dimension = units_calculateSize(group.dimension, options); + return new mathMLTree.SpaceNode(dimension); + } +}); +// CONCATENATED MODULE: ./src/functions/lap.js +// Horizontal overlap functions + + + + + +defineFunction({ + type: "lap", + names: ["\\mathllap", "\\mathrlap", "\\mathclap"], + props: { + numArgs: 1, + allowedInText: true + }, + handler: function handler(_ref, args) { + var parser = _ref.parser, + funcName = _ref.funcName; + var body = args[0]; + return { + type: "lap", + mode: parser.mode, + alignment: funcName.slice(5), + body: body + }; + }, + htmlBuilder: function htmlBuilder(group, options) { + // mathllap, mathrlap, mathclap + var inner; + + if (group.alignment === "clap") { + // ref: https://www.math.lsu.edu/~aperlis/publications/mathclap/ + inner = buildCommon.makeSpan([], [buildHTML_buildGroup(group.body, options)]); // wrap, since CSS will center a .clap > .inner > span + + inner = buildCommon.makeSpan(["inner"], [inner], options); + } else { + inner = buildCommon.makeSpan(["inner"], [buildHTML_buildGroup(group.body, options)]); + } + + var fix = buildCommon.makeSpan(["fix"], []); + var node = buildCommon.makeSpan([group.alignment], [inner, fix], options); // At this point, we have correctly set horizontal alignment of the + // two items involved in the lap. + // Next, use a strut to set the height of the HTML bounding box. + // Otherwise, a tall argument may be misplaced. + + var strut = buildCommon.makeSpan(["strut"]); + strut.style.height = node.height + node.depth + "em"; + strut.style.verticalAlign = -node.depth + "em"; + node.children.unshift(strut); // Next, prevent vertical misplacement when next to something tall. + + node = buildCommon.makeVList({ + positionType: "firstBaseline", + children: [{ + type: "elem", + elem: node + }] + }, options); // Get the horizontal spacing correct relative to adjacent items. + + return buildCommon.makeSpan(["mord"], [node], options); + }, + mathmlBuilder: function mathmlBuilder(group, options) { + // mathllap, mathrlap, mathclap + var node = new mathMLTree.MathNode("mpadded", [buildMathML_buildGroup(group.body, options)]); + + if (group.alignment !== "rlap") { + var offset = group.alignment === "llap" ? "-1" : "-0.5"; + node.setAttribute("lspace", offset + "width"); + } + + node.setAttribute("width", "0px"); + return node; + } +}); +// CONCATENATED MODULE: ./src/functions/math.js + + // Switching from text mode back to math mode + +defineFunction({ + type: "styling", + names: ["\\(", "$"], + props: { + numArgs: 0, + allowedInText: true, + allowedInMath: false + }, + handler: function handler(_ref, args) { + var funcName = _ref.funcName, + parser = _ref.parser; + var outerMode = parser.mode; + parser.switchMode("math"); + var close = funcName === "\\(" ? "\\)" : "$"; + var body = parser.parseExpression(false, close); + parser.expect(close); + parser.switchMode(outerMode); + return { + type: "styling", + mode: parser.mode, + style: "text", + body: body + }; + } +}); // Check for extra closing math delimiters + +defineFunction({ + type: "text", + // Doesn't matter what this is. + names: ["\\)", "\\]"], + props: { + numArgs: 0, + allowedInText: true, + allowedInMath: false + }, + handler: function handler(context, args) { + throw new src_ParseError("Mismatched " + context.funcName); + } +}); +// CONCATENATED MODULE: ./src/functions/mathchoice.js + + + + + + +var mathchoice_chooseMathStyle = function chooseMathStyle(group, options) { + switch (options.style.size) { + case src_Style.DISPLAY.size: + return group.display; + + case src_Style.TEXT.size: + return group.text; + + case src_Style.SCRIPT.size: + return group.script; + + case src_Style.SCRIPTSCRIPT.size: + return group.scriptscript; + + default: + return group.text; + } +}; + +defineFunction({ + type: "mathchoice", + names: ["\\mathchoice"], + props: { + numArgs: 4 + }, + handler: function handler(_ref, args) { + var parser = _ref.parser; + return { + type: "mathchoice", + mode: parser.mode, + display: defineFunction_ordargument(args[0]), + text: defineFunction_ordargument(args[1]), + script: defineFunction_ordargument(args[2]), + scriptscript: defineFunction_ordargument(args[3]) + }; + }, + htmlBuilder: function htmlBuilder(group, options) { + var body = mathchoice_chooseMathStyle(group, options); + var elements = buildHTML_buildExpression(body, options, false); + return buildCommon.makeFragment(elements); + }, + mathmlBuilder: function mathmlBuilder(group, options) { + var body = mathchoice_chooseMathStyle(group, options); + return buildExpressionRow(body, options); + } +}); +// CONCATENATED MODULE: ./src/functions/utils/assembleSupSub.js + + +// For an operator with limits, assemble the base, sup, and sub into a span. +var assembleSupSub_assembleSupSub = function assembleSupSub(base, supGroup, subGroup, options, style, slant, baseShift) { + // IE 8 clips \int if it is in a display: inline-block. We wrap it + // in a new span so it is an inline, and works. + base = buildCommon.makeSpan([], [base]); + var sub; + var sup; // We manually have to handle the superscripts and subscripts. This, + // aside from the kern calculations, is copied from supsub. + + if (supGroup) { + var elem = buildHTML_buildGroup(supGroup, options.havingStyle(style.sup()), options); + sup = { + elem: elem, + kern: Math.max(options.fontMetrics().bigOpSpacing1, options.fontMetrics().bigOpSpacing3 - elem.depth) + }; + } + + if (subGroup) { + var _elem = buildHTML_buildGroup(subGroup, options.havingStyle(style.sub()), options); + + sub = { + elem: _elem, + kern: Math.max(options.fontMetrics().bigOpSpacing2, options.fontMetrics().bigOpSpacing4 - _elem.height) + }; + } // Build the final group as a vlist of the possible subscript, base, + // and possible superscript. + + + var finalGroup; + + if (sup && sub) { + var bottom = options.fontMetrics().bigOpSpacing5 + sub.elem.height + sub.elem.depth + sub.kern + base.depth + baseShift; + finalGroup = buildCommon.makeVList({ + positionType: "bottom", + positionData: bottom, + children: [{ + type: "kern", + size: options.fontMetrics().bigOpSpacing5 + }, { + type: "elem", + elem: sub.elem, + marginLeft: -slant + "em" + }, { + type: "kern", + size: sub.kern + }, { + type: "elem", + elem: base + }, { + type: "kern", + size: sup.kern + }, { + type: "elem", + elem: sup.elem, + marginLeft: slant + "em" + }, { + type: "kern", + size: options.fontMetrics().bigOpSpacing5 + }] + }, options); + } else if (sub) { + var top = base.height - baseShift; // Shift the limits by the slant of the symbol. Note + // that we are supposed to shift the limits by 1/2 of the slant, + // but since we are centering the limits adding a full slant of + // margin will shift by 1/2 that. + + finalGroup = buildCommon.makeVList({ + positionType: "top", + positionData: top, + children: [{ + type: "kern", + size: options.fontMetrics().bigOpSpacing5 + }, { + type: "elem", + elem: sub.elem, + marginLeft: -slant + "em" + }, { + type: "kern", + size: sub.kern + }, { + type: "elem", + elem: base + }] + }, options); + } else if (sup) { + var _bottom = base.depth + baseShift; + + finalGroup = buildCommon.makeVList({ + positionType: "bottom", + positionData: _bottom, + children: [{ + type: "elem", + elem: base + }, { + type: "kern", + size: sup.kern + }, { + type: "elem", + elem: sup.elem, + marginLeft: slant + "em" + }, { + type: "kern", + size: options.fontMetrics().bigOpSpacing5 + }] + }, options); + } else { + // This case probably shouldn't occur (this would mean the + // supsub was sending us a group with no superscript or + // subscript) but be safe. + return base; + } + + return buildCommon.makeSpan(["mop", "op-limits"], [finalGroup], options); +}; +// CONCATENATED MODULE: ./src/functions/op.js +// Limits, symbols + + + + + + + + + + +// Most operators have a large successor symbol, but these don't. +var noSuccessor = ["\\smallint"]; // NOTE: Unlike most `htmlBuilder`s, this one handles not only "op", but also +// "supsub" since some of them (like \int) can affect super/subscripting. + +var op_htmlBuilder = function htmlBuilder(grp, options) { + // Operators are handled in the TeXbook pg. 443-444, rule 13(a). + var supGroup; + var subGroup; + var hasLimits = false; + var group; + var supSub = checkNodeType(grp, "supsub"); + + if (supSub) { + // If we have limits, supsub will pass us its group to handle. Pull + // out the superscript and subscript and set the group to the op in + // its base. + supGroup = supSub.sup; + subGroup = supSub.sub; + group = assertNodeType(supSub.base, "op"); + hasLimits = true; + } else { + group = assertNodeType(grp, "op"); + } + + var style = options.style; + var large = false; + + if (style.size === src_Style.DISPLAY.size && group.symbol && !utils.contains(noSuccessor, group.name)) { + // Most symbol operators get larger in displaystyle (rule 13) + large = true; + } + + var base; + + if (group.symbol) { + // If this is a symbol, create the symbol. + var fontName = large ? "Size2-Regular" : "Size1-Regular"; + var stash = ""; + + if (group.name === "\\oiint" || group.name === "\\oiiint") { + // No font glyphs yet, so use a glyph w/o the oval. + // TODO: When font glyphs are available, delete this code. + stash = group.name.substr(1); // $FlowFixMe + + group.name = stash === "oiint" ? "\\iint" : "\\iiint"; + } + + base = buildCommon.makeSymbol(group.name, fontName, "math", options, ["mop", "op-symbol", large ? "large-op" : "small-op"]); + + if (stash.length > 0) { + // We're in \oiint or \oiiint. Overlay the oval. + // TODO: When font glyphs are available, delete this code. + var italic = base.italic; + var oval = buildCommon.staticSvg(stash + "Size" + (large ? "2" : "1"), options); + base = buildCommon.makeVList({ + positionType: "individualShift", + children: [{ + type: "elem", + elem: base, + shift: 0 + }, { + type: "elem", + elem: oval, + shift: large ? 0.08 : 0 + }] + }, options); // $FlowFixMe + + group.name = "\\" + stash; + base.classes.unshift("mop"); // $FlowFixMe + + base.italic = italic; + } + } else if (group.body) { + // If this is a list, compose that list. + var inner = buildHTML_buildExpression(group.body, options, true); + + if (inner.length === 1 && inner[0] instanceof domTree_SymbolNode) { + base = inner[0]; + base.classes[0] = "mop"; // replace old mclass + } else { + base = buildCommon.makeSpan(["mop"], buildCommon.tryCombineChars(inner), options); + } + } else { + // Otherwise, this is a text operator. Build the text from the + // operator's name. + // TODO(emily): Add a space in the middle of some of these + // operators, like \limsup + var output = []; + + for (var i = 1; i < group.name.length; i++) { + output.push(buildCommon.mathsym(group.name[i], group.mode, options)); + } + + base = buildCommon.makeSpan(["mop"], output, options); + } // If content of op is a single symbol, shift it vertically. + + + var baseShift = 0; + var slant = 0; + + if ((base instanceof domTree_SymbolNode || group.name === "\\oiint" || group.name === "\\oiiint") && !group.suppressBaseShift) { + // We suppress the shift of the base of \overset and \underset. Otherwise, + // shift the symbol so its center lies on the axis (rule 13). It + // appears that our fonts have the centers of the symbols already + // almost on the axis, so these numbers are very small. Note we + // don't actually apply this here, but instead it is used either in + // the vlist creation or separately when there are no limits. + baseShift = (base.height - base.depth) / 2 - options.fontMetrics().axisHeight; // The slant of the symbol is just its italic correction. + // $FlowFixMe + + slant = base.italic; + } + + if (hasLimits) { + return assembleSupSub_assembleSupSub(base, supGroup, subGroup, options, style, slant, baseShift); + } else { + if (baseShift) { + base.style.position = "relative"; + base.style.top = baseShift + "em"; + } + + return base; + } +}; + +var op_mathmlBuilder = function mathmlBuilder(group, options) { + var node; + + if (group.symbol) { + // This is a symbol. Just add the symbol. + node = new mathMLTree_MathNode("mo", [buildMathML_makeText(group.name, group.mode)]); + + if (utils.contains(noSuccessor, group.name)) { + node.setAttribute("largeop", "false"); + } + } else if (group.body) { + // This is an operator with children. Add them. + node = new mathMLTree_MathNode("mo", buildMathML_buildExpression(group.body, options)); + } else { + // This is a text operator. Add all of the characters from the + // operator's name. + node = new mathMLTree_MathNode("mi", [new mathMLTree_TextNode(group.name.slice(1))]); // Append an . + // ref: https://www.w3.org/TR/REC-MathML/chap3_2.html#sec3.2.4 + + var operator = new mathMLTree_MathNode("mo", [buildMathML_makeText("\u2061", "text")]); + + if (group.parentIsSupSub) { + node = new mathMLTree_MathNode("mo", [node, operator]); + } else { + node = newDocumentFragment([node, operator]); + } + } + + return node; +}; + +var singleCharBigOps = { + "\u220F": "\\prod", + "\u2210": "\\coprod", + "\u2211": "\\sum", + "\u22C0": "\\bigwedge", + "\u22C1": "\\bigvee", + "\u22C2": "\\bigcap", + "\u22C3": "\\bigcup", + "\u2A00": "\\bigodot", + "\u2A01": "\\bigoplus", + "\u2A02": "\\bigotimes", + "\u2A04": "\\biguplus", + "\u2A06": "\\bigsqcup" +}; +defineFunction({ + type: "op", + names: ["\\coprod", "\\bigvee", "\\bigwedge", "\\biguplus", "\\bigcap", "\\bigcup", "\\intop", "\\prod", "\\sum", "\\bigotimes", "\\bigoplus", "\\bigodot", "\\bigsqcup", "\\smallint", "\u220F", "\u2210", "\u2211", "\u22C0", "\u22C1", "\u22C2", "\u22C3", "\u2A00", "\u2A01", "\u2A02", "\u2A04", "\u2A06"], + props: { + numArgs: 0 + }, + handler: function handler(_ref, args) { + var parser = _ref.parser, + funcName = _ref.funcName; + var fName = funcName; + + if (fName.length === 1) { + fName = singleCharBigOps[fName]; + } + + return { + type: "op", + mode: parser.mode, + limits: true, + parentIsSupSub: false, + symbol: true, + name: fName + }; + }, + htmlBuilder: op_htmlBuilder, + mathmlBuilder: op_mathmlBuilder +}); // Note: calling defineFunction with a type that's already been defined only +// works because the same htmlBuilder and mathmlBuilder are being used. + +defineFunction({ + type: "op", + names: ["\\mathop"], + props: { + numArgs: 1 + }, + handler: function handler(_ref2, args) { + var parser = _ref2.parser; + var body = args[0]; + return { + type: "op", + mode: parser.mode, + limits: false, + parentIsSupSub: false, + symbol: false, + body: defineFunction_ordargument(body) + }; + }, + htmlBuilder: op_htmlBuilder, + mathmlBuilder: op_mathmlBuilder +}); // There are 2 flags for operators; whether they produce limits in +// displaystyle, and whether they are symbols and should grow in +// displaystyle. These four groups cover the four possible choices. + +var singleCharIntegrals = { + "\u222B": "\\int", + "\u222C": "\\iint", + "\u222D": "\\iiint", + "\u222E": "\\oint", + "\u222F": "\\oiint", + "\u2230": "\\oiiint" +}; // No limits, not symbols + +defineFunction({ + type: "op", + names: ["\\arcsin", "\\arccos", "\\arctan", "\\arctg", "\\arcctg", "\\arg", "\\ch", "\\cos", "\\cosec", "\\cosh", "\\cot", "\\cotg", "\\coth", "\\csc", "\\ctg", "\\cth", "\\deg", "\\dim", "\\exp", "\\hom", "\\ker", "\\lg", "\\ln", "\\log", "\\sec", "\\sin", "\\sinh", "\\sh", "\\tan", "\\tanh", "\\tg", "\\th"], + props: { + numArgs: 0 + }, + handler: function handler(_ref3) { + var parser = _ref3.parser, + funcName = _ref3.funcName; + return { + type: "op", + mode: parser.mode, + limits: false, + parentIsSupSub: false, + symbol: false, + name: funcName + }; + }, + htmlBuilder: op_htmlBuilder, + mathmlBuilder: op_mathmlBuilder +}); // Limits, not symbols + +defineFunction({ + type: "op", + names: ["\\det", "\\gcd", "\\inf", "\\lim", "\\max", "\\min", "\\Pr", "\\sup"], + props: { + numArgs: 0 + }, + handler: function handler(_ref4) { + var parser = _ref4.parser, + funcName = _ref4.funcName; + return { + type: "op", + mode: parser.mode, + limits: true, + parentIsSupSub: false, + symbol: false, + name: funcName + }; + }, + htmlBuilder: op_htmlBuilder, + mathmlBuilder: op_mathmlBuilder +}); // No limits, symbols + +defineFunction({ + type: "op", + names: ["\\int", "\\iint", "\\iiint", "\\oint", "\\oiint", "\\oiiint", "\u222B", "\u222C", "\u222D", "\u222E", "\u222F", "\u2230"], + props: { + numArgs: 0 + }, + handler: function handler(_ref5) { + var parser = _ref5.parser, + funcName = _ref5.funcName; + var fName = funcName; + + if (fName.length === 1) { + fName = singleCharIntegrals[fName]; + } + + return { + type: "op", + mode: parser.mode, + limits: false, + parentIsSupSub: false, + symbol: true, + name: fName + }; + }, + htmlBuilder: op_htmlBuilder, + mathmlBuilder: op_mathmlBuilder +}); +// CONCATENATED MODULE: ./src/functions/operatorname.js + + + + + + + + +// NOTE: Unlike most `htmlBuilder`s, this one handles not only +// "operatorname", but also "supsub" since \operatorname* can +var operatorname_htmlBuilder = function htmlBuilder(grp, options) { + // Operators are handled in the TeXbook pg. 443-444, rule 13(a). + var supGroup; + var subGroup; + var hasLimits = false; + var group; + var supSub = checkNodeType(grp, "supsub"); + + if (supSub) { + // If we have limits, supsub will pass us its group to handle. Pull + // out the superscript and subscript and set the group to the op in + // its base. + supGroup = supSub.sup; + subGroup = supSub.sub; + group = assertNodeType(supSub.base, "operatorname"); + hasLimits = true; + } else { + group = assertNodeType(grp, "operatorname"); + } + + var base; + + if (group.body.length > 0) { + var body = group.body.map(function (child) { + // $FlowFixMe: Check if the node has a string `text` property. + var childText = child.text; + + if (typeof childText === "string") { + return { + type: "textord", + mode: child.mode, + text: childText + }; + } else { + return child; + } + }); // Consolidate function names into symbol characters. + + var expression = buildHTML_buildExpression(body, options.withFont("mathrm"), true); + + for (var i = 0; i < expression.length; i++) { + var child = expression[i]; + + if (child instanceof domTree_SymbolNode) { + // Per amsopn package, + // change minus to hyphen and \ast to asterisk + child.text = child.text.replace(/\u2212/, "-").replace(/\u2217/, "*"); + } + } + + base = buildCommon.makeSpan(["mop"], expression, options); + } else { + base = buildCommon.makeSpan(["mop"], [], options); + } + + if (hasLimits) { + return assembleSupSub_assembleSupSub(base, supGroup, subGroup, options, options.style, 0, 0); + } else { + return base; + } +}; + +var operatorname_mathmlBuilder = function mathmlBuilder(group, options) { + // The steps taken here are similar to the html version. + var expression = buildMathML_buildExpression(group.body, options.withFont("mathrm")); // Is expression a string or has it something like a fraction? + + var isAllString = true; // default + + for (var i = 0; i < expression.length; i++) { + var node = expression[i]; + + if (node instanceof mathMLTree.SpaceNode) {// Do nothing + } else if (node instanceof mathMLTree.MathNode) { + switch (node.type) { + case "mi": + case "mn": + case "ms": + case "mspace": + case "mtext": + break; + // Do nothing yet. + + case "mo": + { + var child = node.children[0]; + + if (node.children.length === 1 && child instanceof mathMLTree.TextNode) { + child.text = child.text.replace(/\u2212/, "-").replace(/\u2217/, "*"); + } else { + isAllString = false; + } + + break; + } + + default: + isAllString = false; + } + } else { + isAllString = false; + } + } + + if (isAllString) { + // Write a single TextNode instead of multiple nested tags. + var word = expression.map(function (node) { + return node.toText(); + }).join(""); + expression = [new mathMLTree.TextNode(word)]; + } + + var identifier = new mathMLTree.MathNode("mi", expression); + identifier.setAttribute("mathvariant", "normal"); // \u2061 is the same as ⁡ + // ref: https://www.w3schools.com/charsets/ref_html_entities_a.asp + + var operator = new mathMLTree.MathNode("mo", [buildMathML_makeText("\u2061", "text")]); + + if (group.parentIsSupSub) { + return new mathMLTree.MathNode("mo", [identifier, operator]); + } else { + return mathMLTree.newDocumentFragment([identifier, operator]); + } +}; // \operatorname +// amsopn.dtx: \mathop{#1\kern\z@\operator@font#3}\newmcodes@ + + +defineFunction({ + type: "operatorname", + names: ["\\operatorname", "\\operatorname*"], + props: { + numArgs: 1 + }, + handler: function handler(_ref, args) { + var parser = _ref.parser, + funcName = _ref.funcName; + var body = args[0]; + return { + type: "operatorname", + mode: parser.mode, + body: defineFunction_ordargument(body), + alwaysHandleSupSub: funcName === "\\operatorname*", + limits: false, + parentIsSupSub: false + }; + }, + htmlBuilder: operatorname_htmlBuilder, + mathmlBuilder: operatorname_mathmlBuilder +}); +// CONCATENATED MODULE: ./src/functions/ordgroup.js + + + + +defineFunctionBuilders({ + type: "ordgroup", + htmlBuilder: function htmlBuilder(group, options) { + if (group.semisimple) { + return buildCommon.makeFragment(buildHTML_buildExpression(group.body, options, false)); + } + + return buildCommon.makeSpan(["mord"], buildHTML_buildExpression(group.body, options, true), options); + }, + mathmlBuilder: function mathmlBuilder(group, options) { + return buildExpressionRow(group.body, options, true); + } +}); +// CONCATENATED MODULE: ./src/functions/overline.js + + + + + +defineFunction({ + type: "overline", + names: ["\\overline"], + props: { + numArgs: 1 + }, + handler: function handler(_ref, args) { + var parser = _ref.parser; + var body = args[0]; + return { + type: "overline", + mode: parser.mode, + body: body + }; + }, + htmlBuilder: function htmlBuilder(group, options) { + // Overlines are handled in the TeXbook pg 443, Rule 9. + // Build the inner group in the cramped style. + var innerGroup = buildHTML_buildGroup(group.body, options.havingCrampedStyle()); // Create the line above the body + + var line = buildCommon.makeLineSpan("overline-line", options); // Generate the vlist, with the appropriate kerns + + var defaultRuleThickness = options.fontMetrics().defaultRuleThickness; + var vlist = buildCommon.makeVList({ + positionType: "firstBaseline", + children: [{ + type: "elem", + elem: innerGroup + }, { + type: "kern", + size: 3 * defaultRuleThickness + }, { + type: "elem", + elem: line + }, { + type: "kern", + size: defaultRuleThickness + }] + }, options); + return buildCommon.makeSpan(["mord", "overline"], [vlist], options); + }, + mathmlBuilder: function mathmlBuilder(group, options) { + var operator = new mathMLTree.MathNode("mo", [new mathMLTree.TextNode("\u203E")]); + operator.setAttribute("stretchy", "true"); + var node = new mathMLTree.MathNode("mover", [buildMathML_buildGroup(group.body, options), operator]); + node.setAttribute("accent", "true"); + return node; + } +}); +// CONCATENATED MODULE: ./src/functions/phantom.js + + + + + +defineFunction({ + type: "phantom", + names: ["\\phantom"], + props: { + numArgs: 1, + allowedInText: true + }, + handler: function handler(_ref, args) { + var parser = _ref.parser; + var body = args[0]; + return { + type: "phantom", + mode: parser.mode, + body: defineFunction_ordargument(body) + }; + }, + htmlBuilder: function htmlBuilder(group, options) { + var elements = buildHTML_buildExpression(group.body, options.withPhantom(), false); // \phantom isn't supposed to affect the elements it contains. + // See "color" for more details. + + return buildCommon.makeFragment(elements); + }, + mathmlBuilder: function mathmlBuilder(group, options) { + var inner = buildMathML_buildExpression(group.body, options); + return new mathMLTree.MathNode("mphantom", inner); + } +}); +defineFunction({ + type: "hphantom", + names: ["\\hphantom"], + props: { + numArgs: 1, + allowedInText: true + }, + handler: function handler(_ref2, args) { + var parser = _ref2.parser; + var body = args[0]; + return { + type: "hphantom", + mode: parser.mode, + body: body + }; + }, + htmlBuilder: function htmlBuilder(group, options) { + var node = buildCommon.makeSpan([], [buildHTML_buildGroup(group.body, options.withPhantom())]); + node.height = 0; + node.depth = 0; + + if (node.children) { + for (var i = 0; i < node.children.length; i++) { + node.children[i].height = 0; + node.children[i].depth = 0; + } + } // See smash for comment re: use of makeVList + + + node = buildCommon.makeVList({ + positionType: "firstBaseline", + children: [{ + type: "elem", + elem: node + }] + }, options); // For spacing, TeX treats \smash as a math group (same spacing as ord). + + return buildCommon.makeSpan(["mord"], [node], options); + }, + mathmlBuilder: function mathmlBuilder(group, options) { + var inner = buildMathML_buildExpression(defineFunction_ordargument(group.body), options); + var phantom = new mathMLTree.MathNode("mphantom", inner); + var node = new mathMLTree.MathNode("mpadded", [phantom]); + node.setAttribute("height", "0px"); + node.setAttribute("depth", "0px"); + return node; + } +}); +defineFunction({ + type: "vphantom", + names: ["\\vphantom"], + props: { + numArgs: 1, + allowedInText: true + }, + handler: function handler(_ref3, args) { + var parser = _ref3.parser; + var body = args[0]; + return { + type: "vphantom", + mode: parser.mode, + body: body + }; + }, + htmlBuilder: function htmlBuilder(group, options) { + var inner = buildCommon.makeSpan(["inner"], [buildHTML_buildGroup(group.body, options.withPhantom())]); + var fix = buildCommon.makeSpan(["fix"], []); + return buildCommon.makeSpan(["mord", "rlap"], [inner, fix], options); + }, + mathmlBuilder: function mathmlBuilder(group, options) { + var inner = buildMathML_buildExpression(defineFunction_ordargument(group.body), options); + var phantom = new mathMLTree.MathNode("mphantom", inner); + var node = new mathMLTree.MathNode("mpadded", [phantom]); + node.setAttribute("width", "0px"); + return node; + } +}); +// CONCATENATED MODULE: ./src/functions/raisebox.js + + + + + + + // Box manipulation + +defineFunction({ + type: "raisebox", + names: ["\\raisebox"], + props: { + numArgs: 2, + argTypes: ["size", "hbox"], + allowedInText: true + }, + handler: function handler(_ref, args) { + var parser = _ref.parser; + var amount = assertNodeType(args[0], "size").value; + var body = args[1]; + return { + type: "raisebox", + mode: parser.mode, + dy: amount, + body: body + }; + }, + htmlBuilder: function htmlBuilder(group, options) { + var body = buildHTML_buildGroup(group.body, options); + var dy = units_calculateSize(group.dy, options); + return buildCommon.makeVList({ + positionType: "shift", + positionData: -dy, + children: [{ + type: "elem", + elem: body + }] + }, options); + }, + mathmlBuilder: function mathmlBuilder(group, options) { + var node = new mathMLTree.MathNode("mpadded", [buildMathML_buildGroup(group.body, options)]); + var dy = group.dy.number + group.dy.unit; + node.setAttribute("voffset", dy); + return node; + } +}); +// CONCATENATED MODULE: ./src/functions/rule.js + + + + + +defineFunction({ + type: "rule", + names: ["\\rule"], + props: { + numArgs: 2, + numOptionalArgs: 1, + argTypes: ["size", "size", "size"] + }, + handler: function handler(_ref, args, optArgs) { + var parser = _ref.parser; + var shift = optArgs[0]; + var width = assertNodeType(args[0], "size"); + var height = assertNodeType(args[1], "size"); + return { + type: "rule", + mode: parser.mode, + shift: shift && assertNodeType(shift, "size").value, + width: width.value, + height: height.value + }; + }, + htmlBuilder: function htmlBuilder(group, options) { + // Make an empty span for the rule + var rule = buildCommon.makeSpan(["mord", "rule"], [], options); // Calculate the shift, width, and height of the rule, and account for units + + var width = units_calculateSize(group.width, options); + var height = units_calculateSize(group.height, options); + var shift = group.shift ? units_calculateSize(group.shift, options) : 0; // Style the rule to the right size + + rule.style.borderRightWidth = width + "em"; + rule.style.borderTopWidth = height + "em"; + rule.style.bottom = shift + "em"; // Record the height and width + + rule.width = width; + rule.height = height + shift; + rule.depth = -shift; // Font size is the number large enough that the browser will + // reserve at least `absHeight` space above the baseline. + // The 1.125 factor was empirically determined + + rule.maxFontSize = height * 1.125 * options.sizeMultiplier; + return rule; + }, + mathmlBuilder: function mathmlBuilder(group, options) { + var width = units_calculateSize(group.width, options); + var height = units_calculateSize(group.height, options); + var shift = group.shift ? units_calculateSize(group.shift, options) : 0; + var color = options.color && options.getColor() || "black"; + var rule = new mathMLTree.MathNode("mspace"); + rule.setAttribute("mathbackground", color); + rule.setAttribute("width", width + "em"); + rule.setAttribute("height", height + "em"); + var wrapper = new mathMLTree.MathNode("mpadded", [rule]); + + if (shift >= 0) { + wrapper.setAttribute("height", "+" + shift + "em"); + } else { + wrapper.setAttribute("height", shift + "em"); + wrapper.setAttribute("depth", "+" + -shift + "em"); + } + + wrapper.setAttribute("voffset", shift + "em"); + return wrapper; + } +}); +// CONCATENATED MODULE: ./src/functions/sizing.js + + + + + +function sizingGroup(value, options, baseOptions) { + var inner = buildHTML_buildExpression(value, options, false); + var multiplier = options.sizeMultiplier / baseOptions.sizeMultiplier; // Add size-resetting classes to the inner list and set maxFontSize + // manually. Handle nested size changes. + + for (var i = 0; i < inner.length; i++) { + var pos = inner[i].classes.indexOf("sizing"); + + if (pos < 0) { + Array.prototype.push.apply(inner[i].classes, options.sizingClasses(baseOptions)); + } else if (inner[i].classes[pos + 1] === "reset-size" + options.size) { + // This is a nested size change: e.g., inner[i] is the "b" in + // `\Huge a \small b`. Override the old size (the `reset-` class) + // but not the new size. + inner[i].classes[pos + 1] = "reset-size" + baseOptions.size; + } + + inner[i].height *= multiplier; + inner[i].depth *= multiplier; + } + + return buildCommon.makeFragment(inner); +} +var sizeFuncs = ["\\tiny", "\\sixptsize", "\\scriptsize", "\\footnotesize", "\\small", "\\normalsize", "\\large", "\\Large", "\\LARGE", "\\huge", "\\Huge"]; +var sizing_htmlBuilder = function htmlBuilder(group, options) { + // Handle sizing operators like \Huge. Real TeX doesn't actually allow + // these functions inside of math expressions, so we do some special + // handling. + var newOptions = options.havingSize(group.size); + return sizingGroup(group.body, newOptions, options); +}; +defineFunction({ + type: "sizing", + names: sizeFuncs, + props: { + numArgs: 0, + allowedInText: true + }, + handler: function handler(_ref, args) { + var breakOnTokenText = _ref.breakOnTokenText, + funcName = _ref.funcName, + parser = _ref.parser; + var body = parser.parseExpression(false, breakOnTokenText); + return { + type: "sizing", + mode: parser.mode, + // Figure out what size to use based on the list of functions above + size: sizeFuncs.indexOf(funcName) + 1, + body: body + }; + }, + htmlBuilder: sizing_htmlBuilder, + mathmlBuilder: function mathmlBuilder(group, options) { + var newOptions = options.havingSize(group.size); + var inner = buildMathML_buildExpression(group.body, newOptions); + var node = new mathMLTree.MathNode("mstyle", inner); // TODO(emily): This doesn't produce the correct size for nested size + // changes, because we don't keep state of what style we're currently + // in, so we can't reset the size to normal before changing it. Now + // that we're passing an options parameter we should be able to fix + // this. + + node.setAttribute("mathsize", newOptions.sizeMultiplier + "em"); + return node; + } +}); +// CONCATENATED MODULE: ./src/functions/smash.js +// smash, with optional [tb], as in AMS + + + + + + +defineFunction({ + type: "smash", + names: ["\\smash"], + props: { + numArgs: 1, + numOptionalArgs: 1, + allowedInText: true + }, + handler: function handler(_ref, args, optArgs) { + var parser = _ref.parser; + var smashHeight = false; + var smashDepth = false; + var tbArg = optArgs[0] && assertNodeType(optArgs[0], "ordgroup"); + + if (tbArg) { + // Optional [tb] argument is engaged. + // ref: amsmath: \renewcommand{\smash}[1][tb]{% + // def\mb@t{\ht}\def\mb@b{\dp}\def\mb@tb{\ht\z@\z@\dp}% + var letter = ""; + + for (var i = 0; i < tbArg.body.length; ++i) { + var node = tbArg.body[i]; // $FlowFixMe: Not every node type has a `text` property. + + letter = node.text; + + if (letter === "t") { + smashHeight = true; + } else if (letter === "b") { + smashDepth = true; + } else { + smashHeight = false; + smashDepth = false; + break; + } + } + } else { + smashHeight = true; + smashDepth = true; + } + + var body = args[0]; + return { + type: "smash", + mode: parser.mode, + body: body, + smashHeight: smashHeight, + smashDepth: smashDepth + }; + }, + htmlBuilder: function htmlBuilder(group, options) { + var node = buildCommon.makeSpan([], [buildHTML_buildGroup(group.body, options)]); + + if (!group.smashHeight && !group.smashDepth) { + return node; + } + + if (group.smashHeight) { + node.height = 0; // In order to influence makeVList, we have to reset the children. + + if (node.children) { + for (var i = 0; i < node.children.length; i++) { + node.children[i].height = 0; + } + } + } + + if (group.smashDepth) { + node.depth = 0; + + if (node.children) { + for (var _i = 0; _i < node.children.length; _i++) { + node.children[_i].depth = 0; + } + } + } // At this point, we've reset the TeX-like height and depth values. + // But the span still has an HTML line height. + // makeVList applies "display: table-cell", which prevents the browser + // from acting on that line height. So we'll call makeVList now. + + + var smashedNode = buildCommon.makeVList({ + positionType: "firstBaseline", + children: [{ + type: "elem", + elem: node + }] + }, options); // For spacing, TeX treats \hphantom as a math group (same spacing as ord). + + return buildCommon.makeSpan(["mord"], [smashedNode], options); + }, + mathmlBuilder: function mathmlBuilder(group, options) { + var node = new mathMLTree.MathNode("mpadded", [buildMathML_buildGroup(group.body, options)]); + + if (group.smashHeight) { + node.setAttribute("height", "0px"); + } + + if (group.smashDepth) { + node.setAttribute("depth", "0px"); + } + + return node; + } +}); +// CONCATENATED MODULE: ./src/functions/sqrt.js + + + + + + + +defineFunction({ + type: "sqrt", + names: ["\\sqrt"], + props: { + numArgs: 1, + numOptionalArgs: 1 + }, + handler: function handler(_ref, args, optArgs) { + var parser = _ref.parser; + var index = optArgs[0]; + var body = args[0]; + return { + type: "sqrt", + mode: parser.mode, + body: body, + index: index + }; + }, + htmlBuilder: function htmlBuilder(group, options) { + // Square roots are handled in the TeXbook pg. 443, Rule 11. + // First, we do the same steps as in overline to build the inner group + // and line + var inner = buildHTML_buildGroup(group.body, options.havingCrampedStyle()); + + if (inner.height === 0) { + // Render a small surd. + inner.height = options.fontMetrics().xHeight; + } // Some groups can return document fragments. Handle those by wrapping + // them in a span. + + + inner = buildCommon.wrapFragment(inner, options); // Calculate the minimum size for the \surd delimiter + + var metrics = options.fontMetrics(); + var theta = metrics.defaultRuleThickness; + var phi = theta; + + if (options.style.id < src_Style.TEXT.id) { + phi = options.fontMetrics().xHeight; + } // Calculate the clearance between the body and line + + + var lineClearance = theta + phi / 4; + var minDelimiterHeight = inner.height + inner.depth + lineClearance + theta; // Create a sqrt SVG of the required minimum size + + var _delimiter$sqrtImage = delimiter.sqrtImage(minDelimiterHeight, options), + img = _delimiter$sqrtImage.span, + ruleWidth = _delimiter$sqrtImage.ruleWidth, + advanceWidth = _delimiter$sqrtImage.advanceWidth; + + var delimDepth = img.height - ruleWidth; // Adjust the clearance based on the delimiter size + + if (delimDepth > inner.height + inner.depth + lineClearance) { + lineClearance = (lineClearance + delimDepth - inner.height - inner.depth) / 2; + } // Shift the sqrt image + + + var imgShift = img.height - inner.height - lineClearance - ruleWidth; + inner.style.paddingLeft = advanceWidth + "em"; // Overlay the image and the argument. + + var body = buildCommon.makeVList({ + positionType: "firstBaseline", + children: [{ + type: "elem", + elem: inner, + wrapperClasses: ["svg-align"] + }, { + type: "kern", + size: -(inner.height + imgShift) + }, { + type: "elem", + elem: img + }, { + type: "kern", + size: ruleWidth + }] + }, options); + + if (!group.index) { + return buildCommon.makeSpan(["mord", "sqrt"], [body], options); + } else { + // Handle the optional root index + // The index is always in scriptscript style + var newOptions = options.havingStyle(src_Style.SCRIPTSCRIPT); + var rootm = buildHTML_buildGroup(group.index, newOptions, options); // The amount the index is shifted by. This is taken from the TeX + // source, in the definition of `\r@@t`. + + var toShift = 0.6 * (body.height - body.depth); // Build a VList with the superscript shifted up correctly + + var rootVList = buildCommon.makeVList({ + positionType: "shift", + positionData: -toShift, + children: [{ + type: "elem", + elem: rootm + }] + }, options); // Add a class surrounding it so we can add on the appropriate + // kerning + + var rootVListWrap = buildCommon.makeSpan(["root"], [rootVList]); + return buildCommon.makeSpan(["mord", "sqrt"], [rootVListWrap, body], options); + } + }, + mathmlBuilder: function mathmlBuilder(group, options) { + var body = group.body, + index = group.index; + return index ? new mathMLTree.MathNode("mroot", [buildMathML_buildGroup(body, options), buildMathML_buildGroup(index, options)]) : new mathMLTree.MathNode("msqrt", [buildMathML_buildGroup(body, options)]); + } +}); +// CONCATENATED MODULE: ./src/functions/styling.js + + + + + +var styling_styleMap = { + "display": src_Style.DISPLAY, + "text": src_Style.TEXT, + "script": src_Style.SCRIPT, + "scriptscript": src_Style.SCRIPTSCRIPT +}; +defineFunction({ + type: "styling", + names: ["\\displaystyle", "\\textstyle", "\\scriptstyle", "\\scriptscriptstyle"], + props: { + numArgs: 0, + allowedInText: true + }, + handler: function handler(_ref, args) { + var breakOnTokenText = _ref.breakOnTokenText, + funcName = _ref.funcName, + parser = _ref.parser; + // parse out the implicit body + var body = parser.parseExpression(true, breakOnTokenText); // TODO: Refactor to avoid duplicating styleMap in multiple places (e.g. + // here and in buildHTML and de-dupe the enumeration of all the styles). + // $FlowFixMe: The names above exactly match the styles. + + var style = funcName.slice(1, funcName.length - 5); + return { + type: "styling", + mode: parser.mode, + // Figure out what style to use by pulling out the style from + // the function name + style: style, + body: body + }; + }, + htmlBuilder: function htmlBuilder(group, options) { + // Style changes are handled in the TeXbook on pg. 442, Rule 3. + var newStyle = styling_styleMap[group.style]; + var newOptions = options.havingStyle(newStyle).withFont(''); + return sizingGroup(group.body, newOptions, options); + }, + mathmlBuilder: function mathmlBuilder(group, options) { + // Figure out what style we're changing to. + var newStyle = styling_styleMap[group.style]; + var newOptions = options.havingStyle(newStyle); + var inner = buildMathML_buildExpression(group.body, newOptions); + var node = new mathMLTree.MathNode("mstyle", inner); + var styleAttributes = { + "display": ["0", "true"], + "text": ["0", "false"], + "script": ["1", "false"], + "scriptscript": ["2", "false"] + }; + var attr = styleAttributes[group.style]; + node.setAttribute("scriptlevel", attr[0]); + node.setAttribute("displaystyle", attr[1]); + return node; + } +}); +// CONCATENATED MODULE: ./src/functions/supsub.js + + + + + + + + + + + + + + +/** + * Sometimes, groups perform special rules when they have superscripts or + * subscripts attached to them. This function lets the `supsub` group know that + * Sometimes, groups perform special rules when they have superscripts or + * its inner element should handle the superscripts and subscripts instead of + * handling them itself. + */ +var supsub_htmlBuilderDelegate = function htmlBuilderDelegate(group, options) { + var base = group.base; + + if (!base) { + return null; + } else if (base.type === "op") { + // Operators handle supsubs differently when they have limits + // (e.g. `\displaystyle\sum_2^3`) + var delegate = base.limits && (options.style.size === src_Style.DISPLAY.size || base.alwaysHandleSupSub); + return delegate ? op_htmlBuilder : null; + } else if (base.type === "operatorname") { + var _delegate = base.alwaysHandleSupSub && (options.style.size === src_Style.DISPLAY.size || base.limits); + + return _delegate ? operatorname_htmlBuilder : null; + } else if (base.type === "accent") { + return utils.isCharacterBox(base.base) ? accent_htmlBuilder : null; + } else if (base.type === "horizBrace") { + var isSup = !group.sub; + return isSup === base.isOver ? horizBrace_htmlBuilder : null; + } else { + return null; + } +}; // Super scripts and subscripts, whose precise placement can depend on other +// functions that precede them. + + +defineFunctionBuilders({ + type: "supsub", + htmlBuilder: function htmlBuilder(group, options) { + // Superscript and subscripts are handled in the TeXbook on page + // 445-446, rules 18(a-f). + // Here is where we defer to the inner group if it should handle + // superscripts and subscripts itself. + var builderDelegate = supsub_htmlBuilderDelegate(group, options); + + if (builderDelegate) { + return builderDelegate(group, options); + } + + var valueBase = group.base, + valueSup = group.sup, + valueSub = group.sub; + var base = buildHTML_buildGroup(valueBase, options); + var supm; + var subm; + var metrics = options.fontMetrics(); // Rule 18a + + var supShift = 0; + var subShift = 0; + var isCharacterBox = valueBase && utils.isCharacterBox(valueBase); + + if (valueSup) { + var newOptions = options.havingStyle(options.style.sup()); + supm = buildHTML_buildGroup(valueSup, newOptions, options); + + if (!isCharacterBox) { + supShift = base.height - newOptions.fontMetrics().supDrop * newOptions.sizeMultiplier / options.sizeMultiplier; + } + } + + if (valueSub) { + var _newOptions = options.havingStyle(options.style.sub()); + + subm = buildHTML_buildGroup(valueSub, _newOptions, options); + + if (!isCharacterBox) { + subShift = base.depth + _newOptions.fontMetrics().subDrop * _newOptions.sizeMultiplier / options.sizeMultiplier; + } + } // Rule 18c + + + var minSupShift; + + if (options.style === src_Style.DISPLAY) { + minSupShift = metrics.sup1; + } else if (options.style.cramped) { + minSupShift = metrics.sup3; + } else { + minSupShift = metrics.sup2; + } // scriptspace is a font-size-independent size, so scale it + // appropriately for use as the marginRight. + + + var multiplier = options.sizeMultiplier; + var marginRight = 0.5 / metrics.ptPerEm / multiplier + "em"; + var marginLeft = null; + + if (subm) { + // Subscripts shouldn't be shifted by the base's italic correction. + // Account for that by shifting the subscript back the appropriate + // amount. Note we only do this when the base is a single symbol. + var isOiint = group.base && group.base.type === "op" && group.base.name && (group.base.name === "\\oiint" || group.base.name === "\\oiiint"); + + if (base instanceof domTree_SymbolNode || isOiint) { + // $FlowFixMe + marginLeft = -base.italic + "em"; + } + } + + var supsub; + + if (supm && subm) { + supShift = Math.max(supShift, minSupShift, supm.depth + 0.25 * metrics.xHeight); + subShift = Math.max(subShift, metrics.sub2); + var ruleWidth = metrics.defaultRuleThickness; // Rule 18e + + var maxWidth = 4 * ruleWidth; + + if (supShift - supm.depth - (subm.height - subShift) < maxWidth) { + subShift = maxWidth - (supShift - supm.depth) + subm.height; + var psi = 0.8 * metrics.xHeight - (supShift - supm.depth); + + if (psi > 0) { + supShift += psi; + subShift -= psi; + } + } + + var vlistElem = [{ + type: "elem", + elem: subm, + shift: subShift, + marginRight: marginRight, + marginLeft: marginLeft + }, { + type: "elem", + elem: supm, + shift: -supShift, + marginRight: marginRight + }]; + supsub = buildCommon.makeVList({ + positionType: "individualShift", + children: vlistElem + }, options); + } else if (subm) { + // Rule 18b + subShift = Math.max(subShift, metrics.sub1, subm.height - 0.8 * metrics.xHeight); + var _vlistElem = [{ + type: "elem", + elem: subm, + marginLeft: marginLeft, + marginRight: marginRight + }]; + supsub = buildCommon.makeVList({ + positionType: "shift", + positionData: subShift, + children: _vlistElem + }, options); + } else if (supm) { + // Rule 18c, d + supShift = Math.max(supShift, minSupShift, supm.depth + 0.25 * metrics.xHeight); + supsub = buildCommon.makeVList({ + positionType: "shift", + positionData: -supShift, + children: [{ + type: "elem", + elem: supm, + marginRight: marginRight + }] + }, options); + } else { + throw new Error("supsub must have either sup or sub."); + } // Wrap the supsub vlist in a span.msupsub to reset text-align. + + + var mclass = getTypeOfDomTree(base, "right") || "mord"; + return buildCommon.makeSpan([mclass], [base, buildCommon.makeSpan(["msupsub"], [supsub])], options); + }, + mathmlBuilder: function mathmlBuilder(group, options) { + // Is the inner group a relevant horizonal brace? + var isBrace = false; + var isOver; + var isSup; + var horizBrace = checkNodeType(group.base, "horizBrace"); + + if (horizBrace) { + isSup = !!group.sup; + + if (isSup === horizBrace.isOver) { + isBrace = true; + isOver = horizBrace.isOver; + } + } + + if (group.base && (group.base.type === "op" || group.base.type === "operatorname")) { + group.base.parentIsSupSub = true; + } + + var children = [buildMathML_buildGroup(group.base, options)]; + + if (group.sub) { + children.push(buildMathML_buildGroup(group.sub, options)); + } + + if (group.sup) { + children.push(buildMathML_buildGroup(group.sup, options)); + } + + var nodeType; + + if (isBrace) { + nodeType = isOver ? "mover" : "munder"; + } else if (!group.sub) { + var base = group.base; + + if (base && base.type === "op" && base.limits && (options.style === src_Style.DISPLAY || base.alwaysHandleSupSub)) { + nodeType = "mover"; + } else if (base && base.type === "operatorname" && base.alwaysHandleSupSub && (base.limits || options.style === src_Style.DISPLAY)) { + nodeType = "mover"; + } else { + nodeType = "msup"; + } + } else if (!group.sup) { + var _base = group.base; + + if (_base && _base.type === "op" && _base.limits && (options.style === src_Style.DISPLAY || _base.alwaysHandleSupSub)) { + nodeType = "munder"; + } else if (_base && _base.type === "operatorname" && _base.alwaysHandleSupSub && (_base.limits || options.style === src_Style.DISPLAY)) { + nodeType = "munder"; + } else { + nodeType = "msub"; + } + } else { + var _base2 = group.base; + + if (_base2 && _base2.type === "op" && _base2.limits && options.style === src_Style.DISPLAY) { + nodeType = "munderover"; + } else if (_base2 && _base2.type === "operatorname" && _base2.alwaysHandleSupSub && (options.style === src_Style.DISPLAY || _base2.limits)) { + nodeType = "munderover"; + } else { + nodeType = "msubsup"; + } + } + + var node = new mathMLTree.MathNode(nodeType, children); + return node; + } +}); +// CONCATENATED MODULE: ./src/functions/symbolsOp.js + + + + // Operator ParseNodes created in Parser.js from symbol Groups in src/symbols.js. + +defineFunctionBuilders({ + type: "atom", + htmlBuilder: function htmlBuilder(group, options) { + return buildCommon.mathsym(group.text, group.mode, options, ["m" + group.family]); + }, + mathmlBuilder: function mathmlBuilder(group, options) { + var node = new mathMLTree.MathNode("mo", [buildMathML_makeText(group.text, group.mode)]); + + if (group.family === "bin") { + var variant = buildMathML_getVariant(group, options); + + if (variant === "bold-italic") { + node.setAttribute("mathvariant", variant); + } + } else if (group.family === "punct") { + node.setAttribute("separator", "true"); + } else if (group.family === "open" || group.family === "close") { + // Delims built here should not stretch vertically. + // See delimsizing.js for stretchy delims. + node.setAttribute("stretchy", "false"); + } + + return node; + } +}); +// CONCATENATED MODULE: ./src/functions/symbolsOrd.js + + + + +// "mathord" and "textord" ParseNodes created in Parser.js from symbol Groups in +var defaultVariant = { + "mi": "italic", + "mn": "normal", + "mtext": "normal" +}; +defineFunctionBuilders({ + type: "mathord", + htmlBuilder: function htmlBuilder(group, options) { + return buildCommon.makeOrd(group, options, "mathord"); + }, + mathmlBuilder: function mathmlBuilder(group, options) { + var node = new mathMLTree.MathNode("mi", [buildMathML_makeText(group.text, group.mode, options)]); + var variant = buildMathML_getVariant(group, options) || "italic"; + + if (variant !== defaultVariant[node.type]) { + node.setAttribute("mathvariant", variant); + } + + return node; + } +}); +defineFunctionBuilders({ + type: "textord", + htmlBuilder: function htmlBuilder(group, options) { + return buildCommon.makeOrd(group, options, "textord"); + }, + mathmlBuilder: function mathmlBuilder(group, options) { + var text = buildMathML_makeText(group.text, group.mode, options); + var variant = buildMathML_getVariant(group, options) || "normal"; + var node; + + if (group.mode === 'text') { + node = new mathMLTree.MathNode("mtext", [text]); + } else if (/[0-9]/.test(group.text)) { + // TODO(kevinb) merge adjacent nodes + // do it as a post processing step + node = new mathMLTree.MathNode("mn", [text]); + } else if (group.text === "\\prime") { + node = new mathMLTree.MathNode("mo", [text]); + } else { + node = new mathMLTree.MathNode("mi", [text]); + } + + if (variant !== defaultVariant[node.type]) { + node.setAttribute("mathvariant", variant); + } + + return node; + } +}); +// CONCATENATED MODULE: ./src/functions/symbolsSpacing.js + + + + // A map of CSS-based spacing functions to their CSS class. + +var cssSpace = { + "\\nobreak": "nobreak", + "\\allowbreak": "allowbreak" +}; // A lookup table to determine whether a spacing function/symbol should be +// treated like a regular space character. If a symbol or command is a key +// in this table, then it should be a regular space character. Furthermore, +// the associated value may have a `className` specifying an extra CSS class +// to add to the created `span`. + +var regularSpace = { + " ": {}, + "\\ ": {}, + "~": { + className: "nobreak" + }, + "\\space": {}, + "\\nobreakspace": { + className: "nobreak" + } +}; // ParseNode<"spacing"> created in Parser.js from the "spacing" symbol Groups in +// src/symbols.js. + +defineFunctionBuilders({ + type: "spacing", + htmlBuilder: function htmlBuilder(group, options) { + if (regularSpace.hasOwnProperty(group.text)) { + var className = regularSpace[group.text].className || ""; // Spaces are generated by adding an actual space. Each of these + // things has an entry in the symbols table, so these will be turned + // into appropriate outputs. + + if (group.mode === "text") { + var ord = buildCommon.makeOrd(group, options, "textord"); + ord.classes.push(className); + return ord; + } else { + return buildCommon.makeSpan(["mspace", className], [buildCommon.mathsym(group.text, group.mode, options)], options); + } + } else if (cssSpace.hasOwnProperty(group.text)) { + // Spaces based on just a CSS class. + return buildCommon.makeSpan(["mspace", cssSpace[group.text]], [], options); + } else { + throw new src_ParseError("Unknown type of space \"" + group.text + "\""); + } + }, + mathmlBuilder: function mathmlBuilder(group, options) { + var node; + + if (regularSpace.hasOwnProperty(group.text)) { + node = new mathMLTree.MathNode("mtext", [new mathMLTree.TextNode("\xA0")]); + } else if (cssSpace.hasOwnProperty(group.text)) { + // CSS-based MathML spaces (\nobreak, \allowbreak) are ignored + return new mathMLTree.MathNode("mspace"); + } else { + throw new src_ParseError("Unknown type of space \"" + group.text + "\""); + } + + return node; + } +}); +// CONCATENATED MODULE: ./src/functions/tag.js + + + + +var tag_pad = function pad() { + var padNode = new mathMLTree.MathNode("mtd", []); + padNode.setAttribute("width", "50%"); + return padNode; +}; + +defineFunctionBuilders({ + type: "tag", + mathmlBuilder: function mathmlBuilder(group, options) { + var table = new mathMLTree.MathNode("mtable", [new mathMLTree.MathNode("mtr", [tag_pad(), new mathMLTree.MathNode("mtd", [buildExpressionRow(group.body, options)]), tag_pad(), new mathMLTree.MathNode("mtd", [buildExpressionRow(group.tag, options)])])]); + table.setAttribute("width", "100%"); + return table; // TODO: Left-aligned tags. + // Currently, the group and options passed here do not contain + // enough info to set tag alignment. `leqno` is in Settings but it is + // not passed to Options. On the HTML side, leqno is + // set by a CSS class applied in buildTree.js. That would have worked + // in MathML if browsers supported . Since they don't, we + // need to rewrite the way this function is called. + } +}); +// CONCATENATED MODULE: ./src/functions/text.js + + + + // Non-mathy text, possibly in a font + +var textFontFamilies = { + "\\text": undefined, + "\\textrm": "textrm", + "\\textsf": "textsf", + "\\texttt": "texttt", + "\\textnormal": "textrm" +}; +var textFontWeights = { + "\\textbf": "textbf", + "\\textmd": "textmd" +}; +var textFontShapes = { + "\\textit": "textit", + "\\textup": "textup" +}; + +var optionsWithFont = function optionsWithFont(group, options) { + var font = group.font; // Checks if the argument is a font family or a font style. + + if (!font) { + return options; + } else if (textFontFamilies[font]) { + return options.withTextFontFamily(textFontFamilies[font]); + } else if (textFontWeights[font]) { + return options.withTextFontWeight(textFontWeights[font]); + } else { + return options.withTextFontShape(textFontShapes[font]); + } +}; + +defineFunction({ + type: "text", + names: [// Font families + "\\text", "\\textrm", "\\textsf", "\\texttt", "\\textnormal", // Font weights + "\\textbf", "\\textmd", // Font Shapes + "\\textit", "\\textup"], + props: { + numArgs: 1, + argTypes: ["text"], + greediness: 2, + allowedInText: true + }, + handler: function handler(_ref, args) { + var parser = _ref.parser, + funcName = _ref.funcName; + var body = args[0]; + return { + type: "text", + mode: parser.mode, + body: defineFunction_ordargument(body), + font: funcName + }; + }, + htmlBuilder: function htmlBuilder(group, options) { + var newOptions = optionsWithFont(group, options); + var inner = buildHTML_buildExpression(group.body, newOptions, true); + return buildCommon.makeSpan(["mord", "text"], buildCommon.tryCombineChars(inner), newOptions); + }, + mathmlBuilder: function mathmlBuilder(group, options) { + var newOptions = optionsWithFont(group, options); + return buildExpressionRow(group.body, newOptions); + } +}); +// CONCATENATED MODULE: ./src/functions/underline.js + + + + + +defineFunction({ + type: "underline", + names: ["\\underline"], + props: { + numArgs: 1, + allowedInText: true + }, + handler: function handler(_ref, args) { + var parser = _ref.parser; + return { + type: "underline", + mode: parser.mode, + body: args[0] + }; + }, + htmlBuilder: function htmlBuilder(group, options) { + // Underlines are handled in the TeXbook pg 443, Rule 10. + // Build the inner group. + var innerGroup = buildHTML_buildGroup(group.body, options); // Create the line to go below the body + + var line = buildCommon.makeLineSpan("underline-line", options); // Generate the vlist, with the appropriate kerns + + var defaultRuleThickness = options.fontMetrics().defaultRuleThickness; + var vlist = buildCommon.makeVList({ + positionType: "top", + positionData: innerGroup.height, + children: [{ + type: "kern", + size: defaultRuleThickness + }, { + type: "elem", + elem: line + }, { + type: "kern", + size: 3 * defaultRuleThickness + }, { + type: "elem", + elem: innerGroup + }] + }, options); + return buildCommon.makeSpan(["mord", "underline"], [vlist], options); + }, + mathmlBuilder: function mathmlBuilder(group, options) { + var operator = new mathMLTree.MathNode("mo", [new mathMLTree.TextNode("\u203E")]); + operator.setAttribute("stretchy", "true"); + var node = new mathMLTree.MathNode("munder", [buildMathML_buildGroup(group.body, options), operator]); + node.setAttribute("accentunder", "true"); + return node; + } +}); +// CONCATENATED MODULE: ./src/functions/verb.js + + + + +defineFunction({ + type: "verb", + names: ["\\verb"], + props: { + numArgs: 0, + allowedInText: true + }, + handler: function handler(context, args, optArgs) { + // \verb and \verb* are dealt with directly in Parser.js. + // If we end up here, it's because of a failure to match the two delimiters + // in the regex in Lexer.js. LaTeX raises the following error when \verb is + // terminated by end of line (or file). + throw new src_ParseError("\\verb ended by end of line instead of matching delimiter"); + }, + htmlBuilder: function htmlBuilder(group, options) { + var text = makeVerb(group); + var body = []; // \verb enters text mode and therefore is sized like \textstyle + + var newOptions = options.havingStyle(options.style.text()); + + for (var i = 0; i < text.length; i++) { + var c = text[i]; + + if (c === '~') { + c = '\\textasciitilde'; + } + + body.push(buildCommon.makeSymbol(c, "Typewriter-Regular", group.mode, newOptions, ["mord", "texttt"])); + } + + return buildCommon.makeSpan(["mord", "text"].concat(newOptions.sizingClasses(options)), buildCommon.tryCombineChars(body), newOptions); + }, + mathmlBuilder: function mathmlBuilder(group, options) { + var text = new mathMLTree.TextNode(makeVerb(group)); + var node = new mathMLTree.MathNode("mtext", [text]); + node.setAttribute("mathvariant", "monospace"); + return node; + } +}); +/** + * Converts verb group into body string. + * + * \verb* replaces each space with an open box \u2423 + * \verb replaces each space with a no-break space \xA0 + */ + +var makeVerb = function makeVerb(group) { + return group.body.replace(/ /g, group.star ? "\u2423" : '\xA0'); +}; +// CONCATENATED MODULE: ./src/functions.js +/** Include this to ensure that all functions are defined. */ + +var functions = _functions; +/* harmony default export */ var src_functions = (functions); // TODO(kevinb): have functions return an object and call defineFunction with +// that object in this file instead of relying on side-effects. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +// CONCATENATED MODULE: ./src/Lexer.js +/** + * The Lexer class handles tokenizing the input in various ways. Since our + * parser expects us to be able to backtrack, the lexer allows lexing from any + * given starting point. + * + * Its main exposed function is the `lex` function, which takes a position to + * lex from and a type of token to lex. It defers to the appropriate `_innerLex` + * function. + * + * The various `_innerLex` functions perform the actual lexing of different + * kinds. + */ + + + + +/* The following tokenRegex + * - matches typical whitespace (but not NBSP etc.) using its first group + * - does not match any control character \x00-\x1f except whitespace + * - does not match a bare backslash + * - matches any ASCII character except those just mentioned + * - does not match the BMP private use area \uE000-\uF8FF + * - does not match bare surrogate code units + * - matches any BMP character except for those just described + * - matches any valid Unicode surrogate pair + * - matches a backslash followed by one or more letters + * - matches a backslash followed by any BMP character, including newline + * Just because the Lexer matches something doesn't mean it's valid input: + * If there is no matching function or symbol definition, the Parser will + * still reject the input. + */ +var spaceRegexString = "[ \r\n\t]"; +var controlWordRegexString = "\\\\[a-zA-Z@]+"; +var controlSymbolRegexString = "\\\\[^\uD800-\uDFFF]"; +var controlWordWhitespaceRegexString = "" + controlWordRegexString + spaceRegexString + "*"; +var controlWordWhitespaceRegex = new RegExp("^(" + controlWordRegexString + ")" + spaceRegexString + "*$"); +var combiningDiacriticalMarkString = "[\u0300-\u036F]"; +var combiningDiacriticalMarksEndRegex = new RegExp(combiningDiacriticalMarkString + "+$"); +var tokenRegexString = "(" + spaceRegexString + "+)|" + // whitespace +"([!-\\[\\]-\u2027\u202A-\uD7FF\uF900-\uFFFF]" + ( // single codepoint +combiningDiacriticalMarkString + "*") + // ...plus accents +"|[\uD800-\uDBFF][\uDC00-\uDFFF]" + ( // surrogate pair +combiningDiacriticalMarkString + "*") + // ...plus accents +"|\\\\verb\\*([^]).*?\\3" + // \verb* +"|\\\\verb([^*a-zA-Z]).*?\\4" + // \verb unstarred +"|\\\\operatorname\\*" + ( // \operatorname* +"|" + controlWordWhitespaceRegexString) + ( // \macroName + spaces +"|" + controlSymbolRegexString + ")"); // \\, \', etc. + +/** Main Lexer class */ + +var Lexer_Lexer = +/*#__PURE__*/ +function () { + // category codes, only supports comment characters (14) for now + function Lexer(input, settings) { + this.input = void 0; + this.settings = void 0; + this.tokenRegex = void 0; + this.catcodes = void 0; + // Separate accents from characters + this.input = input; + this.settings = settings; + this.tokenRegex = new RegExp(tokenRegexString, 'g'); + this.catcodes = { + "%": 14 // comment character + + }; + } + + var _proto = Lexer.prototype; + + _proto.setCatcode = function setCatcode(char, code) { + this.catcodes[char] = code; + } + /** + * This function lexes a single token. + */ + ; + + _proto.lex = function lex() { + var input = this.input; + var pos = this.tokenRegex.lastIndex; + + if (pos === input.length) { + return new Token_Token("EOF", new SourceLocation(this, pos, pos)); + } + + var match = this.tokenRegex.exec(input); + + if (match === null || match.index !== pos) { + throw new src_ParseError("Unexpected character: '" + input[pos] + "'", new Token_Token(input[pos], new SourceLocation(this, pos, pos + 1))); + } + + var text = match[2] || " "; + + if (this.catcodes[text] === 14) { + // comment character + var nlIndex = input.indexOf('\n', this.tokenRegex.lastIndex); + + if (nlIndex === -1) { + this.tokenRegex.lastIndex = input.length; // EOF + + this.settings.reportNonstrict("commentAtEnd", "% comment has no terminating newline; LaTeX would " + "fail because of commenting the end of math mode (e.g. $)"); + } else { + this.tokenRegex.lastIndex = nlIndex + 1; + } + + return this.lex(); + } // Trim any trailing whitespace from control word match + + + var controlMatch = text.match(controlWordWhitespaceRegex); + + if (controlMatch) { + text = controlMatch[1]; + } + + return new Token_Token(text, new SourceLocation(this, pos, this.tokenRegex.lastIndex)); + }; + + return Lexer; +}(); + + +// CONCATENATED MODULE: ./src/Namespace.js +/** + * A `Namespace` refers to a space of nameable things like macros or lengths, + * which can be `set` either globally or local to a nested group, using an + * undo stack similar to how TeX implements this functionality. + * Performance-wise, `get` and local `set` take constant time, while global + * `set` takes time proportional to the depth of group nesting. + */ + + +var Namespace_Namespace = +/*#__PURE__*/ +function () { + /** + * Both arguments are optional. The first argument is an object of + * built-in mappings which never change. The second argument is an object + * of initial (global-level) mappings, which will constantly change + * according to any global/top-level `set`s done. + */ + function Namespace(builtins, globalMacros) { + if (builtins === void 0) { + builtins = {}; + } + + if (globalMacros === void 0) { + globalMacros = {}; + } + + this.current = void 0; + this.builtins = void 0; + this.undefStack = void 0; + this.current = globalMacros; + this.builtins = builtins; + this.undefStack = []; + } + /** + * Start a new nested group, affecting future local `set`s. + */ + + + var _proto = Namespace.prototype; + + _proto.beginGroup = function beginGroup() { + this.undefStack.push({}); + } + /** + * End current nested group, restoring values before the group began. + */ + ; + + _proto.endGroup = function endGroup() { + if (this.undefStack.length === 0) { + throw new src_ParseError("Unbalanced namespace destruction: attempt " + "to pop global namespace; please report this as a bug"); + } + + var undefs = this.undefStack.pop(); + + for (var undef in undefs) { + if (undefs.hasOwnProperty(undef)) { + if (undefs[undef] === undefined) { + delete this.current[undef]; + } else { + this.current[undef] = undefs[undef]; + } + } + } + } + /** + * Detect whether `name` has a definition. Equivalent to + * `get(name) != null`. + */ + ; + + _proto.has = function has(name) { + return this.current.hasOwnProperty(name) || this.builtins.hasOwnProperty(name); + } + /** + * Get the current value of a name, or `undefined` if there is no value. + * + * Note: Do not use `if (namespace.get(...))` to detect whether a macro + * is defined, as the definition may be the empty string which evaluates + * to `false` in JavaScript. Use `if (namespace.get(...) != null)` or + * `if (namespace.has(...))`. + */ + ; + + _proto.get = function get(name) { + if (this.current.hasOwnProperty(name)) { + return this.current[name]; + } else { + return this.builtins[name]; + } + } + /** + * Set the current value of a name, and optionally set it globally too. + * Local set() sets the current value and (when appropriate) adds an undo + * operation to the undo stack. Global set() may change the undo + * operation at every level, so takes time linear in their number. + */ + ; + + _proto.set = function set(name, value, global) { + if (global === void 0) { + global = false; + } + + if (global) { + // Global set is equivalent to setting in all groups. Simulate this + // by destroying any undos currently scheduled for this name, + // and adding an undo with the *new* value (in case it later gets + // locally reset within this environment). + for (var i = 0; i < this.undefStack.length; i++) { + delete this.undefStack[i][name]; + } + + if (this.undefStack.length > 0) { + this.undefStack[this.undefStack.length - 1][name] = value; + } + } else { + // Undo this set at end of this group (possibly to `undefined`), + // unless an undo is already in place, in which case that older + // value is the correct one. + var top = this.undefStack[this.undefStack.length - 1]; + + if (top && !top.hasOwnProperty(name)) { + top[name] = this.current[name]; + } + } + + this.current[name] = value; + }; + + return Namespace; +}(); + + +// CONCATENATED MODULE: ./src/macros.js +/** + * Predefined macros for KaTeX. + * This can be used to define some commands in terms of others. + */ + + + + + +var builtinMacros = {}; +/* harmony default export */ var macros = (builtinMacros); // This function might one day accept an additional argument and do more things. + +function defineMacro(name, body) { + builtinMacros[name] = body; +} ////////////////////////////////////////////////////////////////////// +// macro tools +// LaTeX's \@firstoftwo{#1}{#2} expands to #1, skipping #2 +// TeX source: \long\def\@firstoftwo#1#2{#1} + +defineMacro("\\@firstoftwo", function (context) { + var args = context.consumeArgs(2); + return { + tokens: args[0], + numArgs: 0 + }; +}); // LaTeX's \@secondoftwo{#1}{#2} expands to #2, skipping #1 +// TeX source: \long\def\@secondoftwo#1#2{#2} + +defineMacro("\\@secondoftwo", function (context) { + var args = context.consumeArgs(2); + return { + tokens: args[1], + numArgs: 0 + }; +}); // LaTeX's \@ifnextchar{#1}{#2}{#3} looks ahead to the next (unexpanded) +// symbol. If it matches #1, then the macro expands to #2; otherwise, #3. +// Note, however, that it does not consume the next symbol in either case. + +defineMacro("\\@ifnextchar", function (context) { + var args = context.consumeArgs(3); // symbol, if, else + + var nextToken = context.future(); + + if (args[0].length === 1 && args[0][0].text === nextToken.text) { + return { + tokens: args[1], + numArgs: 0 + }; + } else { + return { + tokens: args[2], + numArgs: 0 + }; + } +}); // LaTeX's \@ifstar{#1}{#2} looks ahead to the next (unexpanded) symbol. +// If it is `*`, then it consumes the symbol, and the macro expands to #1; +// otherwise, the macro expands to #2 (without consuming the symbol). +// TeX source: \def\@ifstar#1{\@ifnextchar *{\@firstoftwo{#1}}} + +defineMacro("\\@ifstar", "\\@ifnextchar *{\\@firstoftwo{#1}}"); // LaTeX's \TextOrMath{#1}{#2} expands to #1 in text mode, #2 in math mode + +defineMacro("\\TextOrMath", function (context) { + var args = context.consumeArgs(2); + + if (context.mode === 'text') { + return { + tokens: args[0], + numArgs: 0 + }; + } else { + return { + tokens: args[1], + numArgs: 0 + }; + } +}); // Lookup table for parsing numbers in base 8 through 16 + +var digitToNumber = { + "0": 0, + "1": 1, + "2": 2, + "3": 3, + "4": 4, + "5": 5, + "6": 6, + "7": 7, + "8": 8, + "9": 9, + "a": 10, + "A": 10, + "b": 11, + "B": 11, + "c": 12, + "C": 12, + "d": 13, + "D": 13, + "e": 14, + "E": 14, + "f": 15, + "F": 15 +}; // TeX \char makes a literal character (catcode 12) using the following forms: +// (see The TeXBook, p. 43) +// \char123 -- decimal +// \char'123 -- octal +// \char"123 -- hex +// \char`x -- character that can be written (i.e. isn't active) +// \char`\x -- character that cannot be written (e.g. %) +// These all refer to characters from the font, so we turn them into special +// calls to a function \@char dealt with in the Parser. + +defineMacro("\\char", function (context) { + var token = context.popToken(); + var base; + var number = ''; + + if (token.text === "'") { + base = 8; + token = context.popToken(); + } else if (token.text === '"') { + base = 16; + token = context.popToken(); + } else if (token.text === "`") { + token = context.popToken(); + + if (token.text[0] === "\\") { + number = token.text.charCodeAt(1); + } else if (token.text === "EOF") { + throw new src_ParseError("\\char` missing argument"); + } else { + number = token.text.charCodeAt(0); + } + } else { + base = 10; + } + + if (base) { + // Parse a number in the given base, starting with first `token`. + number = digitToNumber[token.text]; + + if (number == null || number >= base) { + throw new src_ParseError("Invalid base-" + base + " digit " + token.text); + } + + var digit; + + while ((digit = digitToNumber[context.future().text]) != null && digit < base) { + number *= base; + number += digit; + context.popToken(); + } + } + + return "\\@char{" + number + "}"; +}); // Basic support for macro definitions: +// \def\macro{expansion} +// \def\macro#1{expansion} +// \def\macro#1#2{expansion} +// \def\macro#1#2#3#4#5#6#7#8#9{expansion} +// Also the \gdef and \global\def equivalents + +var macros_def = function def(context, global) { + var arg = context.consumeArgs(1)[0]; + + if (arg.length !== 1) { + throw new src_ParseError("\\gdef's first argument must be a macro name"); + } + + var name = arg[0].text; // Count argument specifiers, and check they are in the order #1 #2 ... + + var numArgs = 0; + arg = context.consumeArgs(1)[0]; + + while (arg.length === 1 && arg[0].text === "#") { + arg = context.consumeArgs(1)[0]; + + if (arg.length !== 1) { + throw new src_ParseError("Invalid argument number length \"" + arg.length + "\""); + } + + if (!/^[1-9]$/.test(arg[0].text)) { + throw new src_ParseError("Invalid argument number \"" + arg[0].text + "\""); + } + + numArgs++; + + if (parseInt(arg[0].text) !== numArgs) { + throw new src_ParseError("Argument number \"" + arg[0].text + "\" out of order"); + } + + arg = context.consumeArgs(1)[0]; + } // Final arg is the expansion of the macro + + + context.macros.set(name, { + tokens: arg, + numArgs: numArgs + }, global); + return ''; +}; + +defineMacro("\\gdef", function (context) { + return macros_def(context, true); +}); +defineMacro("\\def", function (context) { + return macros_def(context, false); +}); +defineMacro("\\global", function (context) { + var next = context.consumeArgs(1)[0]; + + if (next.length !== 1) { + throw new src_ParseError("Invalid command after \\global"); + } + + var command = next[0].text; // TODO: Should expand command + + if (command === "\\def") { + // \global\def is equivalent to \gdef + return macros_def(context, true); + } else { + throw new src_ParseError("Invalid command '" + command + "' after \\global"); + } +}); // \newcommand{\macro}[args]{definition} +// \renewcommand{\macro}[args]{definition} +// TODO: Optional arguments: \newcommand{\macro}[args][default]{definition} + +var macros_newcommand = function newcommand(context, existsOK, nonexistsOK) { + var arg = context.consumeArgs(1)[0]; + + if (arg.length !== 1) { + throw new src_ParseError("\\newcommand's first argument must be a macro name"); + } + + var name = arg[0].text; + var exists = context.isDefined(name); + + if (exists && !existsOK) { + throw new src_ParseError("\\newcommand{" + name + "} attempting to redefine " + (name + "; use \\renewcommand")); + } + + if (!exists && !nonexistsOK) { + throw new src_ParseError("\\renewcommand{" + name + "} when command " + name + " " + "does not yet exist; use \\newcommand"); + } + + var numArgs = 0; + arg = context.consumeArgs(1)[0]; + + if (arg.length === 1 && arg[0].text === "[") { + var argText = ''; + var token = context.expandNextToken(); + + while (token.text !== "]" && token.text !== "EOF") { + // TODO: Should properly expand arg, e.g., ignore {}s + argText += token.text; + token = context.expandNextToken(); + } + + if (!argText.match(/^\s*[0-9]+\s*$/)) { + throw new src_ParseError("Invalid number of arguments: " + argText); + } + + numArgs = parseInt(argText); + arg = context.consumeArgs(1)[0]; + } // Final arg is the expansion of the macro + + + context.macros.set(name, { + tokens: arg, + numArgs: numArgs + }); + return ''; +}; + +defineMacro("\\newcommand", function (context) { + return macros_newcommand(context, false, true); +}); +defineMacro("\\renewcommand", function (context) { + return macros_newcommand(context, true, false); +}); +defineMacro("\\providecommand", function (context) { + return macros_newcommand(context, true, true); +}); ////////////////////////////////////////////////////////////////////// +// Grouping +// \let\bgroup={ \let\egroup=} + +defineMacro("\\bgroup", "{"); +defineMacro("\\egroup", "}"); // Symbols from latex.ltx: +// \def\lq{`} +// \def\rq{'} +// \def \aa {\r a} +// \def \AA {\r A} + +defineMacro("\\lq", "`"); +defineMacro("\\rq", "'"); +defineMacro("\\aa", "\\r a"); +defineMacro("\\AA", "\\r A"); // Copyright (C) and registered (R) symbols. Use raw symbol in MathML. +// \DeclareTextCommandDefault{\textcopyright}{\textcircled{c}} +// \DeclareTextCommandDefault{\textregistered}{\textcircled{% +// \check@mathfonts\fontsize\sf@size\z@\math@fontsfalse\selectfont R}} +// \DeclareRobustCommand{\copyright}{% +// \ifmmode{\nfss@text{\textcopyright}}\else\textcopyright\fi} + +defineMacro("\\textcopyright", "\\html@mathml{\\textcircled{c}}{\\char`©}"); +defineMacro("\\copyright", "\\TextOrMath{\\textcopyright}{\\text{\\textcopyright}}"); +defineMacro("\\textregistered", "\\html@mathml{\\textcircled{\\scriptsize R}}{\\char`®}"); // Characters omitted from Unicode range 1D400–1D7FF + +defineMacro("\u212C", "\\mathscr{B}"); // script + +defineMacro("\u2130", "\\mathscr{E}"); +defineMacro("\u2131", "\\mathscr{F}"); +defineMacro("\u210B", "\\mathscr{H}"); +defineMacro("\u2110", "\\mathscr{I}"); +defineMacro("\u2112", "\\mathscr{L}"); +defineMacro("\u2133", "\\mathscr{M}"); +defineMacro("\u211B", "\\mathscr{R}"); +defineMacro("\u212D", "\\mathfrak{C}"); // Fraktur + +defineMacro("\u210C", "\\mathfrak{H}"); +defineMacro("\u2128", "\\mathfrak{Z}"); // Define \Bbbk with a macro that works in both HTML and MathML. + +defineMacro("\\Bbbk", "\\Bbb{k}"); // Unicode middle dot +// The KaTeX fonts do not contain U+00B7. Instead, \cdotp displays +// the dot at U+22C5 and gives it punct spacing. + +defineMacro("\xB7", "\\cdotp"); // \llap and \rlap render their contents in text mode + +defineMacro("\\llap", "\\mathllap{\\textrm{#1}}"); +defineMacro("\\rlap", "\\mathrlap{\\textrm{#1}}"); +defineMacro("\\clap", "\\mathclap{\\textrm{#1}}"); // \not is defined by base/fontmath.ltx via +// \DeclareMathSymbol{\not}{\mathrel}{symbols}{"36} +// It's thus treated like a \mathrel, but defined by a symbol that has zero +// width but extends to the right. We use \rlap to get that spacing. +// For MathML we write U+0338 here. buildMathML.js will then do the overlay. + +defineMacro("\\not", '\\html@mathml{\\mathrel{\\mathrlap\\@not}}{\\char"338}'); // Negated symbols from base/fontmath.ltx: +// \def\neq{\not=} \let\ne=\neq +// \DeclareRobustCommand +// \notin{\mathrel{\m@th\mathpalette\c@ncel\in}} +// \def\c@ncel#1#2{\m@th\ooalign{$\hfil#1\mkern1mu/\hfil$\crcr$#1#2$}} + +defineMacro("\\neq", "\\html@mathml{\\mathrel{\\not=}}{\\mathrel{\\char`≠}}"); +defineMacro("\\ne", "\\neq"); +defineMacro("\u2260", "\\neq"); +defineMacro("\\notin", "\\html@mathml{\\mathrel{{\\in}\\mathllap{/\\mskip1mu}}}" + "{\\mathrel{\\char`∉}}"); +defineMacro("\u2209", "\\notin"); // Unicode stacked relations + +defineMacro("\u2258", "\\html@mathml{" + "\\mathrel{=\\kern{-1em}\\raisebox{0.4em}{$\\scriptsize\\frown$}}" + "}{\\mathrel{\\char`\u2258}}"); +defineMacro("\u2259", "\\html@mathml{\\stackrel{\\tiny\\wedge}{=}}{\\mathrel{\\char`\u2258}}"); +defineMacro("\u225A", "\\html@mathml{\\stackrel{\\tiny\\vee}{=}}{\\mathrel{\\char`\u225A}}"); +defineMacro("\u225B", "\\html@mathml{\\stackrel{\\scriptsize\\star}{=}}" + "{\\mathrel{\\char`\u225B}}"); +defineMacro("\u225D", "\\html@mathml{\\stackrel{\\tiny\\mathrm{def}}{=}}" + "{\\mathrel{\\char`\u225D}}"); +defineMacro("\u225E", "\\html@mathml{\\stackrel{\\tiny\\mathrm{m}}{=}}" + "{\\mathrel{\\char`\u225E}}"); +defineMacro("\u225F", "\\html@mathml{\\stackrel{\\tiny?}{=}}{\\mathrel{\\char`\u225F}}"); // Misc Unicode + +defineMacro("\u27C2", "\\perp"); +defineMacro("\u203C", "\\mathclose{!\\mkern-0.8mu!}"); +defineMacro("\u220C", "\\notni"); +defineMacro("\u231C", "\\ulcorner"); +defineMacro("\u231D", "\\urcorner"); +defineMacro("\u231E", "\\llcorner"); +defineMacro("\u231F", "\\lrcorner"); +defineMacro("\xA9", "\\copyright"); +defineMacro("\xAE", "\\textregistered"); +defineMacro("\uFE0F", "\\textregistered"); ////////////////////////////////////////////////////////////////////// +// LaTeX_2ε +// \vdots{\vbox{\baselineskip4\p@ \lineskiplimit\z@ +// \kern6\p@\hbox{.}\hbox{.}\hbox{.}}} +// We'll call \varvdots, which gets a glyph from symbols.js. +// The zero-width rule gets us an equivalent to the vertical 6pt kern. + +defineMacro("\\vdots", "\\mathord{\\varvdots\\rule{0pt}{15pt}}"); +defineMacro("\u22EE", "\\vdots"); ////////////////////////////////////////////////////////////////////// +// amsmath.sty +// http://mirrors.concertpass.com/tex-archive/macros/latex/required/amsmath/amsmath.pdf +// Italic Greek capital letters. AMS defines these with \DeclareMathSymbol, +// but they are equivalent to \mathit{\Letter}. + +defineMacro("\\varGamma", "\\mathit{\\Gamma}"); +defineMacro("\\varDelta", "\\mathit{\\Delta}"); +defineMacro("\\varTheta", "\\mathit{\\Theta}"); +defineMacro("\\varLambda", "\\mathit{\\Lambda}"); +defineMacro("\\varXi", "\\mathit{\\Xi}"); +defineMacro("\\varPi", "\\mathit{\\Pi}"); +defineMacro("\\varSigma", "\\mathit{\\Sigma}"); +defineMacro("\\varUpsilon", "\\mathit{\\Upsilon}"); +defineMacro("\\varPhi", "\\mathit{\\Phi}"); +defineMacro("\\varPsi", "\\mathit{\\Psi}"); +defineMacro("\\varOmega", "\\mathit{\\Omega}"); //\newcommand{\substack}[1]{\subarray{c}#1\endsubarray} + +defineMacro("\\substack", "\\begin{subarray}{c}#1\\end{subarray}"); // \renewcommand{\colon}{\nobreak\mskip2mu\mathpunct{}\nonscript +// \mkern-\thinmuskip{:}\mskip6muplus1mu\relax} + +defineMacro("\\colon", "\\nobreak\\mskip2mu\\mathpunct{}" + "\\mathchoice{\\mkern-3mu}{\\mkern-3mu}{}{}{:}\\mskip6mu"); // \newcommand{\boxed}[1]{\fbox{\m@th$\displaystyle#1$}} + +defineMacro("\\boxed", "\\fbox{$\\displaystyle{#1}$}"); // \def\iff{\DOTSB\;\Longleftrightarrow\;} +// \def\implies{\DOTSB\;\Longrightarrow\;} +// \def\impliedby{\DOTSB\;\Longleftarrow\;} + +defineMacro("\\iff", "\\DOTSB\\;\\Longleftrightarrow\\;"); +defineMacro("\\implies", "\\DOTSB\\;\\Longrightarrow\\;"); +defineMacro("\\impliedby", "\\DOTSB\\;\\Longleftarrow\\;"); // AMSMath's automatic \dots, based on \mdots@@ macro. + +var dotsByToken = { + ',': '\\dotsc', + '\\not': '\\dotsb', + // \keybin@ checks for the following: + '+': '\\dotsb', + '=': '\\dotsb', + '<': '\\dotsb', + '>': '\\dotsb', + '-': '\\dotsb', + '*': '\\dotsb', + ':': '\\dotsb', + // Symbols whose definition starts with \DOTSB: + '\\DOTSB': '\\dotsb', + '\\coprod': '\\dotsb', + '\\bigvee': '\\dotsb', + '\\bigwedge': '\\dotsb', + '\\biguplus': '\\dotsb', + '\\bigcap': '\\dotsb', + '\\bigcup': '\\dotsb', + '\\prod': '\\dotsb', + '\\sum': '\\dotsb', + '\\bigotimes': '\\dotsb', + '\\bigoplus': '\\dotsb', + '\\bigodot': '\\dotsb', + '\\bigsqcup': '\\dotsb', + '\\And': '\\dotsb', + '\\longrightarrow': '\\dotsb', + '\\Longrightarrow': '\\dotsb', + '\\longleftarrow': '\\dotsb', + '\\Longleftarrow': '\\dotsb', + '\\longleftrightarrow': '\\dotsb', + '\\Longleftrightarrow': '\\dotsb', + '\\mapsto': '\\dotsb', + '\\longmapsto': '\\dotsb', + '\\hookrightarrow': '\\dotsb', + '\\doteq': '\\dotsb', + // Symbols whose definition starts with \mathbin: + '\\mathbin': '\\dotsb', + // Symbols whose definition starts with \mathrel: + '\\mathrel': '\\dotsb', + '\\relbar': '\\dotsb', + '\\Relbar': '\\dotsb', + '\\xrightarrow': '\\dotsb', + '\\xleftarrow': '\\dotsb', + // Symbols whose definition starts with \DOTSI: + '\\DOTSI': '\\dotsi', + '\\int': '\\dotsi', + '\\oint': '\\dotsi', + '\\iint': '\\dotsi', + '\\iiint': '\\dotsi', + '\\iiiint': '\\dotsi', + '\\idotsint': '\\dotsi', + // Symbols whose definition starts with \DOTSX: + '\\DOTSX': '\\dotsx' +}; +defineMacro("\\dots", function (context) { + // TODO: If used in text mode, should expand to \textellipsis. + // However, in KaTeX, \textellipsis and \ldots behave the same + // (in text mode), and it's unlikely we'd see any of the math commands + // that affect the behavior of \dots when in text mode. So fine for now + // (until we support \ifmmode ... \else ... \fi). + var thedots = '\\dotso'; + var next = context.expandAfterFuture().text; + + if (next in dotsByToken) { + thedots = dotsByToken[next]; + } else if (next.substr(0, 4) === '\\not') { + thedots = '\\dotsb'; + } else if (next in src_symbols.math) { + if (utils.contains(['bin', 'rel'], src_symbols.math[next].group)) { + thedots = '\\dotsb'; + } + } + + return thedots; +}); +var spaceAfterDots = { + // \rightdelim@ checks for the following: + ')': true, + ']': true, + '\\rbrack': true, + '\\}': true, + '\\rbrace': true, + '\\rangle': true, + '\\rceil': true, + '\\rfloor': true, + '\\rgroup': true, + '\\rmoustache': true, + '\\right': true, + '\\bigr': true, + '\\biggr': true, + '\\Bigr': true, + '\\Biggr': true, + // \extra@ also tests for the following: + '$': true, + // \extrap@ checks for the following: + ';': true, + '.': true, + ',': true +}; +defineMacro("\\dotso", function (context) { + var next = context.future().text; + + if (next in spaceAfterDots) { + return "\\ldots\\,"; + } else { + return "\\ldots"; + } +}); +defineMacro("\\dotsc", function (context) { + var next = context.future().text; // \dotsc uses \extra@ but not \extrap@, instead specially checking for + // ';' and '.', but doesn't check for ','. + + if (next in spaceAfterDots && next !== ',') { + return "\\ldots\\,"; + } else { + return "\\ldots"; + } +}); +defineMacro("\\cdots", function (context) { + var next = context.future().text; + + if (next in spaceAfterDots) { + return "\\@cdots\\,"; + } else { + return "\\@cdots"; + } +}); +defineMacro("\\dotsb", "\\cdots"); +defineMacro("\\dotsm", "\\cdots"); +defineMacro("\\dotsi", "\\!\\cdots"); // amsmath doesn't actually define \dotsx, but \dots followed by a macro +// starting with \DOTSX implies \dotso, and then \extra@ detects this case +// and forces the added `\,`. + +defineMacro("\\dotsx", "\\ldots\\,"); // \let\DOTSI\relax +// \let\DOTSB\relax +// \let\DOTSX\relax + +defineMacro("\\DOTSI", "\\relax"); +defineMacro("\\DOTSB", "\\relax"); +defineMacro("\\DOTSX", "\\relax"); // Spacing, based on amsmath.sty's override of LaTeX defaults +// \DeclareRobustCommand{\tmspace}[3]{% +// \ifmmode\mskip#1#2\else\kern#1#3\fi\relax} + +defineMacro("\\tmspace", "\\TextOrMath{\\kern#1#3}{\\mskip#1#2}\\relax"); // \renewcommand{\,}{\tmspace+\thinmuskip{.1667em}} +// TODO: math mode should use \thinmuskip + +defineMacro("\\,", "\\tmspace+{3mu}{.1667em}"); // \let\thinspace\, + +defineMacro("\\thinspace", "\\,"); // \def\>{\mskip\medmuskip} +// \renewcommand{\:}{\tmspace+\medmuskip{.2222em}} +// TODO: \> and math mode of \: should use \medmuskip = 4mu plus 2mu minus 4mu + +defineMacro("\\>", "\\mskip{4mu}"); +defineMacro("\\:", "\\tmspace+{4mu}{.2222em}"); // \let\medspace\: + +defineMacro("\\medspace", "\\:"); // \renewcommand{\;}{\tmspace+\thickmuskip{.2777em}} +// TODO: math mode should use \thickmuskip = 5mu plus 5mu + +defineMacro("\\;", "\\tmspace+{5mu}{.2777em}"); // \let\thickspace\; + +defineMacro("\\thickspace", "\\;"); // \renewcommand{\!}{\tmspace-\thinmuskip{.1667em}} +// TODO: math mode should use \thinmuskip + +defineMacro("\\!", "\\tmspace-{3mu}{.1667em}"); // \let\negthinspace\! + +defineMacro("\\negthinspace", "\\!"); // \newcommand{\negmedspace}{\tmspace-\medmuskip{.2222em}} +// TODO: math mode should use \medmuskip + +defineMacro("\\negmedspace", "\\tmspace-{4mu}{.2222em}"); // \newcommand{\negthickspace}{\tmspace-\thickmuskip{.2777em}} +// TODO: math mode should use \thickmuskip + +defineMacro("\\negthickspace", "\\tmspace-{5mu}{.277em}"); // \def\enspace{\kern.5em } + +defineMacro("\\enspace", "\\kern.5em "); // \def\enskip{\hskip.5em\relax} + +defineMacro("\\enskip", "\\hskip.5em\\relax"); // \def\quad{\hskip1em\relax} + +defineMacro("\\quad", "\\hskip1em\\relax"); // \def\qquad{\hskip2em\relax} + +defineMacro("\\qquad", "\\hskip2em\\relax"); // \tag@in@display form of \tag + +defineMacro("\\tag", "\\@ifstar\\tag@literal\\tag@paren"); +defineMacro("\\tag@paren", "\\tag@literal{({#1})}"); +defineMacro("\\tag@literal", function (context) { + if (context.macros.get("\\df@tag")) { + throw new src_ParseError("Multiple \\tag"); + } + + return "\\gdef\\df@tag{\\text{#1}}"; +}); // \renewcommand{\bmod}{\nonscript\mskip-\medmuskip\mkern5mu\mathbin +// {\operator@font mod}\penalty900 +// \mkern5mu\nonscript\mskip-\medmuskip} +// \newcommand{\pod}[1]{\allowbreak +// \if@display\mkern18mu\else\mkern8mu\fi(#1)} +// \renewcommand{\pmod}[1]{\pod{{\operator@font mod}\mkern6mu#1}} +// \newcommand{\mod}[1]{\allowbreak\if@display\mkern18mu +// \else\mkern12mu\fi{\operator@font mod}\,\,#1} +// TODO: math mode should use \medmuskip = 4mu plus 2mu minus 4mu + +defineMacro("\\bmod", "\\mathchoice{\\mskip1mu}{\\mskip1mu}{\\mskip5mu}{\\mskip5mu}" + "\\mathbin{\\rm mod}" + "\\mathchoice{\\mskip1mu}{\\mskip1mu}{\\mskip5mu}{\\mskip5mu}"); +defineMacro("\\pod", "\\allowbreak" + "\\mathchoice{\\mkern18mu}{\\mkern8mu}{\\mkern8mu}{\\mkern8mu}(#1)"); +defineMacro("\\pmod", "\\pod{{\\rm mod}\\mkern6mu#1}"); +defineMacro("\\mod", "\\allowbreak" + "\\mathchoice{\\mkern18mu}{\\mkern12mu}{\\mkern12mu}{\\mkern12mu}" + "{\\rm mod}\\,\\,#1"); // \pmb -- A simulation of bold. +// The version in ambsy.sty works by typesetting three copies of the argument +// with small offsets. We use two copies. We omit the vertical offset because +// of rendering problems that makeVList encounters in Safari. + +defineMacro("\\pmb", "\\html@mathml{" + "\\@binrel{#1}{\\mathrlap{#1}\\kern0.5px#1}}" + "{\\mathbf{#1}}"); ////////////////////////////////////////////////////////////////////// +// LaTeX source2e +// \\ defaults to \newline, but changes to \cr within array environment + +defineMacro("\\\\", "\\newline"); // \def\TeX{T\kern-.1667em\lower.5ex\hbox{E}\kern-.125emX\@} +// TODO: Doesn't normally work in math mode because \@ fails. KaTeX doesn't +// support \@ yet, so that's omitted, and we add \text so that the result +// doesn't look funny in math mode. + +defineMacro("\\TeX", "\\textrm{\\html@mathml{" + "T\\kern-.1667em\\raisebox{-.5ex}{E}\\kern-.125emX" + "}{TeX}}"); // \DeclareRobustCommand{\LaTeX}{L\kern-.36em% +// {\sbox\z@ T% +// \vbox to\ht\z@{\hbox{\check@mathfonts +// \fontsize\sf@size\z@ +// \math@fontsfalse\selectfont +// A}% +// \vss}% +// }% +// \kern-.15em% +// \TeX} +// This code aligns the top of the A with the T (from the perspective of TeX's +// boxes, though visually the A appears to extend above slightly). +// We compute the corresponding \raisebox when A is rendered in \normalsize +// \scriptstyle, which has a scale factor of 0.7 (see Options.js). + +var latexRaiseA = fontMetricsData['Main-Regular']["T".charCodeAt(0)][1] - 0.7 * fontMetricsData['Main-Regular']["A".charCodeAt(0)][1] + "em"; +defineMacro("\\LaTeX", "\\textrm{\\html@mathml{" + ("L\\kern-.36em\\raisebox{" + latexRaiseA + "}{\\scriptstyle A}") + "\\kern-.15em\\TeX}{LaTeX}}"); // New KaTeX logo based on tweaking LaTeX logo + +defineMacro("\\KaTeX", "\\textrm{\\html@mathml{" + ("K\\kern-.17em\\raisebox{" + latexRaiseA + "}{\\scriptstyle A}") + "\\kern-.15em\\TeX}{KaTeX}}"); // \DeclareRobustCommand\hspace{\@ifstar\@hspacer\@hspace} +// \def\@hspace#1{\hskip #1\relax} +// \def\@hspacer#1{\vrule \@width\z@\nobreak +// \hskip #1\hskip \z@skip} + +defineMacro("\\hspace", "\\@ifstar\\@hspacer\\@hspace"); +defineMacro("\\@hspace", "\\hskip #1\\relax"); +defineMacro("\\@hspacer", "\\rule{0pt}{0pt}\\hskip #1\\relax"); ////////////////////////////////////////////////////////////////////// +// mathtools.sty +//\providecommand\ordinarycolon{:} + +defineMacro("\\ordinarycolon", ":"); //\def\vcentcolon{\mathrel{\mathop\ordinarycolon}} +//TODO(edemaine): Not yet centered. Fix via \raisebox or #726 + +defineMacro("\\vcentcolon", "\\mathrel{\\mathop\\ordinarycolon}"); // \providecommand*\dblcolon{\vcentcolon\mathrel{\mkern-.9mu}\vcentcolon} + +defineMacro("\\dblcolon", "\\html@mathml{" + "\\mathrel{\\vcentcolon\\mathrel{\\mkern-.9mu}\\vcentcolon}}" + "{\\mathop{\\char\"2237}}"); // \providecommand*\coloneqq{\vcentcolon\mathrel{\mkern-1.2mu}=} + +defineMacro("\\coloneqq", "\\html@mathml{" + "\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}=}}" + "{\\mathop{\\char\"2254}}"); // ≔ +// \providecommand*\Coloneqq{\dblcolon\mathrel{\mkern-1.2mu}=} + +defineMacro("\\Coloneqq", "\\html@mathml{" + "\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}=}}" + "{\\mathop{\\char\"2237\\char\"3d}}"); // \providecommand*\coloneq{\vcentcolon\mathrel{\mkern-1.2mu}\mathrel{-}} + +defineMacro("\\coloneq", "\\html@mathml{" + "\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}\\mathrel{-}}}" + "{\\mathop{\\char\"3a\\char\"2212}}"); // \providecommand*\Coloneq{\dblcolon\mathrel{\mkern-1.2mu}\mathrel{-}} + +defineMacro("\\Coloneq", "\\html@mathml{" + "\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}\\mathrel{-}}}" + "{\\mathop{\\char\"2237\\char\"2212}}"); // \providecommand*\eqqcolon{=\mathrel{\mkern-1.2mu}\vcentcolon} + +defineMacro("\\eqqcolon", "\\html@mathml{" + "\\mathrel{=\\mathrel{\\mkern-1.2mu}\\vcentcolon}}" + "{\\mathop{\\char\"2255}}"); // ≕ +// \providecommand*\Eqqcolon{=\mathrel{\mkern-1.2mu}\dblcolon} + +defineMacro("\\Eqqcolon", "\\html@mathml{" + "\\mathrel{=\\mathrel{\\mkern-1.2mu}\\dblcolon}}" + "{\\mathop{\\char\"3d\\char\"2237}}"); // \providecommand*\eqcolon{\mathrel{-}\mathrel{\mkern-1.2mu}\vcentcolon} + +defineMacro("\\eqcolon", "\\html@mathml{" + "\\mathrel{\\mathrel{-}\\mathrel{\\mkern-1.2mu}\\vcentcolon}}" + "{\\mathop{\\char\"2239}}"); // \providecommand*\Eqcolon{\mathrel{-}\mathrel{\mkern-1.2mu}\dblcolon} + +defineMacro("\\Eqcolon", "\\html@mathml{" + "\\mathrel{\\mathrel{-}\\mathrel{\\mkern-1.2mu}\\dblcolon}}" + "{\\mathop{\\char\"2212\\char\"2237}}"); // \providecommand*\colonapprox{\vcentcolon\mathrel{\mkern-1.2mu}\approx} + +defineMacro("\\colonapprox", "\\html@mathml{" + "\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}\\approx}}" + "{\\mathop{\\char\"3a\\char\"2248}}"); // \providecommand*\Colonapprox{\dblcolon\mathrel{\mkern-1.2mu}\approx} + +defineMacro("\\Colonapprox", "\\html@mathml{" + "\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}\\approx}}" + "{\\mathop{\\char\"2237\\char\"2248}}"); // \providecommand*\colonsim{\vcentcolon\mathrel{\mkern-1.2mu}\sim} + +defineMacro("\\colonsim", "\\html@mathml{" + "\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}\\sim}}" + "{\\mathop{\\char\"3a\\char\"223c}}"); // \providecommand*\Colonsim{\dblcolon\mathrel{\mkern-1.2mu}\sim} + +defineMacro("\\Colonsim", "\\html@mathml{" + "\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}\\sim}}" + "{\\mathop{\\char\"2237\\char\"223c}}"); // Some Unicode characters are implemented with macros to mathtools functions. + +defineMacro("\u2237", "\\dblcolon"); // :: + +defineMacro("\u2239", "\\eqcolon"); // -: + +defineMacro("\u2254", "\\coloneqq"); // := + +defineMacro("\u2255", "\\eqqcolon"); // =: + +defineMacro("\u2A74", "\\Coloneqq"); // ::= +////////////////////////////////////////////////////////////////////// +// colonequals.sty +// Alternate names for mathtools's macros: + +defineMacro("\\ratio", "\\vcentcolon"); +defineMacro("\\coloncolon", "\\dblcolon"); +defineMacro("\\colonequals", "\\coloneqq"); +defineMacro("\\coloncolonequals", "\\Coloneqq"); +defineMacro("\\equalscolon", "\\eqqcolon"); +defineMacro("\\equalscoloncolon", "\\Eqqcolon"); +defineMacro("\\colonminus", "\\coloneq"); +defineMacro("\\coloncolonminus", "\\Coloneq"); +defineMacro("\\minuscolon", "\\eqcolon"); +defineMacro("\\minuscoloncolon", "\\Eqcolon"); // \colonapprox name is same in mathtools and colonequals. + +defineMacro("\\coloncolonapprox", "\\Colonapprox"); // \colonsim name is same in mathtools and colonequals. + +defineMacro("\\coloncolonsim", "\\Colonsim"); // Additional macros, implemented by analogy with mathtools definitions: + +defineMacro("\\simcolon", "\\mathrel{\\sim\\mathrel{\\mkern-1.2mu}\\vcentcolon}"); +defineMacro("\\simcoloncolon", "\\mathrel{\\sim\\mathrel{\\mkern-1.2mu}\\dblcolon}"); +defineMacro("\\approxcolon", "\\mathrel{\\approx\\mathrel{\\mkern-1.2mu}\\vcentcolon}"); +defineMacro("\\approxcoloncolon", "\\mathrel{\\approx\\mathrel{\\mkern-1.2mu}\\dblcolon}"); // Present in newtxmath, pxfonts and txfonts + +defineMacro("\\notni", "\\html@mathml{\\not\\ni}{\\mathrel{\\char`\u220C}}"); +defineMacro("\\limsup", "\\DOTSB\\operatorname*{lim\\,sup}"); +defineMacro("\\liminf", "\\DOTSB\\operatorname*{lim\\,inf}"); ////////////////////////////////////////////////////////////////////// +// MathML alternates for KaTeX glyphs in the Unicode private area + +defineMacro("\\gvertneqq", "\\html@mathml{\\@gvertneqq}{\u2269}"); +defineMacro("\\lvertneqq", "\\html@mathml{\\@lvertneqq}{\u2268}"); +defineMacro("\\ngeqq", "\\html@mathml{\\@ngeqq}{\u2271}"); +defineMacro("\\ngeqslant", "\\html@mathml{\\@ngeqslant}{\u2271}"); +defineMacro("\\nleqq", "\\html@mathml{\\@nleqq}{\u2270}"); +defineMacro("\\nleqslant", "\\html@mathml{\\@nleqslant}{\u2270}"); +defineMacro("\\nshortmid", "\\html@mathml{\\@nshortmid}{∤}"); +defineMacro("\\nshortparallel", "\\html@mathml{\\@nshortparallel}{∦}"); +defineMacro("\\nsubseteqq", "\\html@mathml{\\@nsubseteqq}{\u2288}"); +defineMacro("\\nsupseteqq", "\\html@mathml{\\@nsupseteqq}{\u2289}"); +defineMacro("\\varsubsetneq", "\\html@mathml{\\@varsubsetneq}{⊊}"); +defineMacro("\\varsubsetneqq", "\\html@mathml{\\@varsubsetneqq}{⫋}"); +defineMacro("\\varsupsetneq", "\\html@mathml{\\@varsupsetneq}{⊋}"); +defineMacro("\\varsupsetneqq", "\\html@mathml{\\@varsupsetneqq}{⫌}"); ////////////////////////////////////////////////////////////////////// +// stmaryrd and semantic +// The stmaryrd and semantic packages render the next four items by calling a +// glyph. Those glyphs do not exist in the KaTeX fonts. Hence the macros. + +defineMacro("\\llbracket", "\\html@mathml{" + "\\mathopen{[\\mkern-3.2mu[}}" + "{\\mathopen{\\char`\u27E6}}"); +defineMacro("\\rrbracket", "\\html@mathml{" + "\\mathclose{]\\mkern-3.2mu]}}" + "{\\mathclose{\\char`\u27E7}}"); +defineMacro("\u27E6", "\\llbracket"); // blackboard bold [ + +defineMacro("\u27E7", "\\rrbracket"); // blackboard bold ] + +defineMacro("\\lBrace", "\\html@mathml{" + "\\mathopen{\\{\\mkern-3.2mu[}}" + "{\\mathopen{\\char`\u2983}}"); +defineMacro("\\rBrace", "\\html@mathml{" + "\\mathclose{]\\mkern-3.2mu\\}}}" + "{\\mathclose{\\char`\u2984}}"); +defineMacro("\u2983", "\\lBrace"); // blackboard bold { + +defineMacro("\u2984", "\\rBrace"); // blackboard bold } +// TODO: Create variable sized versions of the last two items. I believe that +// will require new font glyphs. +////////////////////////////////////////////////////////////////////// +// texvc.sty +// The texvc package contains macros available in mediawiki pages. +// We omit the functions deprecated at +// https://en.wikipedia.org/wiki/Help:Displaying_a_formula#Deprecated_syntax +// We also omit texvc's \O, which conflicts with \text{\O} + +defineMacro("\\darr", "\\downarrow"); +defineMacro("\\dArr", "\\Downarrow"); +defineMacro("\\Darr", "\\Downarrow"); +defineMacro("\\lang", "\\langle"); +defineMacro("\\rang", "\\rangle"); +defineMacro("\\uarr", "\\uparrow"); +defineMacro("\\uArr", "\\Uparrow"); +defineMacro("\\Uarr", "\\Uparrow"); +defineMacro("\\N", "\\mathbb{N}"); +defineMacro("\\R", "\\mathbb{R}"); +defineMacro("\\Z", "\\mathbb{Z}"); +defineMacro("\\alef", "\\aleph"); +defineMacro("\\alefsym", "\\aleph"); +defineMacro("\\Alpha", "\\mathrm{A}"); +defineMacro("\\Beta", "\\mathrm{B}"); +defineMacro("\\bull", "\\bullet"); +defineMacro("\\Chi", "\\mathrm{X}"); +defineMacro("\\clubs", "\\clubsuit"); +defineMacro("\\cnums", "\\mathbb{C}"); +defineMacro("\\Complex", "\\mathbb{C}"); +defineMacro("\\Dagger", "\\ddagger"); +defineMacro("\\diamonds", "\\diamondsuit"); +defineMacro("\\empty", "\\emptyset"); +defineMacro("\\Epsilon", "\\mathrm{E}"); +defineMacro("\\Eta", "\\mathrm{H}"); +defineMacro("\\exist", "\\exists"); +defineMacro("\\harr", "\\leftrightarrow"); +defineMacro("\\hArr", "\\Leftrightarrow"); +defineMacro("\\Harr", "\\Leftrightarrow"); +defineMacro("\\hearts", "\\heartsuit"); +defineMacro("\\image", "\\Im"); +defineMacro("\\infin", "\\infty"); +defineMacro("\\Iota", "\\mathrm{I}"); +defineMacro("\\isin", "\\in"); +defineMacro("\\Kappa", "\\mathrm{K}"); +defineMacro("\\larr", "\\leftarrow"); +defineMacro("\\lArr", "\\Leftarrow"); +defineMacro("\\Larr", "\\Leftarrow"); +defineMacro("\\lrarr", "\\leftrightarrow"); +defineMacro("\\lrArr", "\\Leftrightarrow"); +defineMacro("\\Lrarr", "\\Leftrightarrow"); +defineMacro("\\Mu", "\\mathrm{M}"); +defineMacro("\\natnums", "\\mathbb{N}"); +defineMacro("\\Nu", "\\mathrm{N}"); +defineMacro("\\Omicron", "\\mathrm{O}"); +defineMacro("\\plusmn", "\\pm"); +defineMacro("\\rarr", "\\rightarrow"); +defineMacro("\\rArr", "\\Rightarrow"); +defineMacro("\\Rarr", "\\Rightarrow"); +defineMacro("\\real", "\\Re"); +defineMacro("\\reals", "\\mathbb{R}"); +defineMacro("\\Reals", "\\mathbb{R}"); +defineMacro("\\Rho", "\\mathrm{P}"); +defineMacro("\\sdot", "\\cdot"); +defineMacro("\\sect", "\\S"); +defineMacro("\\spades", "\\spadesuit"); +defineMacro("\\sub", "\\subset"); +defineMacro("\\sube", "\\subseteq"); +defineMacro("\\supe", "\\supseteq"); +defineMacro("\\Tau", "\\mathrm{T}"); +defineMacro("\\thetasym", "\\vartheta"); // TODO: defineMacro("\\varcoppa", "\\\mbox{\\coppa}"); + +defineMacro("\\weierp", "\\wp"); +defineMacro("\\Zeta", "\\mathrm{Z}"); ////////////////////////////////////////////////////////////////////// +// statmath.sty +// https://ctan.math.illinois.edu/macros/latex/contrib/statmath/statmath.pdf + +defineMacro("\\argmin", "\\DOTSB\\operatorname*{arg\\,min}"); +defineMacro("\\argmax", "\\DOTSB\\operatorname*{arg\\,max}"); +defineMacro("\\plim", "\\DOTSB\\mathop{\\operatorname{plim}}\\limits"); // Custom Khan Academy colors, should be moved to an optional package + +defineMacro("\\blue", "\\textcolor{##6495ed}{#1}"); +defineMacro("\\orange", "\\textcolor{##ffa500}{#1}"); +defineMacro("\\pink", "\\textcolor{##ff00af}{#1}"); +defineMacro("\\red", "\\textcolor{##df0030}{#1}"); +defineMacro("\\green", "\\textcolor{##28ae7b}{#1}"); +defineMacro("\\gray", "\\textcolor{gray}{#1}"); +defineMacro("\\purple", "\\textcolor{##9d38bd}{#1}"); +defineMacro("\\blueA", "\\textcolor{##ccfaff}{#1}"); +defineMacro("\\blueB", "\\textcolor{##80f6ff}{#1}"); +defineMacro("\\blueC", "\\textcolor{##63d9ea}{#1}"); +defineMacro("\\blueD", "\\textcolor{##11accd}{#1}"); +defineMacro("\\blueE", "\\textcolor{##0c7f99}{#1}"); +defineMacro("\\tealA", "\\textcolor{##94fff5}{#1}"); +defineMacro("\\tealB", "\\textcolor{##26edd5}{#1}"); +defineMacro("\\tealC", "\\textcolor{##01d1c1}{#1}"); +defineMacro("\\tealD", "\\textcolor{##01a995}{#1}"); +defineMacro("\\tealE", "\\textcolor{##208170}{#1}"); +defineMacro("\\greenA", "\\textcolor{##b6ffb0}{#1}"); +defineMacro("\\greenB", "\\textcolor{##8af281}{#1}"); +defineMacro("\\greenC", "\\textcolor{##74cf70}{#1}"); +defineMacro("\\greenD", "\\textcolor{##1fab54}{#1}"); +defineMacro("\\greenE", "\\textcolor{##0d923f}{#1}"); +defineMacro("\\goldA", "\\textcolor{##ffd0a9}{#1}"); +defineMacro("\\goldB", "\\textcolor{##ffbb71}{#1}"); +defineMacro("\\goldC", "\\textcolor{##ff9c39}{#1}"); +defineMacro("\\goldD", "\\textcolor{##e07d10}{#1}"); +defineMacro("\\goldE", "\\textcolor{##a75a05}{#1}"); +defineMacro("\\redA", "\\textcolor{##fca9a9}{#1}"); +defineMacro("\\redB", "\\textcolor{##ff8482}{#1}"); +defineMacro("\\redC", "\\textcolor{##f9685d}{#1}"); +defineMacro("\\redD", "\\textcolor{##e84d39}{#1}"); +defineMacro("\\redE", "\\textcolor{##bc2612}{#1}"); +defineMacro("\\maroonA", "\\textcolor{##ffbde0}{#1}"); +defineMacro("\\maroonB", "\\textcolor{##ff92c6}{#1}"); +defineMacro("\\maroonC", "\\textcolor{##ed5fa6}{#1}"); +defineMacro("\\maroonD", "\\textcolor{##ca337c}{#1}"); +defineMacro("\\maroonE", "\\textcolor{##9e034e}{#1}"); +defineMacro("\\purpleA", "\\textcolor{##ddd7ff}{#1}"); +defineMacro("\\purpleB", "\\textcolor{##c6b9fc}{#1}"); +defineMacro("\\purpleC", "\\textcolor{##aa87ff}{#1}"); +defineMacro("\\purpleD", "\\textcolor{##7854ab}{#1}"); +defineMacro("\\purpleE", "\\textcolor{##543b78}{#1}"); +defineMacro("\\mintA", "\\textcolor{##f5f9e8}{#1}"); +defineMacro("\\mintB", "\\textcolor{##edf2df}{#1}"); +defineMacro("\\mintC", "\\textcolor{##e0e5cc}{#1}"); +defineMacro("\\grayA", "\\textcolor{##f6f7f7}{#1}"); +defineMacro("\\grayB", "\\textcolor{##f0f1f2}{#1}"); +defineMacro("\\grayC", "\\textcolor{##e3e5e6}{#1}"); +defineMacro("\\grayD", "\\textcolor{##d6d8da}{#1}"); +defineMacro("\\grayE", "\\textcolor{##babec2}{#1}"); +defineMacro("\\grayF", "\\textcolor{##888d93}{#1}"); +defineMacro("\\grayG", "\\textcolor{##626569}{#1}"); +defineMacro("\\grayH", "\\textcolor{##3b3e40}{#1}"); +defineMacro("\\grayI", "\\textcolor{##21242c}{#1}"); +defineMacro("\\kaBlue", "\\textcolor{##314453}{#1}"); +defineMacro("\\kaGreen", "\\textcolor{##71B307}{#1}"); +// CONCATENATED MODULE: ./src/MacroExpander.js +/** + * This file contains the “gullet” where macros are expanded + * until only non-macro tokens remain. + */ + + + + + + + +// List of commands that act like macros but aren't defined as a macro, +// function, or symbol. Used in `isDefined`. +var implicitCommands = { + "\\relax": true, + // MacroExpander.js + "^": true, + // Parser.js + "_": true, + // Parser.js + "\\limits": true, + // Parser.js + "\\nolimits": true // Parser.js + +}; + +var MacroExpander_MacroExpander = +/*#__PURE__*/ +function () { + function MacroExpander(input, settings, mode) { + this.settings = void 0; + this.expansionCount = void 0; + this.lexer = void 0; + this.macros = void 0; + this.stack = void 0; + this.mode = void 0; + this.settings = settings; + this.expansionCount = 0; + this.feed(input); // Make new global namespace + + this.macros = new Namespace_Namespace(macros, settings.macros); + this.mode = mode; + this.stack = []; // contains tokens in REVERSE order + } + /** + * Feed a new input string to the same MacroExpander + * (with existing macros etc.). + */ + + + var _proto = MacroExpander.prototype; + + _proto.feed = function feed(input) { + this.lexer = new Lexer_Lexer(input, this.settings); + } + /** + * Switches between "text" and "math" modes. + */ + ; + + _proto.switchMode = function switchMode(newMode) { + this.mode = newMode; + } + /** + * Start a new group nesting within all namespaces. + */ + ; + + _proto.beginGroup = function beginGroup() { + this.macros.beginGroup(); + } + /** + * End current group nesting within all namespaces. + */ + ; + + _proto.endGroup = function endGroup() { + this.macros.endGroup(); + } + /** + * Returns the topmost token on the stack, without expanding it. + * Similar in behavior to TeX's `\futurelet`. + */ + ; + + _proto.future = function future() { + if (this.stack.length === 0) { + this.pushToken(this.lexer.lex()); + } + + return this.stack[this.stack.length - 1]; + } + /** + * Remove and return the next unexpanded token. + */ + ; + + _proto.popToken = function popToken() { + this.future(); // ensure non-empty stack + + return this.stack.pop(); + } + /** + * Add a given token to the token stack. In particular, this get be used + * to put back a token returned from one of the other methods. + */ + ; + + _proto.pushToken = function pushToken(token) { + this.stack.push(token); + } + /** + * Append an array of tokens to the token stack. + */ + ; + + _proto.pushTokens = function pushTokens(tokens) { + var _this$stack; + + (_this$stack = this.stack).push.apply(_this$stack, tokens); + } + /** + * Consume all following space tokens, without expansion. + */ + ; + + _proto.consumeSpaces = function consumeSpaces() { + for (;;) { + var token = this.future(); + + if (token.text === " ") { + this.stack.pop(); + } else { + break; + } + } + } + /** + * Consume the specified number of arguments from the token stream, + * and return the resulting array of arguments. + */ + ; + + _proto.consumeArgs = function consumeArgs(numArgs) { + var args = []; // obtain arguments, either single token or balanced {…} group + + for (var i = 0; i < numArgs; ++i) { + this.consumeSpaces(); // ignore spaces before each argument + + var startOfArg = this.popToken(); + + if (startOfArg.text === "{") { + var arg = []; + var depth = 1; + + while (depth !== 0) { + var tok = this.popToken(); + arg.push(tok); + + if (tok.text === "{") { + ++depth; + } else if (tok.text === "}") { + --depth; + } else if (tok.text === "EOF") { + throw new src_ParseError("End of input in macro argument", startOfArg); + } + } + + arg.pop(); // remove last } + + arg.reverse(); // like above, to fit in with stack order + + args[i] = arg; + } else if (startOfArg.text === "EOF") { + throw new src_ParseError("End of input expecting macro argument"); + } else { + args[i] = [startOfArg]; + } + } + + return args; + } + /** + * Expand the next token only once if possible. + * + * If the token is expanded, the resulting tokens will be pushed onto + * the stack in reverse order and will be returned as an array, + * also in reverse order. + * + * If not, the next token will be returned without removing it + * from the stack. This case can be detected by a `Token` return value + * instead of an `Array` return value. + * + * In either case, the next token will be on the top of the stack, + * or the stack will be empty. + * + * Used to implement `expandAfterFuture` and `expandNextToken`. + * + * At the moment, macro expansion doesn't handle delimited macros, + * i.e. things like those defined by \def\foo#1\end{…}. + * See the TeX book page 202ff. for details on how those should behave. + */ + ; + + _proto.expandOnce = function expandOnce() { + var topToken = this.popToken(); + var name = topToken.text; + + var expansion = this._getExpansion(name); + + if (expansion == null) { + // mainly checking for undefined here + // Fully expanded + this.pushToken(topToken); + return topToken; + } + + this.expansionCount++; + + if (this.expansionCount > this.settings.maxExpand) { + throw new src_ParseError("Too many expansions: infinite loop or " + "need to increase maxExpand setting"); + } + + var tokens = expansion.tokens; + + if (expansion.numArgs) { + var args = this.consumeArgs(expansion.numArgs); // paste arguments in place of the placeholders + + tokens = tokens.slice(); // make a shallow copy + + for (var i = tokens.length - 1; i >= 0; --i) { + var tok = tokens[i]; + + if (tok.text === "#") { + if (i === 0) { + throw new src_ParseError("Incomplete placeholder at end of macro body", tok); + } + + tok = tokens[--i]; // next token on stack + + if (tok.text === "#") { + // ## → # + tokens.splice(i + 1, 1); // drop first # + } else if (/^[1-9]$/.test(tok.text)) { + var _tokens; + + // replace the placeholder with the indicated argument + (_tokens = tokens).splice.apply(_tokens, [i, 2].concat(args[+tok.text - 1])); + } else { + throw new src_ParseError("Not a valid argument number", tok); + } + } + } + } // Concatenate expansion onto top of stack. + + + this.pushTokens(tokens); + return tokens; + } + /** + * Expand the next token only once (if possible), and return the resulting + * top token on the stack (without removing anything from the stack). + * Similar in behavior to TeX's `\expandafter\futurelet`. + * Equivalent to expandOnce() followed by future(). + */ + ; + + _proto.expandAfterFuture = function expandAfterFuture() { + this.expandOnce(); + return this.future(); + } + /** + * Recursively expand first token, then return first non-expandable token. + */ + ; + + _proto.expandNextToken = function expandNextToken() { + for (;;) { + var expanded = this.expandOnce(); // expandOnce returns Token if and only if it's fully expanded. + + if (expanded instanceof Token_Token) { + // \relax stops the expansion, but shouldn't get returned (a + // null return value couldn't get implemented as a function). + if (expanded.text === "\\relax") { + this.stack.pop(); + } else { + return this.stack.pop(); // === expanded + } + } + } // Flow unable to figure out that this pathway is impossible. + // https://github.com/facebook/flow/issues/4808 + + + throw new Error(); // eslint-disable-line no-unreachable + } + /** + * Fully expand the given macro name and return the resulting list of + * tokens, or return `undefined` if no such macro is defined. + */ + ; + + _proto.expandMacro = function expandMacro(name) { + if (!this.macros.get(name)) { + return undefined; + } + + var output = []; + var oldStackLength = this.stack.length; + this.pushToken(new Token_Token(name)); + + while (this.stack.length > oldStackLength) { + var expanded = this.expandOnce(); // expandOnce returns Token if and only if it's fully expanded. + + if (expanded instanceof Token_Token) { + output.push(this.stack.pop()); + } + } + + return output; + } + /** + * Fully expand the given macro name and return the result as a string, + * or return `undefined` if no such macro is defined. + */ + ; + + _proto.expandMacroAsText = function expandMacroAsText(name) { + var tokens = this.expandMacro(name); + + if (tokens) { + return tokens.map(function (token) { + return token.text; + }).join(""); + } else { + return tokens; + } + } + /** + * Returns the expanded macro as a reversed array of tokens and a macro + * argument count. Or returns `null` if no such macro. + */ + ; + + _proto._getExpansion = function _getExpansion(name) { + var definition = this.macros.get(name); + + if (definition == null) { + // mainly checking for undefined here + return definition; + } + + var expansion = typeof definition === "function" ? definition(this) : definition; + + if (typeof expansion === "string") { + var numArgs = 0; + + if (expansion.indexOf("#") !== -1) { + var stripped = expansion.replace(/##/g, ""); + + while (stripped.indexOf("#" + (numArgs + 1)) !== -1) { + ++numArgs; + } + } + + var bodyLexer = new Lexer_Lexer(expansion, this.settings); + var tokens = []; + var tok = bodyLexer.lex(); + + while (tok.text !== "EOF") { + tokens.push(tok); + tok = bodyLexer.lex(); + } + + tokens.reverse(); // to fit in with stack using push and pop + + var expanded = { + tokens: tokens, + numArgs: numArgs + }; + return expanded; + } + + return expansion; + } + /** + * Determine whether a command is currently "defined" (has some + * functionality), meaning that it's a macro (in the current group), + * a function, a symbol, or one of the special commands listed in + * `implicitCommands`. + */ + ; + + _proto.isDefined = function isDefined(name) { + return this.macros.has(name) || src_functions.hasOwnProperty(name) || src_symbols.math.hasOwnProperty(name) || src_symbols.text.hasOwnProperty(name) || implicitCommands.hasOwnProperty(name); + }; + + return MacroExpander; +}(); + + +// CONCATENATED MODULE: ./src/unicodeAccents.js +// Mapping of Unicode accent characters to their LaTeX equivalent in text and +// math mode (when they exist). +/* harmony default export */ var unicodeAccents = ({ + "\u0301": { + text: "\\'", + math: '\\acute' + }, + "\u0300": { + text: '\\`', + math: '\\grave' + }, + "\u0308": { + text: '\\"', + math: '\\ddot' + }, + "\u0303": { + text: '\\~', + math: '\\tilde' + }, + "\u0304": { + text: '\\=', + math: '\\bar' + }, + "\u0306": { + text: "\\u", + math: '\\breve' + }, + "\u030C": { + text: '\\v', + math: '\\check' + }, + "\u0302": { + text: '\\^', + math: '\\hat' + }, + "\u0307": { + text: '\\.', + math: '\\dot' + }, + "\u030A": { + text: '\\r', + math: '\\mathring' + }, + "\u030B": { + text: '\\H' + } +}); +// CONCATENATED MODULE: ./src/unicodeSymbols.js +// This file is GENERATED by unicodeMake.js. DO NOT MODIFY. +/* harmony default export */ var unicodeSymbols = ({ + "\xE1": "a\u0301", + // á = \'{a} + "\xE0": "a\u0300", + // à = \`{a} + "\xE4": "a\u0308", + // ä = \"{a} + "\u01DF": "a\u0308\u0304", + // ǟ = \"\={a} + "\xE3": "a\u0303", + // ã = \~{a} + "\u0101": "a\u0304", + // ā = \={a} + "\u0103": "a\u0306", + // ă = \u{a} + "\u1EAF": "a\u0306\u0301", + // ắ = \u\'{a} + "\u1EB1": "a\u0306\u0300", + // ằ = \u\`{a} + "\u1EB5": "a\u0306\u0303", + // ẵ = \u\~{a} + "\u01CE": "a\u030C", + // ǎ = \v{a} + "\xE2": "a\u0302", + // â = \^{a} + "\u1EA5": "a\u0302\u0301", + // ấ = \^\'{a} + "\u1EA7": "a\u0302\u0300", + // ầ = \^\`{a} + "\u1EAB": "a\u0302\u0303", + // ẫ = \^\~{a} + "\u0227": "a\u0307", + // ȧ = \.{a} + "\u01E1": "a\u0307\u0304", + // ǡ = \.\={a} + "\xE5": "a\u030A", + // å = \r{a} + "\u01FB": "a\u030A\u0301", + // ǻ = \r\'{a} + "\u1E03": "b\u0307", + // ḃ = \.{b} + "\u0107": "c\u0301", + // ć = \'{c} + "\u010D": "c\u030C", + // č = \v{c} + "\u0109": "c\u0302", + // ĉ = \^{c} + "\u010B": "c\u0307", + // ċ = \.{c} + "\u010F": "d\u030C", + // ď = \v{d} + "\u1E0B": "d\u0307", + // ḋ = \.{d} + "\xE9": "e\u0301", + // é = \'{e} + "\xE8": "e\u0300", + // è = \`{e} + "\xEB": "e\u0308", + // ë = \"{e} + "\u1EBD": "e\u0303", + // ẽ = \~{e} + "\u0113": "e\u0304", + // ē = \={e} + "\u1E17": "e\u0304\u0301", + // ḗ = \=\'{e} + "\u1E15": "e\u0304\u0300", + // ḕ = \=\`{e} + "\u0115": "e\u0306", + // ĕ = \u{e} + "\u011B": "e\u030C", + // ě = \v{e} + "\xEA": "e\u0302", + // ê = \^{e} + "\u1EBF": "e\u0302\u0301", + // ế = \^\'{e} + "\u1EC1": "e\u0302\u0300", + // ề = \^\`{e} + "\u1EC5": "e\u0302\u0303", + // ễ = \^\~{e} + "\u0117": "e\u0307", + // ė = \.{e} + "\u1E1F": "f\u0307", + // ḟ = \.{f} + "\u01F5": "g\u0301", + // ǵ = \'{g} + "\u1E21": "g\u0304", + // ḡ = \={g} + "\u011F": "g\u0306", + // ğ = \u{g} + "\u01E7": "g\u030C", + // ǧ = \v{g} + "\u011D": "g\u0302", + // ĝ = \^{g} + "\u0121": "g\u0307", + // ġ = \.{g} + "\u1E27": "h\u0308", + // ḧ = \"{h} + "\u021F": "h\u030C", + // ȟ = \v{h} + "\u0125": "h\u0302", + // ĥ = \^{h} + "\u1E23": "h\u0307", + // ḣ = \.{h} + "\xED": "i\u0301", + // í = \'{i} + "\xEC": "i\u0300", + // ì = \`{i} + "\xEF": "i\u0308", + // ï = \"{i} + "\u1E2F": "i\u0308\u0301", + // ḯ = \"\'{i} + "\u0129": "i\u0303", + // ĩ = \~{i} + "\u012B": "i\u0304", + // ī = \={i} + "\u012D": "i\u0306", + // ĭ = \u{i} + "\u01D0": "i\u030C", + // ǐ = \v{i} + "\xEE": "i\u0302", + // î = \^{i} + "\u01F0": "j\u030C", + // ǰ = \v{j} + "\u0135": "j\u0302", + // ĵ = \^{j} + "\u1E31": "k\u0301", + // ḱ = \'{k} + "\u01E9": "k\u030C", + // ǩ = \v{k} + "\u013A": "l\u0301", + // ĺ = \'{l} + "\u013E": "l\u030C", + // ľ = \v{l} + "\u1E3F": "m\u0301", + // ḿ = \'{m} + "\u1E41": "m\u0307", + // ṁ = \.{m} + "\u0144": "n\u0301", + // ń = \'{n} + "\u01F9": "n\u0300", + // ǹ = \`{n} + "\xF1": "n\u0303", + // ñ = \~{n} + "\u0148": "n\u030C", + // ň = \v{n} + "\u1E45": "n\u0307", + // ṅ = \.{n} + "\xF3": "o\u0301", + // ó = \'{o} + "\xF2": "o\u0300", + // ò = \`{o} + "\xF6": "o\u0308", + // ö = \"{o} + "\u022B": "o\u0308\u0304", + // ȫ = \"\={o} + "\xF5": "o\u0303", + // õ = \~{o} + "\u1E4D": "o\u0303\u0301", + // ṍ = \~\'{o} + "\u1E4F": "o\u0303\u0308", + // ṏ = \~\"{o} + "\u022D": "o\u0303\u0304", + // ȭ = \~\={o} + "\u014D": "o\u0304", + // ō = \={o} + "\u1E53": "o\u0304\u0301", + // ṓ = \=\'{o} + "\u1E51": "o\u0304\u0300", + // ṑ = \=\`{o} + "\u014F": "o\u0306", + // ŏ = \u{o} + "\u01D2": "o\u030C", + // ǒ = \v{o} + "\xF4": "o\u0302", + // ô = \^{o} + "\u1ED1": "o\u0302\u0301", + // ố = \^\'{o} + "\u1ED3": "o\u0302\u0300", + // ồ = \^\`{o} + "\u1ED7": "o\u0302\u0303", + // ỗ = \^\~{o} + "\u022F": "o\u0307", + // ȯ = \.{o} + "\u0231": "o\u0307\u0304", + // ȱ = \.\={o} + "\u0151": "o\u030B", + // ő = \H{o} + "\u1E55": "p\u0301", + // ṕ = \'{p} + "\u1E57": "p\u0307", + // ṗ = \.{p} + "\u0155": "r\u0301", + // ŕ = \'{r} + "\u0159": "r\u030C", + // ř = \v{r} + "\u1E59": "r\u0307", + // ṙ = \.{r} + "\u015B": "s\u0301", + // ś = \'{s} + "\u1E65": "s\u0301\u0307", + // ṥ = \'\.{s} + "\u0161": "s\u030C", + // š = \v{s} + "\u1E67": "s\u030C\u0307", + // ṧ = \v\.{s} + "\u015D": "s\u0302", + // ŝ = \^{s} + "\u1E61": "s\u0307", + // ṡ = \.{s} + "\u1E97": "t\u0308", + // ẗ = \"{t} + "\u0165": "t\u030C", + // ť = \v{t} + "\u1E6B": "t\u0307", + // ṫ = \.{t} + "\xFA": "u\u0301", + // ú = \'{u} + "\xF9": "u\u0300", + // ù = \`{u} + "\xFC": "u\u0308", + // ü = \"{u} + "\u01D8": "u\u0308\u0301", + // ǘ = \"\'{u} + "\u01DC": "u\u0308\u0300", + // ǜ = \"\`{u} + "\u01D6": "u\u0308\u0304", + // ǖ = \"\={u} + "\u01DA": "u\u0308\u030C", + // ǚ = \"\v{u} + "\u0169": "u\u0303", + // ũ = \~{u} + "\u1E79": "u\u0303\u0301", + // ṹ = \~\'{u} + "\u016B": "u\u0304", + // ū = \={u} + "\u1E7B": "u\u0304\u0308", + // ṻ = \=\"{u} + "\u016D": "u\u0306", + // ŭ = \u{u} + "\u01D4": "u\u030C", + // ǔ = \v{u} + "\xFB": "u\u0302", + // û = \^{u} + "\u016F": "u\u030A", + // ů = \r{u} + "\u0171": "u\u030B", + // ű = \H{u} + "\u1E7D": "v\u0303", + // ṽ = \~{v} + "\u1E83": "w\u0301", + // ẃ = \'{w} + "\u1E81": "w\u0300", + // ẁ = \`{w} + "\u1E85": "w\u0308", + // ẅ = \"{w} + "\u0175": "w\u0302", + // ŵ = \^{w} + "\u1E87": "w\u0307", + // ẇ = \.{w} + "\u1E98": "w\u030A", + // ẘ = \r{w} + "\u1E8D": "x\u0308", + // ẍ = \"{x} + "\u1E8B": "x\u0307", + // ẋ = \.{x} + "\xFD": "y\u0301", + // ý = \'{y} + "\u1EF3": "y\u0300", + // ỳ = \`{y} + "\xFF": "y\u0308", + // ÿ = \"{y} + "\u1EF9": "y\u0303", + // ỹ = \~{y} + "\u0233": "y\u0304", + // ȳ = \={y} + "\u0177": "y\u0302", + // ŷ = \^{y} + "\u1E8F": "y\u0307", + // ẏ = \.{y} + "\u1E99": "y\u030A", + // ẙ = \r{y} + "\u017A": "z\u0301", + // ź = \'{z} + "\u017E": "z\u030C", + // ž = \v{z} + "\u1E91": "z\u0302", + // ẑ = \^{z} + "\u017C": "z\u0307", + // ż = \.{z} + "\xC1": "A\u0301", + // Á = \'{A} + "\xC0": "A\u0300", + // À = \`{A} + "\xC4": "A\u0308", + // Ä = \"{A} + "\u01DE": "A\u0308\u0304", + // Ǟ = \"\={A} + "\xC3": "A\u0303", + // Ã = \~{A} + "\u0100": "A\u0304", + // Ā = \={A} + "\u0102": "A\u0306", + // Ă = \u{A} + "\u1EAE": "A\u0306\u0301", + // Ắ = \u\'{A} + "\u1EB0": "A\u0306\u0300", + // Ằ = \u\`{A} + "\u1EB4": "A\u0306\u0303", + // Ẵ = \u\~{A} + "\u01CD": "A\u030C", + // Ǎ = \v{A} + "\xC2": "A\u0302", + // Â = \^{A} + "\u1EA4": "A\u0302\u0301", + // Ấ = \^\'{A} + "\u1EA6": "A\u0302\u0300", + // Ầ = \^\`{A} + "\u1EAA": "A\u0302\u0303", + // Ẫ = \^\~{A} + "\u0226": "A\u0307", + // Ȧ = \.{A} + "\u01E0": "A\u0307\u0304", + // Ǡ = \.\={A} + "\xC5": "A\u030A", + // Å = \r{A} + "\u01FA": "A\u030A\u0301", + // Ǻ = \r\'{A} + "\u1E02": "B\u0307", + // Ḃ = \.{B} + "\u0106": "C\u0301", + // Ć = \'{C} + "\u010C": "C\u030C", + // Č = \v{C} + "\u0108": "C\u0302", + // Ĉ = \^{C} + "\u010A": "C\u0307", + // Ċ = \.{C} + "\u010E": "D\u030C", + // Ď = \v{D} + "\u1E0A": "D\u0307", + // Ḋ = \.{D} + "\xC9": "E\u0301", + // É = \'{E} + "\xC8": "E\u0300", + // È = \`{E} + "\xCB": "E\u0308", + // Ë = \"{E} + "\u1EBC": "E\u0303", + // Ẽ = \~{E} + "\u0112": "E\u0304", + // Ē = \={E} + "\u1E16": "E\u0304\u0301", + // Ḗ = \=\'{E} + "\u1E14": "E\u0304\u0300", + // Ḕ = \=\`{E} + "\u0114": "E\u0306", + // Ĕ = \u{E} + "\u011A": "E\u030C", + // Ě = \v{E} + "\xCA": "E\u0302", + // Ê = \^{E} + "\u1EBE": "E\u0302\u0301", + // Ế = \^\'{E} + "\u1EC0": "E\u0302\u0300", + // Ề = \^\`{E} + "\u1EC4": "E\u0302\u0303", + // Ễ = \^\~{E} + "\u0116": "E\u0307", + // Ė = \.{E} + "\u1E1E": "F\u0307", + // Ḟ = \.{F} + "\u01F4": "G\u0301", + // Ǵ = \'{G} + "\u1E20": "G\u0304", + // Ḡ = \={G} + "\u011E": "G\u0306", + // Ğ = \u{G} + "\u01E6": "G\u030C", + // Ǧ = \v{G} + "\u011C": "G\u0302", + // Ĝ = \^{G} + "\u0120": "G\u0307", + // Ġ = \.{G} + "\u1E26": "H\u0308", + // Ḧ = \"{H} + "\u021E": "H\u030C", + // Ȟ = \v{H} + "\u0124": "H\u0302", + // Ĥ = \^{H} + "\u1E22": "H\u0307", + // Ḣ = \.{H} + "\xCD": "I\u0301", + // Í = \'{I} + "\xCC": "I\u0300", + // Ì = \`{I} + "\xCF": "I\u0308", + // Ï = \"{I} + "\u1E2E": "I\u0308\u0301", + // Ḯ = \"\'{I} + "\u0128": "I\u0303", + // Ĩ = \~{I} + "\u012A": "I\u0304", + // Ī = \={I} + "\u012C": "I\u0306", + // Ĭ = \u{I} + "\u01CF": "I\u030C", + // Ǐ = \v{I} + "\xCE": "I\u0302", + // Î = \^{I} + "\u0130": "I\u0307", + // İ = \.{I} + "\u0134": "J\u0302", + // Ĵ = \^{J} + "\u1E30": "K\u0301", + // Ḱ = \'{K} + "\u01E8": "K\u030C", + // Ǩ = \v{K} + "\u0139": "L\u0301", + // Ĺ = \'{L} + "\u013D": "L\u030C", + // Ľ = \v{L} + "\u1E3E": "M\u0301", + // Ḿ = \'{M} + "\u1E40": "M\u0307", + // Ṁ = \.{M} + "\u0143": "N\u0301", + // Ń = \'{N} + "\u01F8": "N\u0300", + // Ǹ = \`{N} + "\xD1": "N\u0303", + // Ñ = \~{N} + "\u0147": "N\u030C", + // Ň = \v{N} + "\u1E44": "N\u0307", + // Ṅ = \.{N} + "\xD3": "O\u0301", + // Ó = \'{O} + "\xD2": "O\u0300", + // Ò = \`{O} + "\xD6": "O\u0308", + // Ö = \"{O} + "\u022A": "O\u0308\u0304", + // Ȫ = \"\={O} + "\xD5": "O\u0303", + // Õ = \~{O} + "\u1E4C": "O\u0303\u0301", + // Ṍ = \~\'{O} + "\u1E4E": "O\u0303\u0308", + // Ṏ = \~\"{O} + "\u022C": "O\u0303\u0304", + // Ȭ = \~\={O} + "\u014C": "O\u0304", + // Ō = \={O} + "\u1E52": "O\u0304\u0301", + // Ṓ = \=\'{O} + "\u1E50": "O\u0304\u0300", + // Ṑ = \=\`{O} + "\u014E": "O\u0306", + // Ŏ = \u{O} + "\u01D1": "O\u030C", + // Ǒ = \v{O} + "\xD4": "O\u0302", + // Ô = \^{O} + "\u1ED0": "O\u0302\u0301", + // Ố = \^\'{O} + "\u1ED2": "O\u0302\u0300", + // Ồ = \^\`{O} + "\u1ED6": "O\u0302\u0303", + // Ỗ = \^\~{O} + "\u022E": "O\u0307", + // Ȯ = \.{O} + "\u0230": "O\u0307\u0304", + // Ȱ = \.\={O} + "\u0150": "O\u030B", + // Ő = \H{O} + "\u1E54": "P\u0301", + // Ṕ = \'{P} + "\u1E56": "P\u0307", + // Ṗ = \.{P} + "\u0154": "R\u0301", + // Ŕ = \'{R} + "\u0158": "R\u030C", + // Ř = \v{R} + "\u1E58": "R\u0307", + // Ṙ = \.{R} + "\u015A": "S\u0301", + // Ś = \'{S} + "\u1E64": "S\u0301\u0307", + // Ṥ = \'\.{S} + "\u0160": "S\u030C", + // Š = \v{S} + "\u1E66": "S\u030C\u0307", + // Ṧ = \v\.{S} + "\u015C": "S\u0302", + // Ŝ = \^{S} + "\u1E60": "S\u0307", + // Ṡ = \.{S} + "\u0164": "T\u030C", + // Ť = \v{T} + "\u1E6A": "T\u0307", + // Ṫ = \.{T} + "\xDA": "U\u0301", + // Ú = \'{U} + "\xD9": "U\u0300", + // Ù = \`{U} + "\xDC": "U\u0308", + // Ü = \"{U} + "\u01D7": "U\u0308\u0301", + // Ǘ = \"\'{U} + "\u01DB": "U\u0308\u0300", + // Ǜ = \"\`{U} + "\u01D5": "U\u0308\u0304", + // Ǖ = \"\={U} + "\u01D9": "U\u0308\u030C", + // Ǚ = \"\v{U} + "\u0168": "U\u0303", + // Ũ = \~{U} + "\u1E78": "U\u0303\u0301", + // Ṹ = \~\'{U} + "\u016A": "U\u0304", + // Ū = \={U} + "\u1E7A": "U\u0304\u0308", + // Ṻ = \=\"{U} + "\u016C": "U\u0306", + // Ŭ = \u{U} + "\u01D3": "U\u030C", + // Ǔ = \v{U} + "\xDB": "U\u0302", + // Û = \^{U} + "\u016E": "U\u030A", + // Ů = \r{U} + "\u0170": "U\u030B", + // Ű = \H{U} + "\u1E7C": "V\u0303", + // Ṽ = \~{V} + "\u1E82": "W\u0301", + // Ẃ = \'{W} + "\u1E80": "W\u0300", + // Ẁ = \`{W} + "\u1E84": "W\u0308", + // Ẅ = \"{W} + "\u0174": "W\u0302", + // Ŵ = \^{W} + "\u1E86": "W\u0307", + // Ẇ = \.{W} + "\u1E8C": "X\u0308", + // Ẍ = \"{X} + "\u1E8A": "X\u0307", + // Ẋ = \.{X} + "\xDD": "Y\u0301", + // Ý = \'{Y} + "\u1EF2": "Y\u0300", + // Ỳ = \`{Y} + "\u0178": "Y\u0308", + // Ÿ = \"{Y} + "\u1EF8": "Y\u0303", + // Ỹ = \~{Y} + "\u0232": "Y\u0304", + // Ȳ = \={Y} + "\u0176": "Y\u0302", + // Ŷ = \^{Y} + "\u1E8E": "Y\u0307", + // Ẏ = \.{Y} + "\u0179": "Z\u0301", + // Ź = \'{Z} + "\u017D": "Z\u030C", + // Ž = \v{Z} + "\u1E90": "Z\u0302", + // Ẑ = \^{Z} + "\u017B": "Z\u0307", + // Ż = \.{Z} + "\u03AC": "\u03B1\u0301", + // ά = \'{α} + "\u1F70": "\u03B1\u0300", + // ὰ = \`{α} + "\u1FB1": "\u03B1\u0304", + // ᾱ = \={α} + "\u1FB0": "\u03B1\u0306", + // ᾰ = \u{α} + "\u03AD": "\u03B5\u0301", + // έ = \'{ε} + "\u1F72": "\u03B5\u0300", + // ὲ = \`{ε} + "\u03AE": "\u03B7\u0301", + // ή = \'{η} + "\u1F74": "\u03B7\u0300", + // ὴ = \`{η} + "\u03AF": "\u03B9\u0301", + // ί = \'{ι} + "\u1F76": "\u03B9\u0300", + // ὶ = \`{ι} + "\u03CA": "\u03B9\u0308", + // ϊ = \"{ι} + "\u0390": "\u03B9\u0308\u0301", + // ΐ = \"\'{ι} + "\u1FD2": "\u03B9\u0308\u0300", + // ῒ = \"\`{ι} + "\u1FD1": "\u03B9\u0304", + // ῑ = \={ι} + "\u1FD0": "\u03B9\u0306", + // ῐ = \u{ι} + "\u03CC": "\u03BF\u0301", + // ό = \'{ο} + "\u1F78": "\u03BF\u0300", + // ὸ = \`{ο} + "\u03CD": "\u03C5\u0301", + // ύ = \'{υ} + "\u1F7A": "\u03C5\u0300", + // ὺ = \`{υ} + "\u03CB": "\u03C5\u0308", + // ϋ = \"{υ} + "\u03B0": "\u03C5\u0308\u0301", + // ΰ = \"\'{υ} + "\u1FE2": "\u03C5\u0308\u0300", + // ῢ = \"\`{υ} + "\u1FE1": "\u03C5\u0304", + // ῡ = \={υ} + "\u1FE0": "\u03C5\u0306", + // ῠ = \u{υ} + "\u03CE": "\u03C9\u0301", + // ώ = \'{ω} + "\u1F7C": "\u03C9\u0300", + // ὼ = \`{ω} + "\u038E": "\u03A5\u0301", + // Ύ = \'{Υ} + "\u1FEA": "\u03A5\u0300", + // Ὺ = \`{Υ} + "\u03AB": "\u03A5\u0308", + // Ϋ = \"{Υ} + "\u1FE9": "\u03A5\u0304", + // Ῡ = \={Υ} + "\u1FE8": "\u03A5\u0306", + // Ῠ = \u{Υ} + "\u038F": "\u03A9\u0301", + // Ώ = \'{Ω} + "\u1FFA": "\u03A9\u0300" // Ὼ = \`{Ω} + +}); +// CONCATENATED MODULE: ./src/Parser.js +/* eslint no-constant-condition:0 */ + + + + + + + + + + + + + + +/** + * This file contains the parser used to parse out a TeX expression from the + * input. Since TeX isn't context-free, standard parsers don't work particularly + * well. + * + * The strategy of this parser is as such: + * + * The main functions (the `.parse...` ones) take a position in the current + * parse string to parse tokens from. The lexer (found in Lexer.js, stored at + * this.gullet.lexer) also supports pulling out tokens at arbitrary places. When + * individual tokens are needed at a position, the lexer is called to pull out a + * token, which is then used. + * + * The parser has a property called "mode" indicating the mode that + * the parser is currently in. Currently it has to be one of "math" or + * "text", which denotes whether the current environment is a math-y + * one or a text-y one (e.g. inside \text). Currently, this serves to + * limit the functions which can be used in text mode. + * + * The main functions then return an object which contains the useful data that + * was parsed at its given point, and a new position at the end of the parsed + * data. The main functions can call each other and continue the parsing by + * using the returned position as a new starting point. + * + * There are also extra `.handle...` functions, which pull out some reused + * functionality into self-contained functions. + * + * The functions return ParseNodes. + */ +var Parser_Parser = +/*#__PURE__*/ +function () { + function Parser(input, settings) { + this.mode = void 0; + this.gullet = void 0; + this.settings = void 0; + this.leftrightDepth = void 0; + this.nextToken = void 0; + // Start in math mode + this.mode = "math"; // Create a new macro expander (gullet) and (indirectly via that) also a + // new lexer (mouth) for this parser (stomach, in the language of TeX) + + this.gullet = new MacroExpander_MacroExpander(input, settings, this.mode); // Store the settings for use in parsing + + this.settings = settings; // Count leftright depth (for \middle errors) + + this.leftrightDepth = 0; + } + /** + * Checks a result to make sure it has the right type, and throws an + * appropriate error otherwise. + */ + + + var _proto = Parser.prototype; + + _proto.expect = function expect(text, consume) { + if (consume === void 0) { + consume = true; + } + + if (this.fetch().text !== text) { + throw new src_ParseError("Expected '" + text + "', got '" + this.fetch().text + "'", this.fetch()); + } + + if (consume) { + this.consume(); + } + } + /** + * Discards the current lookahead token, considering it consumed. + */ + ; + + _proto.consume = function consume() { + this.nextToken = null; + } + /** + * Return the current lookahead token, or if there isn't one (at the + * beginning, or if the previous lookahead token was consume()d), + * fetch the next token as the new lookahead token and return it. + */ + ; + + _proto.fetch = function fetch() { + if (this.nextToken == null) { + this.nextToken = this.gullet.expandNextToken(); + } + + return this.nextToken; + } + /** + * Switches between "text" and "math" modes. + */ + ; + + _proto.switchMode = function switchMode(newMode) { + this.mode = newMode; + this.gullet.switchMode(newMode); + } + /** + * Main parsing function, which parses an entire input. + */ + ; + + _proto.parse = function parse() { + // Create a group namespace for the math expression. + // (LaTeX creates a new group for every $...$, $$...$$, \[...\].) + this.gullet.beginGroup(); // Use old \color behavior (same as LaTeX's \textcolor) if requested. + // We do this within the group for the math expression, so it doesn't + // pollute settings.macros. + + if (this.settings.colorIsTextColor) { + this.gullet.macros.set("\\color", "\\textcolor"); + } // Try to parse the input + + + var parse = this.parseExpression(false); // If we succeeded, make sure there's an EOF at the end + + this.expect("EOF"); // End the group namespace for the expression + + this.gullet.endGroup(); + return parse; + }; + + _proto.parseExpression = function parseExpression(breakOnInfix, breakOnTokenText) { + var body = []; // Keep adding atoms to the body until we can't parse any more atoms (either + // we reached the end, a }, or a \right) + + while (true) { + // Ignore spaces in math mode + if (this.mode === "math") { + this.consumeSpaces(); + } + + var lex = this.fetch(); + + if (Parser.endOfExpression.indexOf(lex.text) !== -1) { + break; + } + + if (breakOnTokenText && lex.text === breakOnTokenText) { + break; + } + + if (breakOnInfix && src_functions[lex.text] && src_functions[lex.text].infix) { + break; + } + + var atom = this.parseAtom(breakOnTokenText); + + if (!atom) { + break; + } + + body.push(atom); + } + + if (this.mode === "text") { + this.formLigatures(body); + } + + return this.handleInfixNodes(body); + } + /** + * Rewrites infix operators such as \over with corresponding commands such + * as \frac. + * + * There can only be one infix operator per group. If there's more than one + * then the expression is ambiguous. This can be resolved by adding {}. + */ + ; + + _proto.handleInfixNodes = function handleInfixNodes(body) { + var overIndex = -1; + var funcName; + + for (var i = 0; i < body.length; i++) { + var node = checkNodeType(body[i], "infix"); + + if (node) { + if (overIndex !== -1) { + throw new src_ParseError("only one infix operator per group", node.token); + } + + overIndex = i; + funcName = node.replaceWith; + } + } + + if (overIndex !== -1 && funcName) { + var numerNode; + var denomNode; + var numerBody = body.slice(0, overIndex); + var denomBody = body.slice(overIndex + 1); + + if (numerBody.length === 1 && numerBody[0].type === "ordgroup") { + numerNode = numerBody[0]; + } else { + numerNode = { + type: "ordgroup", + mode: this.mode, + body: numerBody + }; + } + + if (denomBody.length === 1 && denomBody[0].type === "ordgroup") { + denomNode = denomBody[0]; + } else { + denomNode = { + type: "ordgroup", + mode: this.mode, + body: denomBody + }; + } + + var _node; + + if (funcName === "\\\\abovefrac") { + _node = this.callFunction(funcName, [numerNode, body[overIndex], denomNode], []); + } else { + _node = this.callFunction(funcName, [numerNode, denomNode], []); + } + + return [_node]; + } else { + return body; + } + } // The greediness of a superscript or subscript + ; + + /** + * Handle a subscript or superscript with nice errors. + */ + _proto.handleSupSubscript = function handleSupSubscript(name) { + var symbolToken = this.fetch(); + var symbol = symbolToken.text; + this.consume(); + var group = this.parseGroup(name, false, Parser.SUPSUB_GREEDINESS, undefined, undefined, true); // ignore spaces before sup/subscript argument + + if (!group) { + throw new src_ParseError("Expected group after '" + symbol + "'", symbolToken); + } + + return group; + } + /** + * Converts the textual input of an unsupported command into a text node + * contained within a color node whose color is determined by errorColor + */ + ; + + _proto.formatUnsupportedCmd = function formatUnsupportedCmd(text) { + var textordArray = []; + + for (var i = 0; i < text.length; i++) { + textordArray.push({ + type: "textord", + mode: "text", + text: text[i] + }); + } + + var textNode = { + type: "text", + mode: this.mode, + body: textordArray + }; + var colorNode = { + type: "color", + mode: this.mode, + color: this.settings.errorColor, + body: [textNode] + }; + return colorNode; + } + /** + * Parses a group with optional super/subscripts. + */ + ; + + _proto.parseAtom = function parseAtom(breakOnTokenText) { + // The body of an atom is an implicit group, so that things like + // \left(x\right)^2 work correctly. + var base = this.parseGroup("atom", false, null, breakOnTokenText); // In text mode, we don't have superscripts or subscripts + + if (this.mode === "text") { + return base; + } // Note that base may be empty (i.e. null) at this point. + + + var superscript; + var subscript; + + while (true) { + // Guaranteed in math mode, so eat any spaces first. + this.consumeSpaces(); // Lex the first token + + var lex = this.fetch(); + + if (lex.text === "\\limits" || lex.text === "\\nolimits") { + // We got a limit control + var opNode = checkNodeType(base, "op"); + + if (opNode) { + var limits = lex.text === "\\limits"; + opNode.limits = limits; + opNode.alwaysHandleSupSub = true; + } else { + opNode = checkNodeType(base, "operatorname"); + + if (opNode && opNode.alwaysHandleSupSub) { + var _limits = lex.text === "\\limits"; + + opNode.limits = _limits; + } else { + throw new src_ParseError("Limit controls must follow a math operator", lex); + } + } + + this.consume(); + } else if (lex.text === "^") { + // We got a superscript start + if (superscript) { + throw new src_ParseError("Double superscript", lex); + } + + superscript = this.handleSupSubscript("superscript"); + } else if (lex.text === "_") { + // We got a subscript start + if (subscript) { + throw new src_ParseError("Double subscript", lex); + } + + subscript = this.handleSupSubscript("subscript"); + } else if (lex.text === "'") { + // We got a prime + if (superscript) { + throw new src_ParseError("Double superscript", lex); + } + + var prime = { + type: "textord", + mode: this.mode, + text: "\\prime" + }; // Many primes can be grouped together, so we handle this here + + var primes = [prime]; + this.consume(); // Keep lexing tokens until we get something that's not a prime + + while (this.fetch().text === "'") { + // For each one, add another prime to the list + primes.push(prime); + this.consume(); + } // If there's a superscript following the primes, combine that + // superscript in with the primes. + + + if (this.fetch().text === "^") { + primes.push(this.handleSupSubscript("superscript")); + } // Put everything into an ordgroup as the superscript + + + superscript = { + type: "ordgroup", + mode: this.mode, + body: primes + }; + } else { + // If it wasn't ^, _, or ', stop parsing super/subscripts + break; + } + } // Base must be set if superscript or subscript are set per logic above, + // but need to check here for type check to pass. + + + if (superscript || subscript) { + // If we got either a superscript or subscript, create a supsub + return { + type: "supsub", + mode: this.mode, + base: base, + sup: superscript, + sub: subscript + }; + } else { + // Otherwise return the original body + return base; + } + } + /** + * Parses an entire function, including its base and all of its arguments. + */ + ; + + _proto.parseFunction = function parseFunction(breakOnTokenText, name, // For error reporting. + greediness) { + var token = this.fetch(); + var func = token.text; + var funcData = src_functions[func]; + + if (!funcData) { + return null; + } + + this.consume(); // consume command token + + if (greediness != null && funcData.greediness <= greediness) { + throw new src_ParseError("Got function '" + func + "' with no arguments" + (name ? " as " + name : ""), token); + } else if (this.mode === "text" && !funcData.allowedInText) { + throw new src_ParseError("Can't use function '" + func + "' in text mode", token); + } else if (this.mode === "math" && funcData.allowedInMath === false) { + throw new src_ParseError("Can't use function '" + func + "' in math mode", token); + } + + var _this$parseArguments = this.parseArguments(func, funcData), + args = _this$parseArguments.args, + optArgs = _this$parseArguments.optArgs; + + return this.callFunction(func, args, optArgs, token, breakOnTokenText); + } + /** + * Call a function handler with a suitable context and arguments. + */ + ; + + _proto.callFunction = function callFunction(name, args, optArgs, token, breakOnTokenText) { + var context = { + funcName: name, + parser: this, + token: token, + breakOnTokenText: breakOnTokenText + }; + var func = src_functions[name]; + + if (func && func.handler) { + return func.handler(context, args, optArgs); + } else { + throw new src_ParseError("No function handler for " + name); + } + } + /** + * Parses the arguments of a function or environment + */ + ; + + _proto.parseArguments = function parseArguments(func, // Should look like "\name" or "\begin{name}". + funcData) { + var totalArgs = funcData.numArgs + funcData.numOptionalArgs; + + if (totalArgs === 0) { + return { + args: [], + optArgs: [] + }; + } + + var baseGreediness = funcData.greediness; + var args = []; + var optArgs = []; + + for (var i = 0; i < totalArgs; i++) { + var argType = funcData.argTypes && funcData.argTypes[i]; + var isOptional = i < funcData.numOptionalArgs; // Ignore spaces between arguments. As the TeXbook says: + // "After you have said ‘\def\row#1#2{...}’, you are allowed to + // put spaces between the arguments (e.g., ‘\row x n’), because + // TeX doesn’t use single spaces as undelimited arguments." + + var consumeSpaces = i > 0 && !isOptional || // Also consume leading spaces in math mode, as parseSymbol + // won't know what to do with them. This can only happen with + // macros, e.g. \frac\foo\foo where \foo expands to a space symbol. + // In LaTeX, the \foo's get treated as (blank) arguments. + // In KaTeX, for now, both spaces will get consumed. + // TODO(edemaine) + i === 0 && !isOptional && this.mode === "math"; + var arg = this.parseGroupOfType("argument to '" + func + "'", argType, isOptional, baseGreediness, consumeSpaces); + + if (!arg) { + if (isOptional) { + optArgs.push(null); + continue; + } + + throw new src_ParseError("Expected group after '" + func + "'", this.fetch()); + } + + (isOptional ? optArgs : args).push(arg); + } + + return { + args: args, + optArgs: optArgs + }; + } + /** + * Parses a group when the mode is changing. + */ + ; + + _proto.parseGroupOfType = function parseGroupOfType(name, type, optional, greediness, consumeSpaces) { + switch (type) { + case "color": + if (consumeSpaces) { + this.consumeSpaces(); + } + + return this.parseColorGroup(optional); + + case "size": + if (consumeSpaces) { + this.consumeSpaces(); + } + + return this.parseSizeGroup(optional); + + case "url": + return this.parseUrlGroup(optional, consumeSpaces); + + case "math": + case "text": + return this.parseGroup(name, optional, greediness, undefined, type, consumeSpaces); + + case "hbox": + { + // hbox argument type wraps the argument in the equivalent of + // \hbox, which is like \text but switching to \textstyle size. + var group = this.parseGroup(name, optional, greediness, undefined, "text", consumeSpaces); + + if (!group) { + return group; + } + + var styledGroup = { + type: "styling", + mode: group.mode, + body: [group], + style: "text" // simulate \textstyle + + }; + return styledGroup; + } + + case "raw": + { + if (consumeSpaces) { + this.consumeSpaces(); + } + + if (optional && this.fetch().text === "{") { + return null; + } + + var token = this.parseStringGroup("raw", optional, true); + + if (token) { + return { + type: "raw", + mode: "text", + string: token.text + }; + } else { + throw new src_ParseError("Expected raw group", this.fetch()); + } + } + + case "original": + case null: + case undefined: + return this.parseGroup(name, optional, greediness, undefined, undefined, consumeSpaces); + + default: + throw new src_ParseError("Unknown group type as " + name, this.fetch()); + } + } + /** + * Discard any space tokens, fetching the next non-space token. + */ + ; + + _proto.consumeSpaces = function consumeSpaces() { + while (this.fetch().text === " ") { + this.consume(); + } + } + /** + * Parses a group, essentially returning the string formed by the + * brace-enclosed tokens plus some position information. + */ + ; + + _proto.parseStringGroup = function parseStringGroup(modeName, // Used to describe the mode in error messages. + optional, raw) { + var groupBegin = optional ? "[" : "{"; + var groupEnd = optional ? "]" : "}"; + var beginToken = this.fetch(); + + if (beginToken.text !== groupBegin) { + if (optional) { + return null; + } else if (raw && beginToken.text !== "EOF" && /[^{}[\]]/.test(beginToken.text)) { + this.consume(); + return beginToken; + } + } + + var outerMode = this.mode; + this.mode = "text"; + this.expect(groupBegin); + var str = ""; + var firstToken = this.fetch(); + var nested = 0; // allow nested braces in raw string group + + var lastToken = firstToken; + var nextToken; + + while ((nextToken = this.fetch()).text !== groupEnd || raw && nested > 0) { + switch (nextToken.text) { + case "EOF": + throw new src_ParseError("Unexpected end of input in " + modeName, firstToken.range(lastToken, str)); + + case groupBegin: + nested++; + break; + + case groupEnd: + nested--; + break; + } + + lastToken = nextToken; + str += lastToken.text; + this.consume(); + } + + this.expect(groupEnd); + this.mode = outerMode; + return firstToken.range(lastToken, str); + } + /** + * Parses a regex-delimited group: the largest sequence of tokens + * whose concatenated strings match `regex`. Returns the string + * formed by the tokens plus some position information. + */ + ; + + _proto.parseRegexGroup = function parseRegexGroup(regex, modeName) { + var outerMode = this.mode; + this.mode = "text"; + var firstToken = this.fetch(); + var lastToken = firstToken; + var str = ""; + var nextToken; + + while ((nextToken = this.fetch()).text !== "EOF" && regex.test(str + nextToken.text)) { + lastToken = nextToken; + str += lastToken.text; + this.consume(); + } + + if (str === "") { + throw new src_ParseError("Invalid " + modeName + ": '" + firstToken.text + "'", firstToken); + } + + this.mode = outerMode; + return firstToken.range(lastToken, str); + } + /** + * Parses a color description. + */ + ; + + _proto.parseColorGroup = function parseColorGroup(optional) { + var res = this.parseStringGroup("color", optional); + + if (!res) { + return null; + } + + var match = /^(#[a-f0-9]{3}|#?[a-f0-9]{6}|[a-z]+)$/i.exec(res.text); + + if (!match) { + throw new src_ParseError("Invalid color: '" + res.text + "'", res); + } + + var color = match[0]; + + if (/^[0-9a-f]{6}$/i.test(color)) { + // We allow a 6-digit HTML color spec without a leading "#". + // This follows the xcolor package's HTML color model. + // Predefined color names are all missed by this RegEx pattern. + color = "#" + color; + } + + return { + type: "color-token", + mode: this.mode, + color: color + }; + } + /** + * Parses a size specification, consisting of magnitude and unit. + */ + ; + + _proto.parseSizeGroup = function parseSizeGroup(optional) { + var res; + var isBlank = false; + + if (!optional && this.fetch().text !== "{") { + res = this.parseRegexGroup(/^[-+]? *(?:$|\d+|\d+\.\d*|\.\d*) *[a-z]{0,2} *$/, "size"); + } else { + res = this.parseStringGroup("size", optional); + } + + if (!res) { + return null; + } + + if (!optional && res.text.length === 0) { + // Because we've tested for what is !optional, this block won't + // affect \kern, \hspace, etc. It will capture the mandatory arguments + // to \genfrac and \above. + res.text = "0pt"; // Enable \above{} + + isBlank = true; // This is here specifically for \genfrac + } + + var match = /([-+]?) *(\d+(?:\.\d*)?|\.\d+) *([a-z]{2})/.exec(res.text); + + if (!match) { + throw new src_ParseError("Invalid size: '" + res.text + "'", res); + } + + var data = { + number: +(match[1] + match[2]), + // sign + magnitude, cast to number + unit: match[3] + }; + + if (!validUnit(data)) { + throw new src_ParseError("Invalid unit: '" + data.unit + "'", res); + } + + return { + type: "size", + mode: this.mode, + value: data, + isBlank: isBlank + }; + } + /** + * Parses an URL, checking escaped letters and allowed protocols, + * and setting the catcode of % as an active character (as in \hyperref). + */ + ; + + _proto.parseUrlGroup = function parseUrlGroup(optional, consumeSpaces) { + this.gullet.lexer.setCatcode("%", 13); // active character + + var res = this.parseStringGroup("url", optional, true); // get raw string + + this.gullet.lexer.setCatcode("%", 14); // comment character + + if (!res) { + return null; + } // hyperref package allows backslashes alone in href, but doesn't + // generate valid links in such cases; we interpret this as + // "undefined" behaviour, and keep them as-is. Some browser will + // replace backslashes with forward slashes. + + + var url = res.text.replace(/\\([#$%&~_^{}])/g, '$1'); + return { + type: "url", + mode: this.mode, + url: url + }; + } + /** + * If `optional` is false or absent, this parses an ordinary group, + * which is either a single nucleus (like "x") or an expression + * in braces (like "{x+y}") or an implicit group, a group that starts + * at the current position, and ends right before a higher explicit + * group ends, or at EOF. + * If `optional` is true, it parses either a bracket-delimited expression + * (like "[x+y]") or returns null to indicate the absence of a + * bracket-enclosed group. + * If `mode` is present, switches to that mode while parsing the group, + * and switches back after. + */ + ; + + _proto.parseGroup = function parseGroup(name, // For error reporting. + optional, greediness, breakOnTokenText, mode, consumeSpaces) { + // Switch to specified mode + var outerMode = this.mode; + + if (mode) { + this.switchMode(mode); + } // Consume spaces if requested, crucially *after* we switch modes, + // so that the next non-space token is parsed in the correct mode. + + + if (consumeSpaces) { + this.consumeSpaces(); + } // Get first token + + + var firstToken = this.fetch(); + var text = firstToken.text; + var result; // Try to parse an open brace or \begingroup + + if (optional ? text === "[" : text === "{" || text === "\\begingroup") { + this.consume(); + var groupEnd = Parser.endOfGroup[text]; // Start a new group namespace + + this.gullet.beginGroup(); // If we get a brace, parse an expression + + var expression = this.parseExpression(false, groupEnd); + var lastToken = this.fetch(); // Check that we got a matching closing brace + + this.expect(groupEnd); // End group namespace + + this.gullet.endGroup(); + result = { + type: "ordgroup", + mode: this.mode, + loc: SourceLocation.range(firstToken, lastToken), + body: expression, + // A group formed by \begingroup...\endgroup is a semi-simple group + // which doesn't affect spacing in math mode, i.e., is transparent. + // https://tex.stackexchange.com/questions/1930/when-should-one- + // use-begingroup-instead-of-bgroup + semisimple: text === "\\begingroup" || undefined + }; + } else if (optional) { + // Return nothing for an optional group + result = null; + } else { + // If there exists a function with this name, parse the function. + // Otherwise, just return a nucleus + result = this.parseFunction(breakOnTokenText, name, greediness) || this.parseSymbol(); + + if (result == null && text[0] === "\\" && !implicitCommands.hasOwnProperty(text)) { + if (this.settings.throwOnError) { + throw new src_ParseError("Undefined control sequence: " + text, firstToken); + } + + result = this.formatUnsupportedCmd(text); + this.consume(); + } + } // Switch mode back + + + if (mode) { + this.switchMode(outerMode); + } + + return result; + } + /** + * Form ligature-like combinations of characters for text mode. + * This includes inputs like "--", "---", "``" and "''". + * The result will simply replace multiple textord nodes with a single + * character in each value by a single textord node having multiple + * characters in its value. The representation is still ASCII source. + * The group will be modified in place. + */ + ; + + _proto.formLigatures = function formLigatures(group) { + var n = group.length - 1; + + for (var i = 0; i < n; ++i) { + var a = group[i]; // $FlowFixMe: Not every node type has a `text` property. + + var v = a.text; + + if (v === "-" && group[i + 1].text === "-") { + if (i + 1 < n && group[i + 2].text === "-") { + group.splice(i, 3, { + type: "textord", + mode: "text", + loc: SourceLocation.range(a, group[i + 2]), + text: "---" + }); + n -= 2; + } else { + group.splice(i, 2, { + type: "textord", + mode: "text", + loc: SourceLocation.range(a, group[i + 1]), + text: "--" + }); + n -= 1; + } + } + + if ((v === "'" || v === "`") && group[i + 1].text === v) { + group.splice(i, 2, { + type: "textord", + mode: "text", + loc: SourceLocation.range(a, group[i + 1]), + text: v + v + }); + n -= 1; + } + } + } + /** + * Parse a single symbol out of the string. Here, we handle single character + * symbols and special functions like \verb. + */ + ; + + _proto.parseSymbol = function parseSymbol() { + var nucleus = this.fetch(); + var text = nucleus.text; + + if (/^\\verb[^a-zA-Z]/.test(text)) { + this.consume(); + var arg = text.slice(5); + var star = arg.charAt(0) === "*"; + + if (star) { + arg = arg.slice(1); + } // Lexer's tokenRegex is constructed to always have matching + // first/last characters. + + + if (arg.length < 2 || arg.charAt(0) !== arg.slice(-1)) { + throw new src_ParseError("\\verb assertion failed --\n please report what input caused this bug"); + } + + arg = arg.slice(1, -1); // remove first and last char + + return { + type: "verb", + mode: "text", + body: arg, + star: star + }; + } // At this point, we should have a symbol, possibly with accents. + // First expand any accented base symbol according to unicodeSymbols. + + + if (unicodeSymbols.hasOwnProperty(text[0]) && !src_symbols[this.mode][text[0]]) { + // This behavior is not strict (XeTeX-compatible) in math mode. + if (this.settings.strict && this.mode === "math") { + this.settings.reportNonstrict("unicodeTextInMathMode", "Accented Unicode text character \"" + text[0] + "\" used in " + "math mode", nucleus); + } + + text = unicodeSymbols[text[0]] + text.substr(1); + } // Strip off any combining characters + + + var match = combiningDiacriticalMarksEndRegex.exec(text); + + if (match) { + text = text.substring(0, match.index); + + if (text === 'i') { + text = "\u0131"; // dotless i, in math and text mode + } else if (text === 'j') { + text = "\u0237"; // dotless j, in math and text mode + } + } // Recognize base symbol + + + var symbol; + + if (src_symbols[this.mode][text]) { + if (this.settings.strict && this.mode === 'math' && extraLatin.indexOf(text) >= 0) { + this.settings.reportNonstrict("unicodeTextInMathMode", "Latin-1/Unicode text character \"" + text[0] + "\" used in " + "math mode", nucleus); + } + + var group = src_symbols[this.mode][text].group; + var loc = SourceLocation.range(nucleus); + var s; + + if (ATOMS.hasOwnProperty(group)) { + // $FlowFixMe + var family = group; + s = { + type: "atom", + mode: this.mode, + family: family, + loc: loc, + text: text + }; + } else { + // $FlowFixMe + s = { + type: group, + mode: this.mode, + loc: loc, + text: text + }; + } + + symbol = s; + } else if (text.charCodeAt(0) >= 0x80) { + // no symbol for e.g. ^ + if (this.settings.strict) { + if (!supportedCodepoint(text.charCodeAt(0))) { + this.settings.reportNonstrict("unknownSymbol", "Unrecognized Unicode character \"" + text[0] + "\"" + (" (" + text.charCodeAt(0) + ")"), nucleus); + } else if (this.mode === "math") { + this.settings.reportNonstrict("unicodeTextInMathMode", "Unicode text character \"" + text[0] + "\" used in math mode", nucleus); + } + } // All nonmathematical Unicode characters are rendered as if they + // are in text mode (wrapped in \text) because that's what it + // takes to render them in LaTeX. Setting `mode: this.mode` is + // another natural choice (the user requested math mode), but + // this makes it more difficult for getCharacterMetrics() to + // distinguish Unicode characters without metrics and those for + // which we want to simulate the letter M. + + + symbol = { + type: "textord", + mode: "text", + loc: SourceLocation.range(nucleus), + text: text + }; + } else { + return null; // EOF, ^, _, {, }, etc. + } + + this.consume(); // Transform combining characters into accents + + if (match) { + for (var i = 0; i < match[0].length; i++) { + var accent = match[0][i]; + + if (!unicodeAccents[accent]) { + throw new src_ParseError("Unknown accent ' " + accent + "'", nucleus); + } + + var command = unicodeAccents[accent][this.mode]; + + if (!command) { + throw new src_ParseError("Accent " + accent + " unsupported in " + this.mode + " mode", nucleus); + } + + symbol = { + type: "accent", + mode: this.mode, + loc: SourceLocation.range(nucleus), + label: command, + isStretchy: false, + isShifty: true, + base: symbol + }; + } + } + + return symbol; + }; + + return Parser; +}(); + +Parser_Parser.endOfExpression = ["}", "\\endgroup", "\\end", "\\right", "&"]; +Parser_Parser.endOfGroup = { + "[": "]", + "{": "}", + "\\begingroup": "\\endgroup" + /** + * Parses an "expression", which is a list of atoms. + * + * `breakOnInfix`: Should the parsing stop when we hit infix nodes? This + * happens when functions have higher precendence han infix + * nodes in implicit parses. + * + * `breakOnTokenText`: The text of the token that the expression should end + * with, or `null` if something else should end the + * expression. + */ + +}; +Parser_Parser.SUPSUB_GREEDINESS = 1; + +// CONCATENATED MODULE: ./src/parseTree.js +/** + * Provides a single function for parsing an expression using a Parser + * TODO(emily): Remove this + */ + + + +/** + * Parses an expression using a Parser, then returns the parsed result. + */ +var parseTree_parseTree = function parseTree(toParse, settings) { + if (!(typeof toParse === 'string' || toParse instanceof String)) { + throw new TypeError('KaTeX can only parse string typed expression'); + } + + var parser = new Parser_Parser(toParse, settings); // Blank out any \df@tag to avoid spurious "Duplicate \tag" errors + + delete parser.gullet.macros.current["\\df@tag"]; + var tree = parser.parse(); // If the input used \tag, it will set the \df@tag macro to the tag. + // In this case, we separately parse the tag and wrap the tree. + + if (parser.gullet.macros.get("\\df@tag")) { + if (!settings.displayMode) { + throw new src_ParseError("\\tag works only in display equations"); + } + + parser.gullet.feed("\\df@tag"); + tree = [{ + type: "tag", + mode: "text", + body: tree, + tag: parser.parse() + }]; + } + + return tree; +}; + +/* harmony default export */ var src_parseTree = (parseTree_parseTree); +// CONCATENATED MODULE: ./katex.js +/* eslint no-console:0 */ + +/** + * This is the main entry point for KaTeX. Here, we expose functions for + * rendering expressions either to DOM nodes or to markup strings. + * + * We also expose the ParseError class to check if errors thrown from KaTeX are + * errors in the expression, or errors in javascript handling. + */ + + + + + + + + + + +/** + * Parse and build an expression, and place that expression in the DOM node + * given. + */ +var katex_render = function render(expression, baseNode, options) { + baseNode.textContent = ""; + var node = katex_renderToDomTree(expression, options).toNode(); + baseNode.appendChild(node); +}; // KaTeX's styles don't work properly in quirks mode. Print out an error, and +// disable rendering. + + +if (typeof document !== "undefined") { + if (document.compatMode !== "CSS1Compat") { + typeof console !== "undefined" && console.warn("Warning: KaTeX doesn't work in quirks mode. Make sure your " + "website has a suitable doctype."); + + katex_render = function render() { + throw new src_ParseError("KaTeX doesn't work in quirks mode."); + }; + } +} +/** + * Parse and build an expression, and return the markup for that. + */ + + +var renderToString = function renderToString(expression, options) { + var markup = katex_renderToDomTree(expression, options).toMarkup(); + return markup; +}; +/** + * Parse an expression and return the parse tree. + */ + + +var katex_generateParseTree = function generateParseTree(expression, options) { + var settings = new Settings_Settings(options); + return src_parseTree(expression, settings); +}; +/** + * If the given error is a KaTeX ParseError and options.throwOnError is false, + * renders the invalid LaTeX as a span with hover title giving the KaTeX + * error message. Otherwise, simply throws the error. + */ + + +var katex_renderError = function renderError(error, expression, options) { + if (options.throwOnError || !(error instanceof src_ParseError)) { + throw error; + } + + var node = buildCommon.makeSpan(["katex-error"], [new domTree_SymbolNode(expression)]); + node.setAttribute("title", error.toString()); + node.setAttribute("style", "color:" + options.errorColor); + return node; +}; +/** + * Generates and returns the katex build tree. This is used for advanced + * use cases (like rendering to custom output). + */ + + +var katex_renderToDomTree = function renderToDomTree(expression, options) { + var settings = new Settings_Settings(options); + + try { + var tree = src_parseTree(expression, settings); + return buildTree_buildTree(tree, expression, settings); + } catch (error) { + return katex_renderError(error, expression, settings); + } +}; +/** + * Generates and returns the katex build tree, with just HTML (no MathML). + * This is used for advanced use cases (like rendering to custom output). + */ + + +var katex_renderToHTMLTree = function renderToHTMLTree(expression, options) { + var settings = new Settings_Settings(options); + + try { + var tree = src_parseTree(expression, settings); + return buildTree_buildHTMLTree(tree, expression, settings); + } catch (error) { + return katex_renderError(error, expression, settings); + } +}; + +/* harmony default export */ var katex_0 = ({ + /** + * Current KaTeX version + */ + version: "0.11.1", + + /** + * Renders the given LaTeX into an HTML+MathML combination, and adds + * it as a child to the specified DOM node. + */ + render: katex_render, + + /** + * Renders the given LaTeX into an HTML+MathML combination string, + * for sending to the client. + */ + renderToString: renderToString, + + /** + * KaTeX error, usually during parsing. + */ + ParseError: src_ParseError, + + /** + * Parses the given LaTeX into KaTeX's internal parse tree structure, + * without rendering to HTML or MathML. + * + * NOTE: This method is not currently recommended for public use. + * The internal tree representation is unstable and is very likely + * to change. Use at your own risk. + */ + __parse: katex_generateParseTree, + + /** + * Renders the given LaTeX into an HTML+MathML internal DOM tree + * representation, without flattening that representation to a string. + * + * NOTE: This method is not currently recommended for public use. + * The internal tree representation is unstable and is very likely + * to change. Use at your own risk. + */ + __renderToDomTree: katex_renderToDomTree, + + /** + * Renders the given LaTeX into an HTML internal DOM tree representation, + * without MathML and without flattening that representation to a string. + * + * NOTE: This method is not currently recommended for public use. + * The internal tree representation is unstable and is very likely + * to change. Use at your own risk. + */ + __renderToHTMLTree: katex_renderToHTMLTree, + + /** + * extends internal font metrics object with a new object + * each key in the new object represents a font name + */ + __setFontMetrics: setFontMetrics, + + /** + * adds a new symbol to builtin symbols table + */ + __defineSymbol: defineSymbol, + + /** + * adds a new macro to builtin macro list + */ + __defineMacro: defineMacro, + + /** + * Expose the dom tree node types, which can be useful for type checking nodes. + * + * NOTE: This method is not currently recommended for public use. + * The internal tree representation is unstable and is very likely + * to change. Use at your own risk. + */ + __domTree: { + Span: domTree_Span, + Anchor: domTree_Anchor, + SymbolNode: domTree_SymbolNode, + SvgNode: SvgNode, + PathNode: domTree_PathNode, + LineNode: LineNode + } +}); +// CONCATENATED MODULE: ./katex.webpack.js +/** + * This is the webpack entry point for KaTeX. As ECMAScript, flow[1] and jest[2] + * doesn't support CSS modules natively, a separate entry point is used and + * it is not flowtyped. + * + * [1] https://gist.github.com/lambdahands/d19e0da96285b749f0ef + * [2] https://facebook.github.io/jest/docs/en/webpack.html + */ + + +/* harmony default export */ var katex_webpack = __webpack_exports__["default"] = (katex_0); + +/***/ }) +/******/ ])["default"]; +}); \ No newline at end of file diff --git a/adoc/katex/katex.min.css b/adoc/katex/katex.min.css new file mode 100644 index 00000000..c0cd1451 --- /dev/null +++ b/adoc/katex/katex.min.css @@ -0,0 +1 @@ +@font-face{font-family:KaTeX_AMS;src:url(fonts/KaTeX_AMS-Regular.woff2) format("woff2"),url(fonts/KaTeX_AMS-Regular.woff) format("woff"),url(fonts/KaTeX_AMS-Regular.ttf) format("truetype");font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Caligraphic;src:url(fonts/KaTeX_Caligraphic-Bold.woff2) format("woff2"),url(fonts/KaTeX_Caligraphic-Bold.woff) format("woff"),url(fonts/KaTeX_Caligraphic-Bold.ttf) format("truetype");font-weight:700;font-style:normal}@font-face{font-family:KaTeX_Caligraphic;src:url(fonts/KaTeX_Caligraphic-Regular.woff2) format("woff2"),url(fonts/KaTeX_Caligraphic-Regular.woff) format("woff"),url(fonts/KaTeX_Caligraphic-Regular.ttf) format("truetype");font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Fraktur;src:url(fonts/KaTeX_Fraktur-Bold.woff2) format("woff2"),url(fonts/KaTeX_Fraktur-Bold.woff) format("woff"),url(fonts/KaTeX_Fraktur-Bold.ttf) format("truetype");font-weight:700;font-style:normal}@font-face{font-family:KaTeX_Fraktur;src:url(fonts/KaTeX_Fraktur-Regular.woff2) format("woff2"),url(fonts/KaTeX_Fraktur-Regular.woff) format("woff"),url(fonts/KaTeX_Fraktur-Regular.ttf) format("truetype");font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Main;src:url(fonts/KaTeX_Main-Bold.woff2) format("woff2"),url(fonts/KaTeX_Main-Bold.woff) format("woff"),url(fonts/KaTeX_Main-Bold.ttf) format("truetype");font-weight:700;font-style:normal}@font-face{font-family:KaTeX_Main;src:url(fonts/KaTeX_Main-BoldItalic.woff2) format("woff2"),url(fonts/KaTeX_Main-BoldItalic.woff) format("woff"),url(fonts/KaTeX_Main-BoldItalic.ttf) format("truetype");font-weight:700;font-style:italic}@font-face{font-family:KaTeX_Main;src:url(fonts/KaTeX_Main-Italic.woff2) format("woff2"),url(fonts/KaTeX_Main-Italic.woff) format("woff"),url(fonts/KaTeX_Main-Italic.ttf) format("truetype");font-weight:400;font-style:italic}@font-face{font-family:KaTeX_Main;src:url(fonts/KaTeX_Main-Regular.woff2) format("woff2"),url(fonts/KaTeX_Main-Regular.woff) format("woff"),url(fonts/KaTeX_Main-Regular.ttf) format("truetype");font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Math;src:url(fonts/KaTeX_Math-BoldItalic.woff2) format("woff2"),url(fonts/KaTeX_Math-BoldItalic.woff) format("woff"),url(fonts/KaTeX_Math-BoldItalic.ttf) format("truetype");font-weight:700;font-style:italic}@font-face{font-family:KaTeX_Math;src:url(fonts/KaTeX_Math-Italic.woff2) format("woff2"),url(fonts/KaTeX_Math-Italic.woff) format("woff"),url(fonts/KaTeX_Math-Italic.ttf) format("truetype");font-weight:400;font-style:italic}@font-face{font-family:"KaTeX_SansSerif";src:url(fonts/KaTeX_SansSerif-Bold.woff2) format("woff2"),url(fonts/KaTeX_SansSerif-Bold.woff) format("woff"),url(fonts/KaTeX_SansSerif-Bold.ttf) format("truetype");font-weight:700;font-style:normal}@font-face{font-family:"KaTeX_SansSerif";src:url(fonts/KaTeX_SansSerif-Italic.woff2) format("woff2"),url(fonts/KaTeX_SansSerif-Italic.woff) format("woff"),url(fonts/KaTeX_SansSerif-Italic.ttf) format("truetype");font-weight:400;font-style:italic}@font-face{font-family:"KaTeX_SansSerif";src:url(fonts/KaTeX_SansSerif-Regular.woff2) format("woff2"),url(fonts/KaTeX_SansSerif-Regular.woff) format("woff"),url(fonts/KaTeX_SansSerif-Regular.ttf) format("truetype");font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Script;src:url(fonts/KaTeX_Script-Regular.woff2) format("woff2"),url(fonts/KaTeX_Script-Regular.woff) format("woff"),url(fonts/KaTeX_Script-Regular.ttf) format("truetype");font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Size1;src:url(fonts/KaTeX_Size1-Regular.woff2) format("woff2"),url(fonts/KaTeX_Size1-Regular.woff) format("woff"),url(fonts/KaTeX_Size1-Regular.ttf) format("truetype");font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Size2;src:url(fonts/KaTeX_Size2-Regular.woff2) format("woff2"),url(fonts/KaTeX_Size2-Regular.woff) format("woff"),url(fonts/KaTeX_Size2-Regular.ttf) format("truetype");font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Size3;src:url(fonts/KaTeX_Size3-Regular.woff2) format("woff2"),url(fonts/KaTeX_Size3-Regular.woff) format("woff"),url(fonts/KaTeX_Size3-Regular.ttf) format("truetype");font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Size4;src:url(fonts/KaTeX_Size4-Regular.woff2) format("woff2"),url(fonts/KaTeX_Size4-Regular.woff) format("woff"),url(fonts/KaTeX_Size4-Regular.ttf) format("truetype");font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Typewriter;src:url(fonts/KaTeX_Typewriter-Regular.woff2) format("woff2"),url(fonts/KaTeX_Typewriter-Regular.woff) format("woff"),url(fonts/KaTeX_Typewriter-Regular.ttf) format("truetype");font-weight:400;font-style:normal}.katex{font:normal 1.21em KaTeX_Main,Times New Roman,serif;line-height:1.2;text-indent:0;text-rendering:auto}.katex *{-ms-high-contrast-adjust:none!important}.katex .katex-version:after{content:"0.11.1"}.katex .katex-mathml{position:absolute;clip:rect(1px,1px,1px,1px);padding:0;border:0;height:1px;width:1px;overflow:hidden}.katex .katex-html>.newline{display:block}.katex .base{position:relative;white-space:nowrap;width:min-content}.katex .base,.katex .strut{display:inline-block}.katex .textbf{font-weight:700}.katex .textit{font-style:italic}.katex .textrm{font-family:KaTeX_Main}.katex .textsf{font-family:KaTeX_SansSerif}.katex .texttt{font-family:KaTeX_Typewriter}.katex .mathdefault{font-family:KaTeX_Math;font-style:italic}.katex .mathit{font-family:KaTeX_Main;font-style:italic}.katex .mathrm{font-style:normal}.katex .mathbf{font-family:KaTeX_Main;font-weight:700}.katex .boldsymbol{font-family:KaTeX_Math;font-weight:700;font-style:italic}.katex .amsrm,.katex .mathbb,.katex .textbb{font-family:KaTeX_AMS}.katex .mathcal{font-family:KaTeX_Caligraphic}.katex .mathfrak,.katex .textfrak{font-family:KaTeX_Fraktur}.katex .mathtt{font-family:KaTeX_Typewriter}.katex .mathscr,.katex .textscr{font-family:KaTeX_Script}.katex .mathsf,.katex .textsf{font-family:KaTeX_SansSerif}.katex .mathboldsf,.katex .textboldsf{font-family:KaTeX_SansSerif;font-weight:700}.katex .mathitsf,.katex .textitsf{font-family:KaTeX_SansSerif;font-style:italic}.katex .mainrm{font-family:KaTeX_Main;font-style:normal}.katex .vlist-t{display:inline-table;table-layout:fixed}.katex .vlist-r{display:table-row}.katex .vlist{display:table-cell;vertical-align:bottom;position:relative}.katex .vlist>span{display:block;height:0;position:relative}.katex .vlist>span>span{display:inline-block}.katex .vlist>span>.pstrut{overflow:hidden;width:0}.katex .vlist-t2{margin-right:-2px}.katex .vlist-s{display:table-cell;vertical-align:bottom;font-size:1px;width:2px;min-width:2px}.katex .msupsub{text-align:left}.katex .mfrac>span>span{text-align:center}.katex .mfrac .frac-line{display:inline-block;width:100%;border-bottom-style:solid}.katex .hdashline,.katex .hline,.katex .mfrac .frac-line,.katex .overline .overline-line,.katex .rule,.katex .underline .underline-line{min-height:1px}.katex .mspace{display:inline-block}.katex .clap,.katex .llap,.katex .rlap{width:0;position:relative}.katex .clap>.inner,.katex .llap>.inner,.katex .rlap>.inner{position:absolute}.katex .clap>.fix,.katex .llap>.fix,.katex .rlap>.fix{display:inline-block}.katex .llap>.inner{right:0}.katex .clap>.inner,.katex .rlap>.inner{left:0}.katex .clap>.inner>span{margin-left:-50%;margin-right:50%}.katex .rule{display:inline-block;border:0 solid;position:relative}.katex .hline,.katex .overline .overline-line,.katex .underline .underline-line{display:inline-block;width:100%;border-bottom-style:solid}.katex .hdashline{display:inline-block;width:100%;border-bottom-style:dashed}.katex .sqrt>.root{margin-left:.27777778em;margin-right:-.55555556em}.katex .fontsize-ensurer.reset-size1.size1,.katex .sizing.reset-size1.size1{font-size:1em}.katex .fontsize-ensurer.reset-size1.size2,.katex .sizing.reset-size1.size2{font-size:1.2em}.katex .fontsize-ensurer.reset-size1.size3,.katex .sizing.reset-size1.size3{font-size:1.4em}.katex .fontsize-ensurer.reset-size1.size4,.katex .sizing.reset-size1.size4{font-size:1.6em}.katex .fontsize-ensurer.reset-size1.size5,.katex .sizing.reset-size1.size5{font-size:1.8em}.katex .fontsize-ensurer.reset-size1.size6,.katex .sizing.reset-size1.size6{font-size:2em}.katex .fontsize-ensurer.reset-size1.size7,.katex .sizing.reset-size1.size7{font-size:2.4em}.katex .fontsize-ensurer.reset-size1.size8,.katex .sizing.reset-size1.size8{font-size:2.88em}.katex .fontsize-ensurer.reset-size1.size9,.katex .sizing.reset-size1.size9{font-size:3.456em}.katex .fontsize-ensurer.reset-size1.size10,.katex .sizing.reset-size1.size10{font-size:4.148em}.katex .fontsize-ensurer.reset-size1.size11,.katex .sizing.reset-size1.size11{font-size:4.976em}.katex .fontsize-ensurer.reset-size2.size1,.katex .sizing.reset-size2.size1{font-size:.83333333em}.katex .fontsize-ensurer.reset-size2.size2,.katex .sizing.reset-size2.size2{font-size:1em}.katex .fontsize-ensurer.reset-size2.size3,.katex .sizing.reset-size2.size3{font-size:1.16666667em}.katex .fontsize-ensurer.reset-size2.size4,.katex .sizing.reset-size2.size4{font-size:1.33333333em}.katex .fontsize-ensurer.reset-size2.size5,.katex .sizing.reset-size2.size5{font-size:1.5em}.katex .fontsize-ensurer.reset-size2.size6,.katex .sizing.reset-size2.size6{font-size:1.66666667em}.katex .fontsize-ensurer.reset-size2.size7,.katex .sizing.reset-size2.size7{font-size:2em}.katex .fontsize-ensurer.reset-size2.size8,.katex .sizing.reset-size2.size8{font-size:2.4em}.katex .fontsize-ensurer.reset-size2.size9,.katex .sizing.reset-size2.size9{font-size:2.88em}.katex .fontsize-ensurer.reset-size2.size10,.katex .sizing.reset-size2.size10{font-size:3.45666667em}.katex .fontsize-ensurer.reset-size2.size11,.katex .sizing.reset-size2.size11{font-size:4.14666667em}.katex .fontsize-ensurer.reset-size3.size1,.katex .sizing.reset-size3.size1{font-size:.71428571em}.katex .fontsize-ensurer.reset-size3.size2,.katex .sizing.reset-size3.size2{font-size:.85714286em}.katex .fontsize-ensurer.reset-size3.size3,.katex .sizing.reset-size3.size3{font-size:1em}.katex .fontsize-ensurer.reset-size3.size4,.katex .sizing.reset-size3.size4{font-size:1.14285714em}.katex .fontsize-ensurer.reset-size3.size5,.katex .sizing.reset-size3.size5{font-size:1.28571429em}.katex .fontsize-ensurer.reset-size3.size6,.katex .sizing.reset-size3.size6{font-size:1.42857143em}.katex .fontsize-ensurer.reset-size3.size7,.katex .sizing.reset-size3.size7{font-size:1.71428571em}.katex .fontsize-ensurer.reset-size3.size8,.katex .sizing.reset-size3.size8{font-size:2.05714286em}.katex .fontsize-ensurer.reset-size3.size9,.katex .sizing.reset-size3.size9{font-size:2.46857143em}.katex .fontsize-ensurer.reset-size3.size10,.katex .sizing.reset-size3.size10{font-size:2.96285714em}.katex .fontsize-ensurer.reset-size3.size11,.katex .sizing.reset-size3.size11{font-size:3.55428571em}.katex .fontsize-ensurer.reset-size4.size1,.katex .sizing.reset-size4.size1{font-size:.625em}.katex .fontsize-ensurer.reset-size4.size2,.katex .sizing.reset-size4.size2{font-size:.75em}.katex .fontsize-ensurer.reset-size4.size3,.katex .sizing.reset-size4.size3{font-size:.875em}.katex .fontsize-ensurer.reset-size4.size4,.katex .sizing.reset-size4.size4{font-size:1em}.katex .fontsize-ensurer.reset-size4.size5,.katex .sizing.reset-size4.size5{font-size:1.125em}.katex .fontsize-ensurer.reset-size4.size6,.katex .sizing.reset-size4.size6{font-size:1.25em}.katex .fontsize-ensurer.reset-size4.size7,.katex .sizing.reset-size4.size7{font-size:1.5em}.katex .fontsize-ensurer.reset-size4.size8,.katex .sizing.reset-size4.size8{font-size:1.8em}.katex .fontsize-ensurer.reset-size4.size9,.katex .sizing.reset-size4.size9{font-size:2.16em}.katex .fontsize-ensurer.reset-size4.size10,.katex .sizing.reset-size4.size10{font-size:2.5925em}.katex .fontsize-ensurer.reset-size4.size11,.katex .sizing.reset-size4.size11{font-size:3.11em}.katex .fontsize-ensurer.reset-size5.size1,.katex .sizing.reset-size5.size1{font-size:.55555556em}.katex .fontsize-ensurer.reset-size5.size2,.katex .sizing.reset-size5.size2{font-size:.66666667em}.katex .fontsize-ensurer.reset-size5.size3,.katex .sizing.reset-size5.size3{font-size:.77777778em}.katex .fontsize-ensurer.reset-size5.size4,.katex .sizing.reset-size5.size4{font-size:.88888889em}.katex .fontsize-ensurer.reset-size5.size5,.katex .sizing.reset-size5.size5{font-size:1em}.katex .fontsize-ensurer.reset-size5.size6,.katex .sizing.reset-size5.size6{font-size:1.11111111em}.katex .fontsize-ensurer.reset-size5.size7,.katex .sizing.reset-size5.size7{font-size:1.33333333em}.katex .fontsize-ensurer.reset-size5.size8,.katex .sizing.reset-size5.size8{font-size:1.6em}.katex .fontsize-ensurer.reset-size5.size9,.katex .sizing.reset-size5.size9{font-size:1.92em}.katex .fontsize-ensurer.reset-size5.size10,.katex .sizing.reset-size5.size10{font-size:2.30444444em}.katex .fontsize-ensurer.reset-size5.size11,.katex .sizing.reset-size5.size11{font-size:2.76444444em}.katex .fontsize-ensurer.reset-size6.size1,.katex .sizing.reset-size6.size1{font-size:.5em}.katex .fontsize-ensurer.reset-size6.size2,.katex .sizing.reset-size6.size2{font-size:.6em}.katex .fontsize-ensurer.reset-size6.size3,.katex .sizing.reset-size6.size3{font-size:.7em}.katex .fontsize-ensurer.reset-size6.size4,.katex .sizing.reset-size6.size4{font-size:.8em}.katex .fontsize-ensurer.reset-size6.size5,.katex .sizing.reset-size6.size5{font-size:.9em}.katex .fontsize-ensurer.reset-size6.size6,.katex .sizing.reset-size6.size6{font-size:1em}.katex .fontsize-ensurer.reset-size6.size7,.katex .sizing.reset-size6.size7{font-size:1.2em}.katex .fontsize-ensurer.reset-size6.size8,.katex .sizing.reset-size6.size8{font-size:1.44em}.katex .fontsize-ensurer.reset-size6.size9,.katex .sizing.reset-size6.size9{font-size:1.728em}.katex .fontsize-ensurer.reset-size6.size10,.katex .sizing.reset-size6.size10{font-size:2.074em}.katex .fontsize-ensurer.reset-size6.size11,.katex .sizing.reset-size6.size11{font-size:2.488em}.katex .fontsize-ensurer.reset-size7.size1,.katex .sizing.reset-size7.size1{font-size:.41666667em}.katex .fontsize-ensurer.reset-size7.size2,.katex .sizing.reset-size7.size2{font-size:.5em}.katex .fontsize-ensurer.reset-size7.size3,.katex .sizing.reset-size7.size3{font-size:.58333333em}.katex .fontsize-ensurer.reset-size7.size4,.katex .sizing.reset-size7.size4{font-size:.66666667em}.katex .fontsize-ensurer.reset-size7.size5,.katex .sizing.reset-size7.size5{font-size:.75em}.katex .fontsize-ensurer.reset-size7.size6,.katex .sizing.reset-size7.size6{font-size:.83333333em}.katex .fontsize-ensurer.reset-size7.size7,.katex .sizing.reset-size7.size7{font-size:1em}.katex .fontsize-ensurer.reset-size7.size8,.katex .sizing.reset-size7.size8{font-size:1.2em}.katex .fontsize-ensurer.reset-size7.size9,.katex .sizing.reset-size7.size9{font-size:1.44em}.katex .fontsize-ensurer.reset-size7.size10,.katex .sizing.reset-size7.size10{font-size:1.72833333em}.katex .fontsize-ensurer.reset-size7.size11,.katex .sizing.reset-size7.size11{font-size:2.07333333em}.katex .fontsize-ensurer.reset-size8.size1,.katex .sizing.reset-size8.size1{font-size:.34722222em}.katex .fontsize-ensurer.reset-size8.size2,.katex .sizing.reset-size8.size2{font-size:.41666667em}.katex .fontsize-ensurer.reset-size8.size3,.katex .sizing.reset-size8.size3{font-size:.48611111em}.katex .fontsize-ensurer.reset-size8.size4,.katex .sizing.reset-size8.size4{font-size:.55555556em}.katex .fontsize-ensurer.reset-size8.size5,.katex .sizing.reset-size8.size5{font-size:.625em}.katex .fontsize-ensurer.reset-size8.size6,.katex .sizing.reset-size8.size6{font-size:.69444444em}.katex .fontsize-ensurer.reset-size8.size7,.katex .sizing.reset-size8.size7{font-size:.83333333em}.katex .fontsize-ensurer.reset-size8.size8,.katex .sizing.reset-size8.size8{font-size:1em}.katex .fontsize-ensurer.reset-size8.size9,.katex .sizing.reset-size8.size9{font-size:1.2em}.katex .fontsize-ensurer.reset-size8.size10,.katex .sizing.reset-size8.size10{font-size:1.44027778em}.katex .fontsize-ensurer.reset-size8.size11,.katex .sizing.reset-size8.size11{font-size:1.72777778em}.katex .fontsize-ensurer.reset-size9.size1,.katex .sizing.reset-size9.size1{font-size:.28935185em}.katex .fontsize-ensurer.reset-size9.size2,.katex .sizing.reset-size9.size2{font-size:.34722222em}.katex .fontsize-ensurer.reset-size9.size3,.katex .sizing.reset-size9.size3{font-size:.40509259em}.katex .fontsize-ensurer.reset-size9.size4,.katex .sizing.reset-size9.size4{font-size:.46296296em}.katex .fontsize-ensurer.reset-size9.size5,.katex .sizing.reset-size9.size5{font-size:.52083333em}.katex .fontsize-ensurer.reset-size9.size6,.katex .sizing.reset-size9.size6{font-size:.5787037em}.katex .fontsize-ensurer.reset-size9.size7,.katex .sizing.reset-size9.size7{font-size:.69444444em}.katex .fontsize-ensurer.reset-size9.size8,.katex .sizing.reset-size9.size8{font-size:.83333333em}.katex .fontsize-ensurer.reset-size9.size9,.katex .sizing.reset-size9.size9{font-size:1em}.katex .fontsize-ensurer.reset-size9.size10,.katex .sizing.reset-size9.size10{font-size:1.20023148em}.katex .fontsize-ensurer.reset-size9.size11,.katex .sizing.reset-size9.size11{font-size:1.43981481em}.katex .fontsize-ensurer.reset-size10.size1,.katex .sizing.reset-size10.size1{font-size:.24108004em}.katex .fontsize-ensurer.reset-size10.size2,.katex .sizing.reset-size10.size2{font-size:.28929605em}.katex .fontsize-ensurer.reset-size10.size3,.katex .sizing.reset-size10.size3{font-size:.33751205em}.katex .fontsize-ensurer.reset-size10.size4,.katex .sizing.reset-size10.size4{font-size:.38572806em}.katex .fontsize-ensurer.reset-size10.size5,.katex .sizing.reset-size10.size5{font-size:.43394407em}.katex .fontsize-ensurer.reset-size10.size6,.katex .sizing.reset-size10.size6{font-size:.48216008em}.katex .fontsize-ensurer.reset-size10.size7,.katex .sizing.reset-size10.size7{font-size:.57859209em}.katex .fontsize-ensurer.reset-size10.size8,.katex .sizing.reset-size10.size8{font-size:.69431051em}.katex .fontsize-ensurer.reset-size10.size9,.katex .sizing.reset-size10.size9{font-size:.83317261em}.katex .fontsize-ensurer.reset-size10.size10,.katex .sizing.reset-size10.size10{font-size:1em}.katex .fontsize-ensurer.reset-size10.size11,.katex .sizing.reset-size10.size11{font-size:1.19961427em}.katex .fontsize-ensurer.reset-size11.size1,.katex .sizing.reset-size11.size1{font-size:.20096463em}.katex .fontsize-ensurer.reset-size11.size2,.katex .sizing.reset-size11.size2{font-size:.24115756em}.katex .fontsize-ensurer.reset-size11.size3,.katex .sizing.reset-size11.size3{font-size:.28135048em}.katex .fontsize-ensurer.reset-size11.size4,.katex .sizing.reset-size11.size4{font-size:.32154341em}.katex .fontsize-ensurer.reset-size11.size5,.katex .sizing.reset-size11.size5{font-size:.36173633em}.katex .fontsize-ensurer.reset-size11.size6,.katex .sizing.reset-size11.size6{font-size:.40192926em}.katex .fontsize-ensurer.reset-size11.size7,.katex .sizing.reset-size11.size7{font-size:.48231511em}.katex .fontsize-ensurer.reset-size11.size8,.katex .sizing.reset-size11.size8{font-size:.57877814em}.katex .fontsize-ensurer.reset-size11.size9,.katex .sizing.reset-size11.size9{font-size:.69453376em}.katex .fontsize-ensurer.reset-size11.size10,.katex .sizing.reset-size11.size10{font-size:.83360129em}.katex .fontsize-ensurer.reset-size11.size11,.katex .sizing.reset-size11.size11{font-size:1em}.katex .delimsizing.size1{font-family:KaTeX_Size1}.katex .delimsizing.size2{font-family:KaTeX_Size2}.katex .delimsizing.size3{font-family:KaTeX_Size3}.katex .delimsizing.size4{font-family:KaTeX_Size4}.katex .delimsizing.mult .delim-size1>span{font-family:KaTeX_Size1}.katex .delimsizing.mult .delim-size4>span{font-family:KaTeX_Size4}.katex .nulldelimiter{display:inline-block;width:.12em}.katex .delimcenter,.katex .op-symbol{position:relative}.katex .op-symbol.small-op{font-family:KaTeX_Size1}.katex .op-symbol.large-op{font-family:KaTeX_Size2}.katex .op-limits>.vlist-t{text-align:center}.katex .accent>.vlist-t{text-align:center}.katex .accent .accent-body{position:relative}.katex .accent .accent-body:not(.accent-full){width:0}.katex .overlay{display:block}.katex .mtable .vertical-separator{display:inline-block;min-width:1px}.katex .mtable .arraycolsep{display:inline-block}.katex .mtable .col-align-c>.vlist-t{text-align:center}.katex .mtable .col-align-l>.vlist-t{text-align:left}.katex .mtable .col-align-r>.vlist-t{text-align:right}.katex .svg-align{text-align:left}.katex svg{display:block;position:absolute;width:100%;height:inherit;fill:currentColor;stroke:currentColor;fill-rule:nonzero;fill-opacity:1;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1}.katex svg path{stroke:none}.katex img{border-style:none;min-width:0;min-height:0;max-width:none;max-height:none}.katex .stretchy{width:100%;display:block;position:relative;overflow:hidden}.katex .stretchy:after,.katex .stretchy:before{content:""}.katex .hide-tail{width:100%;position:relative;overflow:hidden}.katex .halfarrow-left{position:absolute;left:0;width:50.2%;overflow:hidden}.katex .halfarrow-right{position:absolute;right:0;width:50.2%;overflow:hidden}.katex .brace-left{position:absolute;left:0;width:25.1%;overflow:hidden}.katex .brace-center{position:absolute;left:25%;width:50%;overflow:hidden}.katex .brace-right{position:absolute;right:0;width:25.1%;overflow:hidden}.katex .x-arrow-pad{padding:0 .5em}.katex .mover,.katex .munder,.katex .x-arrow{text-align:center}.katex .boxpad{padding:0 .3em}.katex .fbox,.katex .fcolorbox{box-sizing:border-box;border:.04em solid}.katex .cancel-pad{padding:0 .2em}.katex .cancel-lap{margin-left:-.2em;margin-right:-.2em}.katex .sout{border-bottom-style:solid;border-bottom-width:.08em}.katex-display{display:block;margin:1em 0;text-align:center}.katex-display>.katex{display:block;text-align:center;white-space:nowrap}.katex-display>.katex>.katex-html{display:block;position:relative}.katex-display>.katex>.katex-html>.tag{position:absolute;right:0}.katex-display.leqno>.katex>.katex-html>.tag{left:0;right:auto}.katex-display.fleqn>.katex{text-align:left} diff --git a/adoc/katex/katex.min.js b/adoc/katex/katex.min.js new file mode 100644 index 00000000..906ce128 --- /dev/null +++ b/adoc/katex/katex.min.js @@ -0,0 +1 @@ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.katex=e():t.katex=e()}("undefined"!=typeof self?self:this,function(){return function(t){var e={};function r(a){if(e[a])return e[a].exports;var n=e[a]={i:a,l:!1,exports:{}};return t[a].call(n.exports,n,n.exports,r),n.l=!0,n.exports}return r.m=t,r.c=e,r.d=function(t,e,a){r.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:a})},r.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},r.t=function(t,e){if(1&e&&(t=r(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var a=Object.create(null);if(r.r(a),Object.defineProperty(a,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var n in t)r.d(a,n,function(e){return t[e]}.bind(null,n));return a},r.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return r.d(e,"a",e),e},r.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},r.p="",r(r.s=1)}([function(t,e,r){},function(t,e,r){"use strict";r.r(e);r(0);var a=function(){function t(t,e,r){this.lexer=void 0,this.start=void 0,this.end=void 0,this.lexer=t,this.start=e,this.end=r}return t.range=function(e,r){return r?e&&e.loc&&r.loc&&e.loc.lexer===r.loc.lexer?new t(e.loc.lexer,e.loc.start,r.loc.end):null:e&&e.loc},t}(),n=function(){function t(t,e){this.text=void 0,this.loc=void 0,this.text=t,this.loc=e}return t.prototype.range=function(e,r){return new t(r,a.range(this,e))},t}(),i=function t(e,r){this.position=void 0;var a,n="KaTeX parse error: "+e,i=r&&r.loc;if(i&&i.start<=i.end){var o=i.lexer.input;a=i.start;var s=i.end;a===o.length?n+=" at end of input: ":n+=" at position "+(a+1)+": ";var h=o.slice(a,s).replace(/[^]/g,"$&\u0332");n+=(a>15?"\u2026"+o.slice(a-15,a):o.slice(0,a))+h+(s+15":">","<":"<",'"':""","'":"'"},l=/[&><"']/g;var m=function t(e){return"ordgroup"===e.type?1===e.body.length?t(e.body[0]):e:"color"===e.type?1===e.body.length?t(e.body[0]):e:"font"===e.type?t(e.body):e},c={contains:function(t,e){return-1!==t.indexOf(e)},deflt:function(t,e){return void 0===t?e:t},escape:function(t){return String(t).replace(l,function(t){return h[t]})},hyphenate:function(t){return t.replace(s,"-$1").toLowerCase()},getBaseElem:m,isCharacterBox:function(t){var e=m(t);return"mathord"===e.type||"textord"===e.type||"atom"===e.type},protocolFromUrl:function(t){var e=/^\s*([^\\\/#]*?)(?::|�*58|�*3a)/i.exec(t);return null!=e?e[1]:"_relative"}},u=function(){function t(t){this.displayMode=void 0,this.output=void 0,this.leqno=void 0,this.fleqn=void 0,this.throwOnError=void 0,this.errorColor=void 0,this.macros=void 0,this.minRuleThickness=void 0,this.colorIsTextColor=void 0,this.strict=void 0,this.trust=void 0,this.maxSize=void 0,this.maxExpand=void 0,t=t||{},this.displayMode=c.deflt(t.displayMode,!1),this.output=c.deflt(t.output,"htmlAndMathml"),this.leqno=c.deflt(t.leqno,!1),this.fleqn=c.deflt(t.fleqn,!1),this.throwOnError=c.deflt(t.throwOnError,!0),this.errorColor=c.deflt(t.errorColor,"#cc0000"),this.macros=t.macros||{},this.minRuleThickness=Math.max(0,c.deflt(t.minRuleThickness,0)),this.colorIsTextColor=c.deflt(t.colorIsTextColor,!1),this.strict=c.deflt(t.strict,"warn"),this.trust=c.deflt(t.trust,!1),this.maxSize=Math.max(0,c.deflt(t.maxSize,1/0)),this.maxExpand=Math.max(0,c.deflt(t.maxExpand,1e3))}var e=t.prototype;return e.reportNonstrict=function(t,e,r){var a=this.strict;if("function"==typeof a&&(a=a(t,e,r)),a&&"ignore"!==a){if(!0===a||"error"===a)throw new o("LaTeX-incompatible input and strict mode is set to 'error': "+e+" ["+t+"]",r);"warn"===a?"undefined"!=typeof console&&console.warn("LaTeX-incompatible input and strict mode is set to 'warn': "+e+" ["+t+"]"):"undefined"!=typeof console&&console.warn("LaTeX-incompatible input and strict mode is set to unrecognized '"+a+"': "+e+" ["+t+"]")}},e.useStrictBehavior=function(t,e,r){var a=this.strict;if("function"==typeof a)try{a=a(t,e,r)}catch(t){a="error"}return!(!a||"ignore"===a)&&(!0===a||"error"===a||("warn"===a?("undefined"!=typeof console&&console.warn("LaTeX-incompatible input and strict mode is set to 'warn': "+e+" ["+t+"]"),!1):("undefined"!=typeof console&&console.warn("LaTeX-incompatible input and strict mode is set to unrecognized '"+a+"': "+e+" ["+t+"]"),!1)))},e.isTrusted=function(t){t.url&&!t.protocol&&(t.protocol=c.protocolFromUrl(t.url));var e="function"==typeof this.trust?this.trust(t):this.trust;return Boolean(e)},t}(),p=function(){function t(t,e,r){this.id=void 0,this.size=void 0,this.cramped=void 0,this.id=t,this.size=e,this.cramped=r}var e=t.prototype;return e.sup=function(){return d[f[this.id]]},e.sub=function(){return d[g[this.id]]},e.fracNum=function(){return d[x[this.id]]},e.fracDen=function(){return d[v[this.id]]},e.cramp=function(){return d[b[this.id]]},e.text=function(){return d[y[this.id]]},e.isTight=function(){return this.size>=2},t}(),d=[new p(0,0,!1),new p(1,0,!0),new p(2,1,!1),new p(3,1,!0),new p(4,2,!1),new p(5,2,!0),new p(6,3,!1),new p(7,3,!0)],f=[4,5,4,5,6,7,6,7],g=[5,5,5,5,7,7,7,7],x=[2,3,4,5,6,7,6,7],v=[3,3,5,5,7,7,7,7],b=[1,1,3,3,5,5,7,7],y=[0,1,2,3,2,3,2,3],w={DISPLAY:d[0],TEXT:d[2],SCRIPT:d[4],SCRIPTSCRIPT:d[6]},k=[{name:"latin",blocks:[[256,591],[768,879]]},{name:"cyrillic",blocks:[[1024,1279]]},{name:"brahmic",blocks:[[2304,4255]]},{name:"georgian",blocks:[[4256,4351]]},{name:"cjk",blocks:[[12288,12543],[19968,40879],[65280,65376]]},{name:"hangul",blocks:[[44032,55215]]}];var S=[];function M(t){for(var e=0;e=S[e]&&t<=S[e+1])return!0;return!1}k.forEach(function(t){return t.blocks.forEach(function(t){return S.push.apply(S,t)})});var z={doubleleftarrow:"M262 157\nl10-10c34-36 62.7-77 86-123 3.3-8 5-13.3 5-16 0-5.3-6.7-8-20-8-7.3\n 0-12.2.5-14.5 1.5-2.3 1-4.8 4.5-7.5 10.5-49.3 97.3-121.7 169.3-217 216-28\n 14-57.3 25-88 33-6.7 2-11 3.8-13 5.5-2 1.7-3 4.2-3 7.5s1 5.8 3 7.5\nc2 1.7 6.3 3.5 13 5.5 68 17.3 128.2 47.8 180.5 91.5 52.3 43.7 93.8 96.2 124.5\n 157.5 9.3 8 15.3 12.3 18 13h6c12-.7 18-4 18-10 0-2-1.7-7-5-15-23.3-46-52-87\n-86-123l-10-10h399738v-40H218c328 0 0 0 0 0l-10-8c-26.7-20-65.7-43-117-69 2.7\n-2 6-3.7 10-5 36.7-16 72.3-37.3 107-64l10-8h399782v-40z\nm8 0v40h399730v-40zm0 194v40h399730v-40z",doublerightarrow:"M399738 392l\n-10 10c-34 36-62.7 77-86 123-3.3 8-5 13.3-5 16 0 5.3 6.7 8 20 8 7.3 0 12.2-.5\n 14.5-1.5 2.3-1 4.8-4.5 7.5-10.5 49.3-97.3 121.7-169.3 217-216 28-14 57.3-25 88\n-33 6.7-2 11-3.8 13-5.5 2-1.7 3-4.2 3-7.5s-1-5.8-3-7.5c-2-1.7-6.3-3.5-13-5.5-68\n-17.3-128.2-47.8-180.5-91.5-52.3-43.7-93.8-96.2-124.5-157.5-9.3-8-15.3-12.3-18\n-13h-6c-12 .7-18 4-18 10 0 2 1.7 7 5 15 23.3 46 52 87 86 123l10 10H0v40h399782\nc-328 0 0 0 0 0l10 8c26.7 20 65.7 43 117 69-2.7 2-6 3.7-10 5-36.7 16-72.3 37.3\n-107 64l-10 8H0v40zM0 157v40h399730v-40zm0 194v40h399730v-40z",leftarrow:"M400000 241H110l3-3c68.7-52.7 113.7-120\n 135-202 4-14.7 6-23 6-25 0-7.3-7-11-21-11-8 0-13.2.8-15.5 2.5-2.3 1.7-4.2 5.8\n-5.5 12.5-1.3 4.7-2.7 10.3-4 17-12 48.7-34.8 92-68.5 130S65.3 228.3 18 247\nc-10 4-16 7.7-18 11 0 8.7 6 14.3 18 17 47.3 18.7 87.8 47 121.5 85S196 441.3 208\n 490c.7 2 1.3 5 2 9s1.2 6.7 1.5 8c.3 1.3 1 3.3 2 6s2.2 4.5 3.5 5.5c1.3 1 3.3\n 1.8 6 2.5s6 1 10 1c14 0 21-3.7 21-11 0-2-2-10.3-6-25-20-79.3-65-146.7-135-202\n l-3-3h399890zM100 241v40h399900v-40z",leftbrace:"M6 548l-6-6v-35l6-11c56-104 135.3-181.3 238-232 57.3-28.7 117\n-45 179-50h399577v120H403c-43.3 7-81 15-113 26-100.7 33-179.7 91-237 174-2.7\n 5-6 9-10 13-.7 1-7.3 1-20 1H6z",leftbraceunder:"M0 6l6-6h17c12.688 0 19.313.3 20 1 4 4 7.313 8.3 10 13\n 35.313 51.3 80.813 93.8 136.5 127.5 55.688 33.7 117.188 55.8 184.5 66.5.688\n 0 2 .3 4 1 18.688 2.7 76 4.3 172 5h399450v120H429l-6-1c-124.688-8-235-61.7\n-331-161C60.687 138.7 32.312 99.3 7 54L0 41V6z",leftgroup:"M400000 80\nH435C64 80 168.3 229.4 21 260c-5.9 1.2-18 0-18 0-2 0-3-1-3-3v-38C76 61 257 0\n 435 0h399565z",leftgroupunder:"M400000 262\nH435C64 262 168.3 112.6 21 82c-5.9-1.2-18 0-18 0-2 0-3 1-3 3v38c76 158 257 219\n 435 219h399565z",leftharpoon:"M0 267c.7 5.3 3 10 7 14h399993v-40H93c3.3\n-3.3 10.2-9.5 20.5-18.5s17.8-15.8 22.5-20.5c50.7-52 88-110.3 112-175 4-11.3 5\n-18.3 3-21-1.3-4-7.3-6-18-6-8 0-13 .7-15 2s-4.7 6.7-8 16c-42 98.7-107.3 174.7\n-196 228-6.7 4.7-10.7 8-12 10-1.3 2-2 5.7-2 11zm100-26v40h399900v-40z",leftharpoonplus:"M0 267c.7 5.3 3 10 7 14h399993v-40H93c3.3-3.3 10.2-9.5\n 20.5-18.5s17.8-15.8 22.5-20.5c50.7-52 88-110.3 112-175 4-11.3 5-18.3 3-21-1.3\n-4-7.3-6-18-6-8 0-13 .7-15 2s-4.7 6.7-8 16c-42 98.7-107.3 174.7-196 228-6.7 4.7\n-10.7 8-12 10-1.3 2-2 5.7-2 11zm100-26v40h399900v-40zM0 435v40h400000v-40z\nm0 0v40h400000v-40z",leftharpoondown:"M7 241c-4 4-6.333 8.667-7 14 0 5.333.667 9 2 11s5.333\n 5.333 12 10c90.667 54 156 130 196 228 3.333 10.667 6.333 16.333 9 17 2 .667 5\n 1 9 1h5c10.667 0 16.667-2 18-6 2-2.667 1-9.667-3-21-32-87.333-82.667-157.667\n-152-211l-3-3h399907v-40zM93 281 H400000 v-40L7 241z",leftharpoondownplus:"M7 435c-4 4-6.3 8.7-7 14 0 5.3.7 9 2 11s5.3 5.3 12\n 10c90.7 54 156 130 196 228 3.3 10.7 6.3 16.3 9 17 2 .7 5 1 9 1h5c10.7 0 16.7\n-2 18-6 2-2.7 1-9.7-3-21-32-87.3-82.7-157.7-152-211l-3-3h399907v-40H7zm93 0\nv40h399900v-40zM0 241v40h399900v-40zm0 0v40h399900v-40z",lefthook:"M400000 281 H103s-33-11.2-61-33.5S0 197.3 0 164s14.2-61.2 42.5\n-83.5C70.8 58.2 104 47 142 47 c16.7 0 25 6.7 25 20 0 12-8.7 18.7-26 20-40 3.3\n-68.7 15.7-86 37-10 12-15 25.3-15 40 0 22.7 9.8 40.7 29.5 54 19.7 13.3 43.5 21\n 71.5 23h399859zM103 281v-40h399897v40z",leftlinesegment:"M40 281 V428 H0 V94 H40 V241 H400000 v40z\nM40 281 V428 H0 V94 H40 V241 H400000 v40z",leftmapsto:"M40 281 V448H0V74H40V241H400000v40z\nM40 281 V448H0V74H40V241H400000v40z",leftToFrom:"M0 147h400000v40H0zm0 214c68 40 115.7 95.7 143 167h22c15.3 0 23\n-.3 23-1 0-1.3-5.3-13.7-16-37-18-35.3-41.3-69-70-101l-7-8h399905v-40H95l7-8\nc28.7-32 52-65.7 70-101 10.7-23.3 16-35.7 16-37 0-.7-7.7-1-23-1h-22C115.7 265.3\n 68 321 0 361zm0-174v-40h399900v40zm100 154v40h399900v-40z",longequal:"M0 50 h400000 v40H0z m0 194h40000v40H0z\nM0 50 h400000 v40H0z m0 194h40000v40H0z",midbrace:"M200428 334\nc-100.7-8.3-195.3-44-280-108-55.3-42-101.7-93-139-153l-9-14c-2.7 4-5.7 8.7-9 14\n-53.3 86.7-123.7 153-211 199-66.7 36-137.3 56.3-212 62H0V214h199568c178.3-11.7\n 311.7-78.3 403-201 6-8 9.7-12 11-12 .7-.7 6.7-1 18-1s17.3.3 18 1c1.3 0 5 4 11\n 12 44.7 59.3 101.3 106.3 170 141s145.3 54.3 229 60h199572v120z",midbraceunder:"M199572 214\nc100.7 8.3 195.3 44 280 108 55.3 42 101.7 93 139 153l9 14c2.7-4 5.7-8.7 9-14\n 53.3-86.7 123.7-153 211-199 66.7-36 137.3-56.3 212-62h199568v120H200432c-178.3\n 11.7-311.7 78.3-403 201-6 8-9.7 12-11 12-.7.7-6.7 1-18 1s-17.3-.3-18-1c-1.3 0\n-5-4-11-12-44.7-59.3-101.3-106.3-170-141s-145.3-54.3-229-60H0V214z",oiintSize1:"M512.6 71.6c272.6 0 320.3 106.8 320.3 178.2 0 70.8-47.7 177.6\n-320.3 177.6S193.1 320.6 193.1 249.8c0-71.4 46.9-178.2 319.5-178.2z\nm368.1 178.2c0-86.4-60.9-215.4-368.1-215.4-306.4 0-367.3 129-367.3 215.4 0 85.8\n60.9 214.8 367.3 214.8 307.2 0 368.1-129 368.1-214.8z",oiintSize2:"M757.8 100.1c384.7 0 451.1 137.6 451.1 230 0 91.3-66.4 228.8\n-451.1 228.8-386.3 0-452.7-137.5-452.7-228.8 0-92.4 66.4-230 452.7-230z\nm502.4 230c0-111.2-82.4-277.2-502.4-277.2s-504 166-504 277.2\nc0 110 84 276 504 276s502.4-166 502.4-276z",oiiintSize1:"M681.4 71.6c408.9 0 480.5 106.8 480.5 178.2 0 70.8-71.6 177.6\n-480.5 177.6S202.1 320.6 202.1 249.8c0-71.4 70.5-178.2 479.3-178.2z\nm525.8 178.2c0-86.4-86.8-215.4-525.7-215.4-437.9 0-524.7 129-524.7 215.4 0\n85.8 86.8 214.8 524.7 214.8 438.9 0 525.7-129 525.7-214.8z",oiiintSize2:"M1021.2 53c603.6 0 707.8 165.8 707.8 277.2 0 110-104.2 275.8\n-707.8 275.8-606 0-710.2-165.8-710.2-275.8C311 218.8 415.2 53 1021.2 53z\nm770.4 277.1c0-131.2-126.4-327.6-770.5-327.6S248.4 198.9 248.4 330.1\nc0 130 128.8 326.4 772.7 326.4s770.5-196.4 770.5-326.4z",rightarrow:"M0 241v40h399891c-47.3 35.3-84 78-110 128\n-16.7 32-27.7 63.7-33 95 0 1.3-.2 2.7-.5 4-.3 1.3-.5 2.3-.5 3 0 7.3 6.7 11 20\n 11 8 0 13.2-.8 15.5-2.5 2.3-1.7 4.2-5.5 5.5-11.5 2-13.3 5.7-27 11-41 14.7-44.7\n 39-84.5 73-119.5s73.7-60.2 119-75.5c6-2 9-5.7 9-11s-3-9-9-11c-45.3-15.3-85\n-40.5-119-75.5s-58.3-74.8-73-119.5c-4.7-14-8.3-27.3-11-40-1.3-6.7-3.2-10.8-5.5\n-12.5-2.3-1.7-7.5-2.5-15.5-2.5-14 0-21 3.7-21 11 0 2 2 10.3 6 25 20.7 83.3 67\n 151.7 139 205zm0 0v40h399900v-40z",rightbrace:"M400000 542l\n-6 6h-17c-12.7 0-19.3-.3-20-1-4-4-7.3-8.3-10-13-35.3-51.3-80.8-93.8-136.5-127.5\ns-117.2-55.8-184.5-66.5c-.7 0-2-.3-4-1-18.7-2.7-76-4.3-172-5H0V214h399571l6 1\nc124.7 8 235 61.7 331 161 31.3 33.3 59.7 72.7 85 118l7 13v35z",rightbraceunder:"M399994 0l6 6v35l-6 11c-56 104-135.3 181.3-238 232-57.3\n 28.7-117 45-179 50H-300V214h399897c43.3-7 81-15 113-26 100.7-33 179.7-91 237\n-174 2.7-5 6-9 10-13 .7-1 7.3-1 20-1h17z",rightgroup:"M0 80h399565c371 0 266.7 149.4 414 180 5.9 1.2 18 0 18 0 2 0\n 3-1 3-3v-38c-76-158-257-219-435-219H0z",rightgroupunder:"M0 262h399565c371 0 266.7-149.4 414-180 5.9-1.2 18 0 18\n 0 2 0 3 1 3 3v38c-76 158-257 219-435 219H0z",rightharpoon:"M0 241v40h399993c4.7-4.7 7-9.3 7-14 0-9.3\n-3.7-15.3-11-18-92.7-56.7-159-133.7-199-231-3.3-9.3-6-14.7-8-16-2-1.3-7-2-15-2\n-10.7 0-16.7 2-18 6-2 2.7-1 9.7 3 21 15.3 42 36.7 81.8 64 119.5 27.3 37.7 58\n 69.2 92 94.5zm0 0v40h399900v-40z",rightharpoonplus:"M0 241v40h399993c4.7-4.7 7-9.3 7-14 0-9.3-3.7-15.3-11\n-18-92.7-56.7-159-133.7-199-231-3.3-9.3-6-14.7-8-16-2-1.3-7-2-15-2-10.7 0-16.7\n 2-18 6-2 2.7-1 9.7 3 21 15.3 42 36.7 81.8 64 119.5 27.3 37.7 58 69.2 92 94.5z\nm0 0v40h399900v-40z m100 194v40h399900v-40zm0 0v40h399900v-40z",rightharpoondown:"M399747 511c0 7.3 6.7 11 20 11 8 0 13-.8 15-2.5s4.7-6.8\n 8-15.5c40-94 99.3-166.3 178-217 13.3-8 20.3-12.3 21-13 5.3-3.3 8.5-5.8 9.5\n-7.5 1-1.7 1.5-5.2 1.5-10.5s-2.3-10.3-7-15H0v40h399908c-34 25.3-64.7 57-92 95\n-27.3 38-48.7 77.7-64 119-3.3 8.7-5 14-5 16zM0 241v40h399900v-40z",rightharpoondownplus:"M399747 705c0 7.3 6.7 11 20 11 8 0 13-.8\n 15-2.5s4.7-6.8 8-15.5c40-94 99.3-166.3 178-217 13.3-8 20.3-12.3 21-13 5.3-3.3\n 8.5-5.8 9.5-7.5 1-1.7 1.5-5.2 1.5-10.5s-2.3-10.3-7-15H0v40h399908c-34 25.3\n-64.7 57-92 95-27.3 38-48.7 77.7-64 119-3.3 8.7-5 14-5 16zM0 435v40h399900v-40z\nm0-194v40h400000v-40zm0 0v40h400000v-40z",righthook:"M399859 241c-764 0 0 0 0 0 40-3.3 68.7-15.7 86-37 10-12 15-25.3\n 15-40 0-22.7-9.8-40.7-29.5-54-19.7-13.3-43.5-21-71.5-23-17.3-1.3-26-8-26-20 0\n-13.3 8.7-20 26-20 38 0 71 11.2 99 33.5 0 0 7 5.6 21 16.7 14 11.2 21 33.5 21\n 66.8s-14 61.2-42 83.5c-28 22.3-61 33.5-99 33.5L0 241z M0 281v-40h399859v40z",rightlinesegment:"M399960 241 V94 h40 V428 h-40 V281 H0 v-40z\nM399960 241 V94 h40 V428 h-40 V281 H0 v-40z",rightToFrom:"M400000 167c-70.7-42-118-97.7-142-167h-23c-15.3 0-23 .3-23\n 1 0 1.3 5.3 13.7 16 37 18 35.3 41.3 69 70 101l7 8H0v40h399905l-7 8c-28.7 32\n-52 65.7-70 101-10.7 23.3-16 35.7-16 37 0 .7 7.7 1 23 1h23c24-69.3 71.3-125 142\n-167z M100 147v40h399900v-40zM0 341v40h399900v-40z",twoheadleftarrow:"M0 167c68 40\n 115.7 95.7 143 167h22c15.3 0 23-.3 23-1 0-1.3-5.3-13.7-16-37-18-35.3-41.3-69\n-70-101l-7-8h125l9 7c50.7 39.3 85 86 103 140h46c0-4.7-6.3-18.7-19-42-18-35.3\n-40-67.3-66-96l-9-9h399716v-40H284l9-9c26-28.7 48-60.7 66-96 12.7-23.333 19\n-37.333 19-42h-46c-18 54-52.3 100.7-103 140l-9 7H95l7-8c28.7-32 52-65.7 70-101\n 10.7-23.333 16-35.7 16-37 0-.7-7.7-1-23-1h-22C115.7 71.3 68 127 0 167z",twoheadrightarrow:"M400000 167\nc-68-40-115.7-95.7-143-167h-22c-15.3 0-23 .3-23 1 0 1.3 5.3 13.7 16 37 18 35.3\n 41.3 69 70 101l7 8h-125l-9-7c-50.7-39.3-85-86-103-140h-46c0 4.7 6.3 18.7 19 42\n 18 35.3 40 67.3 66 96l9 9H0v40h399716l-9 9c-26 28.7-48 60.7-66 96-12.7 23.333\n-19 37.333-19 42h46c18-54 52.3-100.7 103-140l9-7h125l-7 8c-28.7 32-52 65.7-70\n 101-10.7 23.333-16 35.7-16 37 0 .7 7.7 1 23 1h22c27.3-71.3 75-127 143-167z",tilde1:"M200 55.538c-77 0-168 73.953-177 73.953-3 0-7\n-2.175-9-5.437L2 97c-1-2-2-4-2-6 0-4 2-7 5-9l20-12C116 12 171 0 207 0c86 0\n 114 68 191 68 78 0 168-68 177-68 4 0 7 2 9 5l12 19c1 2.175 2 4.35 2 6.525 0\n 4.35-2 7.613-5 9.788l-19 13.05c-92 63.077-116.937 75.308-183 76.128\n-68.267.847-113-73.952-191-73.952z",tilde2:"M344 55.266c-142 0-300.638 81.316-311.5 86.418\n-8.01 3.762-22.5 10.91-23.5 5.562L1 120c-1-2-1-3-1-4 0-5 3-9 8-10l18.4-9C160.9\n 31.9 283 0 358 0c148 0 188 122 331 122s314-97 326-97c4 0 8 2 10 7l7 21.114\nc1 2.14 1 3.21 1 4.28 0 5.347-3 9.626-7 10.696l-22.3 12.622C852.6 158.372 751\n 181.476 676 181.476c-149 0-189-126.21-332-126.21z",tilde3:"M786 59C457 59 32 175.242 13 175.242c-6 0-10-3.457\n-11-10.37L.15 138c-1-7 3-12 10-13l19.2-6.4C378.4 40.7 634.3 0 804.3 0c337 0\n 411.8 157 746.8 157 328 0 754-112 773-112 5 0 10 3 11 9l1 14.075c1 8.066-.697\n 16.595-6.697 17.492l-21.052 7.31c-367.9 98.146-609.15 122.696-778.15 122.696\n -338 0-409-156.573-744-156.573z",tilde4:"M786 58C457 58 32 177.487 13 177.487c-6 0-10-3.345\n-11-10.035L.15 143c-1-7 3-12 10-13l22-6.7C381.2 35 637.15 0 807.15 0c337 0 409\n 177 744 177 328 0 754-127 773-127 5 0 10 3 11 9l1 14.794c1 7.805-3 13.38-9\n 14.495l-20.7 5.574c-366.85 99.79-607.3 139.372-776.3 139.372-338 0-409\n -175.236-744-175.236z",vec:"M377 20c0-5.333 1.833-10 5.5-14S391 0 397 0c4.667 0 8.667 1.667 12 5\n3.333 2.667 6.667 9 10 19 6.667 24.667 20.333 43.667 41 57 7.333 4.667 11\n10.667 11 18 0 6-1 10-3 12s-6.667 5-14 9c-28.667 14.667-53.667 35.667-75 63\n-1.333 1.333-3.167 3.5-5.5 6.5s-4 4.833-5 5.5c-1 .667-2.5 1.333-4.5 2s-4.333 1\n-7 1c-4.667 0-9.167-1.833-13.5-5.5S337 184 337 178c0-12.667 15.667-32.333 47-59\nH213l-171-1c-8.667-6-13-12.333-13-19 0-4.667 4.333-11.333 13-20h359\nc-16-25.333-24-45-24-59z",widehat1:"M529 0h5l519 115c5 1 9 5 9 10 0 1-1 2-1 3l-4 22\nc-1 5-5 9-11 9h-2L532 67 19 159h-2c-5 0-9-4-11-9l-5-22c-1-6 2-12 8-13z",widehat2:"M1181 0h2l1171 176c6 0 10 5 10 11l-2 23c-1 6-5 10\n-11 10h-1L1182 67 15 220h-1c-6 0-10-4-11-10l-2-23c-1-6 4-11 10-11z",widehat3:"M1181 0h2l1171 236c6 0 10 5 10 11l-2 23c-1 6-5 10\n-11 10h-1L1182 67 15 280h-1c-6 0-10-4-11-10l-2-23c-1-6 4-11 10-11z",widehat4:"M1181 0h2l1171 296c6 0 10 5 10 11l-2 23c-1 6-5 10\n-11 10h-1L1182 67 15 340h-1c-6 0-10-4-11-10l-2-23c-1-6 4-11 10-11z",widecheck1:"M529,159h5l519,-115c5,-1,9,-5,9,-10c0,-1,-1,-2,-1,-3l-4,-22c-1,\n-5,-5,-9,-11,-9h-2l-512,92l-513,-92h-2c-5,0,-9,4,-11,9l-5,22c-1,6,2,12,8,13z",widecheck2:"M1181,220h2l1171,-176c6,0,10,-5,10,-11l-2,-23c-1,-6,-5,-10,\n-11,-10h-1l-1168,153l-1167,-153h-1c-6,0,-10,4,-11,10l-2,23c-1,6,4,11,10,11z",widecheck3:"M1181,280h2l1171,-236c6,0,10,-5,10,-11l-2,-23c-1,-6,-5,-10,\n-11,-10h-1l-1168,213l-1167,-213h-1c-6,0,-10,4,-11,10l-2,23c-1,6,4,11,10,11z",widecheck4:"M1181,340h2l1171,-296c6,0,10,-5,10,-11l-2,-23c-1,-6,-5,-10,\n-11,-10h-1l-1168,273l-1167,-273h-1c-6,0,-10,4,-11,10l-2,23c-1,6,4,11,10,11z",baraboveleftarrow:"M400000 620h-399890l3 -3c68.7 -52.7 113.7 -120 135 -202\nc4 -14.7 6 -23 6 -25c0 -7.3 -7 -11 -21 -11c-8 0 -13.2 0.8 -15.5 2.5\nc-2.3 1.7 -4.2 5.8 -5.5 12.5c-1.3 4.7 -2.7 10.3 -4 17c-12 48.7 -34.8 92 -68.5 130\ns-74.2 66.3 -121.5 85c-10 4 -16 7.7 -18 11c0 8.7 6 14.3 18 17c47.3 18.7 87.8 47\n121.5 85s56.5 81.3 68.5 130c0.7 2 1.3 5 2 9s1.2 6.7 1.5 8c0.3 1.3 1 3.3 2 6\ns2.2 4.5 3.5 5.5c1.3 1 3.3 1.8 6 2.5s6 1 10 1c14 0 21 -3.7 21 -11\nc0 -2 -2 -10.3 -6 -25c-20 -79.3 -65 -146.7 -135 -202l-3 -3h399890z\nM100 620v40h399900v-40z M0 241v40h399900v-40zM0 241v40h399900v-40z",rightarrowabovebar:"M0 241v40h399891c-47.3 35.3-84 78-110 128-16.7 32\n-27.7 63.7-33 95 0 1.3-.2 2.7-.5 4-.3 1.3-.5 2.3-.5 3 0 7.3 6.7 11 20 11 8 0\n13.2-.8 15.5-2.5 2.3-1.7 4.2-5.5 5.5-11.5 2-13.3 5.7-27 11-41 14.7-44.7 39\n-84.5 73-119.5s73.7-60.2 119-75.5c6-2 9-5.7 9-11s-3-9-9-11c-45.3-15.3-85-40.5\n-119-75.5s-58.3-74.8-73-119.5c-4.7-14-8.3-27.3-11-40-1.3-6.7-3.2-10.8-5.5\n-12.5-2.3-1.7-7.5-2.5-15.5-2.5-14 0-21 3.7-21 11 0 2 2 10.3 6 25 20.7 83.3 67\n151.7 139 205zm96 379h399894v40H0zm0 0h399904v40H0z",baraboveshortleftharpoon:"M507,435c-4,4,-6.3,8.7,-7,14c0,5.3,0.7,9,2,11\nc1.3,2,5.3,5.3,12,10c90.7,54,156,130,196,228c3.3,10.7,6.3,16.3,9,17\nc2,0.7,5,1,9,1c0,0,5,0,5,0c10.7,0,16.7,-2,18,-6c2,-2.7,1,-9.7,-3,-21\nc-32,-87.3,-82.7,-157.7,-152,-211c0,0,-3,-3,-3,-3l399351,0l0,-40\nc-398570,0,-399437,0,-399437,0z M593 435 v40 H399500 v-40z\nM0 281 v-40 H399908 v40z M0 281 v-40 H399908 v40z",rightharpoonaboveshortbar:"M0,241 l0,40c399126,0,399993,0,399993,0\nc4.7,-4.7,7,-9.3,7,-14c0,-9.3,-3.7,-15.3,-11,-18c-92.7,-56.7,-159,-133.7,-199,\n-231c-3.3,-9.3,-6,-14.7,-8,-16c-2,-1.3,-7,-2,-15,-2c-10.7,0,-16.7,2,-18,6\nc-2,2.7,-1,9.7,3,21c15.3,42,36.7,81.8,64,119.5c27.3,37.7,58,69.2,92,94.5z\nM0 241 v40 H399908 v-40z M0 475 v-40 H399500 v40z M0 475 v-40 H399500 v40z",shortbaraboveleftharpoon:"M7,435c-4,4,-6.3,8.7,-7,14c0,5.3,0.7,9,2,11\nc1.3,2,5.3,5.3,12,10c90.7,54,156,130,196,228c3.3,10.7,6.3,16.3,9,17c2,0.7,5,1,9,\n1c0,0,5,0,5,0c10.7,0,16.7,-2,18,-6c2,-2.7,1,-9.7,-3,-21c-32,-87.3,-82.7,-157.7,\n-152,-211c0,0,-3,-3,-3,-3l399907,0l0,-40c-399126,0,-399993,0,-399993,0z\nM93 435 v40 H400000 v-40z M500 241 v40 H400000 v-40z M500 241 v40 H400000 v-40z",shortrightharpoonabovebar:"M53,241l0,40c398570,0,399437,0,399437,0\nc4.7,-4.7,7,-9.3,7,-14c0,-9.3,-3.7,-15.3,-11,-18c-92.7,-56.7,-159,-133.7,-199,\n-231c-3.3,-9.3,-6,-14.7,-8,-16c-2,-1.3,-7,-2,-15,-2c-10.7,0,-16.7,2,-18,6\nc-2,2.7,-1,9.7,3,21c15.3,42,36.7,81.8,64,119.5c27.3,37.7,58,69.2,92,94.5z\nM500 241 v40 H399408 v-40z M500 435 v40 H400000 v-40z"},A=function(){function t(t){this.children=void 0,this.classes=void 0,this.height=void 0,this.depth=void 0,this.maxFontSize=void 0,this.style=void 0,this.children=t,this.classes=[],this.height=0,this.depth=0,this.maxFontSize=0,this.style={}}var e=t.prototype;return e.hasClass=function(t){return c.contains(this.classes,t)},e.toNode=function(){for(var t=document.createDocumentFragment(),e=0;e"},N=function(){function t(t,e,r,a){this.children=void 0,this.attributes=void 0,this.classes=void 0,this.height=void 0,this.depth=void 0,this.width=void 0,this.maxFontSize=void 0,this.style=void 0,B.call(this,t,r,a),this.children=e||[]}var e=t.prototype;return e.setAttribute=function(t,e){this.attributes[t]=e},e.hasClass=function(t){return c.contains(this.classes,t)},e.toNode=function(){return C.call(this,"span")},e.toMarkup=function(){return q.call(this,"span")},t}(),I=function(){function t(t,e,r,a){this.children=void 0,this.attributes=void 0,this.classes=void 0,this.height=void 0,this.depth=void 0,this.maxFontSize=void 0,this.style=void 0,B.call(this,e,a),this.children=r||[],this.setAttribute("href",t)}var e=t.prototype;return e.setAttribute=function(t,e){this.attributes[t]=e},e.hasClass=function(t){return c.contains(this.classes,t)},e.toNode=function(){return C.call(this,"a")},e.toMarkup=function(){return q.call(this,"a")},t}(),R=function(){function t(t,e,r){this.src=void 0,this.alt=void 0,this.classes=void 0,this.height=void 0,this.depth=void 0,this.maxFontSize=void 0,this.style=void 0,this.alt=e,this.src=t,this.classes=["mord"],this.style=r}var e=t.prototype;return e.hasClass=function(t){return c.contains(this.classes,t)},e.toNode=function(){var t=document.createElement("img");for(var e in t.src=this.src,t.alt=this.alt,t.className="mord",this.style)this.style.hasOwnProperty(e)&&(t.style[e]=this.style[e]);return t},e.toMarkup=function(){var t=""+this.alt+"=n[0]&&t<=n[1])return r.name}return null}(this.text.charCodeAt(0));h&&this.classes.push(h+"_fallback"),/[\xee\xef\xed\xec]/.test(this.text)&&(this.text=O[this.text])}var e=t.prototype;return e.hasClass=function(t){return c.contains(this.classes,t)},e.toNode=function(){var t=document.createTextNode(this.text),e=null;for(var r in this.italic>0&&((e=document.createElement("span")).style.marginRight=this.italic+"em"),this.classes.length>0&&((e=e||document.createElement("span")).className=T(this.classes)),this.style)this.style.hasOwnProperty(r)&&((e=e||document.createElement("span")).style[r]=this.style[r]);return e?(e.appendChild(t),e):t},e.toMarkup=function(){var t=!1,e="0&&(r+="margin-right:"+this.italic+"em;"),this.style)this.style.hasOwnProperty(a)&&(r+=c.hyphenate(a)+":"+this.style[a]+";");r&&(t=!0,e+=' style="'+c.escape(r)+'"');var n=c.escape(this.text);return t?(e+=">",e+=n,e+=""):n},t}(),L=function(){function t(t,e){this.children=void 0,this.attributes=void 0,this.children=t||[],this.attributes=e||{}}var e=t.prototype;return e.toNode=function(){var t=document.createElementNS("http://www.w3.org/2000/svg","svg");for(var e in this.attributes)Object.prototype.hasOwnProperty.call(this.attributes,e)&&t.setAttribute(e,this.attributes[e]);for(var r=0;r":""},t}(),P=function(){function t(t){this.attributes=void 0,this.attributes=t||{}}var e=t.prototype;return e.toNode=function(){var t=document.createElementNS("http://www.w3.org/2000/svg","line");for(var e in this.attributes)Object.prototype.hasOwnProperty.call(this.attributes,e)&&t.setAttribute(e,this.attributes[e]);return t},e.toMarkup=function(){var t="",">"),$("math",Z,et,":",":"),$("math",Z,et,"\u2248","\\approx",!0),$("math",Z,et,"\u2245","\\cong",!0),$("math",Z,et,"\u2265","\\ge"),$("math",Z,et,"\u2265","\\geq",!0),$("math",Z,et,"\u2190","\\gets"),$("math",Z,et,">","\\gt"),$("math",Z,et,"\u2208","\\in",!0),$("math",Z,et,"\ue020","\\@not"),$("math",Z,et,"\u2282","\\subset",!0),$("math",Z,et,"\u2283","\\supset",!0),$("math",Z,et,"\u2286","\\subseteq",!0),$("math",Z,et,"\u2287","\\supseteq",!0),$("math",K,et,"\u2288","\\nsubseteq",!0),$("math",K,et,"\u2289","\\nsupseteq",!0),$("math",Z,et,"\u22a8","\\models"),$("math",Z,et,"\u2190","\\leftarrow",!0),$("math",Z,et,"\u2264","\\le"),$("math",Z,et,"\u2264","\\leq",!0),$("math",Z,et,"<","\\lt"),$("math",Z,et,"\u2192","\\rightarrow",!0),$("math",Z,et,"\u2192","\\to"),$("math",K,et,"\u2271","\\ngeq",!0),$("math",K,et,"\u2270","\\nleq",!0),$("math",Z,"spacing","\xa0","\\ "),$("math",Z,"spacing","\xa0","~"),$("math",Z,"spacing","\xa0","\\space"),$("math",Z,"spacing","\xa0","\\nobreakspace"),$("text",Z,"spacing","\xa0","\\ "),$("text",Z,"spacing","\xa0","~"),$("text",Z,"spacing","\xa0","\\space"),$("text",Z,"spacing","\xa0","\\nobreakspace"),$("math",Z,"spacing",null,"\\nobreak"),$("math",Z,"spacing",null,"\\allowbreak"),$("math",Z,"punct",",",","),$("math",Z,"punct",";",";"),$("math",K,J,"\u22bc","\\barwedge",!0),$("math",K,J,"\u22bb","\\veebar",!0),$("math",Z,J,"\u2299","\\odot",!0),$("math",Z,J,"\u2295","\\oplus",!0),$("math",Z,J,"\u2297","\\otimes",!0),$("math",Z,"textord","\u2202","\\partial",!0),$("math",Z,J,"\u2298","\\oslash",!0),$("math",K,J,"\u229a","\\circledcirc",!0),$("math",K,J,"\u22a1","\\boxdot",!0),$("math",Z,J,"\u25b3","\\bigtriangleup"),$("math",Z,J,"\u25bd","\\bigtriangledown"),$("math",Z,J,"\u2020","\\dagger"),$("math",Z,J,"\u22c4","\\diamond"),$("math",Z,J,"\u22c6","\\star"),$("math",Z,J,"\u25c3","\\triangleleft"),$("math",Z,J,"\u25b9","\\triangleright"),$("math",Z,"open","{","\\{"),$("text",Z,"textord","{","\\{"),$("text",Z,"textord","{","\\textbraceleft"),$("math",Z,"close","}","\\}"),$("text",Z,"textord","}","\\}"),$("text",Z,"textord","}","\\textbraceright"),$("math",Z,"open","{","\\lbrace"),$("math",Z,"close","}","\\rbrace"),$("math",Z,"open","[","\\lbrack"),$("text",Z,"textord","[","\\lbrack"),$("math",Z,"close","]","\\rbrack"),$("text",Z,"textord","]","\\rbrack"),$("math",Z,"open","(","\\lparen"),$("math",Z,"close",")","\\rparen"),$("text",Z,"textord","<","\\textless"),$("text",Z,"textord",">","\\textgreater"),$("math",Z,"open","\u230a","\\lfloor",!0),$("math",Z,"close","\u230b","\\rfloor",!0),$("math",Z,"open","\u2308","\\lceil",!0),$("math",Z,"close","\u2309","\\rceil",!0),$("math",Z,"textord","\\","\\backslash"),$("math",Z,"textord","\u2223","|"),$("math",Z,"textord","\u2223","\\vert"),$("text",Z,"textord","|","\\textbar"),$("math",Z,"textord","\u2225","\\|"),$("math",Z,"textord","\u2225","\\Vert"),$("text",Z,"textord","\u2225","\\textbardbl"),$("text",Z,"textord","~","\\textasciitilde"),$("text",Z,"textord","\\","\\textbackslash"),$("text",Z,"textord","^","\\textasciicircum"),$("math",Z,et,"\u2191","\\uparrow",!0),$("math",Z,et,"\u21d1","\\Uparrow",!0),$("math",Z,et,"\u2193","\\downarrow",!0),$("math",Z,et,"\u21d3","\\Downarrow",!0),$("math",Z,et,"\u2195","\\updownarrow",!0),$("math",Z,et,"\u21d5","\\Updownarrow",!0),$("math",Z,tt,"\u2210","\\coprod"),$("math",Z,tt,"\u22c1","\\bigvee"),$("math",Z,tt,"\u22c0","\\bigwedge"),$("math",Z,tt,"\u2a04","\\biguplus"),$("math",Z,tt,"\u22c2","\\bigcap"),$("math",Z,tt,"\u22c3","\\bigcup"),$("math",Z,tt,"\u222b","\\int"),$("math",Z,tt,"\u222b","\\intop"),$("math",Z,tt,"\u222c","\\iint"),$("math",Z,tt,"\u222d","\\iiint"),$("math",Z,tt,"\u220f","\\prod"),$("math",Z,tt,"\u2211","\\sum"),$("math",Z,tt,"\u2a02","\\bigotimes"),$("math",Z,tt,"\u2a01","\\bigoplus"),$("math",Z,tt,"\u2a00","\\bigodot"),$("math",Z,tt,"\u222e","\\oint"),$("math",Z,tt,"\u222f","\\oiint"),$("math",Z,tt,"\u2230","\\oiiint"),$("math",Z,tt,"\u2a06","\\bigsqcup"),$("math",Z,tt,"\u222b","\\smallint"),$("text",Z,"inner","\u2026","\\textellipsis"),$("math",Z,"inner","\u2026","\\mathellipsis"),$("text",Z,"inner","\u2026","\\ldots",!0),$("math",Z,"inner","\u2026","\\ldots",!0),$("math",Z,"inner","\u22ef","\\@cdots",!0),$("math",Z,"inner","\u22f1","\\ddots",!0),$("math",Z,"textord","\u22ee","\\varvdots"),$("math",Z,"accent-token","\u02ca","\\acute"),$("math",Z,"accent-token","\u02cb","\\grave"),$("math",Z,"accent-token","\xa8","\\ddot"),$("math",Z,"accent-token","~","\\tilde"),$("math",Z,"accent-token","\u02c9","\\bar"),$("math",Z,"accent-token","\u02d8","\\breve"),$("math",Z,"accent-token","\u02c7","\\check"),$("math",Z,"accent-token","^","\\hat"),$("math",Z,"accent-token","\u20d7","\\vec"),$("math",Z,"accent-token","\u02d9","\\dot"),$("math",Z,"accent-token","\u02da","\\mathring"),$("math",Z,Q,"\u0131","\\imath",!0),$("math",Z,Q,"\u0237","\\jmath",!0),$("text",Z,"textord","\u0131","\\i",!0),$("text",Z,"textord","\u0237","\\j",!0),$("text",Z,"textord","\xdf","\\ss",!0),$("text",Z,"textord","\xe6","\\ae",!0),$("text",Z,"textord","\xe6","\\ae",!0),$("text",Z,"textord","\u0153","\\oe",!0),$("text",Z,"textord","\xf8","\\o",!0),$("text",Z,"textord","\xc6","\\AE",!0),$("text",Z,"textord","\u0152","\\OE",!0),$("text",Z,"textord","\xd8","\\O",!0),$("text",Z,"accent-token","\u02ca","\\'"),$("text",Z,"accent-token","\u02cb","\\`"),$("text",Z,"accent-token","\u02c6","\\^"),$("text",Z,"accent-token","\u02dc","\\~"),$("text",Z,"accent-token","\u02c9","\\="),$("text",Z,"accent-token","\u02d8","\\u"),$("text",Z,"accent-token","\u02d9","\\."),$("text",Z,"accent-token","\u02da","\\r"),$("text",Z,"accent-token","\u02c7","\\v"),$("text",Z,"accent-token","\xa8",'\\"'),$("text",Z,"accent-token","\u02dd","\\H"),$("text",Z,"accent-token","\u25ef","\\textcircled");var rt={"--":!0,"---":!0,"``":!0,"''":!0};$("text",Z,"textord","\u2013","--"),$("text",Z,"textord","\u2013","\\textendash"),$("text",Z,"textord","\u2014","---"),$("text",Z,"textord","\u2014","\\textemdash"),$("text",Z,"textord","\u2018","`"),$("text",Z,"textord","\u2018","\\textquoteleft"),$("text",Z,"textord","\u2019","'"),$("text",Z,"textord","\u2019","\\textquoteright"),$("text",Z,"textord","\u201c","``"),$("text",Z,"textord","\u201c","\\textquotedblleft"),$("text",Z,"textord","\u201d","''"),$("text",Z,"textord","\u201d","\\textquotedblright"),$("math",Z,"textord","\xb0","\\degree",!0),$("text",Z,"textord","\xb0","\\degree"),$("text",Z,"textord","\xb0","\\textdegree",!0),$("math",Z,Q,"\xa3","\\pounds"),$("math",Z,Q,"\xa3","\\mathsterling",!0),$("text",Z,Q,"\xa3","\\pounds"),$("text",Z,Q,"\xa3","\\textsterling",!0),$("math",K,"textord","\u2720","\\maltese"),$("text",K,"textord","\u2720","\\maltese"),$("text",Z,"spacing","\xa0","\\ "),$("text",Z,"spacing","\xa0"," "),$("text",Z,"spacing","\xa0","~");for(var at=0;at<'0123456789/@."'.length;at++){var nt='0123456789/@."'.charAt(at);$("math",Z,"textord",nt,nt)}for(var it=0;it<'0123456789!@*()-=+[]<>|";:?/.,'.length;it++){var ot='0123456789!@*()-=+[]<>|";:?/.,'.charAt(it);$("text",Z,"textord",ot,ot)}for(var st="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",ht=0;ht=5?0:t>=3?1:2]){var r=Y[e]={cssEmPerMu:V.quad[e]/18};for(var a in V)V.hasOwnProperty(a)&&(r[a]=V[a][e])}return Y[e]}(this.size)),this._fontMetrics},e.getColor=function(){return this.phantom?"transparent":this.color},t}();kt.BASESIZE=6;var St=kt,Mt={pt:1,mm:7227/2540,cm:7227/254,in:72.27,bp:1.00375,pc:12,dd:1238/1157,cc:14856/1157,nd:685/642,nc:1370/107,sp:1/65536,px:1.00375},zt={ex:!0,em:!0,mu:!0},At=function(t){return"string"!=typeof t&&(t=t.unit),t in Mt||t in zt||"ex"===t},Tt=function(t,e){var r;if(t.unit in Mt)r=Mt[t.unit]/e.fontMetrics().ptPerEm/e.sizeMultiplier;else if("mu"===t.unit)r=e.fontMetrics().cssEmPerMu;else{var a;if(a=e.style.isTight()?e.havingStyle(e.style.text()):e,"ex"===t.unit)r=a.fontMetrics().xHeight;else{if("em"!==t.unit)throw new o("Invalid unit: '"+t.unit+"'");r=a.fontMetrics().quad}a!==e&&(r*=a.sizeMultiplier/e.sizeMultiplier)}return Math.min(t.number*r,e.maxSize)},Bt=["\\imath","\u0131","\\jmath","\u0237","\\pounds","\\mathsterling","\\textsterling","\xa3"],Ct=function(t,e,r){return j[r][t]&&j[r][t].replace&&(t=j[r][t].replace),{value:t,metrics:G(t,e,r)}},qt=function(t,e,r,a,n){var i,o=Ct(t,e,r),s=o.metrics;if(t=o.value,s){var h=s.italic;("text"===r||a&&"mathit"===a.font)&&(h=0),i=new E(t,s.height,s.depth,h,s.skew,s.width,n)}else"undefined"!=typeof console&&console.warn("No character metrics for '"+t+"' in style '"+e+"' and mode '"+r+"'"),i=new E(t,0,0,0,0,0,n);if(a){i.maxFontSize=a.sizeMultiplier,a.style.isTight()&&i.classes.push("mtight");var l=a.getColor();l&&(i.style.color=l)}return i},Nt=function(t,e){if(T(t.classes)!==T(e.classes)||t.skew!==e.skew||t.maxFontSize!==e.maxFontSize)return!1;for(var r in t.style)if(t.style.hasOwnProperty(r)&&t.style[r]!==e.style[r])return!1;for(var a in e.style)if(e.style.hasOwnProperty(a)&&t.style[a]!==e.style[a])return!1;return!0},It=function(t){for(var e=0,r=0,a=0,n=0;ne&&(e=i.height),i.depth>r&&(r=i.depth),i.maxFontSize>a&&(a=i.maxFontSize)}t.height=e,t.depth=r,t.maxFontSize=a},Rt=function(t,e,r,a){var n=new N(t,e,r,a);return It(n),n},Ot=function(t,e,r,a){return new N(t,e,r,a)},Et=function(t){var e=new A(t);return It(e),e},Lt=function(t,e,r){var a="";switch(t){case"amsrm":a="AMS";break;case"textrm":a="Main";break;case"textsf":a="SansSerif";break;case"texttt":a="Typewriter";break;default:a=t}return a+"-"+("textbf"===e&&"textit"===r?"BoldItalic":"textbf"===e?"Bold":"textit"===e?"Italic":"Regular")},Ht={mathbf:{variant:"bold",fontName:"Main-Bold"},mathrm:{variant:"normal",fontName:"Main-Regular"},textit:{variant:"italic",fontName:"Main-Italic"},mathit:{variant:"italic",fontName:"Main-Italic"},mathbb:{variant:"double-struck",fontName:"AMS-Regular"},mathcal:{variant:"script",fontName:"Caligraphic-Regular"},mathfrak:{variant:"fraktur",fontName:"Fraktur-Regular"},mathscr:{variant:"script",fontName:"Script-Regular"},mathsf:{variant:"sans-serif",fontName:"SansSerif-Regular"},mathtt:{variant:"monospace",fontName:"Typewriter-Regular"}},Pt={vec:["vec",.471,.714],oiintSize1:["oiintSize1",.957,.499],oiintSize2:["oiintSize2",1.472,.659],oiiintSize1:["oiiintSize1",1.304,.499],oiiintSize2:["oiiintSize2",1.98,.659]},Dt={fontMap:Ht,makeSymbol:qt,mathsym:function(t,e,r,a){return void 0===a&&(a=[]),"boldsymbol"===r.font&&Ct(t,"Main-Bold",e).metrics?qt(t,"Main-Bold",e,r,a.concat(["mathbf"])):"\\"===t||"main"===j[e][t].font?qt(t,"Main-Regular",e,r,a):qt(t,"AMS-Regular",e,r,a.concat(["amsrm"]))},makeSpan:Rt,makeSvgSpan:Ot,makeLineSpan:function(t,e,r){var a=Rt([t],[],e);return a.height=Math.max(r||e.fontMetrics().defaultRuleThickness,e.minRuleThickness),a.style.borderBottomWidth=a.height+"em",a.maxFontSize=1,a},makeAnchor:function(t,e,r,a){var n=new I(t,e,r,a);return It(n),n},makeFragment:Et,wrapFragment:function(t,e){return t instanceof A?Rt([],[t],e):t},makeVList:function(t,e){for(var r=function(t){if("individualShift"===t.positionType){for(var e=t.children,r=[e[0]],a=-e[0].shift-e[0].elem.depth,n=a,i=1;i0&&(i.push(pe(o,e)),o=[]),i.push(n[s]));o.length>0&&i.push(pe(o,e)),r&&((a=pe(se(r,e,!0))).classes=["tag"],i.push(a));var l=re(["katex-html"],i);if(l.setAttribute("aria-hidden","true"),a){var m=a.children[0];m.style.height=l.height+l.depth+"em",m.style.verticalAlign=-l.depth+"em"}return l}function fe(t){return new A(t)}var ge=function(){function t(t,e){this.type=void 0,this.attributes=void 0,this.children=void 0,this.type=t,this.attributes={},this.children=e||[]}var e=t.prototype;return e.setAttribute=function(t,e){this.attributes[t]=e},e.getAttribute=function(t){return this.attributes[t]},e.toNode=function(){var t=document.createElementNS("http://www.w3.org/1998/Math/MathML",this.type);for(var e in this.attributes)Object.prototype.hasOwnProperty.call(this.attributes,e)&&t.setAttribute(e,this.attributes[e]);for(var r=0;r"},e.toText=function(){return this.children.map(function(t){return t.toText()}).join("")},t}(),xe=function(){function t(t){this.text=void 0,this.text=t}var e=t.prototype;return e.toNode=function(){return document.createTextNode(this.text)},e.toMarkup=function(){return c.escape(this.toText())},e.toText=function(){return this.text},t}(),ve={MathNode:ge,TextNode:xe,SpaceNode:function(){function t(t){this.width=void 0,this.character=void 0,this.width=t,this.character=t>=.05555&&t<=.05556?"\u200a":t>=.1666&&t<=.1667?"\u2009":t>=.2222&&t<=.2223?"\u2005":t>=.2777&&t<=.2778?"\u2005\u200a":t>=-.05556&&t<=-.05555?"\u200a\u2063":t>=-.1667&&t<=-.1666?"\u2009\u2063":t>=-.2223&&t<=-.2222?"\u205f\u2063":t>=-.2778&&t<=-.2777?"\u2005\u2063":null}var e=t.prototype;return e.toNode=function(){if(this.character)return document.createTextNode(this.character);var t=document.createElementNS("http://www.w3.org/1998/Math/MathML","mspace");return t.setAttribute("width",this.width+"em"),t},e.toMarkup=function(){return this.character?""+this.character+"":''},e.toText=function(){return this.character?this.character:" "},t}(),newDocumentFragment:fe},be=function(t,e,r){return!j[e][t]||!j[e][t].replace||55349===t.charCodeAt(0)||rt.hasOwnProperty(t)&&r&&(r.fontFamily&&"tt"===r.fontFamily.substr(4,2)||r.font&&"tt"===r.font.substr(4,2))||(t=j[e][t].replace),new ve.TextNode(t)},ye=function(t){return 1===t.length?t[0]:new ve.MathNode("mrow",t)},we=function(t,e){if("texttt"===e.fontFamily)return"monospace";if("textsf"===e.fontFamily)return"textit"===e.fontShape&&"textbf"===e.fontWeight?"sans-serif-bold-italic":"textit"===e.fontShape?"sans-serif-italic":"textbf"===e.fontWeight?"bold-sans-serif":"sans-serif";if("textit"===e.fontShape&&"textbf"===e.fontWeight)return"bold-italic";if("textit"===e.fontShape)return"italic";if("textbf"===e.fontWeight)return"bold";var r=e.font;if(!r||"mathnormal"===r)return null;var a=t.mode;if("mathit"===r)return"italic";if("boldsymbol"===r)return"bold-italic";if("mathbf"===r)return"bold";if("mathbb"===r)return"double-struck";if("mathfrak"===r)return"fraktur";if("mathscr"===r||"mathcal"===r)return"script";if("mathsf"===r)return"sans-serif";if("mathtt"===r)return"monospace";var n=t.text;return c.contains(["\\imath","\\jmath"],n)?null:(j[a][n]&&j[a][n].replace&&(n=j[a][n].replace),G(n,Dt.fontMap[r].fontName,a)?Dt.fontMap[r].variant:null)},ke=function(t,e,r){if(1===t.length){var a=Me(t[0],e);return r&&a instanceof ge&&"mo"===a.type&&(a.setAttribute("lspace","0em"),a.setAttribute("rspace","0em")),[a]}for(var n,i=[],o=0;o0&&(p.text=p.text.slice(0,1)+"\u0338"+p.text.slice(1),i.pop())}}}i.push(s),n=s}return i},Se=function(t,e,r){return ye(ke(t,e,r))},Me=function(t,e){if(!t)return new ve.MathNode("mrow");if(Jt[t.type])return Jt[t.type](t,e);throw new o("Got group of unknown type: '"+t.type+"'")};function ze(t,e,r,a){var n,i=ke(t,r);n=1===i.length&&i[0]instanceof ge&&c.contains(["mrow","mtable"],i[0].type)?i[0]:new ve.MathNode("mrow",i);var o=new ve.MathNode("annotation",[new ve.TextNode(e)]);o.setAttribute("encoding","application/x-tex");var s=new ve.MathNode("semantics",[n,o]),h=new ve.MathNode("math",[s]);h.setAttribute("xmlns","http://www.w3.org/1998/Math/MathML");var l=a?"katex":"katex-mathml";return Dt.makeSpan([l],[h])}var Ae=function(t){return new St({style:t.displayMode?w.DISPLAY:w.TEXT,maxSize:t.maxSize,minRuleThickness:t.minRuleThickness})},Te=function(t,e){if(e.displayMode){var r=["katex-display"];e.leqno&&r.push("leqno"),e.fleqn&&r.push("fleqn"),t=Dt.makeSpan(r,[t])}return t},Be=function(t,e,r){var a,n=Ae(r);if("mathml"===r.output)return ze(t,e,n,!0);if("html"===r.output){var i=de(t,n);a=Dt.makeSpan(["katex"],[i])}else{var o=ze(t,e,n,!1),s=de(t,n);a=Dt.makeSpan(["katex"],[o,s])}return Te(a,r)},Ce={widehat:"^",widecheck:"\u02c7",widetilde:"~",utilde:"~",overleftarrow:"\u2190",underleftarrow:"\u2190",xleftarrow:"\u2190",overrightarrow:"\u2192",underrightarrow:"\u2192",xrightarrow:"\u2192",underbrace:"\u23df",overbrace:"\u23de",overgroup:"\u23e0",undergroup:"\u23e1",overleftrightarrow:"\u2194",underleftrightarrow:"\u2194",xleftrightarrow:"\u2194",Overrightarrow:"\u21d2",xRightarrow:"\u21d2",overleftharpoon:"\u21bc",xleftharpoonup:"\u21bc",overrightharpoon:"\u21c0",xrightharpoonup:"\u21c0",xLeftarrow:"\u21d0",xLeftrightarrow:"\u21d4",xhookleftarrow:"\u21a9",xhookrightarrow:"\u21aa",xmapsto:"\u21a6",xrightharpoondown:"\u21c1",xleftharpoondown:"\u21bd",xrightleftharpoons:"\u21cc",xleftrightharpoons:"\u21cb",xtwoheadleftarrow:"\u219e",xtwoheadrightarrow:"\u21a0",xlongequal:"=",xtofrom:"\u21c4",xrightleftarrows:"\u21c4",xrightequilibrium:"\u21cc",xleftequilibrium:"\u21cb"},qe={overrightarrow:[["rightarrow"],.888,522,"xMaxYMin"],overleftarrow:[["leftarrow"],.888,522,"xMinYMin"],underrightarrow:[["rightarrow"],.888,522,"xMaxYMin"],underleftarrow:[["leftarrow"],.888,522,"xMinYMin"],xrightarrow:[["rightarrow"],1.469,522,"xMaxYMin"],xleftarrow:[["leftarrow"],1.469,522,"xMinYMin"],Overrightarrow:[["doublerightarrow"],.888,560,"xMaxYMin"],xRightarrow:[["doublerightarrow"],1.526,560,"xMaxYMin"],xLeftarrow:[["doubleleftarrow"],1.526,560,"xMinYMin"],overleftharpoon:[["leftharpoon"],.888,522,"xMinYMin"],xleftharpoonup:[["leftharpoon"],.888,522,"xMinYMin"],xleftharpoondown:[["leftharpoondown"],.888,522,"xMinYMin"],overrightharpoon:[["rightharpoon"],.888,522,"xMaxYMin"],xrightharpoonup:[["rightharpoon"],.888,522,"xMaxYMin"],xrightharpoondown:[["rightharpoondown"],.888,522,"xMaxYMin"],xlongequal:[["longequal"],.888,334,"xMinYMin"],xtwoheadleftarrow:[["twoheadleftarrow"],.888,334,"xMinYMin"],xtwoheadrightarrow:[["twoheadrightarrow"],.888,334,"xMaxYMin"],overleftrightarrow:[["leftarrow","rightarrow"],.888,522],overbrace:[["leftbrace","midbrace","rightbrace"],1.6,548],underbrace:[["leftbraceunder","midbraceunder","rightbraceunder"],1.6,548],underleftrightarrow:[["leftarrow","rightarrow"],.888,522],xleftrightarrow:[["leftarrow","rightarrow"],1.75,522],xLeftrightarrow:[["doubleleftarrow","doublerightarrow"],1.75,560],xrightleftharpoons:[["leftharpoondownplus","rightharpoonplus"],1.75,716],xleftrightharpoons:[["leftharpoonplus","rightharpoondownplus"],1.75,716],xhookleftarrow:[["leftarrow","righthook"],1.08,522],xhookrightarrow:[["lefthook","rightarrow"],1.08,522],overlinesegment:[["leftlinesegment","rightlinesegment"],.888,522],underlinesegment:[["leftlinesegment","rightlinesegment"],.888,522],overgroup:[["leftgroup","rightgroup"],.888,342],undergroup:[["leftgroupunder","rightgroupunder"],.888,342],xmapsto:[["leftmapsto","rightarrow"],1.5,522],xtofrom:[["leftToFrom","rightToFrom"],1.75,528],xrightleftarrows:[["baraboveleftarrow","rightarrowabovebar"],1.75,901],xrightequilibrium:[["baraboveshortleftharpoon","rightharpoonaboveshortbar"],1.75,716],xleftequilibrium:[["shortbaraboveleftharpoon","shortrightharpoonabovebar"],1.75,716]},Ne=function(t){return"ordgroup"===t.type?t.body.length:1},Ie=function(t,e,r,a){var n,i=t.height+t.depth+2*r;if(/fbox|color/.test(e)){if(n=Dt.makeSpan(["stretchy",e],[],a),"fbox"===e){var o=a.color&&a.getColor();o&&(n.style.borderColor=o)}}else{var s=[];/^[bx]cancel$/.test(e)&&s.push(new P({x1:"0",y1:"0",x2:"100%",y2:"100%","stroke-width":"0.046em"})),/^x?cancel$/.test(e)&&s.push(new P({x1:"0",y1:"100%",x2:"100%",y2:"0","stroke-width":"0.046em"}));var h=new L(s,{width:"100%",height:i+"em"});n=Dt.makeSvgSpan([],[h],a)}return n.height=i,n.style.height=i+"em",n},Re=function(t){var e=new ve.MathNode("mo",[new ve.TextNode(Ce[t.substr(1)])]);return e.setAttribute("stretchy","true"),e},Oe=function(t,e){var r=function(){var r=4e5,a=t.label.substr(1);if(c.contains(["widehat","widecheck","widetilde","utilde"],a)){var n,i,o,s=Ne(t.base);if(s>5)"widehat"===a||"widecheck"===a?(n=420,r=2364,o=.42,i=a+"4"):(n=312,r=2340,o=.34,i="tilde4");else{var h=[1,1,2,2,3,3][s];"widehat"===a||"widecheck"===a?(r=[0,1062,2364,2364,2364][h],n=[0,239,300,360,420][h],o=[0,.24,.3,.3,.36,.42][h],i=a+h):(r=[0,600,1033,2339,2340][h],n=[0,260,286,306,312][h],o=[0,.26,.286,.3,.306,.34][h],i="tilde"+h)}var l=new H(i),m=new L([l],{width:"100%",height:o+"em",viewBox:"0 0 "+r+" "+n,preserveAspectRatio:"none"});return{span:Dt.makeSvgSpan([],[m],e),minWidth:0,height:o}}var u,p,d=[],f=qe[a],g=f[0],x=f[1],v=f[2],b=v/1e3,y=g.length;if(1===y)u=["hide-tail"],p=[f[3]];else if(2===y)u=["halfarrow-left","halfarrow-right"],p=["xMinYMin","xMaxYMin"];else{if(3!==y)throw new Error("Correct katexImagesData or update code here to support\n "+y+" children.");u=["brace-left","brace-center","brace-right"],p=["xMinYMin","xMidYMin","xMaxYMin"]}for(var w=0;w0&&(a.style.minWidth=n+"em"),a},Ee=function(t,e){var r,a,n,i=Vt(t,"supsub");i?(r=(a=Ft(i.base,"accent")).base,i.base=r,n=function(t){if(t instanceof N)return t;throw new Error("Expected span but got "+String(t)+".")}(ue(i,e)),i.base=a):r=(a=Ft(t,"accent")).base;var o=ue(r,e.havingCrampedStyle()),s=0;if(a.isShifty&&c.isCharacterBox(r)){var h=c.getBaseElem(r);s=D(ue(h,e.havingCrampedStyle())).skew}var l,m=Math.min(o.height,e.fontMetrics().xHeight);if(a.isStretchy)l=Oe(a,e),l=Dt.makeVList({positionType:"firstBaseline",children:[{type:"elem",elem:o},{type:"elem",elem:l,wrapperClasses:["svg-align"],wrapperStyle:s>0?{width:"calc(100% - "+2*s+"em)",marginLeft:2*s+"em"}:void 0}]},e);else{var u,p;"\\vec"===a.label?(u=Dt.staticSvg("vec",e),p=Dt.svgData.vec[1]):((u=D(u=Dt.makeOrd({mode:a.mode,text:a.label},e,"textord"))).italic=0,p=u.width),l=Dt.makeSpan(["accent-body"],[u]);var d="\\textcircled"===a.label;d&&(l.classes.push("accent-full"),m=o.height);var f=s;d||(f-=p/2),l.style.left=f+"em","\\textcircled"===a.label&&(l.style.top=".2em"),l=Dt.makeVList({positionType:"firstBaseline",children:[{type:"elem",elem:o},{type:"kern",size:-m},{type:"elem",elem:l}]},e)}var g=Dt.makeSpan(["mord","accent"],[l],e);return n?(n.children[0]=g,n.height=Math.max(g.height,n.height),n.classes[0]="mord",n):g},Le=function(t,e){var r=t.isStretchy?Re(t.label):new ve.MathNode("mo",[be(t.label,t.mode)]),a=new ve.MathNode("mover",[Me(t.base,e),r]);return a.setAttribute("accent","true"),a},He=new RegExp(["\\acute","\\grave","\\ddot","\\tilde","\\bar","\\breve","\\check","\\hat","\\vec","\\dot","\\mathring"].map(function(t){return"\\"+t}).join("|"));Qt({type:"accent",names:["\\acute","\\grave","\\ddot","\\tilde","\\bar","\\breve","\\check","\\hat","\\vec","\\dot","\\mathring","\\widecheck","\\widehat","\\widetilde","\\overrightarrow","\\overleftarrow","\\Overrightarrow","\\overleftrightarrow","\\overgroup","\\overlinesegment","\\overleftharpoon","\\overrightharpoon"],props:{numArgs:1},handler:function(t,e){var r=e[0],a=!He.test(t.funcName),n=!a||"\\widehat"===t.funcName||"\\widetilde"===t.funcName||"\\widecheck"===t.funcName;return{type:"accent",mode:t.parser.mode,label:t.funcName,isStretchy:a,isShifty:n,base:r}},htmlBuilder:Ee,mathmlBuilder:Le}),Qt({type:"accent",names:["\\'","\\`","\\^","\\~","\\=","\\u","\\.",'\\"',"\\r","\\H","\\v","\\textcircled"],props:{numArgs:1,allowedInText:!0,allowedInMath:!1},handler:function(t,e){var r=e[0];return{type:"accent",mode:t.parser.mode,label:t.funcName,isStretchy:!1,isShifty:!0,base:r}},htmlBuilder:Ee,mathmlBuilder:Le}),Qt({type:"accentUnder",names:["\\underleftarrow","\\underrightarrow","\\underleftrightarrow","\\undergroup","\\underlinesegment","\\utilde"],props:{numArgs:1},handler:function(t,e){var r=t.parser,a=t.funcName,n=e[0];return{type:"accentUnder",mode:r.mode,label:a,base:n}},htmlBuilder:function(t,e){var r=ue(t.base,e),a=Oe(t,e),n="\\utilde"===t.label?.12:0,i=Dt.makeVList({positionType:"bottom",positionData:a.height+n,children:[{type:"elem",elem:a,wrapperClasses:["svg-align"]},{type:"kern",size:n},{type:"elem",elem:r}]},e);return Dt.makeSpan(["mord","accentunder"],[i],e)},mathmlBuilder:function(t,e){var r=Re(t.label),a=new ve.MathNode("munder",[Me(t.base,e),r]);return a.setAttribute("accentunder","true"),a}});var Pe=function(t){var e=new ve.MathNode("mpadded",t?[t]:[]);return e.setAttribute("width","+0.6em"),e.setAttribute("lspace","0.3em"),e};Qt({type:"xArrow",names:["\\xleftarrow","\\xrightarrow","\\xLeftarrow","\\xRightarrow","\\xleftrightarrow","\\xLeftrightarrow","\\xhookleftarrow","\\xhookrightarrow","\\xmapsto","\\xrightharpoondown","\\xrightharpoonup","\\xleftharpoondown","\\xleftharpoonup","\\xrightleftharpoons","\\xleftrightharpoons","\\xlongequal","\\xtwoheadrightarrow","\\xtwoheadleftarrow","\\xtofrom","\\xrightleftarrows","\\xrightequilibrium","\\xleftequilibrium"],props:{numArgs:1,numOptionalArgs:1},handler:function(t,e,r){var a=t.parser,n=t.funcName;return{type:"xArrow",mode:a.mode,label:n,body:e[0],below:r[0]}},htmlBuilder:function(t,e){var r,a=e.style,n=e.havingStyle(a.sup()),i=Dt.wrapFragment(ue(t.body,n,e),e);i.classes.push("x-arrow-pad"),t.below&&(n=e.havingStyle(a.sub()),(r=Dt.wrapFragment(ue(t.below,n,e),e)).classes.push("x-arrow-pad"));var o,s=Oe(t,e),h=-e.fontMetrics().axisHeight+.5*s.height,l=-e.fontMetrics().axisHeight-.5*s.height-.111;if((i.depth>.25||"\\xleftequilibrium"===t.label)&&(l-=i.depth),r){var m=-e.fontMetrics().axisHeight+r.height+.5*s.height+.111;o=Dt.makeVList({positionType:"individualShift",children:[{type:"elem",elem:i,shift:l},{type:"elem",elem:s,shift:h},{type:"elem",elem:r,shift:m}]},e)}else o=Dt.makeVList({positionType:"individualShift",children:[{type:"elem",elem:i,shift:l},{type:"elem",elem:s,shift:h}]},e);return o.children[0].children[0].children[1].classes.push("svg-align"),Dt.makeSpan(["mrel","x-arrow"],[o],e)},mathmlBuilder:function(t,e){var r,a=Re(t.label);if(t.body){var n=Pe(Me(t.body,e));if(t.below){var i=Pe(Me(t.below,e));r=new ve.MathNode("munderover",[a,i,n])}else r=new ve.MathNode("mover",[a,n])}else if(t.below){var o=Pe(Me(t.below,e));r=new ve.MathNode("munder",[a,o])}else r=Pe(),r=new ve.MathNode("mover",[a,r]);return r}}),Qt({type:"textord",names:["\\@char"],props:{numArgs:1,allowedInText:!0},handler:function(t,e){for(var r=t.parser,a=Ft(e[0],"ordgroup").body,n="",i=0;i","\\langle","\\rangle","/","\\backslash","\\lt","\\gt"],Je=[0,1.2,1.8,2.4,3],Qe=[{type:"small",style:w.SCRIPTSCRIPT},{type:"small",style:w.SCRIPT},{type:"small",style:w.TEXT},{type:"large",size:1},{type:"large",size:2},{type:"large",size:3},{type:"large",size:4}],tr=[{type:"small",style:w.SCRIPTSCRIPT},{type:"small",style:w.SCRIPT},{type:"small",style:w.TEXT},{type:"stack"}],er=[{type:"small",style:w.SCRIPTSCRIPT},{type:"small",style:w.SCRIPT},{type:"small",style:w.TEXT},{type:"large",size:1},{type:"large",size:2},{type:"large",size:3},{type:"large",size:4},{type:"stack"}],rr=function(t){if("small"===t.type)return"Main-Regular";if("large"===t.type)return"Size"+t.size+"-Regular";if("stack"===t.type)return"Size4-Regular";throw new Error("Add support for delim type '"+t.type+"' here.")},ar=function(t,e,r,a){for(var n=Math.min(2,3-a.style.size);ne)return r[n]}return r[r.length-1]},nr=function(t,e,r,a,n,i){var o;"<"===t||"\\lt"===t||"\u27e8"===t?t="\\langle":">"!==t&&"\\gt"!==t&&"\u27e9"!==t||(t="\\rangle"),o=c.contains(Ke,t)?Qe:c.contains($e,t)?er:tr;var s=ar(t,e,o,a);return"small"===s.type?function(t,e,r,a,n,i){var o=Dt.makeSymbol(t,"Main-Regular",n,a),s=Ue(o,e,a,i);return r&&Ge(s,a,e),s}(t,s.style,r,a,n,i):"large"===s.type?Ye(t,s.size,r,a,n,i):_e(t,e,r,a,n,i)},ir=function(t,e){var r,a,n=e.havingBaseSizing(),i=ar("\\surd",t*n.sizeMultiplier,er,n),o=n.sizeMultiplier,s=Math.max(0,e.minRuleThickness-e.fontMetrics().sqrtRuleThickness),h=0,l=0,m=0;return"small"===i.type?(t<1?o=1:t<1.4&&(o=.7),l=(1+s)/o,(r=je("sqrtMain",h=(1+s+.08)/o,m=1e3+1e3*s+80,s,e)).style.minWidth="0.853em",a=.833/o):"large"===i.type?(m=1080*Je[i.size],l=(Je[i.size]+s)/o,h=(Je[i.size]+s+.08)/o,(r=je("sqrtSize"+i.size,h,m,s,e)).style.minWidth="1.02em",a=1/o):(h=t+s+.08,l=t+s,m=Math.floor(1e3*t+s)+80,(r=je("sqrtTall",h,m,s,e)).style.minWidth="0.742em",a=1.056),r.height=l,r.style.height=h+"em",{span:r,advanceWidth:a,ruleWidth:(e.fontMetrics().sqrtRuleThickness+s)*o}},or=function(t,e,r,a,n){if("<"===t||"\\lt"===t||"\u27e8"===t?t="\\langle":">"!==t&&"\\gt"!==t&&"\u27e9"!==t||(t="\\rangle"),c.contains($e,t)||c.contains(Ke,t))return Ye(t,e,!1,r,a,n);if(c.contains(Ze,t))return _e(t,Je[e],!1,r,a,n);throw new o("Illegal delimiter: '"+t+"'")},sr=nr,hr=function(t,e,r,a,n,i){var o=a.fontMetrics().axisHeight*a.sizeMultiplier,s=5/a.fontMetrics().ptPerEm,h=Math.max(e-o,r+o),l=Math.max(h/500*901,2*h-s);return nr(t,l,!0,a,n,i)},lr={"\\bigl":{mclass:"mopen",size:1},"\\Bigl":{mclass:"mopen",size:2},"\\biggl":{mclass:"mopen",size:3},"\\Biggl":{mclass:"mopen",size:4},"\\bigr":{mclass:"mclose",size:1},"\\Bigr":{mclass:"mclose",size:2},"\\biggr":{mclass:"mclose",size:3},"\\Biggr":{mclass:"mclose",size:4},"\\bigm":{mclass:"mrel",size:1},"\\Bigm":{mclass:"mrel",size:2},"\\biggm":{mclass:"mrel",size:3},"\\Biggm":{mclass:"mrel",size:4},"\\big":{mclass:"mord",size:1},"\\Big":{mclass:"mord",size:2},"\\bigg":{mclass:"mord",size:3},"\\Bigg":{mclass:"mord",size:4}},mr=["(","\\lparen",")","\\rparen","[","\\lbrack","]","\\rbrack","\\{","\\lbrace","\\}","\\rbrace","\\lfloor","\\rfloor","\u230a","\u230b","\\lceil","\\rceil","\u2308","\u2309","<",">","\\langle","\u27e8","\\rangle","\u27e9","\\lt","\\gt","\\lvert","\\rvert","\\lVert","\\rVert","\\lgroup","\\rgroup","\u27ee","\u27ef","\\lmoustache","\\rmoustache","\u23b0","\u23b1","/","\\backslash","|","\\vert","\\|","\\Vert","\\uparrow","\\Uparrow","\\downarrow","\\Downarrow","\\updownarrow","\\Updownarrow","."];function cr(t,e){var r=Yt(t);if(r&&c.contains(mr,r.text))return r;throw new o("Invalid delimiter: '"+(r?r.text:JSON.stringify(t))+"' after '"+e.funcName+"'",t)}function ur(t){if(!t.body)throw new Error("Bug: The leftright ParseNode wasn't fully parsed.")}Qt({type:"delimsizing",names:["\\bigl","\\Bigl","\\biggl","\\Biggl","\\bigr","\\Bigr","\\biggr","\\Biggr","\\bigm","\\Bigm","\\biggm","\\Biggm","\\big","\\Big","\\bigg","\\Bigg"],props:{numArgs:1},handler:function(t,e){var r=cr(e[0],t);return{type:"delimsizing",mode:t.parser.mode,size:lr[t.funcName].size,mclass:lr[t.funcName].mclass,delim:r.text}},htmlBuilder:function(t,e){return"."===t.delim?Dt.makeSpan([t.mclass]):or(t.delim,t.size,e,t.mode,[t.mclass])},mathmlBuilder:function(t){var e=[];"."!==t.delim&&e.push(be(t.delim,t.mode));var r=new ve.MathNode("mo",e);return"mopen"===t.mclass||"mclose"===t.mclass?r.setAttribute("fence","true"):r.setAttribute("fence","false"),r}}),Qt({type:"leftright-right",names:["\\right"],props:{numArgs:1},handler:function(t,e){var r=t.parser.gullet.macros.get("\\current@color");if(r&&"string"!=typeof r)throw new o("\\current@color set to non-string in \\right");return{type:"leftright-right",mode:t.parser.mode,delim:cr(e[0],t).text,color:r}}}),Qt({type:"leftright",names:["\\left"],props:{numArgs:1},handler:function(t,e){var r=cr(e[0],t),a=t.parser;++a.leftrightDepth;var n=a.parseExpression(!1);--a.leftrightDepth,a.expect("\\right",!1);var i=Ft(a.parseFunction(),"leftright-right");return{type:"leftright",mode:a.mode,body:n,left:r.text,right:i.delim,rightColor:i.color}},htmlBuilder:function(t,e){ur(t);for(var r,a,n=se(t.body,e,!0,["mopen","mclose"]),i=0,o=0,s=!1,h=0;h-1?"mpadded":"menclose",[Me(t.body,e)]);switch(t.label){case"\\cancel":a.setAttribute("notation","updiagonalstrike");break;case"\\bcancel":a.setAttribute("notation","downdiagonalstrike");break;case"\\sout":a.setAttribute("notation","horizontalstrike");break;case"\\fbox":a.setAttribute("notation","box");break;case"\\fcolorbox":case"\\colorbox":if(r=e.fontMetrics().fboxsep*e.fontMetrics().ptPerEm,a.setAttribute("width","+"+2*r+"pt"),a.setAttribute("height","+"+2*r+"pt"),a.setAttribute("lspace",r+"pt"),a.setAttribute("voffset",r+"pt"),"\\fcolorbox"===t.label){var n=Math.max(e.fontMetrics().fboxrule,e.minRuleThickness);a.setAttribute("style","border: "+n+"em solid "+String(t.borderColor))}break;case"\\xcancel":a.setAttribute("notation","updiagonalstrike downdiagonalstrike")}return t.backgroundColor&&a.setAttribute("mathbackground",t.backgroundColor),a};Qt({type:"enclose",names:["\\colorbox"],props:{numArgs:2,allowedInText:!0,greediness:3,argTypes:["color","text"]},handler:function(t,e,r){var a=t.parser,n=t.funcName,i=Ft(e[0],"color-token").color,o=e[1];return{type:"enclose",mode:a.mode,label:n,backgroundColor:i,body:o}},htmlBuilder:pr,mathmlBuilder:dr}),Qt({type:"enclose",names:["\\fcolorbox"],props:{numArgs:3,allowedInText:!0,greediness:3,argTypes:["color","color","text"]},handler:function(t,e,r){var a=t.parser,n=t.funcName,i=Ft(e[0],"color-token").color,o=Ft(e[1],"color-token").color,s=e[2];return{type:"enclose",mode:a.mode,label:n,backgroundColor:o,borderColor:i,body:s}},htmlBuilder:pr,mathmlBuilder:dr}),Qt({type:"enclose",names:["\\fbox"],props:{numArgs:1,argTypes:["hbox"],allowedInText:!0},handler:function(t,e){return{type:"enclose",mode:t.parser.mode,label:"\\fbox",body:e[0]}}}),Qt({type:"enclose",names:["\\cancel","\\bcancel","\\xcancel","\\sout"],props:{numArgs:1},handler:function(t,e,r){var a=t.parser,n=t.funcName,i=e[0];return{type:"enclose",mode:a.mode,label:n,body:i}},htmlBuilder:pr,mathmlBuilder:dr});var fr={};function gr(t){for(var e=t.type,r=t.names,a=t.props,n=t.handler,i=t.htmlBuilder,o=t.mathmlBuilder,s={type:e,numArgs:a.numArgs||0,greediness:1,allowedInText:!1,numOptionalArgs:0,handler:n},h=0;h0&&(b+=.25),l.push({pos:b,isDashed:t[e]})}for(y(i[0]),r=0;r0&&(M<(B+=v)&&(M=B),B=0),t.addJot&&(M+=f),z.height=S,z.depth=M,b+=S,z.pos=b,b+=M+B,h[r]=z,y(i[r+1])}var C,q,N=b/2+e.fontMetrics().axisHeight,I=t.cols||[],R=[];for(a=0,q=0;a=s)){var P=void 0;(a>0||t.hskipBeforeAndAfter)&&0!==(P=c.deflt(O.pregap,p))&&((C=Dt.makeSpan(["arraycolsep"],[])).style.width=P+"em",R.push(C));var D=[];for(r=0;r0){for(var G=Dt.makeLineSpan("hline",e,m),Y=Dt.makeLineSpan("hdashline",e,m),W=[{type:"elem",elem:h,shift:0}];l.length>0;){var X=l.pop(),_=X.pos-N;X.isDashed?W.push({type:"elem",elem:Y,shift:_}):W.push({type:"elem",elem:G,shift:_})}h=Dt.makeVList({positionType:"individualShift",children:W},e)}return Dt.makeSpan(["mord"],[h],e)},wr={c:"center ",l:"left ",r:"right "},kr=function(t,e){var r=new ve.MathNode("mtable",t.body.map(function(t){return new ve.MathNode("mtr",t.map(function(t){return new ve.MathNode("mtd",[Me(t,e)])}))})),a=.5===t.arraystretch?.1:.16+t.arraystretch-1+(t.addJot?.09:0);r.setAttribute("rowspacing",a+"em");var n="",i="";if(t.cols){var o=t.cols,s="",h=!1,l=0,m=o.length;"separator"===o[0].type&&(n+="top ",l=1),"separator"===o[o.length-1].type&&(n+="bottom ",m-=1);for(var c=l;c0?"left ":"",n+=g[g.length-1].length>0?"right ":"";for(var x=1;x0&&c&&(d=1),a[u]={type:"align",align:p,pregap:d,postgap:0}}return n.colSeparationType=c?"align":"alignat",n};gr({type:"array",names:["array","darray"],props:{numArgs:1},handler:function(t,e){var r={cols:(Yt(e[0])?[e[0]]:Ft(e[0],"ordgroup").body).map(function(t){var e=Gt(t).text;if(-1!=="lcr".indexOf(e))return{type:"align",align:e};if("|"===e)return{type:"separator",separator:"|"};if(":"===e)return{type:"separator",separator:":"};throw new o("Unknown column alignment: "+e,t)}),hskipBeforeAndAfter:!0};return vr(t.parser,r,br(t.envName))},htmlBuilder:yr,mathmlBuilder:kr}),gr({type:"array",names:["matrix","pmatrix","bmatrix","Bmatrix","vmatrix","Vmatrix"],props:{numArgs:0},handler:function(t){var e={matrix:null,pmatrix:["(",")"],bmatrix:["[","]"],Bmatrix:["\\{","\\}"],vmatrix:["|","|"],Vmatrix:["\\Vert","\\Vert"]}[t.envName],r=vr(t.parser,{hskipBeforeAndAfter:!1},br(t.envName));return e?{type:"leftright",mode:t.mode,body:[r],left:e[0],right:e[1],rightColor:void 0}:r},htmlBuilder:yr,mathmlBuilder:kr}),gr({type:"array",names:["smallmatrix"],props:{numArgs:0},handler:function(t){var e=vr(t.parser,{arraystretch:.5},"script");return e.colSeparationType="small",e},htmlBuilder:yr,mathmlBuilder:kr}),gr({type:"array",names:["subarray"],props:{numArgs:1},handler:function(t,e){var r=(Yt(e[0])?[e[0]]:Ft(e[0],"ordgroup").body).map(function(t){var e=Gt(t).text;if(-1!=="lc".indexOf(e))return{type:"align",align:e};throw new o("Unknown column alignment: "+e,t)});if(r.length>1)throw new o("{subarray} can contain only one column");var a={cols:r,hskipBeforeAndAfter:!1,arraystretch:.5};if((a=vr(t.parser,a,"script")).body[0].length>1)throw new o("{subarray} can contain only one column");return a},htmlBuilder:yr,mathmlBuilder:kr}),gr({type:"array",names:["cases","dcases"],props:{numArgs:0},handler:function(t){var e=vr(t.parser,{arraystretch:1.2,cols:[{type:"align",align:"l",pregap:0,postgap:1},{type:"align",align:"l",pregap:0,postgap:0}]},br(t.envName));return{type:"leftright",mode:t.mode,body:[e],left:"\\{",right:".",rightColor:void 0}},htmlBuilder:yr,mathmlBuilder:kr}),gr({type:"array",names:["aligned"],props:{numArgs:0},handler:Sr,htmlBuilder:yr,mathmlBuilder:kr}),gr({type:"array",names:["gathered"],props:{numArgs:0},handler:function(t){return vr(t.parser,{cols:[{type:"align",align:"c"}],addJot:!0},"display")},htmlBuilder:yr,mathmlBuilder:kr}),gr({type:"array",names:["alignedat"],props:{numArgs:1},handler:Sr,htmlBuilder:yr,mathmlBuilder:kr}),Qt({type:"text",names:["\\hline","\\hdashline"],props:{numArgs:0,allowedInText:!0,allowedInMath:!0},handler:function(t,e){throw new o(t.funcName+" valid only within array environment")}});var Mr=fr;Qt({type:"environment",names:["\\begin","\\end"],props:{numArgs:1,argTypes:["text"]},handler:function(t,e){var r=t.parser,a=t.funcName,n=e[0];if("ordgroup"!==n.type)throw new o("Invalid environment name",n);for(var i="",s=0;s=w.SCRIPT.id?r.text():w.DISPLAY:"text"===t&&r.size===w.DISPLAY.size?r=w.TEXT:"script"===t?r=w.SCRIPT:"scriptscript"===t&&(r=w.SCRIPTSCRIPT),r},Rr=function(t,e){var r,a=Ir(t.size,e.style),n=a.fracNum(),i=a.fracDen();r=e.havingStyle(n);var o=ue(t.numer,r,e);if(t.continued){var s=8.5/e.fontMetrics().ptPerEm,h=3.5/e.fontMetrics().ptPerEm;o.height=o.height0?3*c:7*c,d=e.fontMetrics().denom1):(m>0?(u=e.fontMetrics().num2,p=c):(u=e.fontMetrics().num3,p=3*c),d=e.fontMetrics().denom2),l){var y=e.fontMetrics().axisHeight;u-o.depth-(y+.5*m)0&&(e="."===(e=t)?null:e),e};Qt({type:"genfrac",names:["\\genfrac"],props:{numArgs:6,greediness:6,argTypes:["math","math","size","text","math","math"]},handler:function(t,e){var r=t.parser,a=e[4],n=e[5],i=Vt(e[0],"atom");i&&(i=Ut(e[0],"open"));var o=i?Lr(i.text):null,s=Vt(e[1],"atom");s&&(s=Ut(e[1],"close"));var h,l=s?Lr(s.text):null,m=Ft(e[2],"size"),c=null;h=!!m.isBlank||(c=m.value).number>0;var u="auto",p=Vt(e[3],"ordgroup");if(p){if(p.body.length>0){var d=Ft(p.body[0],"textord");u=Er[Number(d.text)]}}else p=Ft(e[3],"textord"),u=Er[Number(p.text)];return{type:"genfrac",mode:r.mode,numer:a,denom:n,continued:!1,hasBarLine:h,barSize:c,leftDelim:o,rightDelim:l,size:u}},htmlBuilder:Rr,mathmlBuilder:Or}),Qt({type:"infix",names:["\\above"],props:{numArgs:1,argTypes:["size"],infix:!0},handler:function(t,e){var r=t.parser,a=(t.funcName,t.token);return{type:"infix",mode:r.mode,replaceWith:"\\\\abovefrac",size:Ft(e[0],"size").value,token:a}}}),Qt({type:"genfrac",names:["\\\\abovefrac"],props:{numArgs:3,argTypes:["math","size","math"]},handler:function(t,e){var r=t.parser,a=(t.funcName,e[0]),n=function(t){if(!t)throw new Error("Expected non-null, but got "+String(t));return t}(Ft(e[1],"infix").size),i=e[2],o=n.number>0;return{type:"genfrac",mode:r.mode,numer:a,denom:i,continued:!1,hasBarLine:o,barSize:n,leftDelim:null,rightDelim:null,size:"auto"}},htmlBuilder:Rr,mathmlBuilder:Or});var Hr=function(t,e){var r,a,n=e.style,i=Vt(t,"supsub");i?(r=i.sup?ue(i.sup,e.havingStyle(n.sup()),e):ue(i.sub,e.havingStyle(n.sub()),e),a=Ft(i.base,"horizBrace")):a=Ft(t,"horizBrace");var o,s=ue(a.base,e.havingBaseStyle(w.DISPLAY)),h=Oe(a,e);if(a.isOver?(o=Dt.makeVList({positionType:"firstBaseline",children:[{type:"elem",elem:s},{type:"kern",size:.1},{type:"elem",elem:h}]},e)).children[0].children[0].children[1].classes.push("svg-align"):(o=Dt.makeVList({positionType:"bottom",positionData:s.depth+.1+h.height,children:[{type:"elem",elem:h},{type:"kern",size:.1},{type:"elem",elem:s}]},e)).children[0].children[0].children[0].classes.push("svg-align"),r){var l=Dt.makeSpan(["mord",a.isOver?"mover":"munder"],[o],e);o=a.isOver?Dt.makeVList({positionType:"firstBaseline",children:[{type:"elem",elem:l},{type:"kern",size:.2},{type:"elem",elem:r}]},e):Dt.makeVList({positionType:"bottom",positionData:l.depth+.2+r.height+r.depth,children:[{type:"elem",elem:r},{type:"kern",size:.2},{type:"elem",elem:l}]},e)}return Dt.makeSpan(["mord",a.isOver?"mover":"munder"],[o],e)};Qt({type:"horizBrace",names:["\\overbrace","\\underbrace"],props:{numArgs:1},handler:function(t,e){var r=t.parser,a=t.funcName;return{type:"horizBrace",mode:r.mode,label:a,isOver:/^\\over/.test(a),base:e[0]}},htmlBuilder:Hr,mathmlBuilder:function(t,e){var r=Re(t.label);return new ve.MathNode(t.isOver?"mover":"munder",[Me(t.base,e),r])}}),Qt({type:"href",names:["\\href"],props:{numArgs:2,argTypes:["url","original"],allowedInText:!0},handler:function(t,e){var r=t.parser,a=e[1],n=Ft(e[0],"url").url;return r.settings.isTrusted({command:"\\href",url:n})?{type:"href",mode:r.mode,href:n,body:ee(a)}:r.formatUnsupportedCmd("\\href")},htmlBuilder:function(t,e){var r=se(t.body,e,!1);return Dt.makeAnchor(t.href,[],r,e)},mathmlBuilder:function(t,e){var r=Se(t.body,e);return r instanceof ge||(r=new ge("mrow",[r])),r.setAttribute("href",t.href),r}}),Qt({type:"href",names:["\\url"],props:{numArgs:1,argTypes:["url"],allowedInText:!0},handler:function(t,e){var r=t.parser,a=Ft(e[0],"url").url;if(!r.settings.isTrusted({command:"\\url",url:a}))return r.formatUnsupportedCmd("\\url");for(var n=[],i=0;i0&&(a=Tt(t.totalheight,e)-r,a=Number(a.toFixed(2)));var n=0;t.width.number>0&&(n=Tt(t.width,e));var i={height:r+a+"em"};n>0&&(i.width=n+"em"),a>0&&(i.verticalAlign=-a+"em");var o=new R(t.src,t.alt,i);return o.height=r,o.depth=a,o},mathmlBuilder:function(t,e){var r=new ve.MathNode("mglyph",[]);r.setAttribute("alt",t.alt);var a=Tt(t.height,e),n=0;if(t.totalheight.number>0&&(n=(n=Tt(t.totalheight,e)-a).toFixed(2),r.setAttribute("valign","-"+n+"em")),r.setAttribute("height",a+n+"em"),t.width.number>0){var i=Tt(t.width,e);r.setAttribute("width",i+"em")}return r.setAttribute("src",t.src),r}}),Qt({type:"kern",names:["\\kern","\\mkern","\\hskip","\\mskip"],props:{numArgs:1,argTypes:["size"],allowedInText:!0},handler:function(t,e){var r=t.parser,a=t.funcName,n=Ft(e[0],"size");if(r.settings.strict){var i="m"===a[1],o="mu"===n.value.unit;i?(o||r.settings.reportNonstrict("mathVsTextUnits","LaTeX's "+a+" supports only mu units, not "+n.value.unit+" units"),"math"!==r.mode&&r.settings.reportNonstrict("mathVsTextUnits","LaTeX's "+a+" works only in math mode")):o&&r.settings.reportNonstrict("mathVsTextUnits","LaTeX's "+a+" doesn't support mu units")}return{type:"kern",mode:r.mode,dimension:n.value}},htmlBuilder:function(t,e){return Dt.makeGlue(t.dimension,e)},mathmlBuilder:function(t,e){var r=Tt(t.dimension,e);return new ve.SpaceNode(r)}}),Qt({type:"lap",names:["\\mathllap","\\mathrlap","\\mathclap"],props:{numArgs:1,allowedInText:!0},handler:function(t,e){var r=t.parser,a=t.funcName,n=e[0];return{type:"lap",mode:r.mode,alignment:a.slice(5),body:n}},htmlBuilder:function(t,e){var r;"clap"===t.alignment?(r=Dt.makeSpan([],[ue(t.body,e)]),r=Dt.makeSpan(["inner"],[r],e)):r=Dt.makeSpan(["inner"],[ue(t.body,e)]);var a=Dt.makeSpan(["fix"],[]),n=Dt.makeSpan([t.alignment],[r,a],e),i=Dt.makeSpan(["strut"]);return i.style.height=n.height+n.depth+"em",i.style.verticalAlign=-n.depth+"em",n.children.unshift(i),n=Dt.makeVList({positionType:"firstBaseline",children:[{type:"elem",elem:n}]},e),Dt.makeSpan(["mord"],[n],e)},mathmlBuilder:function(t,e){var r=new ve.MathNode("mpadded",[Me(t.body,e)]);if("rlap"!==t.alignment){var a="llap"===t.alignment?"-1":"-0.5";r.setAttribute("lspace",a+"width")}return r.setAttribute("width","0px"),r}}),Qt({type:"styling",names:["\\(","$"],props:{numArgs:0,allowedInText:!0,allowedInMath:!1},handler:function(t,e){var r=t.funcName,a=t.parser,n=a.mode;a.switchMode("math");var i="\\("===r?"\\)":"$",o=a.parseExpression(!1,i);return a.expect(i),a.switchMode(n),{type:"styling",mode:a.mode,style:"text",body:o}}}),Qt({type:"text",names:["\\)","\\]"],props:{numArgs:0,allowedInText:!0,allowedInMath:!1},handler:function(t,e){throw new o("Mismatched "+t.funcName)}});var Dr=function(t,e){switch(e.style.size){case w.DISPLAY.size:return t.display;case w.TEXT.size:return t.text;case w.SCRIPT.size:return t.script;case w.SCRIPTSCRIPT.size:return t.scriptscript;default:return t.text}};Qt({type:"mathchoice",names:["\\mathchoice"],props:{numArgs:4},handler:function(t,e){return{type:"mathchoice",mode:t.parser.mode,display:ee(e[0]),text:ee(e[1]),script:ee(e[2]),scriptscript:ee(e[3])}},htmlBuilder:function(t,e){var r=Dr(t,e),a=se(r,e,!1);return Dt.makeFragment(a)},mathmlBuilder:function(t,e){var r=Dr(t,e);return Se(r,e)}});var Fr=function(t,e,r,a,n,i,o){var s,h,l;if(t=Dt.makeSpan([],[t]),e){var m=ue(e,a.havingStyle(n.sup()),a);h={elem:m,kern:Math.max(a.fontMetrics().bigOpSpacing1,a.fontMetrics().bigOpSpacing3-m.depth)}}if(r){var c=ue(r,a.havingStyle(n.sub()),a);s={elem:c,kern:Math.max(a.fontMetrics().bigOpSpacing2,a.fontMetrics().bigOpSpacing4-c.height)}}if(h&&s){var u=a.fontMetrics().bigOpSpacing5+s.elem.height+s.elem.depth+s.kern+t.depth+o;l=Dt.makeVList({positionType:"bottom",positionData:u,children:[{type:"kern",size:a.fontMetrics().bigOpSpacing5},{type:"elem",elem:s.elem,marginLeft:-i+"em"},{type:"kern",size:s.kern},{type:"elem",elem:t},{type:"kern",size:h.kern},{type:"elem",elem:h.elem,marginLeft:i+"em"},{type:"kern",size:a.fontMetrics().bigOpSpacing5}]},a)}else if(s){var p=t.height-o;l=Dt.makeVList({positionType:"top",positionData:p,children:[{type:"kern",size:a.fontMetrics().bigOpSpacing5},{type:"elem",elem:s.elem,marginLeft:-i+"em"},{type:"kern",size:s.kern},{type:"elem",elem:t}]},a)}else{if(!h)return t;var d=t.depth+o;l=Dt.makeVList({positionType:"bottom",positionData:d,children:[{type:"elem",elem:t},{type:"kern",size:h.kern},{type:"elem",elem:h.elem,marginLeft:i+"em"},{type:"kern",size:a.fontMetrics().bigOpSpacing5}]},a)}return Dt.makeSpan(["mop","op-limits"],[l],a)},Vr=["\\smallint"],Ur=function(t,e){var r,a,n,i=!1,o=Vt(t,"supsub");o?(r=o.sup,a=o.sub,n=Ft(o.base,"op"),i=!0):n=Ft(t,"op");var s,h=e.style,l=!1;if(h.size===w.DISPLAY.size&&n.symbol&&!c.contains(Vr,n.name)&&(l=!0),n.symbol){var m=l?"Size2-Regular":"Size1-Regular",u="";if("\\oiint"!==n.name&&"\\oiiint"!==n.name||(u=n.name.substr(1),n.name="oiint"===u?"\\iint":"\\iiint"),s=Dt.makeSymbol(n.name,m,"math",e,["mop","op-symbol",l?"large-op":"small-op"]),u.length>0){var p=s.italic,d=Dt.staticSvg(u+"Size"+(l?"2":"1"),e);s=Dt.makeVList({positionType:"individualShift",children:[{type:"elem",elem:s,shift:0},{type:"elem",elem:d,shift:l?.08:0}]},e),n.name="\\"+u,s.classes.unshift("mop"),s.italic=p}}else if(n.body){var f=se(n.body,e,!0);1===f.length&&f[0]instanceof E?(s=f[0]).classes[0]="mop":s=Dt.makeSpan(["mop"],Dt.tryCombineChars(f),e)}else{for(var g=[],x=1;x0){for(var h=n.body.map(function(t){var e=t.text;return"string"==typeof e?{type:"textord",mode:t.mode,text:e}:t}),l=se(h,e.withFont("mathrm"),!0),m=0;m=0?s.setAttribute("height","+"+n+"em"):(s.setAttribute("height",n+"em"),s.setAttribute("depth","+"+-n+"em")),s.setAttribute("voffset",n+"em"),s}});var jr=["\\tiny","\\sixptsize","\\scriptsize","\\footnotesize","\\small","\\normalsize","\\large","\\Large","\\LARGE","\\huge","\\Huge"];Qt({type:"sizing",names:jr,props:{numArgs:0,allowedInText:!0},handler:function(t,e){var r=t.breakOnTokenText,a=t.funcName,n=t.parser,i=n.parseExpression(!1,r);return{type:"sizing",mode:n.mode,size:jr.indexOf(a)+1,body:i}},htmlBuilder:function(t,e){var r=e.havingSize(t.size);return _r(t.body,r,e)},mathmlBuilder:function(t,e){var r=e.havingSize(t.size),a=ke(t.body,r),n=new ve.MathNode("mstyle",a);return n.setAttribute("mathsize",r.sizeMultiplier+"em"),n}}),Qt({type:"smash",names:["\\smash"],props:{numArgs:1,numOptionalArgs:1,allowedInText:!0},handler:function(t,e,r){var a=t.parser,n=!1,i=!1,o=r[0]&&Ft(r[0],"ordgroup");if(o)for(var s="",h=0;hr.height+r.depth+i&&(i=(i+c-r.height-r.depth)/2);var u=h.height-r.height-i-l;r.style.paddingLeft=m+"em";var p=Dt.makeVList({positionType:"firstBaseline",children:[{type:"elem",elem:r,wrapperClasses:["svg-align"]},{type:"kern",size:-(r.height+u)},{type:"elem",elem:h},{type:"kern",size:l}]},e);if(t.index){var d=e.havingStyle(w.SCRIPTSCRIPT),f=ue(t.index,d,e),g=.6*(p.height-p.depth),x=Dt.makeVList({positionType:"shift",positionData:-g,children:[{type:"elem",elem:f}]},e),v=Dt.makeSpan(["root"],[x]);return Dt.makeSpan(["mord","sqrt"],[v,p],e)}return Dt.makeSpan(["mord","sqrt"],[p],e)},mathmlBuilder:function(t,e){var r=t.body,a=t.index;return a?new ve.MathNode("mroot",[Me(r,e),Me(a,e)]):new ve.MathNode("msqrt",[Me(r,e)])}});var $r={display:w.DISPLAY,text:w.TEXT,script:w.SCRIPT,scriptscript:w.SCRIPTSCRIPT};Qt({type:"styling",names:["\\displaystyle","\\textstyle","\\scriptstyle","\\scriptscriptstyle"],props:{numArgs:0,allowedInText:!0},handler:function(t,e){var r=t.breakOnTokenText,a=t.funcName,n=t.parser,i=n.parseExpression(!0,r),o=a.slice(1,a.length-5);return{type:"styling",mode:n.mode,style:o,body:i}},htmlBuilder:function(t,e){var r=$r[t.style],a=e.havingStyle(r).withFont("");return _r(t.body,a,e)},mathmlBuilder:function(t,e){var r=$r[t.style],a=e.havingStyle(r),n=ke(t.body,a),i=new ve.MathNode("mstyle",n),o={display:["0","true"],text:["0","false"],script:["1","false"],scriptscript:["2","false"]}[t.style];return i.setAttribute("scriptlevel",o[0]),i.setAttribute("displaystyle",o[1]),i}});te({type:"supsub",htmlBuilder:function(t,e){var r=function(t,e){var r=t.base;return r?"op"===r.type?r.limits&&(e.style.size===w.DISPLAY.size||r.alwaysHandleSupSub)?Ur:null:"operatorname"===r.type?r.alwaysHandleSupSub&&(e.style.size===w.DISPLAY.size||r.limits)?Xr:null:"accent"===r.type?c.isCharacterBox(r.base)?Ee:null:"horizBrace"===r.type&&!t.sub===r.isOver?Hr:null:null}(t,e);if(r)return r(t,e);var a,n,i,o=t.base,s=t.sup,h=t.sub,l=ue(o,e),m=e.fontMetrics(),u=0,p=0,d=o&&c.isCharacterBox(o);if(s){var f=e.havingStyle(e.style.sup());a=ue(s,f,e),d||(u=l.height-f.fontMetrics().supDrop*f.sizeMultiplier/e.sizeMultiplier)}if(h){var g=e.havingStyle(e.style.sub());n=ue(h,g,e),d||(p=l.depth+g.fontMetrics().subDrop*g.sizeMultiplier/e.sizeMultiplier)}i=e.style===w.DISPLAY?m.sup1:e.style.cramped?m.sup3:m.sup2;var x,v=e.sizeMultiplier,b=.5/m.ptPerEm/v+"em",y=null;if(n){var k=t.base&&"op"===t.base.type&&t.base.name&&("\\oiint"===t.base.name||"\\oiiint"===t.base.name);(l instanceof E||k)&&(y=-l.italic+"em")}if(a&&n){u=Math.max(u,i,a.depth+.25*m.xHeight),p=Math.max(p,m.sub2);var S=4*m.defaultRuleThickness;if(u-a.depth-(n.height-p)0&&(u+=M,p-=M)}var z=[{type:"elem",elem:n,shift:p,marginRight:b,marginLeft:y},{type:"elem",elem:a,shift:-u,marginRight:b}];x=Dt.makeVList({positionType:"individualShift",children:z},e)}else if(n){p=Math.max(p,m.sub1,n.height-.8*m.xHeight);var A=[{type:"elem",elem:n,marginLeft:y,marginRight:b}];x=Dt.makeVList({positionType:"shift",positionData:p,children:A},e)}else{if(!a)throw new Error("supsub must have either sup or sub.");u=Math.max(u,i,a.depth+.25*m.xHeight),x=Dt.makeVList({positionType:"shift",positionData:-u,children:[{type:"elem",elem:a,marginRight:b}]},e)}var T=me(l,"right")||"mord";return Dt.makeSpan([T],[l,Dt.makeSpan(["msupsub"],[x])],e)},mathmlBuilder:function(t,e){var r,a=!1,n=Vt(t.base,"horizBrace");n&&!!t.sup===n.isOver&&(a=!0,r=n.isOver),!t.base||"op"!==t.base.type&&"operatorname"!==t.base.type||(t.base.parentIsSupSub=!0);var i,o=[Me(t.base,e)];if(t.sub&&o.push(Me(t.sub,e)),t.sup&&o.push(Me(t.sup,e)),a)i=r?"mover":"munder";else if(t.sub)if(t.sup){var s=t.base;i=s&&"op"===s.type&&s.limits&&e.style===w.DISPLAY?"munderover":s&&"operatorname"===s.type&&s.alwaysHandleSupSub&&(e.style===w.DISPLAY||s.limits)?"munderover":"msubsup"}else{var h=t.base;i=h&&"op"===h.type&&h.limits&&(e.style===w.DISPLAY||h.alwaysHandleSupSub)?"munder":h&&"operatorname"===h.type&&h.alwaysHandleSupSub&&(h.limits||e.style===w.DISPLAY)?"munder":"msub"}else{var l=t.base;i=l&&"op"===l.type&&l.limits&&(e.style===w.DISPLAY||l.alwaysHandleSupSub)?"mover":l&&"operatorname"===l.type&&l.alwaysHandleSupSub&&(l.limits||e.style===w.DISPLAY)?"mover":"msup"}return new ve.MathNode(i,o)}}),te({type:"atom",htmlBuilder:function(t,e){return Dt.mathsym(t.text,t.mode,e,["m"+t.family])},mathmlBuilder:function(t,e){var r=new ve.MathNode("mo",[be(t.text,t.mode)]);if("bin"===t.family){var a=we(t,e);"bold-italic"===a&&r.setAttribute("mathvariant",a)}else"punct"===t.family?r.setAttribute("separator","true"):"open"!==t.family&&"close"!==t.family||r.setAttribute("stretchy","false");return r}});var Zr={mi:"italic",mn:"normal",mtext:"normal"};te({type:"mathord",htmlBuilder:function(t,e){return Dt.makeOrd(t,e,"mathord")},mathmlBuilder:function(t,e){var r=new ve.MathNode("mi",[be(t.text,t.mode,e)]),a=we(t,e)||"italic";return a!==Zr[r.type]&&r.setAttribute("mathvariant",a),r}}),te({type:"textord",htmlBuilder:function(t,e){return Dt.makeOrd(t,e,"textord")},mathmlBuilder:function(t,e){var r,a=be(t.text,t.mode,e),n=we(t,e)||"normal";return r="text"===t.mode?new ve.MathNode("mtext",[a]):/[0-9]/.test(t.text)?new ve.MathNode("mn",[a]):"\\prime"===t.text?new ve.MathNode("mo",[a]):new ve.MathNode("mi",[a]),n!==Zr[r.type]&&r.setAttribute("mathvariant",n),r}});var Kr={"\\nobreak":"nobreak","\\allowbreak":"allowbreak"},Jr={" ":{},"\\ ":{},"~":{className:"nobreak"},"\\space":{},"\\nobreakspace":{className:"nobreak"}};te({type:"spacing",htmlBuilder:function(t,e){if(Jr.hasOwnProperty(t.text)){var r=Jr[t.text].className||"";if("text"===t.mode){var a=Dt.makeOrd(t,e,"textord");return a.classes.push(r),a}return Dt.makeSpan(["mspace",r],[Dt.mathsym(t.text,t.mode,e)],e)}if(Kr.hasOwnProperty(t.text))return Dt.makeSpan(["mspace",Kr[t.text]],[],e);throw new o('Unknown type of space "'+t.text+'"')},mathmlBuilder:function(t,e){if(!Jr.hasOwnProperty(t.text)){if(Kr.hasOwnProperty(t.text))return new ve.MathNode("mspace");throw new o('Unknown type of space "'+t.text+'"')}return new ve.MathNode("mtext",[new ve.TextNode("\xa0")])}});var Qr=function(){var t=new ve.MathNode("mtd",[]);return t.setAttribute("width","50%"),t};te({type:"tag",mathmlBuilder:function(t,e){var r=new ve.MathNode("mtable",[new ve.MathNode("mtr",[Qr(),new ve.MathNode("mtd",[Se(t.body,e)]),Qr(),new ve.MathNode("mtd",[Se(t.tag,e)])])]);return r.setAttribute("width","100%"),r}});var ta={"\\text":void 0,"\\textrm":"textrm","\\textsf":"textsf","\\texttt":"texttt","\\textnormal":"textrm"},ea={"\\textbf":"textbf","\\textmd":"textmd"},ra={"\\textit":"textit","\\textup":"textup"},aa=function(t,e){var r=t.font;return r?ta[r]?e.withTextFontFamily(ta[r]):ea[r]?e.withTextFontWeight(ea[r]):e.withTextFontShape(ra[r]):e};Qt({type:"text",names:["\\text","\\textrm","\\textsf","\\texttt","\\textnormal","\\textbf","\\textmd","\\textit","\\textup"],props:{numArgs:1,argTypes:["text"],greediness:2,allowedInText:!0},handler:function(t,e){var r=t.parser,a=t.funcName,n=e[0];return{type:"text",mode:r.mode,body:ee(n),font:a}},htmlBuilder:function(t,e){var r=aa(t,e),a=se(t.body,r,!0);return Dt.makeSpan(["mord","text"],Dt.tryCombineChars(a),r)},mathmlBuilder:function(t,e){var r=aa(t,e);return Se(t.body,r)}}),Qt({type:"underline",names:["\\underline"],props:{numArgs:1,allowedInText:!0},handler:function(t,e){return{type:"underline",mode:t.parser.mode,body:e[0]}},htmlBuilder:function(t,e){var r=ue(t.body,e),a=Dt.makeLineSpan("underline-line",e),n=e.fontMetrics().defaultRuleThickness,i=Dt.makeVList({positionType:"top",positionData:r.height,children:[{type:"kern",size:n},{type:"elem",elem:a},{type:"kern",size:3*n},{type:"elem",elem:r}]},e);return Dt.makeSpan(["mord","underline"],[i],e)},mathmlBuilder:function(t,e){var r=new ve.MathNode("mo",[new ve.TextNode("\u203e")]);r.setAttribute("stretchy","true");var a=new ve.MathNode("munder",[Me(t.body,e),r]);return a.setAttribute("accentunder","true"),a}}),Qt({type:"verb",names:["\\verb"],props:{numArgs:0,allowedInText:!0},handler:function(t,e,r){throw new o("\\verb ended by end of line instead of matching delimiter")},htmlBuilder:function(t,e){for(var r=na(t),a=[],n=e.havingStyle(e.style.text()),i=0;i0&&(this.undefStack[this.undefStack.length-1][t]=e)}else{var n=this.undefStack[this.undefStack.length-1];n&&!n.hasOwnProperty(t)&&(n[t]=this.current[t])}this.current[t]=e},t}(),ca={},ua=ca;function pa(t,e){ca[t]=e}pa("\\@firstoftwo",function(t){return{tokens:t.consumeArgs(2)[0],numArgs:0}}),pa("\\@secondoftwo",function(t){return{tokens:t.consumeArgs(2)[1],numArgs:0}}),pa("\\@ifnextchar",function(t){var e=t.consumeArgs(3),r=t.future();return 1===e[0].length&&e[0][0].text===r.text?{tokens:e[1],numArgs:0}:{tokens:e[2],numArgs:0}}),pa("\\@ifstar","\\@ifnextchar *{\\@firstoftwo{#1}}"),pa("\\TextOrMath",function(t){var e=t.consumeArgs(2);return"text"===t.mode?{tokens:e[0],numArgs:0}:{tokens:e[1],numArgs:0}});var da={0:0,1:1,2:2,3:3,4:4,5:5,6:6,7:7,8:8,9:9,a:10,A:10,b:11,B:11,c:12,C:12,d:13,D:13,e:14,E:14,f:15,F:15};pa("\\char",function(t){var e,r=t.popToken(),a="";if("'"===r.text)e=8,r=t.popToken();else if('"'===r.text)e=16,r=t.popToken();else if("`"===r.text)if("\\"===(r=t.popToken()).text[0])a=r.text.charCodeAt(1);else{if("EOF"===r.text)throw new o("\\char` missing argument");a=r.text.charCodeAt(0)}else e=10;if(e){if(null==(a=da[r.text])||a>=e)throw new o("Invalid base-"+e+" digit "+r.text);for(var n;null!=(n=da[t.future().text])&&n":"\\dotsb","-":"\\dotsb","*":"\\dotsb",":":"\\dotsb","\\DOTSB":"\\dotsb","\\coprod":"\\dotsb","\\bigvee":"\\dotsb","\\bigwedge":"\\dotsb","\\biguplus":"\\dotsb","\\bigcap":"\\dotsb","\\bigcup":"\\dotsb","\\prod":"\\dotsb","\\sum":"\\dotsb","\\bigotimes":"\\dotsb","\\bigoplus":"\\dotsb","\\bigodot":"\\dotsb","\\bigsqcup":"\\dotsb","\\And":"\\dotsb","\\longrightarrow":"\\dotsb","\\Longrightarrow":"\\dotsb","\\longleftarrow":"\\dotsb","\\Longleftarrow":"\\dotsb","\\longleftrightarrow":"\\dotsb","\\Longleftrightarrow":"\\dotsb","\\mapsto":"\\dotsb","\\longmapsto":"\\dotsb","\\hookrightarrow":"\\dotsb","\\doteq":"\\dotsb","\\mathbin":"\\dotsb","\\mathrel":"\\dotsb","\\relbar":"\\dotsb","\\Relbar":"\\dotsb","\\xrightarrow":"\\dotsb","\\xleftarrow":"\\dotsb","\\DOTSI":"\\dotsi","\\int":"\\dotsi","\\oint":"\\dotsi","\\iint":"\\dotsi","\\iiint":"\\dotsi","\\iiiint":"\\dotsi","\\idotsint":"\\dotsi","\\DOTSX":"\\dotsx"};pa("\\dots",function(t){var e="\\dotso",r=t.expandAfterFuture().text;return r in xa?e=xa[r]:"\\not"===r.substr(0,4)?e="\\dotsb":r in j.math&&c.contains(["bin","rel"],j.math[r].group)&&(e="\\dotsb"),e});var va={")":!0,"]":!0,"\\rbrack":!0,"\\}":!0,"\\rbrace":!0,"\\rangle":!0,"\\rceil":!0,"\\rfloor":!0,"\\rgroup":!0,"\\rmoustache":!0,"\\right":!0,"\\bigr":!0,"\\biggr":!0,"\\Bigr":!0,"\\Biggr":!0,$:!0,";":!0,".":!0,",":!0};pa("\\dotso",function(t){return t.future().text in va?"\\ldots\\,":"\\ldots"}),pa("\\dotsc",function(t){var e=t.future().text;return e in va&&","!==e?"\\ldots\\,":"\\ldots"}),pa("\\cdots",function(t){return t.future().text in va?"\\@cdots\\,":"\\@cdots"}),pa("\\dotsb","\\cdots"),pa("\\dotsm","\\cdots"),pa("\\dotsi","\\!\\cdots"),pa("\\dotsx","\\ldots\\,"),pa("\\DOTSI","\\relax"),pa("\\DOTSB","\\relax"),pa("\\DOTSX","\\relax"),pa("\\tmspace","\\TextOrMath{\\kern#1#3}{\\mskip#1#2}\\relax"),pa("\\,","\\tmspace+{3mu}{.1667em}"),pa("\\thinspace","\\,"),pa("\\>","\\mskip{4mu}"),pa("\\:","\\tmspace+{4mu}{.2222em}"),pa("\\medspace","\\:"),pa("\\;","\\tmspace+{5mu}{.2777em}"),pa("\\thickspace","\\;"),pa("\\!","\\tmspace-{3mu}{.1667em}"),pa("\\negthinspace","\\!"),pa("\\negmedspace","\\tmspace-{4mu}{.2222em}"),pa("\\negthickspace","\\tmspace-{5mu}{.277em}"),pa("\\enspace","\\kern.5em "),pa("\\enskip","\\hskip.5em\\relax"),pa("\\quad","\\hskip1em\\relax"),pa("\\qquad","\\hskip2em\\relax"),pa("\\tag","\\@ifstar\\tag@literal\\tag@paren"),pa("\\tag@paren","\\tag@literal{({#1})}"),pa("\\tag@literal",function(t){if(t.macros.get("\\df@tag"))throw new o("Multiple \\tag");return"\\gdef\\df@tag{\\text{#1}}"}),pa("\\bmod","\\mathchoice{\\mskip1mu}{\\mskip1mu}{\\mskip5mu}{\\mskip5mu}\\mathbin{\\rm mod}\\mathchoice{\\mskip1mu}{\\mskip1mu}{\\mskip5mu}{\\mskip5mu}"),pa("\\pod","\\allowbreak\\mathchoice{\\mkern18mu}{\\mkern8mu}{\\mkern8mu}{\\mkern8mu}(#1)"),pa("\\pmod","\\pod{{\\rm mod}\\mkern6mu#1}"),pa("\\mod","\\allowbreak\\mathchoice{\\mkern18mu}{\\mkern12mu}{\\mkern12mu}{\\mkern12mu}{\\rm mod}\\,\\,#1"),pa("\\pmb","\\html@mathml{\\@binrel{#1}{\\mathrlap{#1}\\kern0.5px#1}}{\\mathbf{#1}}"),pa("\\\\","\\newline"),pa("\\TeX","\\textrm{\\html@mathml{T\\kern-.1667em\\raisebox{-.5ex}{E}\\kern-.125emX}{TeX}}");var ba=F["Main-Regular"]["T".charCodeAt(0)][1]-.7*F["Main-Regular"]["A".charCodeAt(0)][1]+"em";pa("\\LaTeX","\\textrm{\\html@mathml{L\\kern-.36em\\raisebox{"+ba+"}{\\scriptstyle A}\\kern-.15em\\TeX}{LaTeX}}"),pa("\\KaTeX","\\textrm{\\html@mathml{K\\kern-.17em\\raisebox{"+ba+"}{\\scriptstyle A}\\kern-.15em\\TeX}{KaTeX}}"),pa("\\hspace","\\@ifstar\\@hspacer\\@hspace"),pa("\\@hspace","\\hskip #1\\relax"),pa("\\@hspacer","\\rule{0pt}{0pt}\\hskip #1\\relax"),pa("\\ordinarycolon",":"),pa("\\vcentcolon","\\mathrel{\\mathop\\ordinarycolon}"),pa("\\dblcolon",'\\html@mathml{\\mathrel{\\vcentcolon\\mathrel{\\mkern-.9mu}\\vcentcolon}}{\\mathop{\\char"2237}}'),pa("\\coloneqq",'\\html@mathml{\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}=}}{\\mathop{\\char"2254}}'),pa("\\Coloneqq",'\\html@mathml{\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}=}}{\\mathop{\\char"2237\\char"3d}}'),pa("\\coloneq",'\\html@mathml{\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}\\mathrel{-}}}{\\mathop{\\char"3a\\char"2212}}'),pa("\\Coloneq",'\\html@mathml{\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}\\mathrel{-}}}{\\mathop{\\char"2237\\char"2212}}'),pa("\\eqqcolon",'\\html@mathml{\\mathrel{=\\mathrel{\\mkern-1.2mu}\\vcentcolon}}{\\mathop{\\char"2255}}'),pa("\\Eqqcolon",'\\html@mathml{\\mathrel{=\\mathrel{\\mkern-1.2mu}\\dblcolon}}{\\mathop{\\char"3d\\char"2237}}'),pa("\\eqcolon",'\\html@mathml{\\mathrel{\\mathrel{-}\\mathrel{\\mkern-1.2mu}\\vcentcolon}}{\\mathop{\\char"2239}}'),pa("\\Eqcolon",'\\html@mathml{\\mathrel{\\mathrel{-}\\mathrel{\\mkern-1.2mu}\\dblcolon}}{\\mathop{\\char"2212\\char"2237}}'),pa("\\colonapprox",'\\html@mathml{\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}\\approx}}{\\mathop{\\char"3a\\char"2248}}'),pa("\\Colonapprox",'\\html@mathml{\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}\\approx}}{\\mathop{\\char"2237\\char"2248}}'),pa("\\colonsim",'\\html@mathml{\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}\\sim}}{\\mathop{\\char"3a\\char"223c}}'),pa("\\Colonsim",'\\html@mathml{\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}\\sim}}{\\mathop{\\char"2237\\char"223c}}'),pa("\u2237","\\dblcolon"),pa("\u2239","\\eqcolon"),pa("\u2254","\\coloneqq"),pa("\u2255","\\eqqcolon"),pa("\u2a74","\\Coloneqq"),pa("\\ratio","\\vcentcolon"),pa("\\coloncolon","\\dblcolon"),pa("\\colonequals","\\coloneqq"),pa("\\coloncolonequals","\\Coloneqq"),pa("\\equalscolon","\\eqqcolon"),pa("\\equalscoloncolon","\\Eqqcolon"),pa("\\colonminus","\\coloneq"),pa("\\coloncolonminus","\\Coloneq"),pa("\\minuscolon","\\eqcolon"),pa("\\minuscoloncolon","\\Eqcolon"),pa("\\coloncolonapprox","\\Colonapprox"),pa("\\coloncolonsim","\\Colonsim"),pa("\\simcolon","\\mathrel{\\sim\\mathrel{\\mkern-1.2mu}\\vcentcolon}"),pa("\\simcoloncolon","\\mathrel{\\sim\\mathrel{\\mkern-1.2mu}\\dblcolon}"),pa("\\approxcolon","\\mathrel{\\approx\\mathrel{\\mkern-1.2mu}\\vcentcolon}"),pa("\\approxcoloncolon","\\mathrel{\\approx\\mathrel{\\mkern-1.2mu}\\dblcolon}"),pa("\\notni","\\html@mathml{\\not\\ni}{\\mathrel{\\char`\u220c}}"),pa("\\limsup","\\DOTSB\\operatorname*{lim\\,sup}"),pa("\\liminf","\\DOTSB\\operatorname*{lim\\,inf}"),pa("\\gvertneqq","\\html@mathml{\\@gvertneqq}{\u2269}"),pa("\\lvertneqq","\\html@mathml{\\@lvertneqq}{\u2268}"),pa("\\ngeqq","\\html@mathml{\\@ngeqq}{\u2271}"),pa("\\ngeqslant","\\html@mathml{\\@ngeqslant}{\u2271}"),pa("\\nleqq","\\html@mathml{\\@nleqq}{\u2270}"),pa("\\nleqslant","\\html@mathml{\\@nleqslant}{\u2270}"),pa("\\nshortmid","\\html@mathml{\\@nshortmid}{\u2224}"),pa("\\nshortparallel","\\html@mathml{\\@nshortparallel}{\u2226}"),pa("\\nsubseteqq","\\html@mathml{\\@nsubseteqq}{\u2288}"),pa("\\nsupseteqq","\\html@mathml{\\@nsupseteqq}{\u2289}"),pa("\\varsubsetneq","\\html@mathml{\\@varsubsetneq}{\u228a}"),pa("\\varsubsetneqq","\\html@mathml{\\@varsubsetneqq}{\u2acb}"),pa("\\varsupsetneq","\\html@mathml{\\@varsupsetneq}{\u228b}"),pa("\\varsupsetneqq","\\html@mathml{\\@varsupsetneqq}{\u2acc}"),pa("\\llbracket","\\html@mathml{\\mathopen{[\\mkern-3.2mu[}}{\\mathopen{\\char`\u27e6}}"),pa("\\rrbracket","\\html@mathml{\\mathclose{]\\mkern-3.2mu]}}{\\mathclose{\\char`\u27e7}}"),pa("\u27e6","\\llbracket"),pa("\u27e7","\\rrbracket"),pa("\\lBrace","\\html@mathml{\\mathopen{\\{\\mkern-3.2mu[}}{\\mathopen{\\char`\u2983}}"),pa("\\rBrace","\\html@mathml{\\mathclose{]\\mkern-3.2mu\\}}}{\\mathclose{\\char`\u2984}}"),pa("\u2983","\\lBrace"),pa("\u2984","\\rBrace"),pa("\\darr","\\downarrow"),pa("\\dArr","\\Downarrow"),pa("\\Darr","\\Downarrow"),pa("\\lang","\\langle"),pa("\\rang","\\rangle"),pa("\\uarr","\\uparrow"),pa("\\uArr","\\Uparrow"),pa("\\Uarr","\\Uparrow"),pa("\\N","\\mathbb{N}"),pa("\\R","\\mathbb{R}"),pa("\\Z","\\mathbb{Z}"),pa("\\alef","\\aleph"),pa("\\alefsym","\\aleph"),pa("\\Alpha","\\mathrm{A}"),pa("\\Beta","\\mathrm{B}"),pa("\\bull","\\bullet"),pa("\\Chi","\\mathrm{X}"),pa("\\clubs","\\clubsuit"),pa("\\cnums","\\mathbb{C}"),pa("\\Complex","\\mathbb{C}"),pa("\\Dagger","\\ddagger"),pa("\\diamonds","\\diamondsuit"),pa("\\empty","\\emptyset"),pa("\\Epsilon","\\mathrm{E}"),pa("\\Eta","\\mathrm{H}"),pa("\\exist","\\exists"),pa("\\harr","\\leftrightarrow"),pa("\\hArr","\\Leftrightarrow"),pa("\\Harr","\\Leftrightarrow"),pa("\\hearts","\\heartsuit"),pa("\\image","\\Im"),pa("\\infin","\\infty"),pa("\\Iota","\\mathrm{I}"),pa("\\isin","\\in"),pa("\\Kappa","\\mathrm{K}"),pa("\\larr","\\leftarrow"),pa("\\lArr","\\Leftarrow"),pa("\\Larr","\\Leftarrow"),pa("\\lrarr","\\leftrightarrow"),pa("\\lrArr","\\Leftrightarrow"),pa("\\Lrarr","\\Leftrightarrow"),pa("\\Mu","\\mathrm{M}"),pa("\\natnums","\\mathbb{N}"),pa("\\Nu","\\mathrm{N}"),pa("\\Omicron","\\mathrm{O}"),pa("\\plusmn","\\pm"),pa("\\rarr","\\rightarrow"),pa("\\rArr","\\Rightarrow"),pa("\\Rarr","\\Rightarrow"),pa("\\real","\\Re"),pa("\\reals","\\mathbb{R}"),pa("\\Reals","\\mathbb{R}"),pa("\\Rho","\\mathrm{P}"),pa("\\sdot","\\cdot"),pa("\\sect","\\S"),pa("\\spades","\\spadesuit"),pa("\\sub","\\subset"),pa("\\sube","\\subseteq"),pa("\\supe","\\supseteq"),pa("\\Tau","\\mathrm{T}"),pa("\\thetasym","\\vartheta"),pa("\\weierp","\\wp"),pa("\\Zeta","\\mathrm{Z}"),pa("\\argmin","\\DOTSB\\operatorname*{arg\\,min}"),pa("\\argmax","\\DOTSB\\operatorname*{arg\\,max}"),pa("\\plim","\\DOTSB\\mathop{\\operatorname{plim}}\\limits"),pa("\\blue","\\textcolor{##6495ed}{#1}"),pa("\\orange","\\textcolor{##ffa500}{#1}"),pa("\\pink","\\textcolor{##ff00af}{#1}"),pa("\\red","\\textcolor{##df0030}{#1}"),pa("\\green","\\textcolor{##28ae7b}{#1}"),pa("\\gray","\\textcolor{gray}{#1}"),pa("\\purple","\\textcolor{##9d38bd}{#1}"),pa("\\blueA","\\textcolor{##ccfaff}{#1}"),pa("\\blueB","\\textcolor{##80f6ff}{#1}"),pa("\\blueC","\\textcolor{##63d9ea}{#1}"),pa("\\blueD","\\textcolor{##11accd}{#1}"),pa("\\blueE","\\textcolor{##0c7f99}{#1}"),pa("\\tealA","\\textcolor{##94fff5}{#1}"),pa("\\tealB","\\textcolor{##26edd5}{#1}"),pa("\\tealC","\\textcolor{##01d1c1}{#1}"),pa("\\tealD","\\textcolor{##01a995}{#1}"),pa("\\tealE","\\textcolor{##208170}{#1}"),pa("\\greenA","\\textcolor{##b6ffb0}{#1}"),pa("\\greenB","\\textcolor{##8af281}{#1}"),pa("\\greenC","\\textcolor{##74cf70}{#1}"),pa("\\greenD","\\textcolor{##1fab54}{#1}"),pa("\\greenE","\\textcolor{##0d923f}{#1}"),pa("\\goldA","\\textcolor{##ffd0a9}{#1}"),pa("\\goldB","\\textcolor{##ffbb71}{#1}"),pa("\\goldC","\\textcolor{##ff9c39}{#1}"),pa("\\goldD","\\textcolor{##e07d10}{#1}"),pa("\\goldE","\\textcolor{##a75a05}{#1}"),pa("\\redA","\\textcolor{##fca9a9}{#1}"),pa("\\redB","\\textcolor{##ff8482}{#1}"),pa("\\redC","\\textcolor{##f9685d}{#1}"),pa("\\redD","\\textcolor{##e84d39}{#1}"),pa("\\redE","\\textcolor{##bc2612}{#1}"),pa("\\maroonA","\\textcolor{##ffbde0}{#1}"),pa("\\maroonB","\\textcolor{##ff92c6}{#1}"),pa("\\maroonC","\\textcolor{##ed5fa6}{#1}"),pa("\\maroonD","\\textcolor{##ca337c}{#1}"),pa("\\maroonE","\\textcolor{##9e034e}{#1}"),pa("\\purpleA","\\textcolor{##ddd7ff}{#1}"),pa("\\purpleB","\\textcolor{##c6b9fc}{#1}"),pa("\\purpleC","\\textcolor{##aa87ff}{#1}"),pa("\\purpleD","\\textcolor{##7854ab}{#1}"),pa("\\purpleE","\\textcolor{##543b78}{#1}"),pa("\\mintA","\\textcolor{##f5f9e8}{#1}"),pa("\\mintB","\\textcolor{##edf2df}{#1}"),pa("\\mintC","\\textcolor{##e0e5cc}{#1}"),pa("\\grayA","\\textcolor{##f6f7f7}{#1}"),pa("\\grayB","\\textcolor{##f0f1f2}{#1}"),pa("\\grayC","\\textcolor{##e3e5e6}{#1}"),pa("\\grayD","\\textcolor{##d6d8da}{#1}"),pa("\\grayE","\\textcolor{##babec2}{#1}"),pa("\\grayF","\\textcolor{##888d93}{#1}"),pa("\\grayG","\\textcolor{##626569}{#1}"),pa("\\grayH","\\textcolor{##3b3e40}{#1}"),pa("\\grayI","\\textcolor{##21242c}{#1}"),pa("\\kaBlue","\\textcolor{##314453}{#1}"),pa("\\kaGreen","\\textcolor{##71B307}{#1}");var ya={"\\relax":!0,"^":!0,_:!0,"\\limits":!0,"\\nolimits":!0},wa=function(){function t(t,e,r){this.settings=void 0,this.expansionCount=void 0,this.lexer=void 0,this.macros=void 0,this.stack=void 0,this.mode=void 0,this.settings=e,this.expansionCount=0,this.feed(t),this.macros=new ma(ua,e.macros),this.mode=r,this.stack=[]}var e=t.prototype;return e.feed=function(t){this.lexer=new la(t,this.settings)},e.switchMode=function(t){this.mode=t},e.beginGroup=function(){this.macros.beginGroup()},e.endGroup=function(){this.macros.endGroup()},e.future=function(){return 0===this.stack.length&&this.pushToken(this.lexer.lex()),this.stack[this.stack.length-1]},e.popToken=function(){return this.future(),this.stack.pop()},e.pushToken=function(t){this.stack.push(t)},e.pushTokens=function(t){var e;(e=this.stack).push.apply(e,t)},e.consumeSpaces=function(){for(;;){if(" "!==this.future().text)break;this.stack.pop()}},e.consumeArgs=function(t){for(var e=[],r=0;rthis.settings.maxExpand)throw new o("Too many expansions: infinite loop or need to increase maxExpand setting");var a=r.tokens;if(r.numArgs)for(var n=this.consumeArgs(r.numArgs),i=(a=a.slice()).length-1;i>=0;--i){var s=a[i];if("#"===s.text){if(0===i)throw new o("Incomplete placeholder at end of macro body",s);if("#"===(s=a[--i]).text)a.splice(i+1,1);else{if(!/^[1-9]$/.test(s.text))throw new o("Not a valid argument number",s);var h;(h=a).splice.apply(h,[i,2].concat(n[+s.text-1]))}}}return this.pushTokens(a),a},e.expandAfterFuture=function(){return this.expandOnce(),this.future()},e.expandNextToken=function(){for(;;){var t=this.expandOnce();if(t instanceof n){if("\\relax"!==t.text)return this.stack.pop();this.stack.pop()}}throw new Error},e.expandMacro=function(t){if(this.macros.get(t)){var e=[],r=this.stack.length;for(this.pushToken(new n(t));this.stack.length>r;){this.expandOnce()instanceof n&&e.push(this.stack.pop())}return e}},e.expandMacroAsText=function(t){var e=this.expandMacro(t);return e?e.map(function(t){return t.text}).join(""):e},e._getExpansion=function(t){var e=this.macros.get(t);if(null==e)return e;var r="function"==typeof e?e(this):e;if("string"==typeof r){var a=0;if(-1!==r.indexOf("#"))for(var n=r.replace(/##/g,"");-1!==n.indexOf("#"+(a+1));)++a;for(var i=new la(r,this.settings),o=[],s=i.lex();"EOF"!==s.text;)o.push(s),s=i.lex();return o.reverse(),{tokens:o,numArgs:a}}return r},e.isDefined=function(t){return this.macros.has(t)||ia.hasOwnProperty(t)||j.math.hasOwnProperty(t)||j.text.hasOwnProperty(t)||ya.hasOwnProperty(t)},t}(),ka={"\u0301":{text:"\\'",math:"\\acute"},"\u0300":{text:"\\`",math:"\\grave"},"\u0308":{text:'\\"',math:"\\ddot"},"\u0303":{text:"\\~",math:"\\tilde"},"\u0304":{text:"\\=",math:"\\bar"},"\u0306":{text:"\\u",math:"\\breve"},"\u030c":{text:"\\v",math:"\\check"},"\u0302":{text:"\\^",math:"\\hat"},"\u0307":{text:"\\.",math:"\\dot"},"\u030a":{text:"\\r",math:"\\mathring"},"\u030b":{text:"\\H"}},Sa={"\xe1":"a\u0301","\xe0":"a\u0300","\xe4":"a\u0308","\u01df":"a\u0308\u0304","\xe3":"a\u0303","\u0101":"a\u0304","\u0103":"a\u0306","\u1eaf":"a\u0306\u0301","\u1eb1":"a\u0306\u0300","\u1eb5":"a\u0306\u0303","\u01ce":"a\u030c","\xe2":"a\u0302","\u1ea5":"a\u0302\u0301","\u1ea7":"a\u0302\u0300","\u1eab":"a\u0302\u0303","\u0227":"a\u0307","\u01e1":"a\u0307\u0304","\xe5":"a\u030a","\u01fb":"a\u030a\u0301","\u1e03":"b\u0307","\u0107":"c\u0301","\u010d":"c\u030c","\u0109":"c\u0302","\u010b":"c\u0307","\u010f":"d\u030c","\u1e0b":"d\u0307","\xe9":"e\u0301","\xe8":"e\u0300","\xeb":"e\u0308","\u1ebd":"e\u0303","\u0113":"e\u0304","\u1e17":"e\u0304\u0301","\u1e15":"e\u0304\u0300","\u0115":"e\u0306","\u011b":"e\u030c","\xea":"e\u0302","\u1ebf":"e\u0302\u0301","\u1ec1":"e\u0302\u0300","\u1ec5":"e\u0302\u0303","\u0117":"e\u0307","\u1e1f":"f\u0307","\u01f5":"g\u0301","\u1e21":"g\u0304","\u011f":"g\u0306","\u01e7":"g\u030c","\u011d":"g\u0302","\u0121":"g\u0307","\u1e27":"h\u0308","\u021f":"h\u030c","\u0125":"h\u0302","\u1e23":"h\u0307","\xed":"i\u0301","\xec":"i\u0300","\xef":"i\u0308","\u1e2f":"i\u0308\u0301","\u0129":"i\u0303","\u012b":"i\u0304","\u012d":"i\u0306","\u01d0":"i\u030c","\xee":"i\u0302","\u01f0":"j\u030c","\u0135":"j\u0302","\u1e31":"k\u0301","\u01e9":"k\u030c","\u013a":"l\u0301","\u013e":"l\u030c","\u1e3f":"m\u0301","\u1e41":"m\u0307","\u0144":"n\u0301","\u01f9":"n\u0300","\xf1":"n\u0303","\u0148":"n\u030c","\u1e45":"n\u0307","\xf3":"o\u0301","\xf2":"o\u0300","\xf6":"o\u0308","\u022b":"o\u0308\u0304","\xf5":"o\u0303","\u1e4d":"o\u0303\u0301","\u1e4f":"o\u0303\u0308","\u022d":"o\u0303\u0304","\u014d":"o\u0304","\u1e53":"o\u0304\u0301","\u1e51":"o\u0304\u0300","\u014f":"o\u0306","\u01d2":"o\u030c","\xf4":"o\u0302","\u1ed1":"o\u0302\u0301","\u1ed3":"o\u0302\u0300","\u1ed7":"o\u0302\u0303","\u022f":"o\u0307","\u0231":"o\u0307\u0304","\u0151":"o\u030b","\u1e55":"p\u0301","\u1e57":"p\u0307","\u0155":"r\u0301","\u0159":"r\u030c","\u1e59":"r\u0307","\u015b":"s\u0301","\u1e65":"s\u0301\u0307","\u0161":"s\u030c","\u1e67":"s\u030c\u0307","\u015d":"s\u0302","\u1e61":"s\u0307","\u1e97":"t\u0308","\u0165":"t\u030c","\u1e6b":"t\u0307","\xfa":"u\u0301","\xf9":"u\u0300","\xfc":"u\u0308","\u01d8":"u\u0308\u0301","\u01dc":"u\u0308\u0300","\u01d6":"u\u0308\u0304","\u01da":"u\u0308\u030c","\u0169":"u\u0303","\u1e79":"u\u0303\u0301","\u016b":"u\u0304","\u1e7b":"u\u0304\u0308","\u016d":"u\u0306","\u01d4":"u\u030c","\xfb":"u\u0302","\u016f":"u\u030a","\u0171":"u\u030b","\u1e7d":"v\u0303","\u1e83":"w\u0301","\u1e81":"w\u0300","\u1e85":"w\u0308","\u0175":"w\u0302","\u1e87":"w\u0307","\u1e98":"w\u030a","\u1e8d":"x\u0308","\u1e8b":"x\u0307","\xfd":"y\u0301","\u1ef3":"y\u0300","\xff":"y\u0308","\u1ef9":"y\u0303","\u0233":"y\u0304","\u0177":"y\u0302","\u1e8f":"y\u0307","\u1e99":"y\u030a","\u017a":"z\u0301","\u017e":"z\u030c","\u1e91":"z\u0302","\u017c":"z\u0307","\xc1":"A\u0301","\xc0":"A\u0300","\xc4":"A\u0308","\u01de":"A\u0308\u0304","\xc3":"A\u0303","\u0100":"A\u0304","\u0102":"A\u0306","\u1eae":"A\u0306\u0301","\u1eb0":"A\u0306\u0300","\u1eb4":"A\u0306\u0303","\u01cd":"A\u030c","\xc2":"A\u0302","\u1ea4":"A\u0302\u0301","\u1ea6":"A\u0302\u0300","\u1eaa":"A\u0302\u0303","\u0226":"A\u0307","\u01e0":"A\u0307\u0304","\xc5":"A\u030a","\u01fa":"A\u030a\u0301","\u1e02":"B\u0307","\u0106":"C\u0301","\u010c":"C\u030c","\u0108":"C\u0302","\u010a":"C\u0307","\u010e":"D\u030c","\u1e0a":"D\u0307","\xc9":"E\u0301","\xc8":"E\u0300","\xcb":"E\u0308","\u1ebc":"E\u0303","\u0112":"E\u0304","\u1e16":"E\u0304\u0301","\u1e14":"E\u0304\u0300","\u0114":"E\u0306","\u011a":"E\u030c","\xca":"E\u0302","\u1ebe":"E\u0302\u0301","\u1ec0":"E\u0302\u0300","\u1ec4":"E\u0302\u0303","\u0116":"E\u0307","\u1e1e":"F\u0307","\u01f4":"G\u0301","\u1e20":"G\u0304","\u011e":"G\u0306","\u01e6":"G\u030c","\u011c":"G\u0302","\u0120":"G\u0307","\u1e26":"H\u0308","\u021e":"H\u030c","\u0124":"H\u0302","\u1e22":"H\u0307","\xcd":"I\u0301","\xcc":"I\u0300","\xcf":"I\u0308","\u1e2e":"I\u0308\u0301","\u0128":"I\u0303","\u012a":"I\u0304","\u012c":"I\u0306","\u01cf":"I\u030c","\xce":"I\u0302","\u0130":"I\u0307","\u0134":"J\u0302","\u1e30":"K\u0301","\u01e8":"K\u030c","\u0139":"L\u0301","\u013d":"L\u030c","\u1e3e":"M\u0301","\u1e40":"M\u0307","\u0143":"N\u0301","\u01f8":"N\u0300","\xd1":"N\u0303","\u0147":"N\u030c","\u1e44":"N\u0307","\xd3":"O\u0301","\xd2":"O\u0300","\xd6":"O\u0308","\u022a":"O\u0308\u0304","\xd5":"O\u0303","\u1e4c":"O\u0303\u0301","\u1e4e":"O\u0303\u0308","\u022c":"O\u0303\u0304","\u014c":"O\u0304","\u1e52":"O\u0304\u0301","\u1e50":"O\u0304\u0300","\u014e":"O\u0306","\u01d1":"O\u030c","\xd4":"O\u0302","\u1ed0":"O\u0302\u0301","\u1ed2":"O\u0302\u0300","\u1ed6":"O\u0302\u0303","\u022e":"O\u0307","\u0230":"O\u0307\u0304","\u0150":"O\u030b","\u1e54":"P\u0301","\u1e56":"P\u0307","\u0154":"R\u0301","\u0158":"R\u030c","\u1e58":"R\u0307","\u015a":"S\u0301","\u1e64":"S\u0301\u0307","\u0160":"S\u030c","\u1e66":"S\u030c\u0307","\u015c":"S\u0302","\u1e60":"S\u0307","\u0164":"T\u030c","\u1e6a":"T\u0307","\xda":"U\u0301","\xd9":"U\u0300","\xdc":"U\u0308","\u01d7":"U\u0308\u0301","\u01db":"U\u0308\u0300","\u01d5":"U\u0308\u0304","\u01d9":"U\u0308\u030c","\u0168":"U\u0303","\u1e78":"U\u0303\u0301","\u016a":"U\u0304","\u1e7a":"U\u0304\u0308","\u016c":"U\u0306","\u01d3":"U\u030c","\xdb":"U\u0302","\u016e":"U\u030a","\u0170":"U\u030b","\u1e7c":"V\u0303","\u1e82":"W\u0301","\u1e80":"W\u0300","\u1e84":"W\u0308","\u0174":"W\u0302","\u1e86":"W\u0307","\u1e8c":"X\u0308","\u1e8a":"X\u0307","\xdd":"Y\u0301","\u1ef2":"Y\u0300","\u0178":"Y\u0308","\u1ef8":"Y\u0303","\u0232":"Y\u0304","\u0176":"Y\u0302","\u1e8e":"Y\u0307","\u0179":"Z\u0301","\u017d":"Z\u030c","\u1e90":"Z\u0302","\u017b":"Z\u0307","\u03ac":"\u03b1\u0301","\u1f70":"\u03b1\u0300","\u1fb1":"\u03b1\u0304","\u1fb0":"\u03b1\u0306","\u03ad":"\u03b5\u0301","\u1f72":"\u03b5\u0300","\u03ae":"\u03b7\u0301","\u1f74":"\u03b7\u0300","\u03af":"\u03b9\u0301","\u1f76":"\u03b9\u0300","\u03ca":"\u03b9\u0308","\u0390":"\u03b9\u0308\u0301","\u1fd2":"\u03b9\u0308\u0300","\u1fd1":"\u03b9\u0304","\u1fd0":"\u03b9\u0306","\u03cc":"\u03bf\u0301","\u1f78":"\u03bf\u0300","\u03cd":"\u03c5\u0301","\u1f7a":"\u03c5\u0300","\u03cb":"\u03c5\u0308","\u03b0":"\u03c5\u0308\u0301","\u1fe2":"\u03c5\u0308\u0300","\u1fe1":"\u03c5\u0304","\u1fe0":"\u03c5\u0306","\u03ce":"\u03c9\u0301","\u1f7c":"\u03c9\u0300","\u038e":"\u03a5\u0301","\u1fea":"\u03a5\u0300","\u03ab":"\u03a5\u0308","\u1fe9":"\u03a5\u0304","\u1fe8":"\u03a5\u0306","\u038f":"\u03a9\u0301","\u1ffa":"\u03a9\u0300"},Ma=function(){function t(t,e){this.mode=void 0,this.gullet=void 0,this.settings=void 0,this.leftrightDepth=void 0,this.nextToken=void 0,this.mode="math",this.gullet=new wa(t,e,this.mode),this.settings=e,this.leftrightDepth=0}var e=t.prototype;return e.expect=function(t,e){if(void 0===e&&(e=!0),this.fetch().text!==t)throw new o("Expected '"+t+"', got '"+this.fetch().text+"'",this.fetch());e&&this.consume()},e.consume=function(){this.nextToken=null},e.fetch=function(){return null==this.nextToken&&(this.nextToken=this.gullet.expandNextToken()),this.nextToken},e.switchMode=function(t){this.mode=t,this.gullet.switchMode(t)},e.parse=function(){this.gullet.beginGroup(),this.settings.colorIsTextColor&&this.gullet.macros.set("\\color","\\textcolor");var t=this.parseExpression(!1);return this.expect("EOF"),this.gullet.endGroup(),t},e.parseExpression=function(e,r){for(var a=[];;){"math"===this.mode&&this.consumeSpaces();var n=this.fetch();if(-1!==t.endOfExpression.indexOf(n.text))break;if(r&&n.text===r)break;if(e&&ia[n.text]&&ia[n.text].infix)break;var i=this.parseAtom(r);if(!i)break;a.push(i)}return"text"===this.mode&&this.formLigatures(a),this.handleInfixNodes(a)},e.handleInfixNodes=function(t){for(var e,r=-1,a=0;a0&&!l||0===s&&!l&&"math"===this.mode,c=this.parseGroupOfType("argument to '"+t+"'",h,l,a,m);if(!c){if(l){i.push(null);continue}throw new o("Expected group after '"+t+"'",this.fetch())}(l?i:n).push(c)}return{args:n,optArgs:i}},e.parseGroupOfType=function(t,e,r,a,n){switch(e){case"color":return n&&this.consumeSpaces(),this.parseColorGroup(r);case"size":return n&&this.consumeSpaces(),this.parseSizeGroup(r);case"url":return this.parseUrlGroup(r,n);case"math":case"text":return this.parseGroup(t,r,a,void 0,e,n);case"hbox":var i=this.parseGroup(t,r,a,void 0,"text",n);return i?{type:"styling",mode:i.mode,body:[i],style:"text"}:i;case"raw":if(n&&this.consumeSpaces(),r&&"{"===this.fetch().text)return null;var s=this.parseStringGroup("raw",r,!0);if(s)return{type:"raw",mode:"text",string:s.text};throw new o("Expected raw group",this.fetch());case"original":case null:case void 0:return this.parseGroup(t,r,a,void 0,void 0,n);default:throw new o("Unknown group type as "+t,this.fetch())}},e.consumeSpaces=function(){for(;" "===this.fetch().text;)this.consume()},e.parseStringGroup=function(t,e,r){var a=e?"[":"{",n=e?"]":"}",i=this.fetch();if(i.text!==a){if(e)return null;if(r&&"EOF"!==i.text&&/[^{}[\]]/.test(i.text))return this.consume(),i}var s=this.mode;this.mode="text",this.expect(a);for(var h,l="",m=this.fetch(),c=0,u=m;(h=this.fetch()).text!==n||r&&c>0;){switch(h.text){case"EOF":throw new o("Unexpected end of input in "+t,m.range(u,l));case a:c++;break;case n:c--}l+=(u=h).text,this.consume()}return this.expect(n),this.mode=s,m.range(u,l)},e.parseRegexGroup=function(t,e){var r=this.mode;this.mode="text";for(var a,n=this.fetch(),i=n,s="";"EOF"!==(a=this.fetch()).text&&t.test(s+a.text);)s+=(i=a).text,this.consume();if(""===s)throw new o("Invalid "+e+": '"+n.text+"'",n);return this.mode=r,n.range(i,s)},e.parseColorGroup=function(t){var e=this.parseStringGroup("color",t);if(!e)return null;var r=/^(#[a-f0-9]{3}|#?[a-f0-9]{6}|[a-z]+)$/i.exec(e.text);if(!r)throw new o("Invalid color: '"+e.text+"'",e);var a=r[0];return/^[0-9a-f]{6}$/i.test(a)&&(a="#"+a),{type:"color-token",mode:this.mode,color:a}},e.parseSizeGroup=function(t){var e,r=!1;if(!(e=t||"{"===this.fetch().text?this.parseStringGroup("size",t):this.parseRegexGroup(/^[-+]? *(?:$|\d+|\d+\.\d*|\.\d*) *[a-z]{0,2} *$/,"size")))return null;t||0!==e.text.length||(e.text="0pt",r=!0);var a=/([-+]?) *(\d+(?:\.\d*)?|\.\d+) *([a-z]{2})/.exec(e.text);if(!a)throw new o("Invalid size: '"+e.text+"'",e);var n={number:+(a[1]+a[2]),unit:a[3]};if(!At(n))throw new o("Invalid unit: '"+n.unit+"'",e);return{type:"size",mode:this.mode,value:n,isBlank:r}},e.parseUrlGroup=function(t,e){this.gullet.lexer.setCatcode("%",13);var r=this.parseStringGroup("url",t,!0);if(this.gullet.lexer.setCatcode("%",14),!r)return null;var a=r.text.replace(/\\([#$%&~_^{}])/g,"$1");return{type:"url",mode:this.mode,url:a}},e.parseGroup=function(e,r,n,i,s,h){var l=this.mode;s&&this.switchMode(s),h&&this.consumeSpaces();var m,c=this.fetch(),u=c.text;if(r?"["===u:"{"===u||"\\begingroup"===u){this.consume();var p=t.endOfGroup[u];this.gullet.beginGroup();var d=this.parseExpression(!1,p),f=this.fetch();this.expect(p),this.gullet.endGroup(),m={type:"ordgroup",mode:this.mode,loc:a.range(c,f),body:d,semisimple:"\\begingroup"===u||void 0}}else if(r)m=null;else if(null==(m=this.parseFunction(i,e,n)||this.parseSymbol())&&"\\"===u[0]&&!ya.hasOwnProperty(u)){if(this.settings.throwOnError)throw new o("Undefined control sequence: "+u,c);m=this.formatUnsupportedCmd(u),this.consume()}return s&&this.switchMode(l),m},e.formLigatures=function(t){for(var e=t.length-1,r=0;r=0&&this.settings.reportNonstrict("unicodeTextInMathMode",'Latin-1/Unicode text character "'+e[0]+'" used in math mode',t);var h,l=j[this.mode][e].group,m=a.range(t);if(W.hasOwnProperty(l)){var c=l;h={type:"atom",mode:this.mode,family:c,loc:m,text:e}}else h={type:l,mode:this.mode,loc:m,text:e};i=h}else{if(!(e.charCodeAt(0)>=128))return null;this.settings.strict&&(M(e.charCodeAt(0))?"math"===this.mode&&this.settings.reportNonstrict("unicodeTextInMathMode",'Unicode text character "'+e[0]+'" used in math mode',t):this.settings.reportNonstrict("unknownSymbol",'Unrecognized Unicode character "'+e[0]+'" ('+e.charCodeAt(0)+")",t)),i={type:"textord",mode:"text",loc:a.range(t),text:e}}if(this.consume(),s)for(var u=0;u 15) { + left = "…" + input.slice(start - 15, start); + } else { + left = input.slice(0, start); + } + + let right; + + if (end + 15 < input.length) { + right = input.slice(end, end + 15) + "…"; + } else { + right = input.slice(end); + } + + error += left + underlined + right; + } // Some hackery to make ParseError a prototype of Error + // See http://stackoverflow.com/a/8460753 + + + const self = new Error(error); + self.name = "ParseError"; // $FlowFixMe + + self.__proto__ = ParseError.prototype; // $FlowFixMe + + self.position = start; + return self; + } + +} // $FlowFixMe More hackery + + +ParseError.prototype.__proto__ = Error.prototype; + +/** + * This file contains a list of utility functions which are useful in other + * files. + */ + +/** + * Return whether an element is contained in a list + */ +const contains = function contains(list, elem) { + return list.indexOf(elem) !== -1; +}; +/** + * Provide a default value if a setting is undefined + * NOTE: Couldn't use `T` as the output type due to facebook/flow#5022. + */ + + +const deflt = function deflt(setting, defaultIfUndefined) { + return setting === undefined ? defaultIfUndefined : setting; +}; // hyphenate and escape adapted from Facebook's React under Apache 2 license + + +const uppercase = /([A-Z])/g; + +const hyphenate = function hyphenate(str) { + return str.replace(uppercase, "-$1").toLowerCase(); +}; + +const ESCAPE_LOOKUP = { + "&": "&", + ">": ">", + "<": "<", + "\"": """, + "'": "'" +}; +const ESCAPE_REGEX = /[&><"']/g; +/** + * Escapes text to prevent scripting attacks. + */ + +function escape(text) { + return String(text).replace(ESCAPE_REGEX, match => ESCAPE_LOOKUP[match]); +} +/** + * Sometimes we want to pull out the innermost element of a group. In most + * cases, this will just be the group itself, but when ordgroups and colors have + * a single element, we want to pull that out. + */ + + +const getBaseElem = function getBaseElem(group) { + if (group.type === "ordgroup") { + if (group.body.length === 1) { + return getBaseElem(group.body[0]); + } else { + return group; + } + } else if (group.type === "color") { + if (group.body.length === 1) { + return getBaseElem(group.body[0]); + } else { + return group; + } + } else if (group.type === "font") { + return getBaseElem(group.body); + } else { + return group; + } +}; +/** + * TeXbook algorithms often reference "character boxes", which are simply groups + * with a single character in them. To decide if something is a character box, + * we find its innermost group, and see if it is a single character. + */ + + +const isCharacterBox = function isCharacterBox(group) { + const baseElem = getBaseElem(group); // These are all they types of groups which hold single characters + + return baseElem.type === "mathord" || baseElem.type === "textord" || baseElem.type === "atom"; +}; + +const assert = function assert(value) { + if (!value) { + throw new Error('Expected non-null, but got ' + String(value)); + } + + return value; +}; +/** + * Return the protocol of a URL, or "_relative" if the URL does not specify a + * protocol (and thus is relative). + */ + +const protocolFromUrl = function protocolFromUrl(url) { + const protocol = /^\s*([^\\/#]*?)(?::|�*58|�*3a)/i.exec(url); + return protocol != null ? protocol[1] : "_relative"; +}; +var utils = { + contains, + deflt, + escape, + hyphenate, + getBaseElem, + isCharacterBox, + protocolFromUrl +}; + +/* eslint no-console:0 */ + +/** + * The main Settings object + * + * The current options stored are: + * - displayMode: Whether the expression should be typeset as inline math + * (false, the default), meaning that the math starts in + * \textstyle and is placed in an inline-block); or as display + * math (true), meaning that the math starts in \displaystyle + * and is placed in a block with vertical margin. + */ +class Settings { + constructor(options) { + this.displayMode = void 0; + this.output = void 0; + this.leqno = void 0; + this.fleqn = void 0; + this.throwOnError = void 0; + this.errorColor = void 0; + this.macros = void 0; + this.minRuleThickness = void 0; + this.colorIsTextColor = void 0; + this.strict = void 0; + this.trust = void 0; + this.maxSize = void 0; + this.maxExpand = void 0; + // allow null options + options = options || {}; + this.displayMode = utils.deflt(options.displayMode, false); + this.output = utils.deflt(options.output, "htmlAndMathml"); + this.leqno = utils.deflt(options.leqno, false); + this.fleqn = utils.deflt(options.fleqn, false); + this.throwOnError = utils.deflt(options.throwOnError, true); + this.errorColor = utils.deflt(options.errorColor, "#cc0000"); + this.macros = options.macros || {}; + this.minRuleThickness = Math.max(0, utils.deflt(options.minRuleThickness, 0)); + this.colorIsTextColor = utils.deflt(options.colorIsTextColor, false); + this.strict = utils.deflt(options.strict, "warn"); + this.trust = utils.deflt(options.trust, false); + this.maxSize = Math.max(0, utils.deflt(options.maxSize, Infinity)); + this.maxExpand = Math.max(0, utils.deflt(options.maxExpand, 1000)); + } + /** + * Report nonstrict (non-LaTeX-compatible) input. + * Can safely not be called if `this.strict` is false in JavaScript. + */ + + + reportNonstrict(errorCode, errorMsg, token) { + let strict = this.strict; + + if (typeof strict === "function") { + // Allow return value of strict function to be boolean or string + // (or null/undefined, meaning no further processing). + strict = strict(errorCode, errorMsg, token); + } + + if (!strict || strict === "ignore") { + return; + } else if (strict === true || strict === "error") { + throw new ParseError("LaTeX-incompatible input and strict mode is set to 'error': " + `${errorMsg} [${errorCode}]`, token); + } else if (strict === "warn") { + typeof console !== "undefined" && console.warn("LaTeX-incompatible input and strict mode is set to 'warn': " + `${errorMsg} [${errorCode}]`); + } else { + // won't happen in type-safe code + typeof console !== "undefined" && console.warn("LaTeX-incompatible input and strict mode is set to " + `unrecognized '${strict}': ${errorMsg} [${errorCode}]`); + } + } + /** + * Check whether to apply strict (LaTeX-adhering) behavior for unusual + * input (like `\\`). Unlike `nonstrict`, will not throw an error; + * instead, "error" translates to a return value of `true`, while "ignore" + * translates to a return value of `false`. May still print a warning: + * "warn" prints a warning and returns `false`. + * This is for the second category of `errorCode`s listed in the README. + */ + + + useStrictBehavior(errorCode, errorMsg, token) { + let strict = this.strict; + + if (typeof strict === "function") { + // Allow return value of strict function to be boolean or string + // (or null/undefined, meaning no further processing). + // But catch any exceptions thrown by function, treating them + // like "error". + try { + strict = strict(errorCode, errorMsg, token); + } catch (error) { + strict = "error"; + } + } + + if (!strict || strict === "ignore") { + return false; + } else if (strict === true || strict === "error") { + return true; + } else if (strict === "warn") { + typeof console !== "undefined" && console.warn("LaTeX-incompatible input and strict mode is set to 'warn': " + `${errorMsg} [${errorCode}]`); + return false; + } else { + // won't happen in type-safe code + typeof console !== "undefined" && console.warn("LaTeX-incompatible input and strict mode is set to " + `unrecognized '${strict}': ${errorMsg} [${errorCode}]`); + return false; + } + } + /** + * Check whether to test potentially dangerous input, and return + * `true` (trusted) or `false` (untrusted). The sole argument `context` + * should be an object with `command` field specifying the relevant LaTeX + * command (as a string starting with `\`), and any other arguments, etc. + * If `context` has a `url` field, a `protocol` field will automatically + * get added by this function (changing the specified object). + */ + + + isTrusted(context) { + if (context.url && !context.protocol) { + context.protocol = utils.protocolFromUrl(context.url); + } + + const trust = typeof this.trust === "function" ? this.trust(context) : this.trust; + return Boolean(trust); + } + +} + +/** + * This file contains information and classes for the various kinds of styles + * used in TeX. It provides a generic `Style` class, which holds information + * about a specific style. It then provides instances of all the different kinds + * of styles possible, and provides functions to move between them and get + * information about them. + */ + +/** + * The main style class. Contains a unique id for the style, a size (which is + * the same for cramped and uncramped version of a style), and a cramped flag. + */ +class Style { + constructor(id, size, cramped) { + this.id = void 0; + this.size = void 0; + this.cramped = void 0; + this.id = id; + this.size = size; + this.cramped = cramped; + } + /** + * Get the style of a superscript given a base in the current style. + */ + + + sup() { + return styles[sup[this.id]]; + } + /** + * Get the style of a subscript given a base in the current style. + */ + + + sub() { + return styles[sub[this.id]]; + } + /** + * Get the style of a fraction numerator given the fraction in the current + * style. + */ + + + fracNum() { + return styles[fracNum[this.id]]; + } + /** + * Get the style of a fraction denominator given the fraction in the current + * style. + */ + + + fracDen() { + return styles[fracDen[this.id]]; + } + /** + * Get the cramped version of a style (in particular, cramping a cramped style + * doesn't change the style). + */ + + + cramp() { + return styles[cramp[this.id]]; + } + /** + * Get a text or display version of this style. + */ + + + text() { + return styles[text[this.id]]; + } + /** + * Return true if this style is tightly spaced (scriptstyle/scriptscriptstyle) + */ + + + isTight() { + return this.size >= 2; + } + +} // Export an interface for type checking, but don't expose the implementation. +// This way, no more styles can be generated. + + +// IDs of the different styles +const D = 0; +const Dc = 1; +const T = 2; +const Tc = 3; +const S = 4; +const Sc = 5; +const SS = 6; +const SSc = 7; // Instances of the different styles + +const styles = [new Style(D, 0, false), new Style(Dc, 0, true), new Style(T, 1, false), new Style(Tc, 1, true), new Style(S, 2, false), new Style(Sc, 2, true), new Style(SS, 3, false), new Style(SSc, 3, true)]; // Lookup tables for switching from one style to another + +const sup = [S, Sc, S, Sc, SS, SSc, SS, SSc]; +const sub = [Sc, Sc, Sc, Sc, SSc, SSc, SSc, SSc]; +const fracNum = [T, Tc, S, Sc, SS, SSc, SS, SSc]; +const fracDen = [Tc, Tc, Sc, Sc, SSc, SSc, SSc, SSc]; +const cramp = [Dc, Dc, Tc, Tc, Sc, Sc, SSc, SSc]; +const text = [D, Dc, T, Tc, T, Tc, T, Tc]; // We only export some of the styles. + +var Style$1 = { + DISPLAY: styles[D], + TEXT: styles[T], + SCRIPT: styles[S], + SCRIPTSCRIPT: styles[SS] +}; + +/* + * This file defines the Unicode scripts and script families that we + * support. To add new scripts or families, just add a new entry to the + * scriptData array below. Adding scripts to the scriptData array allows + * characters from that script to appear in \text{} environments. + */ + +/** + * Each script or script family has a name and an array of blocks. + * Each block is an array of two numbers which specify the start and + * end points (inclusive) of a block of Unicode codepoints. + */ + +/** + * Unicode block data for the families of scripts we support in \text{}. + * Scripts only need to appear here if they do not have font metrics. + */ +const scriptData = [{ + // Latin characters beyond the Latin-1 characters we have metrics for. + // Needed for Czech, Hungarian and Turkish text, for example. + name: 'latin', + blocks: [[0x0100, 0x024f], // Latin Extended-A and Latin Extended-B + [0x0300, 0x036f]] +}, { + // The Cyrillic script used by Russian and related languages. + // A Cyrillic subset used to be supported as explicitly defined + // symbols in symbols.js + name: 'cyrillic', + blocks: [[0x0400, 0x04ff]] +}, { + // The Brahmic scripts of South and Southeast Asia + // Devanagari (0900–097F) + // Bengali (0980–09FF) + // Gurmukhi (0A00–0A7F) + // Gujarati (0A80–0AFF) + // Oriya (0B00–0B7F) + // Tamil (0B80–0BFF) + // Telugu (0C00–0C7F) + // Kannada (0C80–0CFF) + // Malayalam (0D00–0D7F) + // Sinhala (0D80–0DFF) + // Thai (0E00–0E7F) + // Lao (0E80–0EFF) + // Tibetan (0F00–0FFF) + // Myanmar (1000–109F) + name: 'brahmic', + blocks: [[0x0900, 0x109F]] +}, { + name: 'georgian', + blocks: [[0x10A0, 0x10ff]] +}, { + // Chinese and Japanese. + // The "k" in cjk is for Korean, but we've separated Korean out + name: "cjk", + blocks: [[0x3000, 0x30FF], // CJK symbols and punctuation, Hiragana, Katakana + [0x4E00, 0x9FAF], // CJK ideograms + [0xFF00, 0xFF60]] +}, { + // Korean + name: 'hangul', + blocks: [[0xAC00, 0xD7AF]] +}]; +/** + * Given a codepoint, return the name of the script or script family + * it is from, or null if it is not part of a known block + */ + +function scriptFromCodepoint(codepoint) { + for (let i = 0; i < scriptData.length; i++) { + const script = scriptData[i]; + + for (let i = 0; i < script.blocks.length; i++) { + const block = script.blocks[i]; + + if (codepoint >= block[0] && codepoint <= block[1]) { + return script.name; + } + } + } + + return null; +} +/** + * A flattened version of all the supported blocks in a single array. + * This is an optimization to make supportedCodepoint() fast. + */ + +const allBlocks = []; +scriptData.forEach(s => s.blocks.forEach(b => allBlocks.push(...b))); +/** + * Given a codepoint, return true if it falls within one of the + * scripts or script families defined above and false otherwise. + * + * Micro benchmarks shows that this is faster than + * /[\u3000-\u30FF\u4E00-\u9FAF\uFF00-\uFF60\uAC00-\uD7AF\u0900-\u109F]/.test() + * in Firefox, Chrome and Node. + */ + +function supportedCodepoint(codepoint) { + for (let i = 0; i < allBlocks.length; i += 2) { + if (codepoint >= allBlocks[i] && codepoint <= allBlocks[i + 1]) { + return true; + } + } + + return false; +} + +/** + * This file provides support to domTree.js and delimiter.js. + * It's a storehouse of path geometry for SVG images. + */ +// In all paths below, the viewBox-to-em scale is 1000:1. +const hLinePad = 80; // padding above a sqrt viniculum. Prevents image cropping. +// The viniculum of a \sqrt can be made thicker by a KaTeX rendering option. +// Think of variable extraViniculum as two detours in the SVG path. +// The detour begins at the lower left of the area labeled extraViniculum below. +// The detour proceeds one extraViniculum distance up and slightly to the right, +// displacing the radiused corner between surd and viniculum. The radius is +// traversed as usual, then the detour resumes. It goes right, to the end of +// the very long viniculumn, then down one extraViniculum distance, +// after which it resumes regular path geometry for the radical. + +/* viniculum + / + /▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒←extraViniculum + / █████████████████████←0.04em (40 unit) std viniculum thickness + / / + / / + / /\ + / / surd +*/ + +const sqrtMain = function sqrtMain(extraViniculum, hLinePad) { + // sqrtMain path geometry is from glyph U221A in the font KaTeX Main + return `M95,${622 + extraViniculum + hLinePad} +c-2.7,0,-7.17,-2.7,-13.5,-8c-5.8,-5.3,-9.5,-10,-9.5,-14 +c0,-2,0.3,-3.3,1,-4c1.3,-2.7,23.83,-20.7,67.5,-54 +c44.2,-33.3,65.8,-50.3,66.5,-51c1.3,-1.3,3,-2,5,-2c4.7,0,8.7,3.3,12,10 +s173,378,173,378c0.7,0,35.3,-71,104,-213c68.7,-142,137.5,-285,206.5,-429 +c69,-144,104.5,-217.7,106.5,-221 +l${extraViniculum / 2.075} -${extraViniculum} +c5.3,-9.3,12,-14,20,-14 +H400000v${40 + extraViniculum}H845.2724 +s-225.272,467,-225.272,467s-235,486,-235,486c-2.7,4.7,-9,7,-19,7 +c-6,0,-10,-1,-12,-3s-194,-422,-194,-422s-65,47,-65,47z +M${834 + extraViniculum} ${hLinePad}h400000v${40 + extraViniculum}h-400000z`; +}; + +const sqrtSize1 = function sqrtSize1(extraViniculum, hLinePad) { + // size1 is from glyph U221A in the font KaTeX_Size1-Regular + return `M263,${601 + extraViniculum + hLinePad}c0.7,0,18,39.7,52,119 +c34,79.3,68.167,158.7,102.5,238c34.3,79.3,51.8,119.3,52.5,120 +c340,-704.7,510.7,-1060.3,512,-1067 +l${extraViniculum / 2.084} -${extraViniculum} +c4.7,-7.3,11,-11,19,-11 +H40000v${40 + extraViniculum}H1012.3 +s-271.3,567,-271.3,567c-38.7,80.7,-84,175,-136,283c-52,108,-89.167,185.3,-111.5,232 +c-22.3,46.7,-33.8,70.3,-34.5,71c-4.7,4.7,-12.3,7,-23,7s-12,-1,-12,-1 +s-109,-253,-109,-253c-72.7,-168,-109.3,-252,-110,-252c-10.7,8,-22,16.7,-34,26 +c-22,17.3,-33.3,26,-34,26s-26,-26,-26,-26s76,-59,76,-59s76,-60,76,-60z +M${1001 + extraViniculum} ${hLinePad}h400000v${40 + extraViniculum}h-400000z`; +}; + +const sqrtSize2 = function sqrtSize2(extraViniculum, hLinePad) { + // size2 is from glyph U221A in the font KaTeX_Size2-Regular + return `M983 ${10 + extraViniculum + hLinePad} +l${extraViniculum / 3.13} -${extraViniculum} +c4,-6.7,10,-10,18,-10 H400000v${40 + extraViniculum} +H1013.1s-83.4,268,-264.1,840c-180.7,572,-277,876.3,-289,913c-4.7,4.7,-12.7,7,-24,7 +s-12,0,-12,0c-1.3,-3.3,-3.7,-11.7,-7,-25c-35.3,-125.3,-106.7,-373.3,-214,-744 +c-10,12,-21,25,-33,39s-32,39,-32,39c-6,-5.3,-15,-14,-27,-26s25,-30,25,-30 +c26.7,-32.7,52,-63,76,-91s52,-60,52,-60s208,722,208,722 +c56,-175.3,126.3,-397.3,211,-666c84.7,-268.7,153.8,-488.2,207.5,-658.5 +c53.7,-170.3,84.5,-266.8,92.5,-289.5z +M${1001 + extraViniculum} ${hLinePad}h400000v${40 + extraViniculum}h-400000z`; +}; + +const sqrtSize3 = function sqrtSize3(extraViniculum, hLinePad) { + // size3 is from glyph U221A in the font KaTeX_Size3-Regular + return `M424,${2398 + extraViniculum + hLinePad} +c-1.3,-0.7,-38.5,-172,-111.5,-514c-73,-342,-109.8,-513.3,-110.5,-514 +c0,-2,-10.7,14.3,-32,49c-4.7,7.3,-9.8,15.7,-15.5,25c-5.7,9.3,-9.8,16,-12.5,20 +s-5,7,-5,7c-4,-3.3,-8.3,-7.7,-13,-13s-13,-13,-13,-13s76,-122,76,-122s77,-121,77,-121 +s209,968,209,968c0,-2,84.7,-361.7,254,-1079c169.3,-717.3,254.7,-1077.7,256,-1081 +l${extraViniculum / 4.223} -${extraViniculum}c4,-6.7,10,-10,18,-10 H400000 +v${40 + extraViniculum}H1014.6 +s-87.3,378.7,-272.6,1166c-185.3,787.3,-279.3,1182.3,-282,1185 +c-2,6,-10,9,-24,9 +c-8,0,-12,-0.7,-12,-2z M${1001 + extraViniculum} ${hLinePad} +h400000v${40 + extraViniculum}h-400000z`; +}; + +const sqrtSize4 = function sqrtSize4(extraViniculum, hLinePad) { + // size4 is from glyph U221A in the font KaTeX_Size4-Regular + return `M473,${2713 + extraViniculum + hLinePad} +c339.3,-1799.3,509.3,-2700,510,-2702 l${extraViniculum / 5.298} -${extraViniculum} +c3.3,-7.3,9.3,-11,18,-11 H400000v${40 + extraViniculum}H1017.7 +s-90.5,478,-276.2,1466c-185.7,988,-279.5,1483,-281.5,1485c-2,6,-10,9,-24,9 +c-8,0,-12,-0.7,-12,-2c0,-1.3,-5.3,-32,-16,-92c-50.7,-293.3,-119.7,-693.3,-207,-1200 +c0,-1.3,-5.3,8.7,-16,30c-10.7,21.3,-21.3,42.7,-32,64s-16,33,-16,33s-26,-26,-26,-26 +s76,-153,76,-153s77,-151,77,-151c0.7,0.7,35.7,202,105,604c67.3,400.7,102,602.7,104, +606zM${1001 + extraViniculum} ${hLinePad}h400000v${40 + extraViniculum}H1017.7z`; +}; + +const sqrtTall = function sqrtTall(extraViniculum, hLinePad, viewBoxHeight) { + // sqrtTall is from glyph U23B7 in the font KaTeX_Size4-Regular + // One path edge has a variable length. It runs vertically from the viniculumn + // to a point near (14 units) the bottom of the surd. The viniculum + // is normally 40 units thick. So the length of the line in question is: + const vertSegment = viewBoxHeight - 54 - hLinePad - extraViniculum; + return `M702 ${extraViniculum + hLinePad}H400000${40 + extraViniculum} +H742v${vertSegment}l-4 4-4 4c-.667.7 -2 1.5-4 2.5s-4.167 1.833-6.5 2.5-5.5 1-9.5 1 +h-12l-28-84c-16.667-52-96.667 -294.333-240-727l-212 -643 -85 170 +c-4-3.333-8.333-7.667-13 -13l-13-13l77-155 77-156c66 199.333 139 419.667 +219 661 l218 661zM702 ${hLinePad}H400000v${40 + extraViniculum}H742z`; +}; + +const sqrtPath = function sqrtPath(size, extraViniculum, viewBoxHeight) { + extraViniculum = 1000 * extraViniculum; // Convert from document ems to viewBox. + + let path = ""; + + switch (size) { + case "sqrtMain": + path = sqrtMain(extraViniculum, hLinePad); + break; + + case "sqrtSize1": + path = sqrtSize1(extraViniculum, hLinePad); + break; + + case "sqrtSize2": + path = sqrtSize2(extraViniculum, hLinePad); + break; + + case "sqrtSize3": + path = sqrtSize3(extraViniculum, hLinePad); + break; + + case "sqrtSize4": + path = sqrtSize4(extraViniculum, hLinePad); + break; + + case "sqrtTall": + path = sqrtTall(extraViniculum, hLinePad, viewBoxHeight); + } + + return path; +}; +const path = { + // The doubleleftarrow geometry is from glyph U+21D0 in the font KaTeX Main + doubleleftarrow: `M262 157 +l10-10c34-36 62.7-77 86-123 3.3-8 5-13.3 5-16 0-5.3-6.7-8-20-8-7.3 + 0-12.2.5-14.5 1.5-2.3 1-4.8 4.5-7.5 10.5-49.3 97.3-121.7 169.3-217 216-28 + 14-57.3 25-88 33-6.7 2-11 3.8-13 5.5-2 1.7-3 4.2-3 7.5s1 5.8 3 7.5 +c2 1.7 6.3 3.5 13 5.5 68 17.3 128.2 47.8 180.5 91.5 52.3 43.7 93.8 96.2 124.5 + 157.5 9.3 8 15.3 12.3 18 13h6c12-.7 18-4 18-10 0-2-1.7-7-5-15-23.3-46-52-87 +-86-123l-10-10h399738v-40H218c328 0 0 0 0 0l-10-8c-26.7-20-65.7-43-117-69 2.7 +-2 6-3.7 10-5 36.7-16 72.3-37.3 107-64l10-8h399782v-40z +m8 0v40h399730v-40zm0 194v40h399730v-40z`, + // doublerightarrow is from glyph U+21D2 in font KaTeX Main + doublerightarrow: `M399738 392l +-10 10c-34 36-62.7 77-86 123-3.3 8-5 13.3-5 16 0 5.3 6.7 8 20 8 7.3 0 12.2-.5 + 14.5-1.5 2.3-1 4.8-4.5 7.5-10.5 49.3-97.3 121.7-169.3 217-216 28-14 57.3-25 88 +-33 6.7-2 11-3.8 13-5.5 2-1.7 3-4.2 3-7.5s-1-5.8-3-7.5c-2-1.7-6.3-3.5-13-5.5-68 +-17.3-128.2-47.8-180.5-91.5-52.3-43.7-93.8-96.2-124.5-157.5-9.3-8-15.3-12.3-18 +-13h-6c-12 .7-18 4-18 10 0 2 1.7 7 5 15 23.3 46 52 87 86 123l10 10H0v40h399782 +c-328 0 0 0 0 0l10 8c26.7 20 65.7 43 117 69-2.7 2-6 3.7-10 5-36.7 16-72.3 37.3 +-107 64l-10 8H0v40zM0 157v40h399730v-40zm0 194v40h399730v-40z`, + // leftarrow is from glyph U+2190 in font KaTeX Main + leftarrow: `M400000 241H110l3-3c68.7-52.7 113.7-120 + 135-202 4-14.7 6-23 6-25 0-7.3-7-11-21-11-8 0-13.2.8-15.5 2.5-2.3 1.7-4.2 5.8 +-5.5 12.5-1.3 4.7-2.7 10.3-4 17-12 48.7-34.8 92-68.5 130S65.3 228.3 18 247 +c-10 4-16 7.7-18 11 0 8.7 6 14.3 18 17 47.3 18.7 87.8 47 121.5 85S196 441.3 208 + 490c.7 2 1.3 5 2 9s1.2 6.7 1.5 8c.3 1.3 1 3.3 2 6s2.2 4.5 3.5 5.5c1.3 1 3.3 + 1.8 6 2.5s6 1 10 1c14 0 21-3.7 21-11 0-2-2-10.3-6-25-20-79.3-65-146.7-135-202 + l-3-3h399890zM100 241v40h399900v-40z`, + // overbrace is from glyphs U+23A9/23A8/23A7 in font KaTeX_Size4-Regular + leftbrace: `M6 548l-6-6v-35l6-11c56-104 135.3-181.3 238-232 57.3-28.7 117 +-45 179-50h399577v120H403c-43.3 7-81 15-113 26-100.7 33-179.7 91-237 174-2.7 + 5-6 9-10 13-.7 1-7.3 1-20 1H6z`, + leftbraceunder: `M0 6l6-6h17c12.688 0 19.313.3 20 1 4 4 7.313 8.3 10 13 + 35.313 51.3 80.813 93.8 136.5 127.5 55.688 33.7 117.188 55.8 184.5 66.5.688 + 0 2 .3 4 1 18.688 2.7 76 4.3 172 5h399450v120H429l-6-1c-124.688-8-235-61.7 +-331-161C60.687 138.7 32.312 99.3 7 54L0 41V6z`, + // overgroup is from the MnSymbol package (public domain) + leftgroup: `M400000 80 +H435C64 80 168.3 229.4 21 260c-5.9 1.2-18 0-18 0-2 0-3-1-3-3v-38C76 61 257 0 + 435 0h399565z`, + leftgroupunder: `M400000 262 +H435C64 262 168.3 112.6 21 82c-5.9-1.2-18 0-18 0-2 0-3 1-3 3v38c76 158 257 219 + 435 219h399565z`, + // Harpoons are from glyph U+21BD in font KaTeX Main + leftharpoon: `M0 267c.7 5.3 3 10 7 14h399993v-40H93c3.3 +-3.3 10.2-9.5 20.5-18.5s17.8-15.8 22.5-20.5c50.7-52 88-110.3 112-175 4-11.3 5 +-18.3 3-21-1.3-4-7.3-6-18-6-8 0-13 .7-15 2s-4.7 6.7-8 16c-42 98.7-107.3 174.7 +-196 228-6.7 4.7-10.7 8-12 10-1.3 2-2 5.7-2 11zm100-26v40h399900v-40z`, + leftharpoonplus: `M0 267c.7 5.3 3 10 7 14h399993v-40H93c3.3-3.3 10.2-9.5 + 20.5-18.5s17.8-15.8 22.5-20.5c50.7-52 88-110.3 112-175 4-11.3 5-18.3 3-21-1.3 +-4-7.3-6-18-6-8 0-13 .7-15 2s-4.7 6.7-8 16c-42 98.7-107.3 174.7-196 228-6.7 4.7 +-10.7 8-12 10-1.3 2-2 5.7-2 11zm100-26v40h399900v-40zM0 435v40h400000v-40z +m0 0v40h400000v-40z`, + leftharpoondown: `M7 241c-4 4-6.333 8.667-7 14 0 5.333.667 9 2 11s5.333 + 5.333 12 10c90.667 54 156 130 196 228 3.333 10.667 6.333 16.333 9 17 2 .667 5 + 1 9 1h5c10.667 0 16.667-2 18-6 2-2.667 1-9.667-3-21-32-87.333-82.667-157.667 +-152-211l-3-3h399907v-40zM93 281 H400000 v-40L7 241z`, + leftharpoondownplus: `M7 435c-4 4-6.3 8.7-7 14 0 5.3.7 9 2 11s5.3 5.3 12 + 10c90.7 54 156 130 196 228 3.3 10.7 6.3 16.3 9 17 2 .7 5 1 9 1h5c10.7 0 16.7 +-2 18-6 2-2.7 1-9.7-3-21-32-87.3-82.7-157.7-152-211l-3-3h399907v-40H7zm93 0 +v40h399900v-40zM0 241v40h399900v-40zm0 0v40h399900v-40z`, + // hook is from glyph U+21A9 in font KaTeX Main + lefthook: `M400000 281 H103s-33-11.2-61-33.5S0 197.3 0 164s14.2-61.2 42.5 +-83.5C70.8 58.2 104 47 142 47 c16.7 0 25 6.7 25 20 0 12-8.7 18.7-26 20-40 3.3 +-68.7 15.7-86 37-10 12-15 25.3-15 40 0 22.7 9.8 40.7 29.5 54 19.7 13.3 43.5 21 + 71.5 23h399859zM103 281v-40h399897v40z`, + leftlinesegment: `M40 281 V428 H0 V94 H40 V241 H400000 v40z +M40 281 V428 H0 V94 H40 V241 H400000 v40z`, + leftmapsto: `M40 281 V448H0V74H40V241H400000v40z +M40 281 V448H0V74H40V241H400000v40z`, + // tofrom is from glyph U+21C4 in font KaTeX AMS Regular + leftToFrom: `M0 147h400000v40H0zm0 214c68 40 115.7 95.7 143 167h22c15.3 0 23 +-.3 23-1 0-1.3-5.3-13.7-16-37-18-35.3-41.3-69-70-101l-7-8h399905v-40H95l7-8 +c28.7-32 52-65.7 70-101 10.7-23.3 16-35.7 16-37 0-.7-7.7-1-23-1h-22C115.7 265.3 + 68 321 0 361zm0-174v-40h399900v40zm100 154v40h399900v-40z`, + longequal: `M0 50 h400000 v40H0z m0 194h40000v40H0z +M0 50 h400000 v40H0z m0 194h40000v40H0z`, + midbrace: `M200428 334 +c-100.7-8.3-195.3-44-280-108-55.3-42-101.7-93-139-153l-9-14c-2.7 4-5.7 8.7-9 14 +-53.3 86.7-123.7 153-211 199-66.7 36-137.3 56.3-212 62H0V214h199568c178.3-11.7 + 311.7-78.3 403-201 6-8 9.7-12 11-12 .7-.7 6.7-1 18-1s17.3.3 18 1c1.3 0 5 4 11 + 12 44.7 59.3 101.3 106.3 170 141s145.3 54.3 229 60h199572v120z`, + midbraceunder: `M199572 214 +c100.7 8.3 195.3 44 280 108 55.3 42 101.7 93 139 153l9 14c2.7-4 5.7-8.7 9-14 + 53.3-86.7 123.7-153 211-199 66.7-36 137.3-56.3 212-62h199568v120H200432c-178.3 + 11.7-311.7 78.3-403 201-6 8-9.7 12-11 12-.7.7-6.7 1-18 1s-17.3-.3-18-1c-1.3 0 +-5-4-11-12-44.7-59.3-101.3-106.3-170-141s-145.3-54.3-229-60H0V214z`, + oiintSize1: `M512.6 71.6c272.6 0 320.3 106.8 320.3 178.2 0 70.8-47.7 177.6 +-320.3 177.6S193.1 320.6 193.1 249.8c0-71.4 46.9-178.2 319.5-178.2z +m368.1 178.2c0-86.4-60.9-215.4-368.1-215.4-306.4 0-367.3 129-367.3 215.4 0 85.8 +60.9 214.8 367.3 214.8 307.2 0 368.1-129 368.1-214.8z`, + oiintSize2: `M757.8 100.1c384.7 0 451.1 137.6 451.1 230 0 91.3-66.4 228.8 +-451.1 228.8-386.3 0-452.7-137.5-452.7-228.8 0-92.4 66.4-230 452.7-230z +m502.4 230c0-111.2-82.4-277.2-502.4-277.2s-504 166-504 277.2 +c0 110 84 276 504 276s502.4-166 502.4-276z`, + oiiintSize1: `M681.4 71.6c408.9 0 480.5 106.8 480.5 178.2 0 70.8-71.6 177.6 +-480.5 177.6S202.1 320.6 202.1 249.8c0-71.4 70.5-178.2 479.3-178.2z +m525.8 178.2c0-86.4-86.8-215.4-525.7-215.4-437.9 0-524.7 129-524.7 215.4 0 +85.8 86.8 214.8 524.7 214.8 438.9 0 525.7-129 525.7-214.8z`, + oiiintSize2: `M1021.2 53c603.6 0 707.8 165.8 707.8 277.2 0 110-104.2 275.8 +-707.8 275.8-606 0-710.2-165.8-710.2-275.8C311 218.8 415.2 53 1021.2 53z +m770.4 277.1c0-131.2-126.4-327.6-770.5-327.6S248.4 198.9 248.4 330.1 +c0 130 128.8 326.4 772.7 326.4s770.5-196.4 770.5-326.4z`, + rightarrow: `M0 241v40h399891c-47.3 35.3-84 78-110 128 +-16.7 32-27.7 63.7-33 95 0 1.3-.2 2.7-.5 4-.3 1.3-.5 2.3-.5 3 0 7.3 6.7 11 20 + 11 8 0 13.2-.8 15.5-2.5 2.3-1.7 4.2-5.5 5.5-11.5 2-13.3 5.7-27 11-41 14.7-44.7 + 39-84.5 73-119.5s73.7-60.2 119-75.5c6-2 9-5.7 9-11s-3-9-9-11c-45.3-15.3-85 +-40.5-119-75.5s-58.3-74.8-73-119.5c-4.7-14-8.3-27.3-11-40-1.3-6.7-3.2-10.8-5.5 +-12.5-2.3-1.7-7.5-2.5-15.5-2.5-14 0-21 3.7-21 11 0 2 2 10.3 6 25 20.7 83.3 67 + 151.7 139 205zm0 0v40h399900v-40z`, + rightbrace: `M400000 542l +-6 6h-17c-12.7 0-19.3-.3-20-1-4-4-7.3-8.3-10-13-35.3-51.3-80.8-93.8-136.5-127.5 +s-117.2-55.8-184.5-66.5c-.7 0-2-.3-4-1-18.7-2.7-76-4.3-172-5H0V214h399571l6 1 +c124.7 8 235 61.7 331 161 31.3 33.3 59.7 72.7 85 118l7 13v35z`, + rightbraceunder: `M399994 0l6 6v35l-6 11c-56 104-135.3 181.3-238 232-57.3 + 28.7-117 45-179 50H-300V214h399897c43.3-7 81-15 113-26 100.7-33 179.7-91 237 +-174 2.7-5 6-9 10-13 .7-1 7.3-1 20-1h17z`, + rightgroup: `M0 80h399565c371 0 266.7 149.4 414 180 5.9 1.2 18 0 18 0 2 0 + 3-1 3-3v-38c-76-158-257-219-435-219H0z`, + rightgroupunder: `M0 262h399565c371 0 266.7-149.4 414-180 5.9-1.2 18 0 18 + 0 2 0 3 1 3 3v38c-76 158-257 219-435 219H0z`, + rightharpoon: `M0 241v40h399993c4.7-4.7 7-9.3 7-14 0-9.3 +-3.7-15.3-11-18-92.7-56.7-159-133.7-199-231-3.3-9.3-6-14.7-8-16-2-1.3-7-2-15-2 +-10.7 0-16.7 2-18 6-2 2.7-1 9.7 3 21 15.3 42 36.7 81.8 64 119.5 27.3 37.7 58 + 69.2 92 94.5zm0 0v40h399900v-40z`, + rightharpoonplus: `M0 241v40h399993c4.7-4.7 7-9.3 7-14 0-9.3-3.7-15.3-11 +-18-92.7-56.7-159-133.7-199-231-3.3-9.3-6-14.7-8-16-2-1.3-7-2-15-2-10.7 0-16.7 + 2-18 6-2 2.7-1 9.7 3 21 15.3 42 36.7 81.8 64 119.5 27.3 37.7 58 69.2 92 94.5z +m0 0v40h399900v-40z m100 194v40h399900v-40zm0 0v40h399900v-40z`, + rightharpoondown: `M399747 511c0 7.3 6.7 11 20 11 8 0 13-.8 15-2.5s4.7-6.8 + 8-15.5c40-94 99.3-166.3 178-217 13.3-8 20.3-12.3 21-13 5.3-3.3 8.5-5.8 9.5 +-7.5 1-1.7 1.5-5.2 1.5-10.5s-2.3-10.3-7-15H0v40h399908c-34 25.3-64.7 57-92 95 +-27.3 38-48.7 77.7-64 119-3.3 8.7-5 14-5 16zM0 241v40h399900v-40z`, + rightharpoondownplus: `M399747 705c0 7.3 6.7 11 20 11 8 0 13-.8 + 15-2.5s4.7-6.8 8-15.5c40-94 99.3-166.3 178-217 13.3-8 20.3-12.3 21-13 5.3-3.3 + 8.5-5.8 9.5-7.5 1-1.7 1.5-5.2 1.5-10.5s-2.3-10.3-7-15H0v40h399908c-34 25.3 +-64.7 57-92 95-27.3 38-48.7 77.7-64 119-3.3 8.7-5 14-5 16zM0 435v40h399900v-40z +m0-194v40h400000v-40zm0 0v40h400000v-40z`, + righthook: `M399859 241c-764 0 0 0 0 0 40-3.3 68.7-15.7 86-37 10-12 15-25.3 + 15-40 0-22.7-9.8-40.7-29.5-54-19.7-13.3-43.5-21-71.5-23-17.3-1.3-26-8-26-20 0 +-13.3 8.7-20 26-20 38 0 71 11.2 99 33.5 0 0 7 5.6 21 16.7 14 11.2 21 33.5 21 + 66.8s-14 61.2-42 83.5c-28 22.3-61 33.5-99 33.5L0 241z M0 281v-40h399859v40z`, + rightlinesegment: `M399960 241 V94 h40 V428 h-40 V281 H0 v-40z +M399960 241 V94 h40 V428 h-40 V281 H0 v-40z`, + rightToFrom: `M400000 167c-70.7-42-118-97.7-142-167h-23c-15.3 0-23 .3-23 + 1 0 1.3 5.3 13.7 16 37 18 35.3 41.3 69 70 101l7 8H0v40h399905l-7 8c-28.7 32 +-52 65.7-70 101-10.7 23.3-16 35.7-16 37 0 .7 7.7 1 23 1h23c24-69.3 71.3-125 142 +-167z M100 147v40h399900v-40zM0 341v40h399900v-40z`, + // twoheadleftarrow is from glyph U+219E in font KaTeX AMS Regular + twoheadleftarrow: `M0 167c68 40 + 115.7 95.7 143 167h22c15.3 0 23-.3 23-1 0-1.3-5.3-13.7-16-37-18-35.3-41.3-69 +-70-101l-7-8h125l9 7c50.7 39.3 85 86 103 140h46c0-4.7-6.3-18.7-19-42-18-35.3 +-40-67.3-66-96l-9-9h399716v-40H284l9-9c26-28.7 48-60.7 66-96 12.7-23.333 19 +-37.333 19-42h-46c-18 54-52.3 100.7-103 140l-9 7H95l7-8c28.7-32 52-65.7 70-101 + 10.7-23.333 16-35.7 16-37 0-.7-7.7-1-23-1h-22C115.7 71.3 68 127 0 167z`, + twoheadrightarrow: `M400000 167 +c-68-40-115.7-95.7-143-167h-22c-15.3 0-23 .3-23 1 0 1.3 5.3 13.7 16 37 18 35.3 + 41.3 69 70 101l7 8h-125l-9-7c-50.7-39.3-85-86-103-140h-46c0 4.7 6.3 18.7 19 42 + 18 35.3 40 67.3 66 96l9 9H0v40h399716l-9 9c-26 28.7-48 60.7-66 96-12.7 23.333 +-19 37.333-19 42h46c18-54 52.3-100.7 103-140l9-7h125l-7 8c-28.7 32-52 65.7-70 + 101-10.7 23.333-16 35.7-16 37 0 .7 7.7 1 23 1h22c27.3-71.3 75-127 143-167z`, + // tilde1 is a modified version of a glyph from the MnSymbol package + tilde1: `M200 55.538c-77 0-168 73.953-177 73.953-3 0-7 +-2.175-9-5.437L2 97c-1-2-2-4-2-6 0-4 2-7 5-9l20-12C116 12 171 0 207 0c86 0 + 114 68 191 68 78 0 168-68 177-68 4 0 7 2 9 5l12 19c1 2.175 2 4.35 2 6.525 0 + 4.35-2 7.613-5 9.788l-19 13.05c-92 63.077-116.937 75.308-183 76.128 +-68.267.847-113-73.952-191-73.952z`, + // ditto tilde2, tilde3, & tilde4 + tilde2: `M344 55.266c-142 0-300.638 81.316-311.5 86.418 +-8.01 3.762-22.5 10.91-23.5 5.562L1 120c-1-2-1-3-1-4 0-5 3-9 8-10l18.4-9C160.9 + 31.9 283 0 358 0c148 0 188 122 331 122s314-97 326-97c4 0 8 2 10 7l7 21.114 +c1 2.14 1 3.21 1 4.28 0 5.347-3 9.626-7 10.696l-22.3 12.622C852.6 158.372 751 + 181.476 676 181.476c-149 0-189-126.21-332-126.21z`, + tilde3: `M786 59C457 59 32 175.242 13 175.242c-6 0-10-3.457 +-11-10.37L.15 138c-1-7 3-12 10-13l19.2-6.4C378.4 40.7 634.3 0 804.3 0c337 0 + 411.8 157 746.8 157 328 0 754-112 773-112 5 0 10 3 11 9l1 14.075c1 8.066-.697 + 16.595-6.697 17.492l-21.052 7.31c-367.9 98.146-609.15 122.696-778.15 122.696 + -338 0-409-156.573-744-156.573z`, + tilde4: `M786 58C457 58 32 177.487 13 177.487c-6 0-10-3.345 +-11-10.035L.15 143c-1-7 3-12 10-13l22-6.7C381.2 35 637.15 0 807.15 0c337 0 409 + 177 744 177 328 0 754-127 773-127 5 0 10 3 11 9l1 14.794c1 7.805-3 13.38-9 + 14.495l-20.7 5.574c-366.85 99.79-607.3 139.372-776.3 139.372-338 0-409 + -175.236-744-175.236z`, + // vec is from glyph U+20D7 in font KaTeX Main + vec: `M377 20c0-5.333 1.833-10 5.5-14S391 0 397 0c4.667 0 8.667 1.667 12 5 +3.333 2.667 6.667 9 10 19 6.667 24.667 20.333 43.667 41 57 7.333 4.667 11 +10.667 11 18 0 6-1 10-3 12s-6.667 5-14 9c-28.667 14.667-53.667 35.667-75 63 +-1.333 1.333-3.167 3.5-5.5 6.5s-4 4.833-5 5.5c-1 .667-2.5 1.333-4.5 2s-4.333 1 +-7 1c-4.667 0-9.167-1.833-13.5-5.5S337 184 337 178c0-12.667 15.667-32.333 47-59 +H213l-171-1c-8.667-6-13-12.333-13-19 0-4.667 4.333-11.333 13-20h359 +c-16-25.333-24-45-24-59z`, + // widehat1 is a modified version of a glyph from the MnSymbol package + widehat1: `M529 0h5l519 115c5 1 9 5 9 10 0 1-1 2-1 3l-4 22 +c-1 5-5 9-11 9h-2L532 67 19 159h-2c-5 0-9-4-11-9l-5-22c-1-6 2-12 8-13z`, + // ditto widehat2, widehat3, & widehat4 + widehat2: `M1181 0h2l1171 176c6 0 10 5 10 11l-2 23c-1 6-5 10 +-11 10h-1L1182 67 15 220h-1c-6 0-10-4-11-10l-2-23c-1-6 4-11 10-11z`, + widehat3: `M1181 0h2l1171 236c6 0 10 5 10 11l-2 23c-1 6-5 10 +-11 10h-1L1182 67 15 280h-1c-6 0-10-4-11-10l-2-23c-1-6 4-11 10-11z`, + widehat4: `M1181 0h2l1171 296c6 0 10 5 10 11l-2 23c-1 6-5 10 +-11 10h-1L1182 67 15 340h-1c-6 0-10-4-11-10l-2-23c-1-6 4-11 10-11z`, + // widecheck paths are all inverted versions of widehat + widecheck1: `M529,159h5l519,-115c5,-1,9,-5,9,-10c0,-1,-1,-2,-1,-3l-4,-22c-1, +-5,-5,-9,-11,-9h-2l-512,92l-513,-92h-2c-5,0,-9,4,-11,9l-5,22c-1,6,2,12,8,13z`, + widecheck2: `M1181,220h2l1171,-176c6,0,10,-5,10,-11l-2,-23c-1,-6,-5,-10, +-11,-10h-1l-1168,153l-1167,-153h-1c-6,0,-10,4,-11,10l-2,23c-1,6,4,11,10,11z`, + widecheck3: `M1181,280h2l1171,-236c6,0,10,-5,10,-11l-2,-23c-1,-6,-5,-10, +-11,-10h-1l-1168,213l-1167,-213h-1c-6,0,-10,4,-11,10l-2,23c-1,6,4,11,10,11z`, + widecheck4: `M1181,340h2l1171,-296c6,0,10,-5,10,-11l-2,-23c-1,-6,-5,-10, +-11,-10h-1l-1168,273l-1167,-273h-1c-6,0,-10,4,-11,10l-2,23c-1,6,4,11,10,11z`, + // The next ten paths support reaction arrows from the mhchem package. + // Arrows for \ce{<-->} are offset from xAxis by 0.22ex, per mhchem in LaTeX + // baraboveleftarrow is mostly from from glyph U+2190 in font KaTeX Main + baraboveleftarrow: `M400000 620h-399890l3 -3c68.7 -52.7 113.7 -120 135 -202 +c4 -14.7 6 -23 6 -25c0 -7.3 -7 -11 -21 -11c-8 0 -13.2 0.8 -15.5 2.5 +c-2.3 1.7 -4.2 5.8 -5.5 12.5c-1.3 4.7 -2.7 10.3 -4 17c-12 48.7 -34.8 92 -68.5 130 +s-74.2 66.3 -121.5 85c-10 4 -16 7.7 -18 11c0 8.7 6 14.3 18 17c47.3 18.7 87.8 47 +121.5 85s56.5 81.3 68.5 130c0.7 2 1.3 5 2 9s1.2 6.7 1.5 8c0.3 1.3 1 3.3 2 6 +s2.2 4.5 3.5 5.5c1.3 1 3.3 1.8 6 2.5s6 1 10 1c14 0 21 -3.7 21 -11 +c0 -2 -2 -10.3 -6 -25c-20 -79.3 -65 -146.7 -135 -202l-3 -3h399890z +M100 620v40h399900v-40z M0 241v40h399900v-40zM0 241v40h399900v-40z`, + // rightarrowabovebar is mostly from glyph U+2192, KaTeX Main + rightarrowabovebar: `M0 241v40h399891c-47.3 35.3-84 78-110 128-16.7 32 +-27.7 63.7-33 95 0 1.3-.2 2.7-.5 4-.3 1.3-.5 2.3-.5 3 0 7.3 6.7 11 20 11 8 0 +13.2-.8 15.5-2.5 2.3-1.7 4.2-5.5 5.5-11.5 2-13.3 5.7-27 11-41 14.7-44.7 39 +-84.5 73-119.5s73.7-60.2 119-75.5c6-2 9-5.7 9-11s-3-9-9-11c-45.3-15.3-85-40.5 +-119-75.5s-58.3-74.8-73-119.5c-4.7-14-8.3-27.3-11-40-1.3-6.7-3.2-10.8-5.5 +-12.5-2.3-1.7-7.5-2.5-15.5-2.5-14 0-21 3.7-21 11 0 2 2 10.3 6 25 20.7 83.3 67 +151.7 139 205zm96 379h399894v40H0zm0 0h399904v40H0z`, + // The short left harpoon has 0.5em (i.e. 500 units) kern on the left end. + // Ref from mhchem.sty: \rlap{\raisebox{-.22ex}{$\kern0.5em + baraboveshortleftharpoon: `M507,435c-4,4,-6.3,8.7,-7,14c0,5.3,0.7,9,2,11 +c1.3,2,5.3,5.3,12,10c90.7,54,156,130,196,228c3.3,10.7,6.3,16.3,9,17 +c2,0.7,5,1,9,1c0,0,5,0,5,0c10.7,0,16.7,-2,18,-6c2,-2.7,1,-9.7,-3,-21 +c-32,-87.3,-82.7,-157.7,-152,-211c0,0,-3,-3,-3,-3l399351,0l0,-40 +c-398570,0,-399437,0,-399437,0z M593 435 v40 H399500 v-40z +M0 281 v-40 H399908 v40z M0 281 v-40 H399908 v40z`, + rightharpoonaboveshortbar: `M0,241 l0,40c399126,0,399993,0,399993,0 +c4.7,-4.7,7,-9.3,7,-14c0,-9.3,-3.7,-15.3,-11,-18c-92.7,-56.7,-159,-133.7,-199, +-231c-3.3,-9.3,-6,-14.7,-8,-16c-2,-1.3,-7,-2,-15,-2c-10.7,0,-16.7,2,-18,6 +c-2,2.7,-1,9.7,3,21c15.3,42,36.7,81.8,64,119.5c27.3,37.7,58,69.2,92,94.5z +M0 241 v40 H399908 v-40z M0 475 v-40 H399500 v40z M0 475 v-40 H399500 v40z`, + shortbaraboveleftharpoon: `M7,435c-4,4,-6.3,8.7,-7,14c0,5.3,0.7,9,2,11 +c1.3,2,5.3,5.3,12,10c90.7,54,156,130,196,228c3.3,10.7,6.3,16.3,9,17c2,0.7,5,1,9, +1c0,0,5,0,5,0c10.7,0,16.7,-2,18,-6c2,-2.7,1,-9.7,-3,-21c-32,-87.3,-82.7,-157.7, +-152,-211c0,0,-3,-3,-3,-3l399907,0l0,-40c-399126,0,-399993,0,-399993,0z +M93 435 v40 H400000 v-40z M500 241 v40 H400000 v-40z M500 241 v40 H400000 v-40z`, + shortrightharpoonabovebar: `M53,241l0,40c398570,0,399437,0,399437,0 +c4.7,-4.7,7,-9.3,7,-14c0,-9.3,-3.7,-15.3,-11,-18c-92.7,-56.7,-159,-133.7,-199, +-231c-3.3,-9.3,-6,-14.7,-8,-16c-2,-1.3,-7,-2,-15,-2c-10.7,0,-16.7,2,-18,6 +c-2,2.7,-1,9.7,3,21c15.3,42,36.7,81.8,64,119.5c27.3,37.7,58,69.2,92,94.5z +M500 241 v40 H399408 v-40z M500 435 v40 H400000 v-40z` +}; + +/** + * This node represents a document fragment, which contains elements, but when + * placed into the DOM doesn't have any representation itself. It only contains + * children and doesn't have any DOM node properties. + */ +class DocumentFragment { + // HtmlDomNode + // Never used; needed for satisfying interface. + constructor(children) { + this.children = void 0; + this.classes = void 0; + this.height = void 0; + this.depth = void 0; + this.maxFontSize = void 0; + this.style = void 0; + this.children = children; + this.classes = []; + this.height = 0; + this.depth = 0; + this.maxFontSize = 0; + this.style = {}; + } + + hasClass(className) { + return utils.contains(this.classes, className); + } + /** Convert the fragment into a node. */ + + + toNode() { + const frag = document.createDocumentFragment(); + + for (let i = 0; i < this.children.length; i++) { + frag.appendChild(this.children[i].toNode()); + } + + return frag; + } + /** Convert the fragment into HTML markup. */ + + + toMarkup() { + let markup = ""; // Simply concatenate the markup for the children together. + + for (let i = 0; i < this.children.length; i++) { + markup += this.children[i].toMarkup(); + } + + return markup; + } + /** + * Converts the math node into a string, similar to innerText. Applies to + * MathDomNode's only. + */ + + + toText() { + // To avoid this, we would subclass documentFragment separately for + // MathML, but polyfills for subclassing is expensive per PR 1469. + // $FlowFixMe: Only works for ChildType = MathDomNode. + const toText = child => child.toText(); + + return this.children.map(toText).join(""); + } + +} + +/** + * These objects store the data about the DOM nodes we create, as well as some + * extra data. They can then be transformed into real DOM nodes with the + * `toNode` function or HTML markup using `toMarkup`. They are useful for both + * storing extra properties on the nodes, as well as providing a way to easily + * work with the DOM. + * + * Similar functions for working with MathML nodes exist in mathMLTree.js. + * + * TODO: refactor `span` and `anchor` into common superclass when + * target environments support class inheritance + */ + +/** + * Create an HTML className based on a list of classes. In addition to joining + * with spaces, we also remove empty classes. + */ +const createClass = function createClass(classes) { + return classes.filter(cls => cls).join(" "); +}; + +const initNode = function initNode(classes, options, style) { + this.classes = classes || []; + this.attributes = {}; + this.height = 0; + this.depth = 0; + this.maxFontSize = 0; + this.style = style || {}; + + if (options) { + if (options.style.isTight()) { + this.classes.push("mtight"); + } + + const color = options.getColor(); + + if (color) { + this.style.color = color; + } + } +}; +/** + * Convert into an HTML node + */ + + +const toNode = function toNode(tagName) { + const node = document.createElement(tagName); // Apply the class + + node.className = createClass(this.classes); // Apply inline styles + + for (const style in this.style) { + if (this.style.hasOwnProperty(style)) { + // $FlowFixMe Flow doesn't seem to understand span.style's type. + node.style[style] = this.style[style]; + } + } // Apply attributes + + + for (const attr in this.attributes) { + if (this.attributes.hasOwnProperty(attr)) { + node.setAttribute(attr, this.attributes[attr]); + } + } // Append the children, also as HTML nodes + + + for (let i = 0; i < this.children.length; i++) { + node.appendChild(this.children[i].toNode()); + } + + return node; +}; +/** + * Convert into an HTML markup string + */ + + +const toMarkup = function toMarkup(tagName) { + let markup = `<${tagName}`; // Add the class + + if (this.classes.length) { + markup += ` class="${utils.escape(createClass(this.classes))}"`; + } + + let styles = ""; // Add the styles, after hyphenation + + for (const style in this.style) { + if (this.style.hasOwnProperty(style)) { + styles += `${utils.hyphenate(style)}:${this.style[style]};`; + } + } + + if (styles) { + markup += ` style="${utils.escape(styles)}"`; + } // Add the attributes + + + for (const attr in this.attributes) { + if (this.attributes.hasOwnProperty(attr)) { + markup += ` ${attr}="${utils.escape(this.attributes[attr])}"`; + } + } + + markup += ">"; // Add the markup of the children, also as markup + + for (let i = 0; i < this.children.length; i++) { + markup += this.children[i].toMarkup(); + } + + markup += ``; + return markup; +}; // Making the type below exact with all optional fields doesn't work due to +// - https://github.com/facebook/flow/issues/4582 +// - https://github.com/facebook/flow/issues/5688 +// However, since *all* fields are optional, $Shape<> works as suggested in 5688 +// above. +// This type does not include all CSS properties. Additional properties should +// be added as needed. + + +/** + * This node represents a span node, with a className, a list of children, and + * an inline style. It also contains information about its height, depth, and + * maxFontSize. + * + * Represents two types with different uses: SvgSpan to wrap an SVG and DomSpan + * otherwise. This typesafety is important when HTML builders access a span's + * children. + */ +class Span { + constructor(classes, children, options, style) { + this.children = void 0; + this.attributes = void 0; + this.classes = void 0; + this.height = void 0; + this.depth = void 0; + this.width = void 0; + this.maxFontSize = void 0; + this.style = void 0; + initNode.call(this, classes, options, style); + this.children = children || []; + } + /** + * Sets an arbitrary attribute on the span. Warning: use this wisely. Not + * all browsers support attributes the same, and having too many custom + * attributes is probably bad. + */ + + + setAttribute(attribute, value) { + this.attributes[attribute] = value; + } + + hasClass(className) { + return utils.contains(this.classes, className); + } + + toNode() { + return toNode.call(this, "span"); + } + + toMarkup() { + return toMarkup.call(this, "span"); + } + +} +/** + * This node represents an anchor () element with a hyperlink. See `span` + * for further details. + */ + +class Anchor { + constructor(href, classes, children, options) { + this.children = void 0; + this.attributes = void 0; + this.classes = void 0; + this.height = void 0; + this.depth = void 0; + this.maxFontSize = void 0; + this.style = void 0; + initNode.call(this, classes, options); + this.children = children || []; + this.setAttribute('href', href); + } + + setAttribute(attribute, value) { + this.attributes[attribute] = value; + } + + hasClass(className) { + return utils.contains(this.classes, className); + } + + toNode() { + return toNode.call(this, "a"); + } + + toMarkup() { + return toMarkup.call(this, "a"); + } + +} +/** + * This node represents an image embed () element. + */ + +class Img { + constructor(src, alt, style) { + this.src = void 0; + this.alt = void 0; + this.classes = void 0; + this.height = void 0; + this.depth = void 0; + this.maxFontSize = void 0; + this.style = void 0; + this.alt = alt; + this.src = src; + this.classes = ["mord"]; + this.style = style; + } + + hasClass(className) { + return utils.contains(this.classes, className); + } + + toNode() { + const node = document.createElement("img"); + node.src = this.src; + node.alt = this.alt; + node.className = "mord"; // Apply inline styles + + for (const style in this.style) { + if (this.style.hasOwnProperty(style)) { + // $FlowFixMe + node.style[style] = this.style[style]; + } + } + + return node; + } + + toMarkup() { + let markup = `${this.alt} 0) { + span = document.createElement("span"); + span.style.marginRight = this.italic + "em"; + } + + if (this.classes.length > 0) { + span = span || document.createElement("span"); + span.className = createClass(this.classes); + } + + for (const style in this.style) { + if (this.style.hasOwnProperty(style)) { + span = span || document.createElement("span"); // $FlowFixMe Flow doesn't seem to understand span.style's type. + + span.style[style] = this.style[style]; + } + } + + if (span) { + span.appendChild(node); + return span; + } else { + return node; + } + } + /** + * Creates markup for a symbol node. + */ + + + toMarkup() { + // TODO(alpert): More duplication than I'd like from + // span.prototype.toMarkup and symbolNode.prototype.toNode... + let needsSpan = false; + let markup = " 0) { + styles += "margin-right:" + this.italic + "em;"; + } + + for (const style in this.style) { + if (this.style.hasOwnProperty(style)) { + styles += utils.hyphenate(style) + ":" + this.style[style] + ";"; + } + } + + if (styles) { + needsSpan = true; + markup += " style=\"" + utils.escape(styles) + "\""; + } + + const escaped = utils.escape(this.text); + + if (needsSpan) { + markup += ">"; + markup += escaped; + markup += ""; + return markup; + } else { + return escaped; + } + } + +} +/** + * SVG nodes are used to render stretchy wide elements. + */ + +class SvgNode { + constructor(children, attributes) { + this.children = void 0; + this.attributes = void 0; + this.children = children || []; + this.attributes = attributes || {}; + } + + toNode() { + const svgNS = "http://www.w3.org/2000/svg"; + const node = document.createElementNS(svgNS, "svg"); // Apply attributes + + for (const attr in this.attributes) { + if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) { + node.setAttribute(attr, this.attributes[attr]); + } + } + + for (let i = 0; i < this.children.length; i++) { + node.appendChild(this.children[i].toNode()); + } + + return node; + } + + toMarkup() { + let markup = "`; + } else { + return ``; + } + } + +} +class LineNode { + constructor(attributes) { + this.attributes = void 0; + this.attributes = attributes || {}; + } + + toNode() { + const svgNS = "http://www.w3.org/2000/svg"; + const node = document.createElementNS(svgNS, "line"); // Apply attributes + + for (const attr in this.attributes) { + if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) { + node.setAttribute(attr, this.attributes[attr]); + } + } + + return node; + } + + toMarkup() { + let markup = " but got ${String(group)}.`); + } +} + +// This file is GENERATED by buildMetrics.sh. DO NOT MODIFY. +var metricMap = { + "AMS-Regular": { + "65": [0, 0.68889, 0, 0, 0.72222], + "66": [0, 0.68889, 0, 0, 0.66667], + "67": [0, 0.68889, 0, 0, 0.72222], + "68": [0, 0.68889, 0, 0, 0.72222], + "69": [0, 0.68889, 0, 0, 0.66667], + "70": [0, 0.68889, 0, 0, 0.61111], + "71": [0, 0.68889, 0, 0, 0.77778], + "72": [0, 0.68889, 0, 0, 0.77778], + "73": [0, 0.68889, 0, 0, 0.38889], + "74": [0.16667, 0.68889, 0, 0, 0.5], + "75": [0, 0.68889, 0, 0, 0.77778], + "76": [0, 0.68889, 0, 0, 0.66667], + "77": [0, 0.68889, 0, 0, 0.94445], + "78": [0, 0.68889, 0, 0, 0.72222], + "79": [0.16667, 0.68889, 0, 0, 0.77778], + "80": [0, 0.68889, 0, 0, 0.61111], + "81": [0.16667, 0.68889, 0, 0, 0.77778], + "82": [0, 0.68889, 0, 0, 0.72222], + "83": [0, 0.68889, 0, 0, 0.55556], + "84": [0, 0.68889, 0, 0, 0.66667], + "85": [0, 0.68889, 0, 0, 0.72222], + "86": [0, 0.68889, 0, 0, 0.72222], + "87": [0, 0.68889, 0, 0, 1.0], + "88": [0, 0.68889, 0, 0, 0.72222], + "89": [0, 0.68889, 0, 0, 0.72222], + "90": [0, 0.68889, 0, 0, 0.66667], + "107": [0, 0.68889, 0, 0, 0.55556], + "165": [0, 0.675, 0.025, 0, 0.75], + "174": [0.15559, 0.69224, 0, 0, 0.94666], + "240": [0, 0.68889, 0, 0, 0.55556], + "295": [0, 0.68889, 0, 0, 0.54028], + "710": [0, 0.825, 0, 0, 2.33334], + "732": [0, 0.9, 0, 0, 2.33334], + "770": [0, 0.825, 0, 0, 2.33334], + "771": [0, 0.9, 0, 0, 2.33334], + "989": [0.08167, 0.58167, 0, 0, 0.77778], + "1008": [0, 0.43056, 0.04028, 0, 0.66667], + "8245": [0, 0.54986, 0, 0, 0.275], + "8463": [0, 0.68889, 0, 0, 0.54028], + "8487": [0, 0.68889, 0, 0, 0.72222], + "8498": [0, 0.68889, 0, 0, 0.55556], + "8502": [0, 0.68889, 0, 0, 0.66667], + "8503": [0, 0.68889, 0, 0, 0.44445], + "8504": [0, 0.68889, 0, 0, 0.66667], + "8513": [0, 0.68889, 0, 0, 0.63889], + "8592": [-0.03598, 0.46402, 0, 0, 0.5], + "8594": [-0.03598, 0.46402, 0, 0, 0.5], + "8602": [-0.13313, 0.36687, 0, 0, 1.0], + "8603": [-0.13313, 0.36687, 0, 0, 1.0], + "8606": [0.01354, 0.52239, 0, 0, 1.0], + "8608": [0.01354, 0.52239, 0, 0, 1.0], + "8610": [0.01354, 0.52239, 0, 0, 1.11111], + "8611": [0.01354, 0.52239, 0, 0, 1.11111], + "8619": [0, 0.54986, 0, 0, 1.0], + "8620": [0, 0.54986, 0, 0, 1.0], + "8621": [-0.13313, 0.37788, 0, 0, 1.38889], + "8622": [-0.13313, 0.36687, 0, 0, 1.0], + "8624": [0, 0.69224, 0, 0, 0.5], + "8625": [0, 0.69224, 0, 0, 0.5], + "8630": [0, 0.43056, 0, 0, 1.0], + "8631": [0, 0.43056, 0, 0, 1.0], + "8634": [0.08198, 0.58198, 0, 0, 0.77778], + "8635": [0.08198, 0.58198, 0, 0, 0.77778], + "8638": [0.19444, 0.69224, 0, 0, 0.41667], + "8639": [0.19444, 0.69224, 0, 0, 0.41667], + "8642": [0.19444, 0.69224, 0, 0, 0.41667], + "8643": [0.19444, 0.69224, 0, 0, 0.41667], + "8644": [0.1808, 0.675, 0, 0, 1.0], + "8646": [0.1808, 0.675, 0, 0, 1.0], + "8647": [0.1808, 0.675, 0, 0, 1.0], + "8648": [0.19444, 0.69224, 0, 0, 0.83334], + "8649": [0.1808, 0.675, 0, 0, 1.0], + "8650": [0.19444, 0.69224, 0, 0, 0.83334], + "8651": [0.01354, 0.52239, 0, 0, 1.0], + "8652": [0.01354, 0.52239, 0, 0, 1.0], + "8653": [-0.13313, 0.36687, 0, 0, 1.0], + "8654": [-0.13313, 0.36687, 0, 0, 1.0], + "8655": [-0.13313, 0.36687, 0, 0, 1.0], + "8666": [0.13667, 0.63667, 0, 0, 1.0], + "8667": [0.13667, 0.63667, 0, 0, 1.0], + "8669": [-0.13313, 0.37788, 0, 0, 1.0], + "8672": [-0.064, 0.437, 0, 0, 1.334], + "8674": [-0.064, 0.437, 0, 0, 1.334], + "8705": [0, 0.825, 0, 0, 0.5], + "8708": [0, 0.68889, 0, 0, 0.55556], + "8709": [0.08167, 0.58167, 0, 0, 0.77778], + "8717": [0, 0.43056, 0, 0, 0.42917], + "8722": [-0.03598, 0.46402, 0, 0, 0.5], + "8724": [0.08198, 0.69224, 0, 0, 0.77778], + "8726": [0.08167, 0.58167, 0, 0, 0.77778], + "8733": [0, 0.69224, 0, 0, 0.77778], + "8736": [0, 0.69224, 0, 0, 0.72222], + "8737": [0, 0.69224, 0, 0, 0.72222], + "8738": [0.03517, 0.52239, 0, 0, 0.72222], + "8739": [0.08167, 0.58167, 0, 0, 0.22222], + "8740": [0.25142, 0.74111, 0, 0, 0.27778], + "8741": [0.08167, 0.58167, 0, 0, 0.38889], + "8742": [0.25142, 0.74111, 0, 0, 0.5], + "8756": [0, 0.69224, 0, 0, 0.66667], + "8757": [0, 0.69224, 0, 0, 0.66667], + "8764": [-0.13313, 0.36687, 0, 0, 0.77778], + "8765": [-0.13313, 0.37788, 0, 0, 0.77778], + "8769": [-0.13313, 0.36687, 0, 0, 0.77778], + "8770": [-0.03625, 0.46375, 0, 0, 0.77778], + "8774": [0.30274, 0.79383, 0, 0, 0.77778], + "8776": [-0.01688, 0.48312, 0, 0, 0.77778], + "8778": [0.08167, 0.58167, 0, 0, 0.77778], + "8782": [0.06062, 0.54986, 0, 0, 0.77778], + "8783": [0.06062, 0.54986, 0, 0, 0.77778], + "8785": [0.08198, 0.58198, 0, 0, 0.77778], + "8786": [0.08198, 0.58198, 0, 0, 0.77778], + "8787": [0.08198, 0.58198, 0, 0, 0.77778], + "8790": [0, 0.69224, 0, 0, 0.77778], + "8791": [0.22958, 0.72958, 0, 0, 0.77778], + "8796": [0.08198, 0.91667, 0, 0, 0.77778], + "8806": [0.25583, 0.75583, 0, 0, 0.77778], + "8807": [0.25583, 0.75583, 0, 0, 0.77778], + "8808": [0.25142, 0.75726, 0, 0, 0.77778], + "8809": [0.25142, 0.75726, 0, 0, 0.77778], + "8812": [0.25583, 0.75583, 0, 0, 0.5], + "8814": [0.20576, 0.70576, 0, 0, 0.77778], + "8815": [0.20576, 0.70576, 0, 0, 0.77778], + "8816": [0.30274, 0.79383, 0, 0, 0.77778], + "8817": [0.30274, 0.79383, 0, 0, 0.77778], + "8818": [0.22958, 0.72958, 0, 0, 0.77778], + "8819": [0.22958, 0.72958, 0, 0, 0.77778], + "8822": [0.1808, 0.675, 0, 0, 0.77778], + "8823": [0.1808, 0.675, 0, 0, 0.77778], + "8828": [0.13667, 0.63667, 0, 0, 0.77778], + "8829": [0.13667, 0.63667, 0, 0, 0.77778], + "8830": [0.22958, 0.72958, 0, 0, 0.77778], + "8831": [0.22958, 0.72958, 0, 0, 0.77778], + "8832": [0.20576, 0.70576, 0, 0, 0.77778], + "8833": [0.20576, 0.70576, 0, 0, 0.77778], + "8840": [0.30274, 0.79383, 0, 0, 0.77778], + "8841": [0.30274, 0.79383, 0, 0, 0.77778], + "8842": [0.13597, 0.63597, 0, 0, 0.77778], + "8843": [0.13597, 0.63597, 0, 0, 0.77778], + "8847": [0.03517, 0.54986, 0, 0, 0.77778], + "8848": [0.03517, 0.54986, 0, 0, 0.77778], + "8858": [0.08198, 0.58198, 0, 0, 0.77778], + "8859": [0.08198, 0.58198, 0, 0, 0.77778], + "8861": [0.08198, 0.58198, 0, 0, 0.77778], + "8862": [0, 0.675, 0, 0, 0.77778], + "8863": [0, 0.675, 0, 0, 0.77778], + "8864": [0, 0.675, 0, 0, 0.77778], + "8865": [0, 0.675, 0, 0, 0.77778], + "8872": [0, 0.69224, 0, 0, 0.61111], + "8873": [0, 0.69224, 0, 0, 0.72222], + "8874": [0, 0.69224, 0, 0, 0.88889], + "8876": [0, 0.68889, 0, 0, 0.61111], + "8877": [0, 0.68889, 0, 0, 0.61111], + "8878": [0, 0.68889, 0, 0, 0.72222], + "8879": [0, 0.68889, 0, 0, 0.72222], + "8882": [0.03517, 0.54986, 0, 0, 0.77778], + "8883": [0.03517, 0.54986, 0, 0, 0.77778], + "8884": [0.13667, 0.63667, 0, 0, 0.77778], + "8885": [0.13667, 0.63667, 0, 0, 0.77778], + "8888": [0, 0.54986, 0, 0, 1.11111], + "8890": [0.19444, 0.43056, 0, 0, 0.55556], + "8891": [0.19444, 0.69224, 0, 0, 0.61111], + "8892": [0.19444, 0.69224, 0, 0, 0.61111], + "8901": [0, 0.54986, 0, 0, 0.27778], + "8903": [0.08167, 0.58167, 0, 0, 0.77778], + "8905": [0.08167, 0.58167, 0, 0, 0.77778], + "8906": [0.08167, 0.58167, 0, 0, 0.77778], + "8907": [0, 0.69224, 0, 0, 0.77778], + "8908": [0, 0.69224, 0, 0, 0.77778], + "8909": [-0.03598, 0.46402, 0, 0, 0.77778], + "8910": [0, 0.54986, 0, 0, 0.76042], + "8911": [0, 0.54986, 0, 0, 0.76042], + "8912": [0.03517, 0.54986, 0, 0, 0.77778], + "8913": [0.03517, 0.54986, 0, 0, 0.77778], + "8914": [0, 0.54986, 0, 0, 0.66667], + "8915": [0, 0.54986, 0, 0, 0.66667], + "8916": [0, 0.69224, 0, 0, 0.66667], + "8918": [0.0391, 0.5391, 0, 0, 0.77778], + "8919": [0.0391, 0.5391, 0, 0, 0.77778], + "8920": [0.03517, 0.54986, 0, 0, 1.33334], + "8921": [0.03517, 0.54986, 0, 0, 1.33334], + "8922": [0.38569, 0.88569, 0, 0, 0.77778], + "8923": [0.38569, 0.88569, 0, 0, 0.77778], + "8926": [0.13667, 0.63667, 0, 0, 0.77778], + "8927": [0.13667, 0.63667, 0, 0, 0.77778], + "8928": [0.30274, 0.79383, 0, 0, 0.77778], + "8929": [0.30274, 0.79383, 0, 0, 0.77778], + "8934": [0.23222, 0.74111, 0, 0, 0.77778], + "8935": [0.23222, 0.74111, 0, 0, 0.77778], + "8936": [0.23222, 0.74111, 0, 0, 0.77778], + "8937": [0.23222, 0.74111, 0, 0, 0.77778], + "8938": [0.20576, 0.70576, 0, 0, 0.77778], + "8939": [0.20576, 0.70576, 0, 0, 0.77778], + "8940": [0.30274, 0.79383, 0, 0, 0.77778], + "8941": [0.30274, 0.79383, 0, 0, 0.77778], + "8994": [0.19444, 0.69224, 0, 0, 0.77778], + "8995": [0.19444, 0.69224, 0, 0, 0.77778], + "9416": [0.15559, 0.69224, 0, 0, 0.90222], + "9484": [0, 0.69224, 0, 0, 0.5], + "9488": [0, 0.69224, 0, 0, 0.5], + "9492": [0, 0.37788, 0, 0, 0.5], + "9496": [0, 0.37788, 0, 0, 0.5], + "9585": [0.19444, 0.68889, 0, 0, 0.88889], + "9586": [0.19444, 0.74111, 0, 0, 0.88889], + "9632": [0, 0.675, 0, 0, 0.77778], + "9633": [0, 0.675, 0, 0, 0.77778], + "9650": [0, 0.54986, 0, 0, 0.72222], + "9651": [0, 0.54986, 0, 0, 0.72222], + "9654": [0.03517, 0.54986, 0, 0, 0.77778], + "9660": [0, 0.54986, 0, 0, 0.72222], + "9661": [0, 0.54986, 0, 0, 0.72222], + "9664": [0.03517, 0.54986, 0, 0, 0.77778], + "9674": [0.11111, 0.69224, 0, 0, 0.66667], + "9733": [0.19444, 0.69224, 0, 0, 0.94445], + "10003": [0, 0.69224, 0, 0, 0.83334], + "10016": [0, 0.69224, 0, 0, 0.83334], + "10731": [0.11111, 0.69224, 0, 0, 0.66667], + "10846": [0.19444, 0.75583, 0, 0, 0.61111], + "10877": [0.13667, 0.63667, 0, 0, 0.77778], + "10878": [0.13667, 0.63667, 0, 0, 0.77778], + "10885": [0.25583, 0.75583, 0, 0, 0.77778], + "10886": [0.25583, 0.75583, 0, 0, 0.77778], + "10887": [0.13597, 0.63597, 0, 0, 0.77778], + "10888": [0.13597, 0.63597, 0, 0, 0.77778], + "10889": [0.26167, 0.75726, 0, 0, 0.77778], + "10890": [0.26167, 0.75726, 0, 0, 0.77778], + "10891": [0.48256, 0.98256, 0, 0, 0.77778], + "10892": [0.48256, 0.98256, 0, 0, 0.77778], + "10901": [0.13667, 0.63667, 0, 0, 0.77778], + "10902": [0.13667, 0.63667, 0, 0, 0.77778], + "10933": [0.25142, 0.75726, 0, 0, 0.77778], + "10934": [0.25142, 0.75726, 0, 0, 0.77778], + "10935": [0.26167, 0.75726, 0, 0, 0.77778], + "10936": [0.26167, 0.75726, 0, 0, 0.77778], + "10937": [0.26167, 0.75726, 0, 0, 0.77778], + "10938": [0.26167, 0.75726, 0, 0, 0.77778], + "10949": [0.25583, 0.75583, 0, 0, 0.77778], + "10950": [0.25583, 0.75583, 0, 0, 0.77778], + "10955": [0.28481, 0.79383, 0, 0, 0.77778], + "10956": [0.28481, 0.79383, 0, 0, 0.77778], + "57350": [0.08167, 0.58167, 0, 0, 0.22222], + "57351": [0.08167, 0.58167, 0, 0, 0.38889], + "57352": [0.08167, 0.58167, 0, 0, 0.77778], + "57353": [0, 0.43056, 0.04028, 0, 0.66667], + "57356": [0.25142, 0.75726, 0, 0, 0.77778], + "57357": [0.25142, 0.75726, 0, 0, 0.77778], + "57358": [0.41951, 0.91951, 0, 0, 0.77778], + "57359": [0.30274, 0.79383, 0, 0, 0.77778], + "57360": [0.30274, 0.79383, 0, 0, 0.77778], + "57361": [0.41951, 0.91951, 0, 0, 0.77778], + "57366": [0.25142, 0.75726, 0, 0, 0.77778], + "57367": [0.25142, 0.75726, 0, 0, 0.77778], + "57368": [0.25142, 0.75726, 0, 0, 0.77778], + "57369": [0.25142, 0.75726, 0, 0, 0.77778], + "57370": [0.13597, 0.63597, 0, 0, 0.77778], + "57371": [0.13597, 0.63597, 0, 0, 0.77778] + }, + "Caligraphic-Regular": { + "48": [0, 0.43056, 0, 0, 0.5], + "49": [0, 0.43056, 0, 0, 0.5], + "50": [0, 0.43056, 0, 0, 0.5], + "51": [0.19444, 0.43056, 0, 0, 0.5], + "52": [0.19444, 0.43056, 0, 0, 0.5], + "53": [0.19444, 0.43056, 0, 0, 0.5], + "54": [0, 0.64444, 0, 0, 0.5], + "55": [0.19444, 0.43056, 0, 0, 0.5], + "56": [0, 0.64444, 0, 0, 0.5], + "57": [0.19444, 0.43056, 0, 0, 0.5], + "65": [0, 0.68333, 0, 0.19445, 0.79847], + "66": [0, 0.68333, 0.03041, 0.13889, 0.65681], + "67": [0, 0.68333, 0.05834, 0.13889, 0.52653], + "68": [0, 0.68333, 0.02778, 0.08334, 0.77139], + "69": [0, 0.68333, 0.08944, 0.11111, 0.52778], + "70": [0, 0.68333, 0.09931, 0.11111, 0.71875], + "71": [0.09722, 0.68333, 0.0593, 0.11111, 0.59487], + "72": [0, 0.68333, 0.00965, 0.11111, 0.84452], + "73": [0, 0.68333, 0.07382, 0, 0.54452], + "74": [0.09722, 0.68333, 0.18472, 0.16667, 0.67778], + "75": [0, 0.68333, 0.01445, 0.05556, 0.76195], + "76": [0, 0.68333, 0, 0.13889, 0.68972], + "77": [0, 0.68333, 0, 0.13889, 1.2009], + "78": [0, 0.68333, 0.14736, 0.08334, 0.82049], + "79": [0, 0.68333, 0.02778, 0.11111, 0.79611], + "80": [0, 0.68333, 0.08222, 0.08334, 0.69556], + "81": [0.09722, 0.68333, 0, 0.11111, 0.81667], + "82": [0, 0.68333, 0, 0.08334, 0.8475], + "83": [0, 0.68333, 0.075, 0.13889, 0.60556], + "84": [0, 0.68333, 0.25417, 0, 0.54464], + "85": [0, 0.68333, 0.09931, 0.08334, 0.62583], + "86": [0, 0.68333, 0.08222, 0, 0.61278], + "87": [0, 0.68333, 0.08222, 0.08334, 0.98778], + "88": [0, 0.68333, 0.14643, 0.13889, 0.7133], + "89": [0.09722, 0.68333, 0.08222, 0.08334, 0.66834], + "90": [0, 0.68333, 0.07944, 0.13889, 0.72473] + }, + "Fraktur-Regular": { + "33": [0, 0.69141, 0, 0, 0.29574], + "34": [0, 0.69141, 0, 0, 0.21471], + "38": [0, 0.69141, 0, 0, 0.73786], + "39": [0, 0.69141, 0, 0, 0.21201], + "40": [0.24982, 0.74947, 0, 0, 0.38865], + "41": [0.24982, 0.74947, 0, 0, 0.38865], + "42": [0, 0.62119, 0, 0, 0.27764], + "43": [0.08319, 0.58283, 0, 0, 0.75623], + "44": [0, 0.10803, 0, 0, 0.27764], + "45": [0.08319, 0.58283, 0, 0, 0.75623], + "46": [0, 0.10803, 0, 0, 0.27764], + "47": [0.24982, 0.74947, 0, 0, 0.50181], + "48": [0, 0.47534, 0, 0, 0.50181], + "49": [0, 0.47534, 0, 0, 0.50181], + "50": [0, 0.47534, 0, 0, 0.50181], + "51": [0.18906, 0.47534, 0, 0, 0.50181], + "52": [0.18906, 0.47534, 0, 0, 0.50181], + "53": [0.18906, 0.47534, 0, 0, 0.50181], + "54": [0, 0.69141, 0, 0, 0.50181], + "55": [0.18906, 0.47534, 0, 0, 0.50181], + "56": [0, 0.69141, 0, 0, 0.50181], + "57": [0.18906, 0.47534, 0, 0, 0.50181], + "58": [0, 0.47534, 0, 0, 0.21606], + "59": [0.12604, 0.47534, 0, 0, 0.21606], + "61": [-0.13099, 0.36866, 0, 0, 0.75623], + "63": [0, 0.69141, 0, 0, 0.36245], + "65": [0, 0.69141, 0, 0, 0.7176], + "66": [0, 0.69141, 0, 0, 0.88397], + "67": [0, 0.69141, 0, 0, 0.61254], + "68": [0, 0.69141, 0, 0, 0.83158], + "69": [0, 0.69141, 0, 0, 0.66278], + "70": [0.12604, 0.69141, 0, 0, 0.61119], + "71": [0, 0.69141, 0, 0, 0.78539], + "72": [0.06302, 0.69141, 0, 0, 0.7203], + "73": [0, 0.69141, 0, 0, 0.55448], + "74": [0.12604, 0.69141, 0, 0, 0.55231], + "75": [0, 0.69141, 0, 0, 0.66845], + "76": [0, 0.69141, 0, 0, 0.66602], + "77": [0, 0.69141, 0, 0, 1.04953], + "78": [0, 0.69141, 0, 0, 0.83212], + "79": [0, 0.69141, 0, 0, 0.82699], + "80": [0.18906, 0.69141, 0, 0, 0.82753], + "81": [0.03781, 0.69141, 0, 0, 0.82699], + "82": [0, 0.69141, 0, 0, 0.82807], + "83": [0, 0.69141, 0, 0, 0.82861], + "84": [0, 0.69141, 0, 0, 0.66899], + "85": [0, 0.69141, 0, 0, 0.64576], + "86": [0, 0.69141, 0, 0, 0.83131], + "87": [0, 0.69141, 0, 0, 1.04602], + "88": [0, 0.69141, 0, 0, 0.71922], + "89": [0.18906, 0.69141, 0, 0, 0.83293], + "90": [0.12604, 0.69141, 0, 0, 0.60201], + "91": [0.24982, 0.74947, 0, 0, 0.27764], + "93": [0.24982, 0.74947, 0, 0, 0.27764], + "94": [0, 0.69141, 0, 0, 0.49965], + "97": [0, 0.47534, 0, 0, 0.50046], + "98": [0, 0.69141, 0, 0, 0.51315], + "99": [0, 0.47534, 0, 0, 0.38946], + "100": [0, 0.62119, 0, 0, 0.49857], + "101": [0, 0.47534, 0, 0, 0.40053], + "102": [0.18906, 0.69141, 0, 0, 0.32626], + "103": [0.18906, 0.47534, 0, 0, 0.5037], + "104": [0.18906, 0.69141, 0, 0, 0.52126], + "105": [0, 0.69141, 0, 0, 0.27899], + "106": [0, 0.69141, 0, 0, 0.28088], + "107": [0, 0.69141, 0, 0, 0.38946], + "108": [0, 0.69141, 0, 0, 0.27953], + "109": [0, 0.47534, 0, 0, 0.76676], + "110": [0, 0.47534, 0, 0, 0.52666], + "111": [0, 0.47534, 0, 0, 0.48885], + "112": [0.18906, 0.52396, 0, 0, 0.50046], + "113": [0.18906, 0.47534, 0, 0, 0.48912], + "114": [0, 0.47534, 0, 0, 0.38919], + "115": [0, 0.47534, 0, 0, 0.44266], + "116": [0, 0.62119, 0, 0, 0.33301], + "117": [0, 0.47534, 0, 0, 0.5172], + "118": [0, 0.52396, 0, 0, 0.5118], + "119": [0, 0.52396, 0, 0, 0.77351], + "120": [0.18906, 0.47534, 0, 0, 0.38865], + "121": [0.18906, 0.47534, 0, 0, 0.49884], + "122": [0.18906, 0.47534, 0, 0, 0.39054], + "8216": [0, 0.69141, 0, 0, 0.21471], + "8217": [0, 0.69141, 0, 0, 0.21471], + "58112": [0, 0.62119, 0, 0, 0.49749], + "58113": [0, 0.62119, 0, 0, 0.4983], + "58114": [0.18906, 0.69141, 0, 0, 0.33328], + "58115": [0.18906, 0.69141, 0, 0, 0.32923], + "58116": [0.18906, 0.47534, 0, 0, 0.50343], + "58117": [0, 0.69141, 0, 0, 0.33301], + "58118": [0, 0.62119, 0, 0, 0.33409], + "58119": [0, 0.47534, 0, 0, 0.50073] + }, + "Main-Bold": { + "33": [0, 0.69444, 0, 0, 0.35], + "34": [0, 0.69444, 0, 0, 0.60278], + "35": [0.19444, 0.69444, 0, 0, 0.95833], + "36": [0.05556, 0.75, 0, 0, 0.575], + "37": [0.05556, 0.75, 0, 0, 0.95833], + "38": [0, 0.69444, 0, 0, 0.89444], + "39": [0, 0.69444, 0, 0, 0.31944], + "40": [0.25, 0.75, 0, 0, 0.44722], + "41": [0.25, 0.75, 0, 0, 0.44722], + "42": [0, 0.75, 0, 0, 0.575], + "43": [0.13333, 0.63333, 0, 0, 0.89444], + "44": [0.19444, 0.15556, 0, 0, 0.31944], + "45": [0, 0.44444, 0, 0, 0.38333], + "46": [0, 0.15556, 0, 0, 0.31944], + "47": [0.25, 0.75, 0, 0, 0.575], + "48": [0, 0.64444, 0, 0, 0.575], + "49": [0, 0.64444, 0, 0, 0.575], + "50": [0, 0.64444, 0, 0, 0.575], + "51": [0, 0.64444, 0, 0, 0.575], + "52": [0, 0.64444, 0, 0, 0.575], + "53": [0, 0.64444, 0, 0, 0.575], + "54": [0, 0.64444, 0, 0, 0.575], + "55": [0, 0.64444, 0, 0, 0.575], + "56": [0, 0.64444, 0, 0, 0.575], + "57": [0, 0.64444, 0, 0, 0.575], + "58": [0, 0.44444, 0, 0, 0.31944], + "59": [0.19444, 0.44444, 0, 0, 0.31944], + "60": [0.08556, 0.58556, 0, 0, 0.89444], + "61": [-0.10889, 0.39111, 0, 0, 0.89444], + "62": [0.08556, 0.58556, 0, 0, 0.89444], + "63": [0, 0.69444, 0, 0, 0.54305], + "64": [0, 0.69444, 0, 0, 0.89444], + "65": [0, 0.68611, 0, 0, 0.86944], + "66": [0, 0.68611, 0, 0, 0.81805], + "67": [0, 0.68611, 0, 0, 0.83055], + "68": [0, 0.68611, 0, 0, 0.88194], + "69": [0, 0.68611, 0, 0, 0.75555], + "70": [0, 0.68611, 0, 0, 0.72361], + "71": [0, 0.68611, 0, 0, 0.90416], + "72": [0, 0.68611, 0, 0, 0.9], + "73": [0, 0.68611, 0, 0, 0.43611], + "74": [0, 0.68611, 0, 0, 0.59444], + "75": [0, 0.68611, 0, 0, 0.90138], + "76": [0, 0.68611, 0, 0, 0.69166], + "77": [0, 0.68611, 0, 0, 1.09166], + "78": [0, 0.68611, 0, 0, 0.9], + "79": [0, 0.68611, 0, 0, 0.86388], + "80": [0, 0.68611, 0, 0, 0.78611], + "81": [0.19444, 0.68611, 0, 0, 0.86388], + "82": [0, 0.68611, 0, 0, 0.8625], + "83": [0, 0.68611, 0, 0, 0.63889], + "84": [0, 0.68611, 0, 0, 0.8], + "85": [0, 0.68611, 0, 0, 0.88472], + "86": [0, 0.68611, 0.01597, 0, 0.86944], + "87": [0, 0.68611, 0.01597, 0, 1.18888], + "88": [0, 0.68611, 0, 0, 0.86944], + "89": [0, 0.68611, 0.02875, 0, 0.86944], + "90": [0, 0.68611, 0, 0, 0.70277], + "91": [0.25, 0.75, 0, 0, 0.31944], + "92": [0.25, 0.75, 0, 0, 0.575], + "93": [0.25, 0.75, 0, 0, 0.31944], + "94": [0, 0.69444, 0, 0, 0.575], + "95": [0.31, 0.13444, 0.03194, 0, 0.575], + "97": [0, 0.44444, 0, 0, 0.55902], + "98": [0, 0.69444, 0, 0, 0.63889], + "99": [0, 0.44444, 0, 0, 0.51111], + "100": [0, 0.69444, 0, 0, 0.63889], + "101": [0, 0.44444, 0, 0, 0.52708], + "102": [0, 0.69444, 0.10903, 0, 0.35139], + "103": [0.19444, 0.44444, 0.01597, 0, 0.575], + "104": [0, 0.69444, 0, 0, 0.63889], + "105": [0, 0.69444, 0, 0, 0.31944], + "106": [0.19444, 0.69444, 0, 0, 0.35139], + "107": [0, 0.69444, 0, 0, 0.60694], + "108": [0, 0.69444, 0, 0, 0.31944], + "109": [0, 0.44444, 0, 0, 0.95833], + "110": [0, 0.44444, 0, 0, 0.63889], + "111": [0, 0.44444, 0, 0, 0.575], + "112": [0.19444, 0.44444, 0, 0, 0.63889], + "113": [0.19444, 0.44444, 0, 0, 0.60694], + "114": [0, 0.44444, 0, 0, 0.47361], + "115": [0, 0.44444, 0, 0, 0.45361], + "116": [0, 0.63492, 0, 0, 0.44722], + "117": [0, 0.44444, 0, 0, 0.63889], + "118": [0, 0.44444, 0.01597, 0, 0.60694], + "119": [0, 0.44444, 0.01597, 0, 0.83055], + "120": [0, 0.44444, 0, 0, 0.60694], + "121": [0.19444, 0.44444, 0.01597, 0, 0.60694], + "122": [0, 0.44444, 0, 0, 0.51111], + "123": [0.25, 0.75, 0, 0, 0.575], + "124": [0.25, 0.75, 0, 0, 0.31944], + "125": [0.25, 0.75, 0, 0, 0.575], + "126": [0.35, 0.34444, 0, 0, 0.575], + "168": [0, 0.69444, 0, 0, 0.575], + "172": [0, 0.44444, 0, 0, 0.76666], + "176": [0, 0.69444, 0, 0, 0.86944], + "177": [0.13333, 0.63333, 0, 0, 0.89444], + "184": [0.17014, 0, 0, 0, 0.51111], + "198": [0, 0.68611, 0, 0, 1.04166], + "215": [0.13333, 0.63333, 0, 0, 0.89444], + "216": [0.04861, 0.73472, 0, 0, 0.89444], + "223": [0, 0.69444, 0, 0, 0.59722], + "230": [0, 0.44444, 0, 0, 0.83055], + "247": [0.13333, 0.63333, 0, 0, 0.89444], + "248": [0.09722, 0.54167, 0, 0, 0.575], + "305": [0, 0.44444, 0, 0, 0.31944], + "338": [0, 0.68611, 0, 0, 1.16944], + "339": [0, 0.44444, 0, 0, 0.89444], + "567": [0.19444, 0.44444, 0, 0, 0.35139], + "710": [0, 0.69444, 0, 0, 0.575], + "711": [0, 0.63194, 0, 0, 0.575], + "713": [0, 0.59611, 0, 0, 0.575], + "714": [0, 0.69444, 0, 0, 0.575], + "715": [0, 0.69444, 0, 0, 0.575], + "728": [0, 0.69444, 0, 0, 0.575], + "729": [0, 0.69444, 0, 0, 0.31944], + "730": [0, 0.69444, 0, 0, 0.86944], + "732": [0, 0.69444, 0, 0, 0.575], + "733": [0, 0.69444, 0, 0, 0.575], + "915": [0, 0.68611, 0, 0, 0.69166], + "916": [0, 0.68611, 0, 0, 0.95833], + "920": [0, 0.68611, 0, 0, 0.89444], + "923": [0, 0.68611, 0, 0, 0.80555], + "926": [0, 0.68611, 0, 0, 0.76666], + "928": [0, 0.68611, 0, 0, 0.9], + "931": [0, 0.68611, 0, 0, 0.83055], + "933": [0, 0.68611, 0, 0, 0.89444], + "934": [0, 0.68611, 0, 0, 0.83055], + "936": [0, 0.68611, 0, 0, 0.89444], + "937": [0, 0.68611, 0, 0, 0.83055], + "8211": [0, 0.44444, 0.03194, 0, 0.575], + "8212": [0, 0.44444, 0.03194, 0, 1.14999], + "8216": [0, 0.69444, 0, 0, 0.31944], + "8217": [0, 0.69444, 0, 0, 0.31944], + "8220": [0, 0.69444, 0, 0, 0.60278], + "8221": [0, 0.69444, 0, 0, 0.60278], + "8224": [0.19444, 0.69444, 0, 0, 0.51111], + "8225": [0.19444, 0.69444, 0, 0, 0.51111], + "8242": [0, 0.55556, 0, 0, 0.34444], + "8407": [0, 0.72444, 0.15486, 0, 0.575], + "8463": [0, 0.69444, 0, 0, 0.66759], + "8465": [0, 0.69444, 0, 0, 0.83055], + "8467": [0, 0.69444, 0, 0, 0.47361], + "8472": [0.19444, 0.44444, 0, 0, 0.74027], + "8476": [0, 0.69444, 0, 0, 0.83055], + "8501": [0, 0.69444, 0, 0, 0.70277], + "8592": [-0.10889, 0.39111, 0, 0, 1.14999], + "8593": [0.19444, 0.69444, 0, 0, 0.575], + "8594": [-0.10889, 0.39111, 0, 0, 1.14999], + "8595": [0.19444, 0.69444, 0, 0, 0.575], + "8596": [-0.10889, 0.39111, 0, 0, 1.14999], + "8597": [0.25, 0.75, 0, 0, 0.575], + "8598": [0.19444, 0.69444, 0, 0, 1.14999], + "8599": [0.19444, 0.69444, 0, 0, 1.14999], + "8600": [0.19444, 0.69444, 0, 0, 1.14999], + "8601": [0.19444, 0.69444, 0, 0, 1.14999], + "8636": [-0.10889, 0.39111, 0, 0, 1.14999], + "8637": [-0.10889, 0.39111, 0, 0, 1.14999], + "8640": [-0.10889, 0.39111, 0, 0, 1.14999], + "8641": [-0.10889, 0.39111, 0, 0, 1.14999], + "8656": [-0.10889, 0.39111, 0, 0, 1.14999], + "8657": [0.19444, 0.69444, 0, 0, 0.70277], + "8658": [-0.10889, 0.39111, 0, 0, 1.14999], + "8659": [0.19444, 0.69444, 0, 0, 0.70277], + "8660": [-0.10889, 0.39111, 0, 0, 1.14999], + "8661": [0.25, 0.75, 0, 0, 0.70277], + "8704": [0, 0.69444, 0, 0, 0.63889], + "8706": [0, 0.69444, 0.06389, 0, 0.62847], + "8707": [0, 0.69444, 0, 0, 0.63889], + "8709": [0.05556, 0.75, 0, 0, 0.575], + "8711": [0, 0.68611, 0, 0, 0.95833], + "8712": [0.08556, 0.58556, 0, 0, 0.76666], + "8715": [0.08556, 0.58556, 0, 0, 0.76666], + "8722": [0.13333, 0.63333, 0, 0, 0.89444], + "8723": [0.13333, 0.63333, 0, 0, 0.89444], + "8725": [0.25, 0.75, 0, 0, 0.575], + "8726": [0.25, 0.75, 0, 0, 0.575], + "8727": [-0.02778, 0.47222, 0, 0, 0.575], + "8728": [-0.02639, 0.47361, 0, 0, 0.575], + "8729": [-0.02639, 0.47361, 0, 0, 0.575], + "8730": [0.18, 0.82, 0, 0, 0.95833], + "8733": [0, 0.44444, 0, 0, 0.89444], + "8734": [0, 0.44444, 0, 0, 1.14999], + "8736": [0, 0.69224, 0, 0, 0.72222], + "8739": [0.25, 0.75, 0, 0, 0.31944], + "8741": [0.25, 0.75, 0, 0, 0.575], + "8743": [0, 0.55556, 0, 0, 0.76666], + "8744": [0, 0.55556, 0, 0, 0.76666], + "8745": [0, 0.55556, 0, 0, 0.76666], + "8746": [0, 0.55556, 0, 0, 0.76666], + "8747": [0.19444, 0.69444, 0.12778, 0, 0.56875], + "8764": [-0.10889, 0.39111, 0, 0, 0.89444], + "8768": [0.19444, 0.69444, 0, 0, 0.31944], + "8771": [0.00222, 0.50222, 0, 0, 0.89444], + "8776": [0.02444, 0.52444, 0, 0, 0.89444], + "8781": [0.00222, 0.50222, 0, 0, 0.89444], + "8801": [0.00222, 0.50222, 0, 0, 0.89444], + "8804": [0.19667, 0.69667, 0, 0, 0.89444], + "8805": [0.19667, 0.69667, 0, 0, 0.89444], + "8810": [0.08556, 0.58556, 0, 0, 1.14999], + "8811": [0.08556, 0.58556, 0, 0, 1.14999], + "8826": [0.08556, 0.58556, 0, 0, 0.89444], + "8827": [0.08556, 0.58556, 0, 0, 0.89444], + "8834": [0.08556, 0.58556, 0, 0, 0.89444], + "8835": [0.08556, 0.58556, 0, 0, 0.89444], + "8838": [0.19667, 0.69667, 0, 0, 0.89444], + "8839": [0.19667, 0.69667, 0, 0, 0.89444], + "8846": [0, 0.55556, 0, 0, 0.76666], + "8849": [0.19667, 0.69667, 0, 0, 0.89444], + "8850": [0.19667, 0.69667, 0, 0, 0.89444], + "8851": [0, 0.55556, 0, 0, 0.76666], + "8852": [0, 0.55556, 0, 0, 0.76666], + "8853": [0.13333, 0.63333, 0, 0, 0.89444], + "8854": [0.13333, 0.63333, 0, 0, 0.89444], + "8855": [0.13333, 0.63333, 0, 0, 0.89444], + "8856": [0.13333, 0.63333, 0, 0, 0.89444], + "8857": [0.13333, 0.63333, 0, 0, 0.89444], + "8866": [0, 0.69444, 0, 0, 0.70277], + "8867": [0, 0.69444, 0, 0, 0.70277], + "8868": [0, 0.69444, 0, 0, 0.89444], + "8869": [0, 0.69444, 0, 0, 0.89444], + "8900": [-0.02639, 0.47361, 0, 0, 0.575], + "8901": [-0.02639, 0.47361, 0, 0, 0.31944], + "8902": [-0.02778, 0.47222, 0, 0, 0.575], + "8968": [0.25, 0.75, 0, 0, 0.51111], + "8969": [0.25, 0.75, 0, 0, 0.51111], + "8970": [0.25, 0.75, 0, 0, 0.51111], + "8971": [0.25, 0.75, 0, 0, 0.51111], + "8994": [-0.13889, 0.36111, 0, 0, 1.14999], + "8995": [-0.13889, 0.36111, 0, 0, 1.14999], + "9651": [0.19444, 0.69444, 0, 0, 1.02222], + "9657": [-0.02778, 0.47222, 0, 0, 0.575], + "9661": [0.19444, 0.69444, 0, 0, 1.02222], + "9667": [-0.02778, 0.47222, 0, 0, 0.575], + "9711": [0.19444, 0.69444, 0, 0, 1.14999], + "9824": [0.12963, 0.69444, 0, 0, 0.89444], + "9825": [0.12963, 0.69444, 0, 0, 0.89444], + "9826": [0.12963, 0.69444, 0, 0, 0.89444], + "9827": [0.12963, 0.69444, 0, 0, 0.89444], + "9837": [0, 0.75, 0, 0, 0.44722], + "9838": [0.19444, 0.69444, 0, 0, 0.44722], + "9839": [0.19444, 0.69444, 0, 0, 0.44722], + "10216": [0.25, 0.75, 0, 0, 0.44722], + "10217": [0.25, 0.75, 0, 0, 0.44722], + "10815": [0, 0.68611, 0, 0, 0.9], + "10927": [0.19667, 0.69667, 0, 0, 0.89444], + "10928": [0.19667, 0.69667, 0, 0, 0.89444], + "57376": [0.19444, 0.69444, 0, 0, 0] + }, + "Main-BoldItalic": { + "33": [0, 0.69444, 0.11417, 0, 0.38611], + "34": [0, 0.69444, 0.07939, 0, 0.62055], + "35": [0.19444, 0.69444, 0.06833, 0, 0.94444], + "37": [0.05556, 0.75, 0.12861, 0, 0.94444], + "38": [0, 0.69444, 0.08528, 0, 0.88555], + "39": [0, 0.69444, 0.12945, 0, 0.35555], + "40": [0.25, 0.75, 0.15806, 0, 0.47333], + "41": [0.25, 0.75, 0.03306, 0, 0.47333], + "42": [0, 0.75, 0.14333, 0, 0.59111], + "43": [0.10333, 0.60333, 0.03306, 0, 0.88555], + "44": [0.19444, 0.14722, 0, 0, 0.35555], + "45": [0, 0.44444, 0.02611, 0, 0.41444], + "46": [0, 0.14722, 0, 0, 0.35555], + "47": [0.25, 0.75, 0.15806, 0, 0.59111], + "48": [0, 0.64444, 0.13167, 0, 0.59111], + "49": [0, 0.64444, 0.13167, 0, 0.59111], + "50": [0, 0.64444, 0.13167, 0, 0.59111], + "51": [0, 0.64444, 0.13167, 0, 0.59111], + "52": [0.19444, 0.64444, 0.13167, 0, 0.59111], + "53": [0, 0.64444, 0.13167, 0, 0.59111], + "54": [0, 0.64444, 0.13167, 0, 0.59111], + "55": [0.19444, 0.64444, 0.13167, 0, 0.59111], + "56": [0, 0.64444, 0.13167, 0, 0.59111], + "57": [0, 0.64444, 0.13167, 0, 0.59111], + "58": [0, 0.44444, 0.06695, 0, 0.35555], + "59": [0.19444, 0.44444, 0.06695, 0, 0.35555], + "61": [-0.10889, 0.39111, 0.06833, 0, 0.88555], + "63": [0, 0.69444, 0.11472, 0, 0.59111], + "64": [0, 0.69444, 0.09208, 0, 0.88555], + "65": [0, 0.68611, 0, 0, 0.86555], + "66": [0, 0.68611, 0.0992, 0, 0.81666], + "67": [0, 0.68611, 0.14208, 0, 0.82666], + "68": [0, 0.68611, 0.09062, 0, 0.87555], + "69": [0, 0.68611, 0.11431, 0, 0.75666], + "70": [0, 0.68611, 0.12903, 0, 0.72722], + "71": [0, 0.68611, 0.07347, 0, 0.89527], + "72": [0, 0.68611, 0.17208, 0, 0.8961], + "73": [0, 0.68611, 0.15681, 0, 0.47166], + "74": [0, 0.68611, 0.145, 0, 0.61055], + "75": [0, 0.68611, 0.14208, 0, 0.89499], + "76": [0, 0.68611, 0, 0, 0.69777], + "77": [0, 0.68611, 0.17208, 0, 1.07277], + "78": [0, 0.68611, 0.17208, 0, 0.8961], + "79": [0, 0.68611, 0.09062, 0, 0.85499], + "80": [0, 0.68611, 0.0992, 0, 0.78721], + "81": [0.19444, 0.68611, 0.09062, 0, 0.85499], + "82": [0, 0.68611, 0.02559, 0, 0.85944], + "83": [0, 0.68611, 0.11264, 0, 0.64999], + "84": [0, 0.68611, 0.12903, 0, 0.7961], + "85": [0, 0.68611, 0.17208, 0, 0.88083], + "86": [0, 0.68611, 0.18625, 0, 0.86555], + "87": [0, 0.68611, 0.18625, 0, 1.15999], + "88": [0, 0.68611, 0.15681, 0, 0.86555], + "89": [0, 0.68611, 0.19803, 0, 0.86555], + "90": [0, 0.68611, 0.14208, 0, 0.70888], + "91": [0.25, 0.75, 0.1875, 0, 0.35611], + "93": [0.25, 0.75, 0.09972, 0, 0.35611], + "94": [0, 0.69444, 0.06709, 0, 0.59111], + "95": [0.31, 0.13444, 0.09811, 0, 0.59111], + "97": [0, 0.44444, 0.09426, 0, 0.59111], + "98": [0, 0.69444, 0.07861, 0, 0.53222], + "99": [0, 0.44444, 0.05222, 0, 0.53222], + "100": [0, 0.69444, 0.10861, 0, 0.59111], + "101": [0, 0.44444, 0.085, 0, 0.53222], + "102": [0.19444, 0.69444, 0.21778, 0, 0.4], + "103": [0.19444, 0.44444, 0.105, 0, 0.53222], + "104": [0, 0.69444, 0.09426, 0, 0.59111], + "105": [0, 0.69326, 0.11387, 0, 0.35555], + "106": [0.19444, 0.69326, 0.1672, 0, 0.35555], + "107": [0, 0.69444, 0.11111, 0, 0.53222], + "108": [0, 0.69444, 0.10861, 0, 0.29666], + "109": [0, 0.44444, 0.09426, 0, 0.94444], + "110": [0, 0.44444, 0.09426, 0, 0.64999], + "111": [0, 0.44444, 0.07861, 0, 0.59111], + "112": [0.19444, 0.44444, 0.07861, 0, 0.59111], + "113": [0.19444, 0.44444, 0.105, 0, 0.53222], + "114": [0, 0.44444, 0.11111, 0, 0.50167], + "115": [0, 0.44444, 0.08167, 0, 0.48694], + "116": [0, 0.63492, 0.09639, 0, 0.385], + "117": [0, 0.44444, 0.09426, 0, 0.62055], + "118": [0, 0.44444, 0.11111, 0, 0.53222], + "119": [0, 0.44444, 0.11111, 0, 0.76777], + "120": [0, 0.44444, 0.12583, 0, 0.56055], + "121": [0.19444, 0.44444, 0.105, 0, 0.56166], + "122": [0, 0.44444, 0.13889, 0, 0.49055], + "126": [0.35, 0.34444, 0.11472, 0, 0.59111], + "163": [0, 0.69444, 0, 0, 0.86853], + "168": [0, 0.69444, 0.11473, 0, 0.59111], + "176": [0, 0.69444, 0, 0, 0.94888], + "184": [0.17014, 0, 0, 0, 0.53222], + "198": [0, 0.68611, 0.11431, 0, 1.02277], + "216": [0.04861, 0.73472, 0.09062, 0, 0.88555], + "223": [0.19444, 0.69444, 0.09736, 0, 0.665], + "230": [0, 0.44444, 0.085, 0, 0.82666], + "248": [0.09722, 0.54167, 0.09458, 0, 0.59111], + "305": [0, 0.44444, 0.09426, 0, 0.35555], + "338": [0, 0.68611, 0.11431, 0, 1.14054], + "339": [0, 0.44444, 0.085, 0, 0.82666], + "567": [0.19444, 0.44444, 0.04611, 0, 0.385], + "710": [0, 0.69444, 0.06709, 0, 0.59111], + "711": [0, 0.63194, 0.08271, 0, 0.59111], + "713": [0, 0.59444, 0.10444, 0, 0.59111], + "714": [0, 0.69444, 0.08528, 0, 0.59111], + "715": [0, 0.69444, 0, 0, 0.59111], + "728": [0, 0.69444, 0.10333, 0, 0.59111], + "729": [0, 0.69444, 0.12945, 0, 0.35555], + "730": [0, 0.69444, 0, 0, 0.94888], + "732": [0, 0.69444, 0.11472, 0, 0.59111], + "733": [0, 0.69444, 0.11472, 0, 0.59111], + "915": [0, 0.68611, 0.12903, 0, 0.69777], + "916": [0, 0.68611, 0, 0, 0.94444], + "920": [0, 0.68611, 0.09062, 0, 0.88555], + "923": [0, 0.68611, 0, 0, 0.80666], + "926": [0, 0.68611, 0.15092, 0, 0.76777], + "928": [0, 0.68611, 0.17208, 0, 0.8961], + "931": [0, 0.68611, 0.11431, 0, 0.82666], + "933": [0, 0.68611, 0.10778, 0, 0.88555], + "934": [0, 0.68611, 0.05632, 0, 0.82666], + "936": [0, 0.68611, 0.10778, 0, 0.88555], + "937": [0, 0.68611, 0.0992, 0, 0.82666], + "8211": [0, 0.44444, 0.09811, 0, 0.59111], + "8212": [0, 0.44444, 0.09811, 0, 1.18221], + "8216": [0, 0.69444, 0.12945, 0, 0.35555], + "8217": [0, 0.69444, 0.12945, 0, 0.35555], + "8220": [0, 0.69444, 0.16772, 0, 0.62055], + "8221": [0, 0.69444, 0.07939, 0, 0.62055] + }, + "Main-Italic": { + "33": [0, 0.69444, 0.12417, 0, 0.30667], + "34": [0, 0.69444, 0.06961, 0, 0.51444], + "35": [0.19444, 0.69444, 0.06616, 0, 0.81777], + "37": [0.05556, 0.75, 0.13639, 0, 0.81777], + "38": [0, 0.69444, 0.09694, 0, 0.76666], + "39": [0, 0.69444, 0.12417, 0, 0.30667], + "40": [0.25, 0.75, 0.16194, 0, 0.40889], + "41": [0.25, 0.75, 0.03694, 0, 0.40889], + "42": [0, 0.75, 0.14917, 0, 0.51111], + "43": [0.05667, 0.56167, 0.03694, 0, 0.76666], + "44": [0.19444, 0.10556, 0, 0, 0.30667], + "45": [0, 0.43056, 0.02826, 0, 0.35778], + "46": [0, 0.10556, 0, 0, 0.30667], + "47": [0.25, 0.75, 0.16194, 0, 0.51111], + "48": [0, 0.64444, 0.13556, 0, 0.51111], + "49": [0, 0.64444, 0.13556, 0, 0.51111], + "50": [0, 0.64444, 0.13556, 0, 0.51111], + "51": [0, 0.64444, 0.13556, 0, 0.51111], + "52": [0.19444, 0.64444, 0.13556, 0, 0.51111], + "53": [0, 0.64444, 0.13556, 0, 0.51111], + "54": [0, 0.64444, 0.13556, 0, 0.51111], + "55": [0.19444, 0.64444, 0.13556, 0, 0.51111], + "56": [0, 0.64444, 0.13556, 0, 0.51111], + "57": [0, 0.64444, 0.13556, 0, 0.51111], + "58": [0, 0.43056, 0.0582, 0, 0.30667], + "59": [0.19444, 0.43056, 0.0582, 0, 0.30667], + "61": [-0.13313, 0.36687, 0.06616, 0, 0.76666], + "63": [0, 0.69444, 0.1225, 0, 0.51111], + "64": [0, 0.69444, 0.09597, 0, 0.76666], + "65": [0, 0.68333, 0, 0, 0.74333], + "66": [0, 0.68333, 0.10257, 0, 0.70389], + "67": [0, 0.68333, 0.14528, 0, 0.71555], + "68": [0, 0.68333, 0.09403, 0, 0.755], + "69": [0, 0.68333, 0.12028, 0, 0.67833], + "70": [0, 0.68333, 0.13305, 0, 0.65277], + "71": [0, 0.68333, 0.08722, 0, 0.77361], + "72": [0, 0.68333, 0.16389, 0, 0.74333], + "73": [0, 0.68333, 0.15806, 0, 0.38555], + "74": [0, 0.68333, 0.14028, 0, 0.525], + "75": [0, 0.68333, 0.14528, 0, 0.76888], + "76": [0, 0.68333, 0, 0, 0.62722], + "77": [0, 0.68333, 0.16389, 0, 0.89666], + "78": [0, 0.68333, 0.16389, 0, 0.74333], + "79": [0, 0.68333, 0.09403, 0, 0.76666], + "80": [0, 0.68333, 0.10257, 0, 0.67833], + "81": [0.19444, 0.68333, 0.09403, 0, 0.76666], + "82": [0, 0.68333, 0.03868, 0, 0.72944], + "83": [0, 0.68333, 0.11972, 0, 0.56222], + "84": [0, 0.68333, 0.13305, 0, 0.71555], + "85": [0, 0.68333, 0.16389, 0, 0.74333], + "86": [0, 0.68333, 0.18361, 0, 0.74333], + "87": [0, 0.68333, 0.18361, 0, 0.99888], + "88": [0, 0.68333, 0.15806, 0, 0.74333], + "89": [0, 0.68333, 0.19383, 0, 0.74333], + "90": [0, 0.68333, 0.14528, 0, 0.61333], + "91": [0.25, 0.75, 0.1875, 0, 0.30667], + "93": [0.25, 0.75, 0.10528, 0, 0.30667], + "94": [0, 0.69444, 0.06646, 0, 0.51111], + "95": [0.31, 0.12056, 0.09208, 0, 0.51111], + "97": [0, 0.43056, 0.07671, 0, 0.51111], + "98": [0, 0.69444, 0.06312, 0, 0.46], + "99": [0, 0.43056, 0.05653, 0, 0.46], + "100": [0, 0.69444, 0.10333, 0, 0.51111], + "101": [0, 0.43056, 0.07514, 0, 0.46], + "102": [0.19444, 0.69444, 0.21194, 0, 0.30667], + "103": [0.19444, 0.43056, 0.08847, 0, 0.46], + "104": [0, 0.69444, 0.07671, 0, 0.51111], + "105": [0, 0.65536, 0.1019, 0, 0.30667], + "106": [0.19444, 0.65536, 0.14467, 0, 0.30667], + "107": [0, 0.69444, 0.10764, 0, 0.46], + "108": [0, 0.69444, 0.10333, 0, 0.25555], + "109": [0, 0.43056, 0.07671, 0, 0.81777], + "110": [0, 0.43056, 0.07671, 0, 0.56222], + "111": [0, 0.43056, 0.06312, 0, 0.51111], + "112": [0.19444, 0.43056, 0.06312, 0, 0.51111], + "113": [0.19444, 0.43056, 0.08847, 0, 0.46], + "114": [0, 0.43056, 0.10764, 0, 0.42166], + "115": [0, 0.43056, 0.08208, 0, 0.40889], + "116": [0, 0.61508, 0.09486, 0, 0.33222], + "117": [0, 0.43056, 0.07671, 0, 0.53666], + "118": [0, 0.43056, 0.10764, 0, 0.46], + "119": [0, 0.43056, 0.10764, 0, 0.66444], + "120": [0, 0.43056, 0.12042, 0, 0.46389], + "121": [0.19444, 0.43056, 0.08847, 0, 0.48555], + "122": [0, 0.43056, 0.12292, 0, 0.40889], + "126": [0.35, 0.31786, 0.11585, 0, 0.51111], + "163": [0, 0.69444, 0, 0, 0.76909], + "168": [0, 0.66786, 0.10474, 0, 0.51111], + "176": [0, 0.69444, 0, 0, 0.83129], + "184": [0.17014, 0, 0, 0, 0.46], + "198": [0, 0.68333, 0.12028, 0, 0.88277], + "216": [0.04861, 0.73194, 0.09403, 0, 0.76666], + "223": [0.19444, 0.69444, 0.10514, 0, 0.53666], + "230": [0, 0.43056, 0.07514, 0, 0.71555], + "248": [0.09722, 0.52778, 0.09194, 0, 0.51111], + "305": [0, 0.43056, 0, 0.02778, 0.32246], + "338": [0, 0.68333, 0.12028, 0, 0.98499], + "339": [0, 0.43056, 0.07514, 0, 0.71555], + "567": [0.19444, 0.43056, 0, 0.08334, 0.38403], + "710": [0, 0.69444, 0.06646, 0, 0.51111], + "711": [0, 0.62847, 0.08295, 0, 0.51111], + "713": [0, 0.56167, 0.10333, 0, 0.51111], + "714": [0, 0.69444, 0.09694, 0, 0.51111], + "715": [0, 0.69444, 0, 0, 0.51111], + "728": [0, 0.69444, 0.10806, 0, 0.51111], + "729": [0, 0.66786, 0.11752, 0, 0.30667], + "730": [0, 0.69444, 0, 0, 0.83129], + "732": [0, 0.66786, 0.11585, 0, 0.51111], + "733": [0, 0.69444, 0.1225, 0, 0.51111], + "915": [0, 0.68333, 0.13305, 0, 0.62722], + "916": [0, 0.68333, 0, 0, 0.81777], + "920": [0, 0.68333, 0.09403, 0, 0.76666], + "923": [0, 0.68333, 0, 0, 0.69222], + "926": [0, 0.68333, 0.15294, 0, 0.66444], + "928": [0, 0.68333, 0.16389, 0, 0.74333], + "931": [0, 0.68333, 0.12028, 0, 0.71555], + "933": [0, 0.68333, 0.11111, 0, 0.76666], + "934": [0, 0.68333, 0.05986, 0, 0.71555], + "936": [0, 0.68333, 0.11111, 0, 0.76666], + "937": [0, 0.68333, 0.10257, 0, 0.71555], + "8211": [0, 0.43056, 0.09208, 0, 0.51111], + "8212": [0, 0.43056, 0.09208, 0, 1.02222], + "8216": [0, 0.69444, 0.12417, 0, 0.30667], + "8217": [0, 0.69444, 0.12417, 0, 0.30667], + "8220": [0, 0.69444, 0.1685, 0, 0.51444], + "8221": [0, 0.69444, 0.06961, 0, 0.51444], + "8463": [0, 0.68889, 0, 0, 0.54028] + }, + "Main-Regular": { + "32": [0, 0, 0, 0, 0.25], + "33": [0, 0.69444, 0, 0, 0.27778], + "34": [0, 0.69444, 0, 0, 0.5], + "35": [0.19444, 0.69444, 0, 0, 0.83334], + "36": [0.05556, 0.75, 0, 0, 0.5], + "37": [0.05556, 0.75, 0, 0, 0.83334], + "38": [0, 0.69444, 0, 0, 0.77778], + "39": [0, 0.69444, 0, 0, 0.27778], + "40": [0.25, 0.75, 0, 0, 0.38889], + "41": [0.25, 0.75, 0, 0, 0.38889], + "42": [0, 0.75, 0, 0, 0.5], + "43": [0.08333, 0.58333, 0, 0, 0.77778], + "44": [0.19444, 0.10556, 0, 0, 0.27778], + "45": [0, 0.43056, 0, 0, 0.33333], + "46": [0, 0.10556, 0, 0, 0.27778], + "47": [0.25, 0.75, 0, 0, 0.5], + "48": [0, 0.64444, 0, 0, 0.5], + "49": [0, 0.64444, 0, 0, 0.5], + "50": [0, 0.64444, 0, 0, 0.5], + "51": [0, 0.64444, 0, 0, 0.5], + "52": [0, 0.64444, 0, 0, 0.5], + "53": [0, 0.64444, 0, 0, 0.5], + "54": [0, 0.64444, 0, 0, 0.5], + "55": [0, 0.64444, 0, 0, 0.5], + "56": [0, 0.64444, 0, 0, 0.5], + "57": [0, 0.64444, 0, 0, 0.5], + "58": [0, 0.43056, 0, 0, 0.27778], + "59": [0.19444, 0.43056, 0, 0, 0.27778], + "60": [0.0391, 0.5391, 0, 0, 0.77778], + "61": [-0.13313, 0.36687, 0, 0, 0.77778], + "62": [0.0391, 0.5391, 0, 0, 0.77778], + "63": [0, 0.69444, 0, 0, 0.47222], + "64": [0, 0.69444, 0, 0, 0.77778], + "65": [0, 0.68333, 0, 0, 0.75], + "66": [0, 0.68333, 0, 0, 0.70834], + "67": [0, 0.68333, 0, 0, 0.72222], + "68": [0, 0.68333, 0, 0, 0.76389], + "69": [0, 0.68333, 0, 0, 0.68056], + "70": [0, 0.68333, 0, 0, 0.65278], + "71": [0, 0.68333, 0, 0, 0.78472], + "72": [0, 0.68333, 0, 0, 0.75], + "73": [0, 0.68333, 0, 0, 0.36111], + "74": [0, 0.68333, 0, 0, 0.51389], + "75": [0, 0.68333, 0, 0, 0.77778], + "76": [0, 0.68333, 0, 0, 0.625], + "77": [0, 0.68333, 0, 0, 0.91667], + "78": [0, 0.68333, 0, 0, 0.75], + "79": [0, 0.68333, 0, 0, 0.77778], + "80": [0, 0.68333, 0, 0, 0.68056], + "81": [0.19444, 0.68333, 0, 0, 0.77778], + "82": [0, 0.68333, 0, 0, 0.73611], + "83": [0, 0.68333, 0, 0, 0.55556], + "84": [0, 0.68333, 0, 0, 0.72222], + "85": [0, 0.68333, 0, 0, 0.75], + "86": [0, 0.68333, 0.01389, 0, 0.75], + "87": [0, 0.68333, 0.01389, 0, 1.02778], + "88": [0, 0.68333, 0, 0, 0.75], + "89": [0, 0.68333, 0.025, 0, 0.75], + "90": [0, 0.68333, 0, 0, 0.61111], + "91": [0.25, 0.75, 0, 0, 0.27778], + "92": [0.25, 0.75, 0, 0, 0.5], + "93": [0.25, 0.75, 0, 0, 0.27778], + "94": [0, 0.69444, 0, 0, 0.5], + "95": [0.31, 0.12056, 0.02778, 0, 0.5], + "97": [0, 0.43056, 0, 0, 0.5], + "98": [0, 0.69444, 0, 0, 0.55556], + "99": [0, 0.43056, 0, 0, 0.44445], + "100": [0, 0.69444, 0, 0, 0.55556], + "101": [0, 0.43056, 0, 0, 0.44445], + "102": [0, 0.69444, 0.07778, 0, 0.30556], + "103": [0.19444, 0.43056, 0.01389, 0, 0.5], + "104": [0, 0.69444, 0, 0, 0.55556], + "105": [0, 0.66786, 0, 0, 0.27778], + "106": [0.19444, 0.66786, 0, 0, 0.30556], + "107": [0, 0.69444, 0, 0, 0.52778], + "108": [0, 0.69444, 0, 0, 0.27778], + "109": [0, 0.43056, 0, 0, 0.83334], + "110": [0, 0.43056, 0, 0, 0.55556], + "111": [0, 0.43056, 0, 0, 0.5], + "112": [0.19444, 0.43056, 0, 0, 0.55556], + "113": [0.19444, 0.43056, 0, 0, 0.52778], + "114": [0, 0.43056, 0, 0, 0.39167], + "115": [0, 0.43056, 0, 0, 0.39445], + "116": [0, 0.61508, 0, 0, 0.38889], + "117": [0, 0.43056, 0, 0, 0.55556], + "118": [0, 0.43056, 0.01389, 0, 0.52778], + "119": [0, 0.43056, 0.01389, 0, 0.72222], + "120": [0, 0.43056, 0, 0, 0.52778], + "121": [0.19444, 0.43056, 0.01389, 0, 0.52778], + "122": [0, 0.43056, 0, 0, 0.44445], + "123": [0.25, 0.75, 0, 0, 0.5], + "124": [0.25, 0.75, 0, 0, 0.27778], + "125": [0.25, 0.75, 0, 0, 0.5], + "126": [0.35, 0.31786, 0, 0, 0.5], + "160": [0, 0, 0, 0, 0.25], + "167": [0.19444, 0.69444, 0, 0, 0.44445], + "168": [0, 0.66786, 0, 0, 0.5], + "172": [0, 0.43056, 0, 0, 0.66667], + "176": [0, 0.69444, 0, 0, 0.75], + "177": [0.08333, 0.58333, 0, 0, 0.77778], + "182": [0.19444, 0.69444, 0, 0, 0.61111], + "184": [0.17014, 0, 0, 0, 0.44445], + "198": [0, 0.68333, 0, 0, 0.90278], + "215": [0.08333, 0.58333, 0, 0, 0.77778], + "216": [0.04861, 0.73194, 0, 0, 0.77778], + "223": [0, 0.69444, 0, 0, 0.5], + "230": [0, 0.43056, 0, 0, 0.72222], + "247": [0.08333, 0.58333, 0, 0, 0.77778], + "248": [0.09722, 0.52778, 0, 0, 0.5], + "305": [0, 0.43056, 0, 0, 0.27778], + "338": [0, 0.68333, 0, 0, 1.01389], + "339": [0, 0.43056, 0, 0, 0.77778], + "567": [0.19444, 0.43056, 0, 0, 0.30556], + "710": [0, 0.69444, 0, 0, 0.5], + "711": [0, 0.62847, 0, 0, 0.5], + "713": [0, 0.56778, 0, 0, 0.5], + "714": [0, 0.69444, 0, 0, 0.5], + "715": [0, 0.69444, 0, 0, 0.5], + "728": [0, 0.69444, 0, 0, 0.5], + "729": [0, 0.66786, 0, 0, 0.27778], + "730": [0, 0.69444, 0, 0, 0.75], + "732": [0, 0.66786, 0, 0, 0.5], + "733": [0, 0.69444, 0, 0, 0.5], + "915": [0, 0.68333, 0, 0, 0.625], + "916": [0, 0.68333, 0, 0, 0.83334], + "920": [0, 0.68333, 0, 0, 0.77778], + "923": [0, 0.68333, 0, 0, 0.69445], + "926": [0, 0.68333, 0, 0, 0.66667], + "928": [0, 0.68333, 0, 0, 0.75], + "931": [0, 0.68333, 0, 0, 0.72222], + "933": [0, 0.68333, 0, 0, 0.77778], + "934": [0, 0.68333, 0, 0, 0.72222], + "936": [0, 0.68333, 0, 0, 0.77778], + "937": [0, 0.68333, 0, 0, 0.72222], + "8211": [0, 0.43056, 0.02778, 0, 0.5], + "8212": [0, 0.43056, 0.02778, 0, 1.0], + "8216": [0, 0.69444, 0, 0, 0.27778], + "8217": [0, 0.69444, 0, 0, 0.27778], + "8220": [0, 0.69444, 0, 0, 0.5], + "8221": [0, 0.69444, 0, 0, 0.5], + "8224": [0.19444, 0.69444, 0, 0, 0.44445], + "8225": [0.19444, 0.69444, 0, 0, 0.44445], + "8230": [0, 0.12, 0, 0, 1.172], + "8242": [0, 0.55556, 0, 0, 0.275], + "8407": [0, 0.71444, 0.15382, 0, 0.5], + "8463": [0, 0.68889, 0, 0, 0.54028], + "8465": [0, 0.69444, 0, 0, 0.72222], + "8467": [0, 0.69444, 0, 0.11111, 0.41667], + "8472": [0.19444, 0.43056, 0, 0.11111, 0.63646], + "8476": [0, 0.69444, 0, 0, 0.72222], + "8501": [0, 0.69444, 0, 0, 0.61111], + "8592": [-0.13313, 0.36687, 0, 0, 1.0], + "8593": [0.19444, 0.69444, 0, 0, 0.5], + "8594": [-0.13313, 0.36687, 0, 0, 1.0], + "8595": [0.19444, 0.69444, 0, 0, 0.5], + "8596": [-0.13313, 0.36687, 0, 0, 1.0], + "8597": [0.25, 0.75, 0, 0, 0.5], + "8598": [0.19444, 0.69444, 0, 0, 1.0], + "8599": [0.19444, 0.69444, 0, 0, 1.0], + "8600": [0.19444, 0.69444, 0, 0, 1.0], + "8601": [0.19444, 0.69444, 0, 0, 1.0], + "8614": [0.011, 0.511, 0, 0, 1.0], + "8617": [0.011, 0.511, 0, 0, 1.126], + "8618": [0.011, 0.511, 0, 0, 1.126], + "8636": [-0.13313, 0.36687, 0, 0, 1.0], + "8637": [-0.13313, 0.36687, 0, 0, 1.0], + "8640": [-0.13313, 0.36687, 0, 0, 1.0], + "8641": [-0.13313, 0.36687, 0, 0, 1.0], + "8652": [0.011, 0.671, 0, 0, 1.0], + "8656": [-0.13313, 0.36687, 0, 0, 1.0], + "8657": [0.19444, 0.69444, 0, 0, 0.61111], + "8658": [-0.13313, 0.36687, 0, 0, 1.0], + "8659": [0.19444, 0.69444, 0, 0, 0.61111], + "8660": [-0.13313, 0.36687, 0, 0, 1.0], + "8661": [0.25, 0.75, 0, 0, 0.61111], + "8704": [0, 0.69444, 0, 0, 0.55556], + "8706": [0, 0.69444, 0.05556, 0.08334, 0.5309], + "8707": [0, 0.69444, 0, 0, 0.55556], + "8709": [0.05556, 0.75, 0, 0, 0.5], + "8711": [0, 0.68333, 0, 0, 0.83334], + "8712": [0.0391, 0.5391, 0, 0, 0.66667], + "8715": [0.0391, 0.5391, 0, 0, 0.66667], + "8722": [0.08333, 0.58333, 0, 0, 0.77778], + "8723": [0.08333, 0.58333, 0, 0, 0.77778], + "8725": [0.25, 0.75, 0, 0, 0.5], + "8726": [0.25, 0.75, 0, 0, 0.5], + "8727": [-0.03472, 0.46528, 0, 0, 0.5], + "8728": [-0.05555, 0.44445, 0, 0, 0.5], + "8729": [-0.05555, 0.44445, 0, 0, 0.5], + "8730": [0.2, 0.8, 0, 0, 0.83334], + "8733": [0, 0.43056, 0, 0, 0.77778], + "8734": [0, 0.43056, 0, 0, 1.0], + "8736": [0, 0.69224, 0, 0, 0.72222], + "8739": [0.25, 0.75, 0, 0, 0.27778], + "8741": [0.25, 0.75, 0, 0, 0.5], + "8743": [0, 0.55556, 0, 0, 0.66667], + "8744": [0, 0.55556, 0, 0, 0.66667], + "8745": [0, 0.55556, 0, 0, 0.66667], + "8746": [0, 0.55556, 0, 0, 0.66667], + "8747": [0.19444, 0.69444, 0.11111, 0, 0.41667], + "8764": [-0.13313, 0.36687, 0, 0, 0.77778], + "8768": [0.19444, 0.69444, 0, 0, 0.27778], + "8771": [-0.03625, 0.46375, 0, 0, 0.77778], + "8773": [-0.022, 0.589, 0, 0, 1.0], + "8776": [-0.01688, 0.48312, 0, 0, 0.77778], + "8781": [-0.03625, 0.46375, 0, 0, 0.77778], + "8784": [-0.133, 0.67, 0, 0, 0.778], + "8801": [-0.03625, 0.46375, 0, 0, 0.77778], + "8804": [0.13597, 0.63597, 0, 0, 0.77778], + "8805": [0.13597, 0.63597, 0, 0, 0.77778], + "8810": [0.0391, 0.5391, 0, 0, 1.0], + "8811": [0.0391, 0.5391, 0, 0, 1.0], + "8826": [0.0391, 0.5391, 0, 0, 0.77778], + "8827": [0.0391, 0.5391, 0, 0, 0.77778], + "8834": [0.0391, 0.5391, 0, 0, 0.77778], + "8835": [0.0391, 0.5391, 0, 0, 0.77778], + "8838": [0.13597, 0.63597, 0, 0, 0.77778], + "8839": [0.13597, 0.63597, 0, 0, 0.77778], + "8846": [0, 0.55556, 0, 0, 0.66667], + "8849": [0.13597, 0.63597, 0, 0, 0.77778], + "8850": [0.13597, 0.63597, 0, 0, 0.77778], + "8851": [0, 0.55556, 0, 0, 0.66667], + "8852": [0, 0.55556, 0, 0, 0.66667], + "8853": [0.08333, 0.58333, 0, 0, 0.77778], + "8854": [0.08333, 0.58333, 0, 0, 0.77778], + "8855": [0.08333, 0.58333, 0, 0, 0.77778], + "8856": [0.08333, 0.58333, 0, 0, 0.77778], + "8857": [0.08333, 0.58333, 0, 0, 0.77778], + "8866": [0, 0.69444, 0, 0, 0.61111], + "8867": [0, 0.69444, 0, 0, 0.61111], + "8868": [0, 0.69444, 0, 0, 0.77778], + "8869": [0, 0.69444, 0, 0, 0.77778], + "8872": [0.249, 0.75, 0, 0, 0.867], + "8900": [-0.05555, 0.44445, 0, 0, 0.5], + "8901": [-0.05555, 0.44445, 0, 0, 0.27778], + "8902": [-0.03472, 0.46528, 0, 0, 0.5], + "8904": [0.005, 0.505, 0, 0, 0.9], + "8942": [0.03, 0.9, 0, 0, 0.278], + "8943": [-0.19, 0.31, 0, 0, 1.172], + "8945": [-0.1, 0.82, 0, 0, 1.282], + "8968": [0.25, 0.75, 0, 0, 0.44445], + "8969": [0.25, 0.75, 0, 0, 0.44445], + "8970": [0.25, 0.75, 0, 0, 0.44445], + "8971": [0.25, 0.75, 0, 0, 0.44445], + "8994": [-0.14236, 0.35764, 0, 0, 1.0], + "8995": [-0.14236, 0.35764, 0, 0, 1.0], + "9136": [0.244, 0.744, 0, 0, 0.412], + "9137": [0.244, 0.744, 0, 0, 0.412], + "9651": [0.19444, 0.69444, 0, 0, 0.88889], + "9657": [-0.03472, 0.46528, 0, 0, 0.5], + "9661": [0.19444, 0.69444, 0, 0, 0.88889], + "9667": [-0.03472, 0.46528, 0, 0, 0.5], + "9711": [0.19444, 0.69444, 0, 0, 1.0], + "9824": [0.12963, 0.69444, 0, 0, 0.77778], + "9825": [0.12963, 0.69444, 0, 0, 0.77778], + "9826": [0.12963, 0.69444, 0, 0, 0.77778], + "9827": [0.12963, 0.69444, 0, 0, 0.77778], + "9837": [0, 0.75, 0, 0, 0.38889], + "9838": [0.19444, 0.69444, 0, 0, 0.38889], + "9839": [0.19444, 0.69444, 0, 0, 0.38889], + "10216": [0.25, 0.75, 0, 0, 0.38889], + "10217": [0.25, 0.75, 0, 0, 0.38889], + "10222": [0.244, 0.744, 0, 0, 0.412], + "10223": [0.244, 0.744, 0, 0, 0.412], + "10229": [0.011, 0.511, 0, 0, 1.609], + "10230": [0.011, 0.511, 0, 0, 1.638], + "10231": [0.011, 0.511, 0, 0, 1.859], + "10232": [0.024, 0.525, 0, 0, 1.609], + "10233": [0.024, 0.525, 0, 0, 1.638], + "10234": [0.024, 0.525, 0, 0, 1.858], + "10236": [0.011, 0.511, 0, 0, 1.638], + "10815": [0, 0.68333, 0, 0, 0.75], + "10927": [0.13597, 0.63597, 0, 0, 0.77778], + "10928": [0.13597, 0.63597, 0, 0, 0.77778], + "57376": [0.19444, 0.69444, 0, 0, 0] + }, + "Math-BoldItalic": { + "65": [0, 0.68611, 0, 0, 0.86944], + "66": [0, 0.68611, 0.04835, 0, 0.8664], + "67": [0, 0.68611, 0.06979, 0, 0.81694], + "68": [0, 0.68611, 0.03194, 0, 0.93812], + "69": [0, 0.68611, 0.05451, 0, 0.81007], + "70": [0, 0.68611, 0.15972, 0, 0.68889], + "71": [0, 0.68611, 0, 0, 0.88673], + "72": [0, 0.68611, 0.08229, 0, 0.98229], + "73": [0, 0.68611, 0.07778, 0, 0.51111], + "74": [0, 0.68611, 0.10069, 0, 0.63125], + "75": [0, 0.68611, 0.06979, 0, 0.97118], + "76": [0, 0.68611, 0, 0, 0.75555], + "77": [0, 0.68611, 0.11424, 0, 1.14201], + "78": [0, 0.68611, 0.11424, 0, 0.95034], + "79": [0, 0.68611, 0.03194, 0, 0.83666], + "80": [0, 0.68611, 0.15972, 0, 0.72309], + "81": [0.19444, 0.68611, 0, 0, 0.86861], + "82": [0, 0.68611, 0.00421, 0, 0.87235], + "83": [0, 0.68611, 0.05382, 0, 0.69271], + "84": [0, 0.68611, 0.15972, 0, 0.63663], + "85": [0, 0.68611, 0.11424, 0, 0.80027], + "86": [0, 0.68611, 0.25555, 0, 0.67778], + "87": [0, 0.68611, 0.15972, 0, 1.09305], + "88": [0, 0.68611, 0.07778, 0, 0.94722], + "89": [0, 0.68611, 0.25555, 0, 0.67458], + "90": [0, 0.68611, 0.06979, 0, 0.77257], + "97": [0, 0.44444, 0, 0, 0.63287], + "98": [0, 0.69444, 0, 0, 0.52083], + "99": [0, 0.44444, 0, 0, 0.51342], + "100": [0, 0.69444, 0, 0, 0.60972], + "101": [0, 0.44444, 0, 0, 0.55361], + "102": [0.19444, 0.69444, 0.11042, 0, 0.56806], + "103": [0.19444, 0.44444, 0.03704, 0, 0.5449], + "104": [0, 0.69444, 0, 0, 0.66759], + "105": [0, 0.69326, 0, 0, 0.4048], + "106": [0.19444, 0.69326, 0.0622, 0, 0.47083], + "107": [0, 0.69444, 0.01852, 0, 0.6037], + "108": [0, 0.69444, 0.0088, 0, 0.34815], + "109": [0, 0.44444, 0, 0, 1.0324], + "110": [0, 0.44444, 0, 0, 0.71296], + "111": [0, 0.44444, 0, 0, 0.58472], + "112": [0.19444, 0.44444, 0, 0, 0.60092], + "113": [0.19444, 0.44444, 0.03704, 0, 0.54213], + "114": [0, 0.44444, 0.03194, 0, 0.5287], + "115": [0, 0.44444, 0, 0, 0.53125], + "116": [0, 0.63492, 0, 0, 0.41528], + "117": [0, 0.44444, 0, 0, 0.68102], + "118": [0, 0.44444, 0.03704, 0, 0.56666], + "119": [0, 0.44444, 0.02778, 0, 0.83148], + "120": [0, 0.44444, 0, 0, 0.65903], + "121": [0.19444, 0.44444, 0.03704, 0, 0.59028], + "122": [0, 0.44444, 0.04213, 0, 0.55509], + "915": [0, 0.68611, 0.15972, 0, 0.65694], + "916": [0, 0.68611, 0, 0, 0.95833], + "920": [0, 0.68611, 0.03194, 0, 0.86722], + "923": [0, 0.68611, 0, 0, 0.80555], + "926": [0, 0.68611, 0.07458, 0, 0.84125], + "928": [0, 0.68611, 0.08229, 0, 0.98229], + "931": [0, 0.68611, 0.05451, 0, 0.88507], + "933": [0, 0.68611, 0.15972, 0, 0.67083], + "934": [0, 0.68611, 0, 0, 0.76666], + "936": [0, 0.68611, 0.11653, 0, 0.71402], + "937": [0, 0.68611, 0.04835, 0, 0.8789], + "945": [0, 0.44444, 0, 0, 0.76064], + "946": [0.19444, 0.69444, 0.03403, 0, 0.65972], + "947": [0.19444, 0.44444, 0.06389, 0, 0.59003], + "948": [0, 0.69444, 0.03819, 0, 0.52222], + "949": [0, 0.44444, 0, 0, 0.52882], + "950": [0.19444, 0.69444, 0.06215, 0, 0.50833], + "951": [0.19444, 0.44444, 0.03704, 0, 0.6], + "952": [0, 0.69444, 0.03194, 0, 0.5618], + "953": [0, 0.44444, 0, 0, 0.41204], + "954": [0, 0.44444, 0, 0, 0.66759], + "955": [0, 0.69444, 0, 0, 0.67083], + "956": [0.19444, 0.44444, 0, 0, 0.70787], + "957": [0, 0.44444, 0.06898, 0, 0.57685], + "958": [0.19444, 0.69444, 0.03021, 0, 0.50833], + "959": [0, 0.44444, 0, 0, 0.58472], + "960": [0, 0.44444, 0.03704, 0, 0.68241], + "961": [0.19444, 0.44444, 0, 0, 0.6118], + "962": [0.09722, 0.44444, 0.07917, 0, 0.42361], + "963": [0, 0.44444, 0.03704, 0, 0.68588], + "964": [0, 0.44444, 0.13472, 0, 0.52083], + "965": [0, 0.44444, 0.03704, 0, 0.63055], + "966": [0.19444, 0.44444, 0, 0, 0.74722], + "967": [0.19444, 0.44444, 0, 0, 0.71805], + "968": [0.19444, 0.69444, 0.03704, 0, 0.75833], + "969": [0, 0.44444, 0.03704, 0, 0.71782], + "977": [0, 0.69444, 0, 0, 0.69155], + "981": [0.19444, 0.69444, 0, 0, 0.7125], + "982": [0, 0.44444, 0.03194, 0, 0.975], + "1009": [0.19444, 0.44444, 0, 0, 0.6118], + "1013": [0, 0.44444, 0, 0, 0.48333] + }, + "Math-Italic": { + "65": [0, 0.68333, 0, 0.13889, 0.75], + "66": [0, 0.68333, 0.05017, 0.08334, 0.75851], + "67": [0, 0.68333, 0.07153, 0.08334, 0.71472], + "68": [0, 0.68333, 0.02778, 0.05556, 0.82792], + "69": [0, 0.68333, 0.05764, 0.08334, 0.7382], + "70": [0, 0.68333, 0.13889, 0.08334, 0.64306], + "71": [0, 0.68333, 0, 0.08334, 0.78625], + "72": [0, 0.68333, 0.08125, 0.05556, 0.83125], + "73": [0, 0.68333, 0.07847, 0.11111, 0.43958], + "74": [0, 0.68333, 0.09618, 0.16667, 0.55451], + "75": [0, 0.68333, 0.07153, 0.05556, 0.84931], + "76": [0, 0.68333, 0, 0.02778, 0.68056], + "77": [0, 0.68333, 0.10903, 0.08334, 0.97014], + "78": [0, 0.68333, 0.10903, 0.08334, 0.80347], + "79": [0, 0.68333, 0.02778, 0.08334, 0.76278], + "80": [0, 0.68333, 0.13889, 0.08334, 0.64201], + "81": [0.19444, 0.68333, 0, 0.08334, 0.79056], + "82": [0, 0.68333, 0.00773, 0.08334, 0.75929], + "83": [0, 0.68333, 0.05764, 0.08334, 0.6132], + "84": [0, 0.68333, 0.13889, 0.08334, 0.58438], + "85": [0, 0.68333, 0.10903, 0.02778, 0.68278], + "86": [0, 0.68333, 0.22222, 0, 0.58333], + "87": [0, 0.68333, 0.13889, 0, 0.94445], + "88": [0, 0.68333, 0.07847, 0.08334, 0.82847], + "89": [0, 0.68333, 0.22222, 0, 0.58056], + "90": [0, 0.68333, 0.07153, 0.08334, 0.68264], + "97": [0, 0.43056, 0, 0, 0.52859], + "98": [0, 0.69444, 0, 0, 0.42917], + "99": [0, 0.43056, 0, 0.05556, 0.43276], + "100": [0, 0.69444, 0, 0.16667, 0.52049], + "101": [0, 0.43056, 0, 0.05556, 0.46563], + "102": [0.19444, 0.69444, 0.10764, 0.16667, 0.48959], + "103": [0.19444, 0.43056, 0.03588, 0.02778, 0.47697], + "104": [0, 0.69444, 0, 0, 0.57616], + "105": [0, 0.65952, 0, 0, 0.34451], + "106": [0.19444, 0.65952, 0.05724, 0, 0.41181], + "107": [0, 0.69444, 0.03148, 0, 0.5206], + "108": [0, 0.69444, 0.01968, 0.08334, 0.29838], + "109": [0, 0.43056, 0, 0, 0.87801], + "110": [0, 0.43056, 0, 0, 0.60023], + "111": [0, 0.43056, 0, 0.05556, 0.48472], + "112": [0.19444, 0.43056, 0, 0.08334, 0.50313], + "113": [0.19444, 0.43056, 0.03588, 0.08334, 0.44641], + "114": [0, 0.43056, 0.02778, 0.05556, 0.45116], + "115": [0, 0.43056, 0, 0.05556, 0.46875], + "116": [0, 0.61508, 0, 0.08334, 0.36111], + "117": [0, 0.43056, 0, 0.02778, 0.57246], + "118": [0, 0.43056, 0.03588, 0.02778, 0.48472], + "119": [0, 0.43056, 0.02691, 0.08334, 0.71592], + "120": [0, 0.43056, 0, 0.02778, 0.57153], + "121": [0.19444, 0.43056, 0.03588, 0.05556, 0.49028], + "122": [0, 0.43056, 0.04398, 0.05556, 0.46505], + "915": [0, 0.68333, 0.13889, 0.08334, 0.61528], + "916": [0, 0.68333, 0, 0.16667, 0.83334], + "920": [0, 0.68333, 0.02778, 0.08334, 0.76278], + "923": [0, 0.68333, 0, 0.16667, 0.69445], + "926": [0, 0.68333, 0.07569, 0.08334, 0.74236], + "928": [0, 0.68333, 0.08125, 0.05556, 0.83125], + "931": [0, 0.68333, 0.05764, 0.08334, 0.77986], + "933": [0, 0.68333, 0.13889, 0.05556, 0.58333], + "934": [0, 0.68333, 0, 0.08334, 0.66667], + "936": [0, 0.68333, 0.11, 0.05556, 0.61222], + "937": [0, 0.68333, 0.05017, 0.08334, 0.7724], + "945": [0, 0.43056, 0.0037, 0.02778, 0.6397], + "946": [0.19444, 0.69444, 0.05278, 0.08334, 0.56563], + "947": [0.19444, 0.43056, 0.05556, 0, 0.51773], + "948": [0, 0.69444, 0.03785, 0.05556, 0.44444], + "949": [0, 0.43056, 0, 0.08334, 0.46632], + "950": [0.19444, 0.69444, 0.07378, 0.08334, 0.4375], + "951": [0.19444, 0.43056, 0.03588, 0.05556, 0.49653], + "952": [0, 0.69444, 0.02778, 0.08334, 0.46944], + "953": [0, 0.43056, 0, 0.05556, 0.35394], + "954": [0, 0.43056, 0, 0, 0.57616], + "955": [0, 0.69444, 0, 0, 0.58334], + "956": [0.19444, 0.43056, 0, 0.02778, 0.60255], + "957": [0, 0.43056, 0.06366, 0.02778, 0.49398], + "958": [0.19444, 0.69444, 0.04601, 0.11111, 0.4375], + "959": [0, 0.43056, 0, 0.05556, 0.48472], + "960": [0, 0.43056, 0.03588, 0, 0.57003], + "961": [0.19444, 0.43056, 0, 0.08334, 0.51702], + "962": [0.09722, 0.43056, 0.07986, 0.08334, 0.36285], + "963": [0, 0.43056, 0.03588, 0, 0.57141], + "964": [0, 0.43056, 0.1132, 0.02778, 0.43715], + "965": [0, 0.43056, 0.03588, 0.02778, 0.54028], + "966": [0.19444, 0.43056, 0, 0.08334, 0.65417], + "967": [0.19444, 0.43056, 0, 0.05556, 0.62569], + "968": [0.19444, 0.69444, 0.03588, 0.11111, 0.65139], + "969": [0, 0.43056, 0.03588, 0, 0.62245], + "977": [0, 0.69444, 0, 0.08334, 0.59144], + "981": [0.19444, 0.69444, 0, 0.08334, 0.59583], + "982": [0, 0.43056, 0.02778, 0, 0.82813], + "1009": [0.19444, 0.43056, 0, 0.08334, 0.51702], + "1013": [0, 0.43056, 0, 0.05556, 0.4059] + }, + "Math-Regular": { + "65": [0, 0.68333, 0, 0.13889, 0.75], + "66": [0, 0.68333, 0.05017, 0.08334, 0.75851], + "67": [0, 0.68333, 0.07153, 0.08334, 0.71472], + "68": [0, 0.68333, 0.02778, 0.05556, 0.82792], + "69": [0, 0.68333, 0.05764, 0.08334, 0.7382], + "70": [0, 0.68333, 0.13889, 0.08334, 0.64306], + "71": [0, 0.68333, 0, 0.08334, 0.78625], + "72": [0, 0.68333, 0.08125, 0.05556, 0.83125], + "73": [0, 0.68333, 0.07847, 0.11111, 0.43958], + "74": [0, 0.68333, 0.09618, 0.16667, 0.55451], + "75": [0, 0.68333, 0.07153, 0.05556, 0.84931], + "76": [0, 0.68333, 0, 0.02778, 0.68056], + "77": [0, 0.68333, 0.10903, 0.08334, 0.97014], + "78": [0, 0.68333, 0.10903, 0.08334, 0.80347], + "79": [0, 0.68333, 0.02778, 0.08334, 0.76278], + "80": [0, 0.68333, 0.13889, 0.08334, 0.64201], + "81": [0.19444, 0.68333, 0, 0.08334, 0.79056], + "82": [0, 0.68333, 0.00773, 0.08334, 0.75929], + "83": [0, 0.68333, 0.05764, 0.08334, 0.6132], + "84": [0, 0.68333, 0.13889, 0.08334, 0.58438], + "85": [0, 0.68333, 0.10903, 0.02778, 0.68278], + "86": [0, 0.68333, 0.22222, 0, 0.58333], + "87": [0, 0.68333, 0.13889, 0, 0.94445], + "88": [0, 0.68333, 0.07847, 0.08334, 0.82847], + "89": [0, 0.68333, 0.22222, 0, 0.58056], + "90": [0, 0.68333, 0.07153, 0.08334, 0.68264], + "97": [0, 0.43056, 0, 0, 0.52859], + "98": [0, 0.69444, 0, 0, 0.42917], + "99": [0, 0.43056, 0, 0.05556, 0.43276], + "100": [0, 0.69444, 0, 0.16667, 0.52049], + "101": [0, 0.43056, 0, 0.05556, 0.46563], + "102": [0.19444, 0.69444, 0.10764, 0.16667, 0.48959], + "103": [0.19444, 0.43056, 0.03588, 0.02778, 0.47697], + "104": [0, 0.69444, 0, 0, 0.57616], + "105": [0, 0.65952, 0, 0, 0.34451], + "106": [0.19444, 0.65952, 0.05724, 0, 0.41181], + "107": [0, 0.69444, 0.03148, 0, 0.5206], + "108": [0, 0.69444, 0.01968, 0.08334, 0.29838], + "109": [0, 0.43056, 0, 0, 0.87801], + "110": [0, 0.43056, 0, 0, 0.60023], + "111": [0, 0.43056, 0, 0.05556, 0.48472], + "112": [0.19444, 0.43056, 0, 0.08334, 0.50313], + "113": [0.19444, 0.43056, 0.03588, 0.08334, 0.44641], + "114": [0, 0.43056, 0.02778, 0.05556, 0.45116], + "115": [0, 0.43056, 0, 0.05556, 0.46875], + "116": [0, 0.61508, 0, 0.08334, 0.36111], + "117": [0, 0.43056, 0, 0.02778, 0.57246], + "118": [0, 0.43056, 0.03588, 0.02778, 0.48472], + "119": [0, 0.43056, 0.02691, 0.08334, 0.71592], + "120": [0, 0.43056, 0, 0.02778, 0.57153], + "121": [0.19444, 0.43056, 0.03588, 0.05556, 0.49028], + "122": [0, 0.43056, 0.04398, 0.05556, 0.46505], + "915": [0, 0.68333, 0.13889, 0.08334, 0.61528], + "916": [0, 0.68333, 0, 0.16667, 0.83334], + "920": [0, 0.68333, 0.02778, 0.08334, 0.76278], + "923": [0, 0.68333, 0, 0.16667, 0.69445], + "926": [0, 0.68333, 0.07569, 0.08334, 0.74236], + "928": [0, 0.68333, 0.08125, 0.05556, 0.83125], + "931": [0, 0.68333, 0.05764, 0.08334, 0.77986], + "933": [0, 0.68333, 0.13889, 0.05556, 0.58333], + "934": [0, 0.68333, 0, 0.08334, 0.66667], + "936": [0, 0.68333, 0.11, 0.05556, 0.61222], + "937": [0, 0.68333, 0.05017, 0.08334, 0.7724], + "945": [0, 0.43056, 0.0037, 0.02778, 0.6397], + "946": [0.19444, 0.69444, 0.05278, 0.08334, 0.56563], + "947": [0.19444, 0.43056, 0.05556, 0, 0.51773], + "948": [0, 0.69444, 0.03785, 0.05556, 0.44444], + "949": [0, 0.43056, 0, 0.08334, 0.46632], + "950": [0.19444, 0.69444, 0.07378, 0.08334, 0.4375], + "951": [0.19444, 0.43056, 0.03588, 0.05556, 0.49653], + "952": [0, 0.69444, 0.02778, 0.08334, 0.46944], + "953": [0, 0.43056, 0, 0.05556, 0.35394], + "954": [0, 0.43056, 0, 0, 0.57616], + "955": [0, 0.69444, 0, 0, 0.58334], + "956": [0.19444, 0.43056, 0, 0.02778, 0.60255], + "957": [0, 0.43056, 0.06366, 0.02778, 0.49398], + "958": [0.19444, 0.69444, 0.04601, 0.11111, 0.4375], + "959": [0, 0.43056, 0, 0.05556, 0.48472], + "960": [0, 0.43056, 0.03588, 0, 0.57003], + "961": [0.19444, 0.43056, 0, 0.08334, 0.51702], + "962": [0.09722, 0.43056, 0.07986, 0.08334, 0.36285], + "963": [0, 0.43056, 0.03588, 0, 0.57141], + "964": [0, 0.43056, 0.1132, 0.02778, 0.43715], + "965": [0, 0.43056, 0.03588, 0.02778, 0.54028], + "966": [0.19444, 0.43056, 0, 0.08334, 0.65417], + "967": [0.19444, 0.43056, 0, 0.05556, 0.62569], + "968": [0.19444, 0.69444, 0.03588, 0.11111, 0.65139], + "969": [0, 0.43056, 0.03588, 0, 0.62245], + "977": [0, 0.69444, 0, 0.08334, 0.59144], + "981": [0.19444, 0.69444, 0, 0.08334, 0.59583], + "982": [0, 0.43056, 0.02778, 0, 0.82813], + "1009": [0.19444, 0.43056, 0, 0.08334, 0.51702], + "1013": [0, 0.43056, 0, 0.05556, 0.4059] + }, + "SansSerif-Bold": { + "33": [0, 0.69444, 0, 0, 0.36667], + "34": [0, 0.69444, 0, 0, 0.55834], + "35": [0.19444, 0.69444, 0, 0, 0.91667], + "36": [0.05556, 0.75, 0, 0, 0.55], + "37": [0.05556, 0.75, 0, 0, 1.02912], + "38": [0, 0.69444, 0, 0, 0.83056], + "39": [0, 0.69444, 0, 0, 0.30556], + "40": [0.25, 0.75, 0, 0, 0.42778], + "41": [0.25, 0.75, 0, 0, 0.42778], + "42": [0, 0.75, 0, 0, 0.55], + "43": [0.11667, 0.61667, 0, 0, 0.85556], + "44": [0.10556, 0.13056, 0, 0, 0.30556], + "45": [0, 0.45833, 0, 0, 0.36667], + "46": [0, 0.13056, 0, 0, 0.30556], + "47": [0.25, 0.75, 0, 0, 0.55], + "48": [0, 0.69444, 0, 0, 0.55], + "49": [0, 0.69444, 0, 0, 0.55], + "50": [0, 0.69444, 0, 0, 0.55], + "51": [0, 0.69444, 0, 0, 0.55], + "52": [0, 0.69444, 0, 0, 0.55], + "53": [0, 0.69444, 0, 0, 0.55], + "54": [0, 0.69444, 0, 0, 0.55], + "55": [0, 0.69444, 0, 0, 0.55], + "56": [0, 0.69444, 0, 0, 0.55], + "57": [0, 0.69444, 0, 0, 0.55], + "58": [0, 0.45833, 0, 0, 0.30556], + "59": [0.10556, 0.45833, 0, 0, 0.30556], + "61": [-0.09375, 0.40625, 0, 0, 0.85556], + "63": [0, 0.69444, 0, 0, 0.51945], + "64": [0, 0.69444, 0, 0, 0.73334], + "65": [0, 0.69444, 0, 0, 0.73334], + "66": [0, 0.69444, 0, 0, 0.73334], + "67": [0, 0.69444, 0, 0, 0.70278], + "68": [0, 0.69444, 0, 0, 0.79445], + "69": [0, 0.69444, 0, 0, 0.64167], + "70": [0, 0.69444, 0, 0, 0.61111], + "71": [0, 0.69444, 0, 0, 0.73334], + "72": [0, 0.69444, 0, 0, 0.79445], + "73": [0, 0.69444, 0, 0, 0.33056], + "74": [0, 0.69444, 0, 0, 0.51945], + "75": [0, 0.69444, 0, 0, 0.76389], + "76": [0, 0.69444, 0, 0, 0.58056], + "77": [0, 0.69444, 0, 0, 0.97778], + "78": [0, 0.69444, 0, 0, 0.79445], + "79": [0, 0.69444, 0, 0, 0.79445], + "80": [0, 0.69444, 0, 0, 0.70278], + "81": [0.10556, 0.69444, 0, 0, 0.79445], + "82": [0, 0.69444, 0, 0, 0.70278], + "83": [0, 0.69444, 0, 0, 0.61111], + "84": [0, 0.69444, 0, 0, 0.73334], + "85": [0, 0.69444, 0, 0, 0.76389], + "86": [0, 0.69444, 0.01528, 0, 0.73334], + "87": [0, 0.69444, 0.01528, 0, 1.03889], + "88": [0, 0.69444, 0, 0, 0.73334], + "89": [0, 0.69444, 0.0275, 0, 0.73334], + "90": [0, 0.69444, 0, 0, 0.67223], + "91": [0.25, 0.75, 0, 0, 0.34306], + "93": [0.25, 0.75, 0, 0, 0.34306], + "94": [0, 0.69444, 0, 0, 0.55], + "95": [0.35, 0.10833, 0.03056, 0, 0.55], + "97": [0, 0.45833, 0, 0, 0.525], + "98": [0, 0.69444, 0, 0, 0.56111], + "99": [0, 0.45833, 0, 0, 0.48889], + "100": [0, 0.69444, 0, 0, 0.56111], + "101": [0, 0.45833, 0, 0, 0.51111], + "102": [0, 0.69444, 0.07639, 0, 0.33611], + "103": [0.19444, 0.45833, 0.01528, 0, 0.55], + "104": [0, 0.69444, 0, 0, 0.56111], + "105": [0, 0.69444, 0, 0, 0.25556], + "106": [0.19444, 0.69444, 0, 0, 0.28611], + "107": [0, 0.69444, 0, 0, 0.53056], + "108": [0, 0.69444, 0, 0, 0.25556], + "109": [0, 0.45833, 0, 0, 0.86667], + "110": [0, 0.45833, 0, 0, 0.56111], + "111": [0, 0.45833, 0, 0, 0.55], + "112": [0.19444, 0.45833, 0, 0, 0.56111], + "113": [0.19444, 0.45833, 0, 0, 0.56111], + "114": [0, 0.45833, 0.01528, 0, 0.37222], + "115": [0, 0.45833, 0, 0, 0.42167], + "116": [0, 0.58929, 0, 0, 0.40417], + "117": [0, 0.45833, 0, 0, 0.56111], + "118": [0, 0.45833, 0.01528, 0, 0.5], + "119": [0, 0.45833, 0.01528, 0, 0.74445], + "120": [0, 0.45833, 0, 0, 0.5], + "121": [0.19444, 0.45833, 0.01528, 0, 0.5], + "122": [0, 0.45833, 0, 0, 0.47639], + "126": [0.35, 0.34444, 0, 0, 0.55], + "168": [0, 0.69444, 0, 0, 0.55], + "176": [0, 0.69444, 0, 0, 0.73334], + "180": [0, 0.69444, 0, 0, 0.55], + "184": [0.17014, 0, 0, 0, 0.48889], + "305": [0, 0.45833, 0, 0, 0.25556], + "567": [0.19444, 0.45833, 0, 0, 0.28611], + "710": [0, 0.69444, 0, 0, 0.55], + "711": [0, 0.63542, 0, 0, 0.55], + "713": [0, 0.63778, 0, 0, 0.55], + "728": [0, 0.69444, 0, 0, 0.55], + "729": [0, 0.69444, 0, 0, 0.30556], + "730": [0, 0.69444, 0, 0, 0.73334], + "732": [0, 0.69444, 0, 0, 0.55], + "733": [0, 0.69444, 0, 0, 0.55], + "915": [0, 0.69444, 0, 0, 0.58056], + "916": [0, 0.69444, 0, 0, 0.91667], + "920": [0, 0.69444, 0, 0, 0.85556], + "923": [0, 0.69444, 0, 0, 0.67223], + "926": [0, 0.69444, 0, 0, 0.73334], + "928": [0, 0.69444, 0, 0, 0.79445], + "931": [0, 0.69444, 0, 0, 0.79445], + "933": [0, 0.69444, 0, 0, 0.85556], + "934": [0, 0.69444, 0, 0, 0.79445], + "936": [0, 0.69444, 0, 0, 0.85556], + "937": [0, 0.69444, 0, 0, 0.79445], + "8211": [0, 0.45833, 0.03056, 0, 0.55], + "8212": [0, 0.45833, 0.03056, 0, 1.10001], + "8216": [0, 0.69444, 0, 0, 0.30556], + "8217": [0, 0.69444, 0, 0, 0.30556], + "8220": [0, 0.69444, 0, 0, 0.55834], + "8221": [0, 0.69444, 0, 0, 0.55834] + }, + "SansSerif-Italic": { + "33": [0, 0.69444, 0.05733, 0, 0.31945], + "34": [0, 0.69444, 0.00316, 0, 0.5], + "35": [0.19444, 0.69444, 0.05087, 0, 0.83334], + "36": [0.05556, 0.75, 0.11156, 0, 0.5], + "37": [0.05556, 0.75, 0.03126, 0, 0.83334], + "38": [0, 0.69444, 0.03058, 0, 0.75834], + "39": [0, 0.69444, 0.07816, 0, 0.27778], + "40": [0.25, 0.75, 0.13164, 0, 0.38889], + "41": [0.25, 0.75, 0.02536, 0, 0.38889], + "42": [0, 0.75, 0.11775, 0, 0.5], + "43": [0.08333, 0.58333, 0.02536, 0, 0.77778], + "44": [0.125, 0.08333, 0, 0, 0.27778], + "45": [0, 0.44444, 0.01946, 0, 0.33333], + "46": [0, 0.08333, 0, 0, 0.27778], + "47": [0.25, 0.75, 0.13164, 0, 0.5], + "48": [0, 0.65556, 0.11156, 0, 0.5], + "49": [0, 0.65556, 0.11156, 0, 0.5], + "50": [0, 0.65556, 0.11156, 0, 0.5], + "51": [0, 0.65556, 0.11156, 0, 0.5], + "52": [0, 0.65556, 0.11156, 0, 0.5], + "53": [0, 0.65556, 0.11156, 0, 0.5], + "54": [0, 0.65556, 0.11156, 0, 0.5], + "55": [0, 0.65556, 0.11156, 0, 0.5], + "56": [0, 0.65556, 0.11156, 0, 0.5], + "57": [0, 0.65556, 0.11156, 0, 0.5], + "58": [0, 0.44444, 0.02502, 0, 0.27778], + "59": [0.125, 0.44444, 0.02502, 0, 0.27778], + "61": [-0.13, 0.37, 0.05087, 0, 0.77778], + "63": [0, 0.69444, 0.11809, 0, 0.47222], + "64": [0, 0.69444, 0.07555, 0, 0.66667], + "65": [0, 0.69444, 0, 0, 0.66667], + "66": [0, 0.69444, 0.08293, 0, 0.66667], + "67": [0, 0.69444, 0.11983, 0, 0.63889], + "68": [0, 0.69444, 0.07555, 0, 0.72223], + "69": [0, 0.69444, 0.11983, 0, 0.59722], + "70": [0, 0.69444, 0.13372, 0, 0.56945], + "71": [0, 0.69444, 0.11983, 0, 0.66667], + "72": [0, 0.69444, 0.08094, 0, 0.70834], + "73": [0, 0.69444, 0.13372, 0, 0.27778], + "74": [0, 0.69444, 0.08094, 0, 0.47222], + "75": [0, 0.69444, 0.11983, 0, 0.69445], + "76": [0, 0.69444, 0, 0, 0.54167], + "77": [0, 0.69444, 0.08094, 0, 0.875], + "78": [0, 0.69444, 0.08094, 0, 0.70834], + "79": [0, 0.69444, 0.07555, 0, 0.73611], + "80": [0, 0.69444, 0.08293, 0, 0.63889], + "81": [0.125, 0.69444, 0.07555, 0, 0.73611], + "82": [0, 0.69444, 0.08293, 0, 0.64584], + "83": [0, 0.69444, 0.09205, 0, 0.55556], + "84": [0, 0.69444, 0.13372, 0, 0.68056], + "85": [0, 0.69444, 0.08094, 0, 0.6875], + "86": [0, 0.69444, 0.1615, 0, 0.66667], + "87": [0, 0.69444, 0.1615, 0, 0.94445], + "88": [0, 0.69444, 0.13372, 0, 0.66667], + "89": [0, 0.69444, 0.17261, 0, 0.66667], + "90": [0, 0.69444, 0.11983, 0, 0.61111], + "91": [0.25, 0.75, 0.15942, 0, 0.28889], + "93": [0.25, 0.75, 0.08719, 0, 0.28889], + "94": [0, 0.69444, 0.0799, 0, 0.5], + "95": [0.35, 0.09444, 0.08616, 0, 0.5], + "97": [0, 0.44444, 0.00981, 0, 0.48056], + "98": [0, 0.69444, 0.03057, 0, 0.51667], + "99": [0, 0.44444, 0.08336, 0, 0.44445], + "100": [0, 0.69444, 0.09483, 0, 0.51667], + "101": [0, 0.44444, 0.06778, 0, 0.44445], + "102": [0, 0.69444, 0.21705, 0, 0.30556], + "103": [0.19444, 0.44444, 0.10836, 0, 0.5], + "104": [0, 0.69444, 0.01778, 0, 0.51667], + "105": [0, 0.67937, 0.09718, 0, 0.23889], + "106": [0.19444, 0.67937, 0.09162, 0, 0.26667], + "107": [0, 0.69444, 0.08336, 0, 0.48889], + "108": [0, 0.69444, 0.09483, 0, 0.23889], + "109": [0, 0.44444, 0.01778, 0, 0.79445], + "110": [0, 0.44444, 0.01778, 0, 0.51667], + "111": [0, 0.44444, 0.06613, 0, 0.5], + "112": [0.19444, 0.44444, 0.0389, 0, 0.51667], + "113": [0.19444, 0.44444, 0.04169, 0, 0.51667], + "114": [0, 0.44444, 0.10836, 0, 0.34167], + "115": [0, 0.44444, 0.0778, 0, 0.38333], + "116": [0, 0.57143, 0.07225, 0, 0.36111], + "117": [0, 0.44444, 0.04169, 0, 0.51667], + "118": [0, 0.44444, 0.10836, 0, 0.46111], + "119": [0, 0.44444, 0.10836, 0, 0.68334], + "120": [0, 0.44444, 0.09169, 0, 0.46111], + "121": [0.19444, 0.44444, 0.10836, 0, 0.46111], + "122": [0, 0.44444, 0.08752, 0, 0.43472], + "126": [0.35, 0.32659, 0.08826, 0, 0.5], + "168": [0, 0.67937, 0.06385, 0, 0.5], + "176": [0, 0.69444, 0, 0, 0.73752], + "184": [0.17014, 0, 0, 0, 0.44445], + "305": [0, 0.44444, 0.04169, 0, 0.23889], + "567": [0.19444, 0.44444, 0.04169, 0, 0.26667], + "710": [0, 0.69444, 0.0799, 0, 0.5], + "711": [0, 0.63194, 0.08432, 0, 0.5], + "713": [0, 0.60889, 0.08776, 0, 0.5], + "714": [0, 0.69444, 0.09205, 0, 0.5], + "715": [0, 0.69444, 0, 0, 0.5], + "728": [0, 0.69444, 0.09483, 0, 0.5], + "729": [0, 0.67937, 0.07774, 0, 0.27778], + "730": [0, 0.69444, 0, 0, 0.73752], + "732": [0, 0.67659, 0.08826, 0, 0.5], + "733": [0, 0.69444, 0.09205, 0, 0.5], + "915": [0, 0.69444, 0.13372, 0, 0.54167], + "916": [0, 0.69444, 0, 0, 0.83334], + "920": [0, 0.69444, 0.07555, 0, 0.77778], + "923": [0, 0.69444, 0, 0, 0.61111], + "926": [0, 0.69444, 0.12816, 0, 0.66667], + "928": [0, 0.69444, 0.08094, 0, 0.70834], + "931": [0, 0.69444, 0.11983, 0, 0.72222], + "933": [0, 0.69444, 0.09031, 0, 0.77778], + "934": [0, 0.69444, 0.04603, 0, 0.72222], + "936": [0, 0.69444, 0.09031, 0, 0.77778], + "937": [0, 0.69444, 0.08293, 0, 0.72222], + "8211": [0, 0.44444, 0.08616, 0, 0.5], + "8212": [0, 0.44444, 0.08616, 0, 1.0], + "8216": [0, 0.69444, 0.07816, 0, 0.27778], + "8217": [0, 0.69444, 0.07816, 0, 0.27778], + "8220": [0, 0.69444, 0.14205, 0, 0.5], + "8221": [0, 0.69444, 0.00316, 0, 0.5] + }, + "SansSerif-Regular": { + "33": [0, 0.69444, 0, 0, 0.31945], + "34": [0, 0.69444, 0, 0, 0.5], + "35": [0.19444, 0.69444, 0, 0, 0.83334], + "36": [0.05556, 0.75, 0, 0, 0.5], + "37": [0.05556, 0.75, 0, 0, 0.83334], + "38": [0, 0.69444, 0, 0, 0.75834], + "39": [0, 0.69444, 0, 0, 0.27778], + "40": [0.25, 0.75, 0, 0, 0.38889], + "41": [0.25, 0.75, 0, 0, 0.38889], + "42": [0, 0.75, 0, 0, 0.5], + "43": [0.08333, 0.58333, 0, 0, 0.77778], + "44": [0.125, 0.08333, 0, 0, 0.27778], + "45": [0, 0.44444, 0, 0, 0.33333], + "46": [0, 0.08333, 0, 0, 0.27778], + "47": [0.25, 0.75, 0, 0, 0.5], + "48": [0, 0.65556, 0, 0, 0.5], + "49": [0, 0.65556, 0, 0, 0.5], + "50": [0, 0.65556, 0, 0, 0.5], + "51": [0, 0.65556, 0, 0, 0.5], + "52": [0, 0.65556, 0, 0, 0.5], + "53": [0, 0.65556, 0, 0, 0.5], + "54": [0, 0.65556, 0, 0, 0.5], + "55": [0, 0.65556, 0, 0, 0.5], + "56": [0, 0.65556, 0, 0, 0.5], + "57": [0, 0.65556, 0, 0, 0.5], + "58": [0, 0.44444, 0, 0, 0.27778], + "59": [0.125, 0.44444, 0, 0, 0.27778], + "61": [-0.13, 0.37, 0, 0, 0.77778], + "63": [0, 0.69444, 0, 0, 0.47222], + "64": [0, 0.69444, 0, 0, 0.66667], + "65": [0, 0.69444, 0, 0, 0.66667], + "66": [0, 0.69444, 0, 0, 0.66667], + "67": [0, 0.69444, 0, 0, 0.63889], + "68": [0, 0.69444, 0, 0, 0.72223], + "69": [0, 0.69444, 0, 0, 0.59722], + "70": [0, 0.69444, 0, 0, 0.56945], + "71": [0, 0.69444, 0, 0, 0.66667], + "72": [0, 0.69444, 0, 0, 0.70834], + "73": [0, 0.69444, 0, 0, 0.27778], + "74": [0, 0.69444, 0, 0, 0.47222], + "75": [0, 0.69444, 0, 0, 0.69445], + "76": [0, 0.69444, 0, 0, 0.54167], + "77": [0, 0.69444, 0, 0, 0.875], + "78": [0, 0.69444, 0, 0, 0.70834], + "79": [0, 0.69444, 0, 0, 0.73611], + "80": [0, 0.69444, 0, 0, 0.63889], + "81": [0.125, 0.69444, 0, 0, 0.73611], + "82": [0, 0.69444, 0, 0, 0.64584], + "83": [0, 0.69444, 0, 0, 0.55556], + "84": [0, 0.69444, 0, 0, 0.68056], + "85": [0, 0.69444, 0, 0, 0.6875], + "86": [0, 0.69444, 0.01389, 0, 0.66667], + "87": [0, 0.69444, 0.01389, 0, 0.94445], + "88": [0, 0.69444, 0, 0, 0.66667], + "89": [0, 0.69444, 0.025, 0, 0.66667], + "90": [0, 0.69444, 0, 0, 0.61111], + "91": [0.25, 0.75, 0, 0, 0.28889], + "93": [0.25, 0.75, 0, 0, 0.28889], + "94": [0, 0.69444, 0, 0, 0.5], + "95": [0.35, 0.09444, 0.02778, 0, 0.5], + "97": [0, 0.44444, 0, 0, 0.48056], + "98": [0, 0.69444, 0, 0, 0.51667], + "99": [0, 0.44444, 0, 0, 0.44445], + "100": [0, 0.69444, 0, 0, 0.51667], + "101": [0, 0.44444, 0, 0, 0.44445], + "102": [0, 0.69444, 0.06944, 0, 0.30556], + "103": [0.19444, 0.44444, 0.01389, 0, 0.5], + "104": [0, 0.69444, 0, 0, 0.51667], + "105": [0, 0.67937, 0, 0, 0.23889], + "106": [0.19444, 0.67937, 0, 0, 0.26667], + "107": [0, 0.69444, 0, 0, 0.48889], + "108": [0, 0.69444, 0, 0, 0.23889], + "109": [0, 0.44444, 0, 0, 0.79445], + "110": [0, 0.44444, 0, 0, 0.51667], + "111": [0, 0.44444, 0, 0, 0.5], + "112": [0.19444, 0.44444, 0, 0, 0.51667], + "113": [0.19444, 0.44444, 0, 0, 0.51667], + "114": [0, 0.44444, 0.01389, 0, 0.34167], + "115": [0, 0.44444, 0, 0, 0.38333], + "116": [0, 0.57143, 0, 0, 0.36111], + "117": [0, 0.44444, 0, 0, 0.51667], + "118": [0, 0.44444, 0.01389, 0, 0.46111], + "119": [0, 0.44444, 0.01389, 0, 0.68334], + "120": [0, 0.44444, 0, 0, 0.46111], + "121": [0.19444, 0.44444, 0.01389, 0, 0.46111], + "122": [0, 0.44444, 0, 0, 0.43472], + "126": [0.35, 0.32659, 0, 0, 0.5], + "168": [0, 0.67937, 0, 0, 0.5], + "176": [0, 0.69444, 0, 0, 0.66667], + "184": [0.17014, 0, 0, 0, 0.44445], + "305": [0, 0.44444, 0, 0, 0.23889], + "567": [0.19444, 0.44444, 0, 0, 0.26667], + "710": [0, 0.69444, 0, 0, 0.5], + "711": [0, 0.63194, 0, 0, 0.5], + "713": [0, 0.60889, 0, 0, 0.5], + "714": [0, 0.69444, 0, 0, 0.5], + "715": [0, 0.69444, 0, 0, 0.5], + "728": [0, 0.69444, 0, 0, 0.5], + "729": [0, 0.67937, 0, 0, 0.27778], + "730": [0, 0.69444, 0, 0, 0.66667], + "732": [0, 0.67659, 0, 0, 0.5], + "733": [0, 0.69444, 0, 0, 0.5], + "915": [0, 0.69444, 0, 0, 0.54167], + "916": [0, 0.69444, 0, 0, 0.83334], + "920": [0, 0.69444, 0, 0, 0.77778], + "923": [0, 0.69444, 0, 0, 0.61111], + "926": [0, 0.69444, 0, 0, 0.66667], + "928": [0, 0.69444, 0, 0, 0.70834], + "931": [0, 0.69444, 0, 0, 0.72222], + "933": [0, 0.69444, 0, 0, 0.77778], + "934": [0, 0.69444, 0, 0, 0.72222], + "936": [0, 0.69444, 0, 0, 0.77778], + "937": [0, 0.69444, 0, 0, 0.72222], + "8211": [0, 0.44444, 0.02778, 0, 0.5], + "8212": [0, 0.44444, 0.02778, 0, 1.0], + "8216": [0, 0.69444, 0, 0, 0.27778], + "8217": [0, 0.69444, 0, 0, 0.27778], + "8220": [0, 0.69444, 0, 0, 0.5], + "8221": [0, 0.69444, 0, 0, 0.5] + }, + "Script-Regular": { + "65": [0, 0.7, 0.22925, 0, 0.80253], + "66": [0, 0.7, 0.04087, 0, 0.90757], + "67": [0, 0.7, 0.1689, 0, 0.66619], + "68": [0, 0.7, 0.09371, 0, 0.77443], + "69": [0, 0.7, 0.18583, 0, 0.56162], + "70": [0, 0.7, 0.13634, 0, 0.89544], + "71": [0, 0.7, 0.17322, 0, 0.60961], + "72": [0, 0.7, 0.29694, 0, 0.96919], + "73": [0, 0.7, 0.19189, 0, 0.80907], + "74": [0.27778, 0.7, 0.19189, 0, 1.05159], + "75": [0, 0.7, 0.31259, 0, 0.91364], + "76": [0, 0.7, 0.19189, 0, 0.87373], + "77": [0, 0.7, 0.15981, 0, 1.08031], + "78": [0, 0.7, 0.3525, 0, 0.9015], + "79": [0, 0.7, 0.08078, 0, 0.73787], + "80": [0, 0.7, 0.08078, 0, 1.01262], + "81": [0, 0.7, 0.03305, 0, 0.88282], + "82": [0, 0.7, 0.06259, 0, 0.85], + "83": [0, 0.7, 0.19189, 0, 0.86767], + "84": [0, 0.7, 0.29087, 0, 0.74697], + "85": [0, 0.7, 0.25815, 0, 0.79996], + "86": [0, 0.7, 0.27523, 0, 0.62204], + "87": [0, 0.7, 0.27523, 0, 0.80532], + "88": [0, 0.7, 0.26006, 0, 0.94445], + "89": [0, 0.7, 0.2939, 0, 0.70961], + "90": [0, 0.7, 0.24037, 0, 0.8212] + }, + "Size1-Regular": { + "40": [0.35001, 0.85, 0, 0, 0.45834], + "41": [0.35001, 0.85, 0, 0, 0.45834], + "47": [0.35001, 0.85, 0, 0, 0.57778], + "91": [0.35001, 0.85, 0, 0, 0.41667], + "92": [0.35001, 0.85, 0, 0, 0.57778], + "93": [0.35001, 0.85, 0, 0, 0.41667], + "123": [0.35001, 0.85, 0, 0, 0.58334], + "125": [0.35001, 0.85, 0, 0, 0.58334], + "710": [0, 0.72222, 0, 0, 0.55556], + "732": [0, 0.72222, 0, 0, 0.55556], + "770": [0, 0.72222, 0, 0, 0.55556], + "771": [0, 0.72222, 0, 0, 0.55556], + "8214": [-0.00099, 0.601, 0, 0, 0.77778], + "8593": [1e-05, 0.6, 0, 0, 0.66667], + "8595": [1e-05, 0.6, 0, 0, 0.66667], + "8657": [1e-05, 0.6, 0, 0, 0.77778], + "8659": [1e-05, 0.6, 0, 0, 0.77778], + "8719": [0.25001, 0.75, 0, 0, 0.94445], + "8720": [0.25001, 0.75, 0, 0, 0.94445], + "8721": [0.25001, 0.75, 0, 0, 1.05556], + "8730": [0.35001, 0.85, 0, 0, 1.0], + "8739": [-0.00599, 0.606, 0, 0, 0.33333], + "8741": [-0.00599, 0.606, 0, 0, 0.55556], + "8747": [0.30612, 0.805, 0.19445, 0, 0.47222], + "8748": [0.306, 0.805, 0.19445, 0, 0.47222], + "8749": [0.306, 0.805, 0.19445, 0, 0.47222], + "8750": [0.30612, 0.805, 0.19445, 0, 0.47222], + "8896": [0.25001, 0.75, 0, 0, 0.83334], + "8897": [0.25001, 0.75, 0, 0, 0.83334], + "8898": [0.25001, 0.75, 0, 0, 0.83334], + "8899": [0.25001, 0.75, 0, 0, 0.83334], + "8968": [0.35001, 0.85, 0, 0, 0.47222], + "8969": [0.35001, 0.85, 0, 0, 0.47222], + "8970": [0.35001, 0.85, 0, 0, 0.47222], + "8971": [0.35001, 0.85, 0, 0, 0.47222], + "9168": [-0.00099, 0.601, 0, 0, 0.66667], + "10216": [0.35001, 0.85, 0, 0, 0.47222], + "10217": [0.35001, 0.85, 0, 0, 0.47222], + "10752": [0.25001, 0.75, 0, 0, 1.11111], + "10753": [0.25001, 0.75, 0, 0, 1.11111], + "10754": [0.25001, 0.75, 0, 0, 1.11111], + "10756": [0.25001, 0.75, 0, 0, 0.83334], + "10758": [0.25001, 0.75, 0, 0, 0.83334] + }, + "Size2-Regular": { + "40": [0.65002, 1.15, 0, 0, 0.59722], + "41": [0.65002, 1.15, 0, 0, 0.59722], + "47": [0.65002, 1.15, 0, 0, 0.81111], + "91": [0.65002, 1.15, 0, 0, 0.47222], + "92": [0.65002, 1.15, 0, 0, 0.81111], + "93": [0.65002, 1.15, 0, 0, 0.47222], + "123": [0.65002, 1.15, 0, 0, 0.66667], + "125": [0.65002, 1.15, 0, 0, 0.66667], + "710": [0, 0.75, 0, 0, 1.0], + "732": [0, 0.75, 0, 0, 1.0], + "770": [0, 0.75, 0, 0, 1.0], + "771": [0, 0.75, 0, 0, 1.0], + "8719": [0.55001, 1.05, 0, 0, 1.27778], + "8720": [0.55001, 1.05, 0, 0, 1.27778], + "8721": [0.55001, 1.05, 0, 0, 1.44445], + "8730": [0.65002, 1.15, 0, 0, 1.0], + "8747": [0.86225, 1.36, 0.44445, 0, 0.55556], + "8748": [0.862, 1.36, 0.44445, 0, 0.55556], + "8749": [0.862, 1.36, 0.44445, 0, 0.55556], + "8750": [0.86225, 1.36, 0.44445, 0, 0.55556], + "8896": [0.55001, 1.05, 0, 0, 1.11111], + "8897": [0.55001, 1.05, 0, 0, 1.11111], + "8898": [0.55001, 1.05, 0, 0, 1.11111], + "8899": [0.55001, 1.05, 0, 0, 1.11111], + "8968": [0.65002, 1.15, 0, 0, 0.52778], + "8969": [0.65002, 1.15, 0, 0, 0.52778], + "8970": [0.65002, 1.15, 0, 0, 0.52778], + "8971": [0.65002, 1.15, 0, 0, 0.52778], + "10216": [0.65002, 1.15, 0, 0, 0.61111], + "10217": [0.65002, 1.15, 0, 0, 0.61111], + "10752": [0.55001, 1.05, 0, 0, 1.51112], + "10753": [0.55001, 1.05, 0, 0, 1.51112], + "10754": [0.55001, 1.05, 0, 0, 1.51112], + "10756": [0.55001, 1.05, 0, 0, 1.11111], + "10758": [0.55001, 1.05, 0, 0, 1.11111] + }, + "Size3-Regular": { + "40": [0.95003, 1.45, 0, 0, 0.73611], + "41": [0.95003, 1.45, 0, 0, 0.73611], + "47": [0.95003, 1.45, 0, 0, 1.04445], + "91": [0.95003, 1.45, 0, 0, 0.52778], + "92": [0.95003, 1.45, 0, 0, 1.04445], + "93": [0.95003, 1.45, 0, 0, 0.52778], + "123": [0.95003, 1.45, 0, 0, 0.75], + "125": [0.95003, 1.45, 0, 0, 0.75], + "710": [0, 0.75, 0, 0, 1.44445], + "732": [0, 0.75, 0, 0, 1.44445], + "770": [0, 0.75, 0, 0, 1.44445], + "771": [0, 0.75, 0, 0, 1.44445], + "8730": [0.95003, 1.45, 0, 0, 1.0], + "8968": [0.95003, 1.45, 0, 0, 0.58334], + "8969": [0.95003, 1.45, 0, 0, 0.58334], + "8970": [0.95003, 1.45, 0, 0, 0.58334], + "8971": [0.95003, 1.45, 0, 0, 0.58334], + "10216": [0.95003, 1.45, 0, 0, 0.75], + "10217": [0.95003, 1.45, 0, 0, 0.75] + }, + "Size4-Regular": { + "40": [1.25003, 1.75, 0, 0, 0.79167], + "41": [1.25003, 1.75, 0, 0, 0.79167], + "47": [1.25003, 1.75, 0, 0, 1.27778], + "91": [1.25003, 1.75, 0, 0, 0.58334], + "92": [1.25003, 1.75, 0, 0, 1.27778], + "93": [1.25003, 1.75, 0, 0, 0.58334], + "123": [1.25003, 1.75, 0, 0, 0.80556], + "125": [1.25003, 1.75, 0, 0, 0.80556], + "710": [0, 0.825, 0, 0, 1.8889], + "732": [0, 0.825, 0, 0, 1.8889], + "770": [0, 0.825, 0, 0, 1.8889], + "771": [0, 0.825, 0, 0, 1.8889], + "8730": [1.25003, 1.75, 0, 0, 1.0], + "8968": [1.25003, 1.75, 0, 0, 0.63889], + "8969": [1.25003, 1.75, 0, 0, 0.63889], + "8970": [1.25003, 1.75, 0, 0, 0.63889], + "8971": [1.25003, 1.75, 0, 0, 0.63889], + "9115": [0.64502, 1.155, 0, 0, 0.875], + "9116": [1e-05, 0.6, 0, 0, 0.875], + "9117": [0.64502, 1.155, 0, 0, 0.875], + "9118": [0.64502, 1.155, 0, 0, 0.875], + "9119": [1e-05, 0.6, 0, 0, 0.875], + "9120": [0.64502, 1.155, 0, 0, 0.875], + "9121": [0.64502, 1.155, 0, 0, 0.66667], + "9122": [-0.00099, 0.601, 0, 0, 0.66667], + "9123": [0.64502, 1.155, 0, 0, 0.66667], + "9124": [0.64502, 1.155, 0, 0, 0.66667], + "9125": [-0.00099, 0.601, 0, 0, 0.66667], + "9126": [0.64502, 1.155, 0, 0, 0.66667], + "9127": [1e-05, 0.9, 0, 0, 0.88889], + "9128": [0.65002, 1.15, 0, 0, 0.88889], + "9129": [0.90001, 0, 0, 0, 0.88889], + "9130": [0, 0.3, 0, 0, 0.88889], + "9131": [1e-05, 0.9, 0, 0, 0.88889], + "9132": [0.65002, 1.15, 0, 0, 0.88889], + "9133": [0.90001, 0, 0, 0, 0.88889], + "9143": [0.88502, 0.915, 0, 0, 1.05556], + "10216": [1.25003, 1.75, 0, 0, 0.80556], + "10217": [1.25003, 1.75, 0, 0, 0.80556], + "57344": [-0.00499, 0.605, 0, 0, 1.05556], + "57345": [-0.00499, 0.605, 0, 0, 1.05556], + "57680": [0, 0.12, 0, 0, 0.45], + "57681": [0, 0.12, 0, 0, 0.45], + "57682": [0, 0.12, 0, 0, 0.45], + "57683": [0, 0.12, 0, 0, 0.45] + }, + "Typewriter-Regular": { + "32": [0, 0, 0, 0, 0.525], + "33": [0, 0.61111, 0, 0, 0.525], + "34": [0, 0.61111, 0, 0, 0.525], + "35": [0, 0.61111, 0, 0, 0.525], + "36": [0.08333, 0.69444, 0, 0, 0.525], + "37": [0.08333, 0.69444, 0, 0, 0.525], + "38": [0, 0.61111, 0, 0, 0.525], + "39": [0, 0.61111, 0, 0, 0.525], + "40": [0.08333, 0.69444, 0, 0, 0.525], + "41": [0.08333, 0.69444, 0, 0, 0.525], + "42": [0, 0.52083, 0, 0, 0.525], + "43": [-0.08056, 0.53055, 0, 0, 0.525], + "44": [0.13889, 0.125, 0, 0, 0.525], + "45": [-0.08056, 0.53055, 0, 0, 0.525], + "46": [0, 0.125, 0, 0, 0.525], + "47": [0.08333, 0.69444, 0, 0, 0.525], + "48": [0, 0.61111, 0, 0, 0.525], + "49": [0, 0.61111, 0, 0, 0.525], + "50": [0, 0.61111, 0, 0, 0.525], + "51": [0, 0.61111, 0, 0, 0.525], + "52": [0, 0.61111, 0, 0, 0.525], + "53": [0, 0.61111, 0, 0, 0.525], + "54": [0, 0.61111, 0, 0, 0.525], + "55": [0, 0.61111, 0, 0, 0.525], + "56": [0, 0.61111, 0, 0, 0.525], + "57": [0, 0.61111, 0, 0, 0.525], + "58": [0, 0.43056, 0, 0, 0.525], + "59": [0.13889, 0.43056, 0, 0, 0.525], + "60": [-0.05556, 0.55556, 0, 0, 0.525], + "61": [-0.19549, 0.41562, 0, 0, 0.525], + "62": [-0.05556, 0.55556, 0, 0, 0.525], + "63": [0, 0.61111, 0, 0, 0.525], + "64": [0, 0.61111, 0, 0, 0.525], + "65": [0, 0.61111, 0, 0, 0.525], + "66": [0, 0.61111, 0, 0, 0.525], + "67": [0, 0.61111, 0, 0, 0.525], + "68": [0, 0.61111, 0, 0, 0.525], + "69": [0, 0.61111, 0, 0, 0.525], + "70": [0, 0.61111, 0, 0, 0.525], + "71": [0, 0.61111, 0, 0, 0.525], + "72": [0, 0.61111, 0, 0, 0.525], + "73": [0, 0.61111, 0, 0, 0.525], + "74": [0, 0.61111, 0, 0, 0.525], + "75": [0, 0.61111, 0, 0, 0.525], + "76": [0, 0.61111, 0, 0, 0.525], + "77": [0, 0.61111, 0, 0, 0.525], + "78": [0, 0.61111, 0, 0, 0.525], + "79": [0, 0.61111, 0, 0, 0.525], + "80": [0, 0.61111, 0, 0, 0.525], + "81": [0.13889, 0.61111, 0, 0, 0.525], + "82": [0, 0.61111, 0, 0, 0.525], + "83": [0, 0.61111, 0, 0, 0.525], + "84": [0, 0.61111, 0, 0, 0.525], + "85": [0, 0.61111, 0, 0, 0.525], + "86": [0, 0.61111, 0, 0, 0.525], + "87": [0, 0.61111, 0, 0, 0.525], + "88": [0, 0.61111, 0, 0, 0.525], + "89": [0, 0.61111, 0, 0, 0.525], + "90": [0, 0.61111, 0, 0, 0.525], + "91": [0.08333, 0.69444, 0, 0, 0.525], + "92": [0.08333, 0.69444, 0, 0, 0.525], + "93": [0.08333, 0.69444, 0, 0, 0.525], + "94": [0, 0.61111, 0, 0, 0.525], + "95": [0.09514, 0, 0, 0, 0.525], + "96": [0, 0.61111, 0, 0, 0.525], + "97": [0, 0.43056, 0, 0, 0.525], + "98": [0, 0.61111, 0, 0, 0.525], + "99": [0, 0.43056, 0, 0, 0.525], + "100": [0, 0.61111, 0, 0, 0.525], + "101": [0, 0.43056, 0, 0, 0.525], + "102": [0, 0.61111, 0, 0, 0.525], + "103": [0.22222, 0.43056, 0, 0, 0.525], + "104": [0, 0.61111, 0, 0, 0.525], + "105": [0, 0.61111, 0, 0, 0.525], + "106": [0.22222, 0.61111, 0, 0, 0.525], + "107": [0, 0.61111, 0, 0, 0.525], + "108": [0, 0.61111, 0, 0, 0.525], + "109": [0, 0.43056, 0, 0, 0.525], + "110": [0, 0.43056, 0, 0, 0.525], + "111": [0, 0.43056, 0, 0, 0.525], + "112": [0.22222, 0.43056, 0, 0, 0.525], + "113": [0.22222, 0.43056, 0, 0, 0.525], + "114": [0, 0.43056, 0, 0, 0.525], + "115": [0, 0.43056, 0, 0, 0.525], + "116": [0, 0.55358, 0, 0, 0.525], + "117": [0, 0.43056, 0, 0, 0.525], + "118": [0, 0.43056, 0, 0, 0.525], + "119": [0, 0.43056, 0, 0, 0.525], + "120": [0, 0.43056, 0, 0, 0.525], + "121": [0.22222, 0.43056, 0, 0, 0.525], + "122": [0, 0.43056, 0, 0, 0.525], + "123": [0.08333, 0.69444, 0, 0, 0.525], + "124": [0.08333, 0.69444, 0, 0, 0.525], + "125": [0.08333, 0.69444, 0, 0, 0.525], + "126": [0, 0.61111, 0, 0, 0.525], + "127": [0, 0.61111, 0, 0, 0.525], + "160": [0, 0, 0, 0, 0.525], + "176": [0, 0.61111, 0, 0, 0.525], + "184": [0.19445, 0, 0, 0, 0.525], + "305": [0, 0.43056, 0, 0, 0.525], + "567": [0.22222, 0.43056, 0, 0, 0.525], + "711": [0, 0.56597, 0, 0, 0.525], + "713": [0, 0.56555, 0, 0, 0.525], + "714": [0, 0.61111, 0, 0, 0.525], + "715": [0, 0.61111, 0, 0, 0.525], + "728": [0, 0.61111, 0, 0, 0.525], + "730": [0, 0.61111, 0, 0, 0.525], + "770": [0, 0.61111, 0, 0, 0.525], + "771": [0, 0.61111, 0, 0, 0.525], + "776": [0, 0.61111, 0, 0, 0.525], + "915": [0, 0.61111, 0, 0, 0.525], + "916": [0, 0.61111, 0, 0, 0.525], + "920": [0, 0.61111, 0, 0, 0.525], + "923": [0, 0.61111, 0, 0, 0.525], + "926": [0, 0.61111, 0, 0, 0.525], + "928": [0, 0.61111, 0, 0, 0.525], + "931": [0, 0.61111, 0, 0, 0.525], + "933": [0, 0.61111, 0, 0, 0.525], + "934": [0, 0.61111, 0, 0, 0.525], + "936": [0, 0.61111, 0, 0, 0.525], + "937": [0, 0.61111, 0, 0, 0.525], + "8216": [0, 0.61111, 0, 0, 0.525], + "8217": [0, 0.61111, 0, 0, 0.525], + "8242": [0, 0.61111, 0, 0, 0.525], + "9251": [0.11111, 0.21944, 0, 0, 0.525] + } +}; + +/** + * This file contains metrics regarding fonts and individual symbols. The sigma + * and xi variables, as well as the metricMap map contain data extracted from + * TeX, TeX font metrics, and the TTF files. These data are then exposed via the + * `metrics` variable and the getCharacterMetrics function. + */ +// In TeX, there are actually three sets of dimensions, one for each of +// textstyle (size index 5 and higher: >=9pt), scriptstyle (size index 3 and 4: +// 7-8pt), and scriptscriptstyle (size index 1 and 2: 5-6pt). These are +// provided in the the arrays below, in that order. +// +// The font metrics are stored in fonts cmsy10, cmsy7, and cmsy5 respsectively. +// This was determined by running the following script: +// +// latex -interaction=nonstopmode \ +// '\documentclass{article}\usepackage{amsmath}\begin{document}' \ +// '$a$ \expandafter\show\the\textfont2' \ +// '\expandafter\show\the\scriptfont2' \ +// '\expandafter\show\the\scriptscriptfont2' \ +// '\stop' +// +// The metrics themselves were retreived using the following commands: +// +// tftopl cmsy10 +// tftopl cmsy7 +// tftopl cmsy5 +// +// The output of each of these commands is quite lengthy. The only part we +// care about is the FONTDIMEN section. Each value is measured in EMs. +const sigmasAndXis = { + slant: [0.250, 0.250, 0.250], + // sigma1 + space: [0.000, 0.000, 0.000], + // sigma2 + stretch: [0.000, 0.000, 0.000], + // sigma3 + shrink: [0.000, 0.000, 0.000], + // sigma4 + xHeight: [0.431, 0.431, 0.431], + // sigma5 + quad: [1.000, 1.171, 1.472], + // sigma6 + extraSpace: [0.000, 0.000, 0.000], + // sigma7 + num1: [0.677, 0.732, 0.925], + // sigma8 + num2: [0.394, 0.384, 0.387], + // sigma9 + num3: [0.444, 0.471, 0.504], + // sigma10 + denom1: [0.686, 0.752, 1.025], + // sigma11 + denom2: [0.345, 0.344, 0.532], + // sigma12 + sup1: [0.413, 0.503, 0.504], + // sigma13 + sup2: [0.363, 0.431, 0.404], + // sigma14 + sup3: [0.289, 0.286, 0.294], + // sigma15 + sub1: [0.150, 0.143, 0.200], + // sigma16 + sub2: [0.247, 0.286, 0.400], + // sigma17 + supDrop: [0.386, 0.353, 0.494], + // sigma18 + subDrop: [0.050, 0.071, 0.100], + // sigma19 + delim1: [2.390, 1.700, 1.980], + // sigma20 + delim2: [1.010, 1.157, 1.420], + // sigma21 + axisHeight: [0.250, 0.250, 0.250], + // sigma22 + // These font metrics are extracted from TeX by using tftopl on cmex10.tfm; + // they correspond to the font parameters of the extension fonts (family 3). + // See the TeXbook, page 441. In AMSTeX, the extension fonts scale; to + // match cmex7, we'd use cmex7.tfm values for script and scriptscript + // values. + defaultRuleThickness: [0.04, 0.049, 0.049], + // xi8; cmex7: 0.049 + bigOpSpacing1: [0.111, 0.111, 0.111], + // xi9 + bigOpSpacing2: [0.166, 0.166, 0.166], + // xi10 + bigOpSpacing3: [0.2, 0.2, 0.2], + // xi11 + bigOpSpacing4: [0.6, 0.611, 0.611], + // xi12; cmex7: 0.611 + bigOpSpacing5: [0.1, 0.143, 0.143], + // xi13; cmex7: 0.143 + // The \sqrt rule width is taken from the height of the surd character. + // Since we use the same font at all sizes, this thickness doesn't scale. + sqrtRuleThickness: [0.04, 0.04, 0.04], + // This value determines how large a pt is, for metrics which are defined + // in terms of pts. + // This value is also used in katex.less; if you change it make sure the + // values match. + ptPerEm: [10.0, 10.0, 10.0], + // The space between adjacent `|` columns in an array definition. From + // `\showthe\doublerulesep` in LaTeX. Equals 2.0 / ptPerEm. + doubleRuleSep: [0.2, 0.2, 0.2], + // The width of separator lines in {array} environments. From + // `\showthe\arrayrulewidth` in LaTeX. Equals 0.4 / ptPerEm. + arrayRuleWidth: [0.04, 0.04, 0.04], + // Two values from LaTeX source2e: + fboxsep: [0.3, 0.3, 0.3], + // 3 pt / ptPerEm + fboxrule: [0.04, 0.04, 0.04] // 0.4 pt / ptPerEm + +}; // This map contains a mapping from font name and character code to character +// should have Latin-1 and Cyrillic characters, but may not depending on the +// operating system. The metrics do not account for extra height from the +// accents. In the case of Cyrillic characters which have both ascenders and +// descenders we prefer approximations with ascenders, primarily to prevent +// the fraction bar or root line from intersecting the glyph. +// TODO(kevinb) allow union of multiple glyph metrics for better accuracy. + +const extraCharacterMap = { + // Latin-1 + 'Å': 'A', + 'Ç': 'C', + 'Ð': 'D', + 'Þ': 'o', + 'å': 'a', + 'ç': 'c', + 'ð': 'd', + 'þ': 'o', + // Cyrillic + 'А': 'A', + 'Б': 'B', + 'В': 'B', + 'Г': 'F', + 'Д': 'A', + 'Е': 'E', + 'Ж': 'K', + 'З': '3', + 'И': 'N', + 'Й': 'N', + 'К': 'K', + 'Л': 'N', + 'М': 'M', + 'Н': 'H', + 'О': 'O', + 'П': 'N', + 'Р': 'P', + 'С': 'C', + 'Т': 'T', + 'У': 'y', + 'Ф': 'O', + 'Х': 'X', + 'Ц': 'U', + 'Ч': 'h', + 'Ш': 'W', + 'Щ': 'W', + 'Ъ': 'B', + 'Ы': 'X', + 'Ь': 'B', + 'Э': '3', + 'Ю': 'X', + 'Я': 'R', + 'а': 'a', + 'б': 'b', + 'в': 'a', + 'г': 'r', + 'д': 'y', + 'е': 'e', + 'ж': 'm', + 'з': 'e', + 'и': 'n', + 'й': 'n', + 'к': 'n', + 'л': 'n', + 'м': 'm', + 'н': 'n', + 'о': 'o', + 'п': 'n', + 'р': 'p', + 'с': 'c', + 'т': 'o', + 'у': 'y', + 'ф': 'b', + 'х': 'x', + 'ц': 'n', + 'ч': 'n', + 'ш': 'w', + 'щ': 'w', + 'ъ': 'a', + 'ы': 'm', + 'ь': 'a', + 'э': 'e', + 'ю': 'm', + 'я': 'r' +}; + +/** + * This function adds new font metrics to default metricMap + * It can also override existing metrics + */ +function setFontMetrics(fontName, metrics) { + metricMap[fontName] = metrics; +} +/** + * This function is a convenience function for looking up information in the + * metricMap table. It takes a character as a string, and a font. + * + * Note: the `width` property may be undefined if fontMetricsData.js wasn't + * built using `Make extended_metrics`. + */ + +function getCharacterMetrics(character, font, mode) { + if (!metricMap[font]) { + throw new Error(`Font metrics not found for font: ${font}.`); + } + + let ch = character.charCodeAt(0); + let metrics = metricMap[font][ch]; + + if (!metrics && character[0] in extraCharacterMap) { + ch = extraCharacterMap[character[0]].charCodeAt(0); + metrics = metricMap[font][ch]; + } + + if (!metrics && mode === 'text') { + // We don't typically have font metrics for Asian scripts. + // But since we support them in text mode, we need to return + // some sort of metrics. + // So if the character is in a script we support but we + // don't have metrics for it, just use the metrics for + // the Latin capital letter M. This is close enough because + // we (currently) only care about the height of the glpyh + // not its width. + if (supportedCodepoint(ch)) { + metrics = metricMap[font][77]; // 77 is the charcode for 'M' + } + } + + if (metrics) { + return { + depth: metrics[0], + height: metrics[1], + italic: metrics[2], + skew: metrics[3], + width: metrics[4] + }; + } +} +const fontMetricsBySizeIndex = {}; +/** + * Get the font metrics for a given size. + */ + +function getGlobalMetrics(size) { + let sizeIndex; + + if (size >= 5) { + sizeIndex = 0; + } else if (size >= 3) { + sizeIndex = 1; + } else { + sizeIndex = 2; + } + + if (!fontMetricsBySizeIndex[sizeIndex]) { + const metrics = fontMetricsBySizeIndex[sizeIndex] = { + cssEmPerMu: sigmasAndXis.quad[sizeIndex] / 18 + }; + + for (const key in sigmasAndXis) { + if (sigmasAndXis.hasOwnProperty(key)) { + metrics[key] = sigmasAndXis[key][sizeIndex]; + } + } + } + + return fontMetricsBySizeIndex[sizeIndex]; +} + +/** + * This file holds a list of all no-argument functions and single-character + * symbols (like 'a' or ';'). + * + * For each of the symbols, there are three properties they can have: + * - font (required): the font to be used for this symbol. Either "main" (the + normal font), or "ams" (the ams fonts). + * - group (required): the ParseNode group type the symbol should have (i.e. + "textord", "mathord", etc). + See https://github.com/KaTeX/KaTeX/wiki/Examining-TeX#group-types + * - replace: the character that this symbol or function should be + * replaced with (i.e. "\phi" has a replace value of "\u03d5", the phi + * character in the main font). + * + * The outermost map in the table indicates what mode the symbols should be + * accepted in (e.g. "math" or "text"). + */ +// Some of these have a "-token" suffix since these are also used as `ParseNode` +// types for raw text tokens, and we want to avoid conflicts with higher-level +// `ParseNode` types. These `ParseNode`s are constructed within `Parser` by +// looking up the `symbols` map. +const ATOMS = { + "bin": 1, + "close": 1, + "inner": 1, + "open": 1, + "punct": 1, + "rel": 1 +}; +const NON_ATOMS = { + "accent-token": 1, + "mathord": 1, + "op-token": 1, + "spacing": 1, + "textord": 1 +}; +const symbols = { + "math": {}, + "text": {} +}; +/** `acceptUnicodeChar = true` is only applicable if `replace` is set. */ + +function defineSymbol(mode, font, group, replace, name, acceptUnicodeChar) { + symbols[mode][name] = { + font, + group, + replace + }; + + if (acceptUnicodeChar && replace) { + symbols[mode][replace] = symbols[mode][name]; + } +} // Some abbreviations for commonly used strings. +// This helps minify the code, and also spotting typos using jshint. +// modes: + +const math = "math"; +const text$1 = "text"; // fonts: + +const main = "main"; +const ams = "ams"; // groups: + +const accent = "accent-token"; +const bin = "bin"; +const close = "close"; +const inner = "inner"; +const mathord = "mathord"; +const op = "op-token"; +const open = "open"; +const punct = "punct"; +const rel = "rel"; +const spacing = "spacing"; +const textord = "textord"; // Now comes the symbol table +// Relation Symbols + +defineSymbol(math, main, rel, "\u2261", "\\equiv", true); +defineSymbol(math, main, rel, "\u227a", "\\prec", true); +defineSymbol(math, main, rel, "\u227b", "\\succ", true); +defineSymbol(math, main, rel, "\u223c", "\\sim", true); +defineSymbol(math, main, rel, "\u22a5", "\\perp"); +defineSymbol(math, main, rel, "\u2aaf", "\\preceq", true); +defineSymbol(math, main, rel, "\u2ab0", "\\succeq", true); +defineSymbol(math, main, rel, "\u2243", "\\simeq", true); +defineSymbol(math, main, rel, "\u2223", "\\mid", true); +defineSymbol(math, main, rel, "\u226a", "\\ll", true); +defineSymbol(math, main, rel, "\u226b", "\\gg", true); +defineSymbol(math, main, rel, "\u224d", "\\asymp", true); +defineSymbol(math, main, rel, "\u2225", "\\parallel"); +defineSymbol(math, main, rel, "\u22c8", "\\bowtie", true); +defineSymbol(math, main, rel, "\u2323", "\\smile", true); +defineSymbol(math, main, rel, "\u2291", "\\sqsubseteq", true); +defineSymbol(math, main, rel, "\u2292", "\\sqsupseteq", true); +defineSymbol(math, main, rel, "\u2250", "\\doteq", true); +defineSymbol(math, main, rel, "\u2322", "\\frown", true); +defineSymbol(math, main, rel, "\u220b", "\\ni", true); +defineSymbol(math, main, rel, "\u221d", "\\propto", true); +defineSymbol(math, main, rel, "\u22a2", "\\vdash", true); +defineSymbol(math, main, rel, "\u22a3", "\\dashv", true); +defineSymbol(math, main, rel, "\u220b", "\\owns"); // Punctuation + +defineSymbol(math, main, punct, "\u002e", "\\ldotp"); +defineSymbol(math, main, punct, "\u22c5", "\\cdotp"); // Misc Symbols + +defineSymbol(math, main, textord, "\u0023", "\\#"); +defineSymbol(text$1, main, textord, "\u0023", "\\#"); +defineSymbol(math, main, textord, "\u0026", "\\&"); +defineSymbol(text$1, main, textord, "\u0026", "\\&"); +defineSymbol(math, main, textord, "\u2135", "\\aleph", true); +defineSymbol(math, main, textord, "\u2200", "\\forall", true); +defineSymbol(math, main, textord, "\u210f", "\\hbar", true); +defineSymbol(math, main, textord, "\u2203", "\\exists", true); +defineSymbol(math, main, textord, "\u2207", "\\nabla", true); +defineSymbol(math, main, textord, "\u266d", "\\flat", true); +defineSymbol(math, main, textord, "\u2113", "\\ell", true); +defineSymbol(math, main, textord, "\u266e", "\\natural", true); +defineSymbol(math, main, textord, "\u2663", "\\clubsuit", true); +defineSymbol(math, main, textord, "\u2118", "\\wp", true); +defineSymbol(math, main, textord, "\u266f", "\\sharp", true); +defineSymbol(math, main, textord, "\u2662", "\\diamondsuit", true); +defineSymbol(math, main, textord, "\u211c", "\\Re", true); +defineSymbol(math, main, textord, "\u2661", "\\heartsuit", true); +defineSymbol(math, main, textord, "\u2111", "\\Im", true); +defineSymbol(math, main, textord, "\u2660", "\\spadesuit", true); +defineSymbol(text$1, main, textord, "\u00a7", "\\S", true); +defineSymbol(text$1, main, textord, "\u00b6", "\\P", true); // Math and Text + +defineSymbol(math, main, textord, "\u2020", "\\dag"); +defineSymbol(text$1, main, textord, "\u2020", "\\dag"); +defineSymbol(text$1, main, textord, "\u2020", "\\textdagger"); +defineSymbol(math, main, textord, "\u2021", "\\ddag"); +defineSymbol(text$1, main, textord, "\u2021", "\\ddag"); +defineSymbol(text$1, main, textord, "\u2021", "\\textdaggerdbl"); // Large Delimiters + +defineSymbol(math, main, close, "\u23b1", "\\rmoustache", true); +defineSymbol(math, main, open, "\u23b0", "\\lmoustache", true); +defineSymbol(math, main, close, "\u27ef", "\\rgroup", true); +defineSymbol(math, main, open, "\u27ee", "\\lgroup", true); // Binary Operators + +defineSymbol(math, main, bin, "\u2213", "\\mp", true); +defineSymbol(math, main, bin, "\u2296", "\\ominus", true); +defineSymbol(math, main, bin, "\u228e", "\\uplus", true); +defineSymbol(math, main, bin, "\u2293", "\\sqcap", true); +defineSymbol(math, main, bin, "\u2217", "\\ast"); +defineSymbol(math, main, bin, "\u2294", "\\sqcup", true); +defineSymbol(math, main, bin, "\u25ef", "\\bigcirc"); +defineSymbol(math, main, bin, "\u2219", "\\bullet"); +defineSymbol(math, main, bin, "\u2021", "\\ddagger"); +defineSymbol(math, main, bin, "\u2240", "\\wr", true); +defineSymbol(math, main, bin, "\u2a3f", "\\amalg"); +defineSymbol(math, main, bin, "\u0026", "\\And"); // from amsmath +// Arrow Symbols + +defineSymbol(math, main, rel, "\u27f5", "\\longleftarrow", true); +defineSymbol(math, main, rel, "\u21d0", "\\Leftarrow", true); +defineSymbol(math, main, rel, "\u27f8", "\\Longleftarrow", true); +defineSymbol(math, main, rel, "\u27f6", "\\longrightarrow", true); +defineSymbol(math, main, rel, "\u21d2", "\\Rightarrow", true); +defineSymbol(math, main, rel, "\u27f9", "\\Longrightarrow", true); +defineSymbol(math, main, rel, "\u2194", "\\leftrightarrow", true); +defineSymbol(math, main, rel, "\u27f7", "\\longleftrightarrow", true); +defineSymbol(math, main, rel, "\u21d4", "\\Leftrightarrow", true); +defineSymbol(math, main, rel, "\u27fa", "\\Longleftrightarrow", true); +defineSymbol(math, main, rel, "\u21a6", "\\mapsto", true); +defineSymbol(math, main, rel, "\u27fc", "\\longmapsto", true); +defineSymbol(math, main, rel, "\u2197", "\\nearrow", true); +defineSymbol(math, main, rel, "\u21a9", "\\hookleftarrow", true); +defineSymbol(math, main, rel, "\u21aa", "\\hookrightarrow", true); +defineSymbol(math, main, rel, "\u2198", "\\searrow", true); +defineSymbol(math, main, rel, "\u21bc", "\\leftharpoonup", true); +defineSymbol(math, main, rel, "\u21c0", "\\rightharpoonup", true); +defineSymbol(math, main, rel, "\u2199", "\\swarrow", true); +defineSymbol(math, main, rel, "\u21bd", "\\leftharpoondown", true); +defineSymbol(math, main, rel, "\u21c1", "\\rightharpoondown", true); +defineSymbol(math, main, rel, "\u2196", "\\nwarrow", true); +defineSymbol(math, main, rel, "\u21cc", "\\rightleftharpoons", true); // AMS Negated Binary Relations + +defineSymbol(math, ams, rel, "\u226e", "\\nless", true); // Symbol names preceeded by "@" each have a corresponding macro. + +defineSymbol(math, ams, rel, "\ue010", "\\@nleqslant"); +defineSymbol(math, ams, rel, "\ue011", "\\@nleqq"); +defineSymbol(math, ams, rel, "\u2a87", "\\lneq", true); +defineSymbol(math, ams, rel, "\u2268", "\\lneqq", true); +defineSymbol(math, ams, rel, "\ue00c", "\\@lvertneqq"); +defineSymbol(math, ams, rel, "\u22e6", "\\lnsim", true); +defineSymbol(math, ams, rel, "\u2a89", "\\lnapprox", true); +defineSymbol(math, ams, rel, "\u2280", "\\nprec", true); // unicode-math maps \u22e0 to \npreccurlyeq. We'll use the AMS synonym. + +defineSymbol(math, ams, rel, "\u22e0", "\\npreceq", true); +defineSymbol(math, ams, rel, "\u22e8", "\\precnsim", true); +defineSymbol(math, ams, rel, "\u2ab9", "\\precnapprox", true); +defineSymbol(math, ams, rel, "\u2241", "\\nsim", true); +defineSymbol(math, ams, rel, "\ue006", "\\@nshortmid"); +defineSymbol(math, ams, rel, "\u2224", "\\nmid", true); +defineSymbol(math, ams, rel, "\u22ac", "\\nvdash", true); +defineSymbol(math, ams, rel, "\u22ad", "\\nvDash", true); +defineSymbol(math, ams, rel, "\u22ea", "\\ntriangleleft"); +defineSymbol(math, ams, rel, "\u22ec", "\\ntrianglelefteq", true); +defineSymbol(math, ams, rel, "\u228a", "\\subsetneq", true); +defineSymbol(math, ams, rel, "\ue01a", "\\@varsubsetneq"); +defineSymbol(math, ams, rel, "\u2acb", "\\subsetneqq", true); +defineSymbol(math, ams, rel, "\ue017", "\\@varsubsetneqq"); +defineSymbol(math, ams, rel, "\u226f", "\\ngtr", true); +defineSymbol(math, ams, rel, "\ue00f", "\\@ngeqslant"); +defineSymbol(math, ams, rel, "\ue00e", "\\@ngeqq"); +defineSymbol(math, ams, rel, "\u2a88", "\\gneq", true); +defineSymbol(math, ams, rel, "\u2269", "\\gneqq", true); +defineSymbol(math, ams, rel, "\ue00d", "\\@gvertneqq"); +defineSymbol(math, ams, rel, "\u22e7", "\\gnsim", true); +defineSymbol(math, ams, rel, "\u2a8a", "\\gnapprox", true); +defineSymbol(math, ams, rel, "\u2281", "\\nsucc", true); // unicode-math maps \u22e1 to \nsucccurlyeq. We'll use the AMS synonym. + +defineSymbol(math, ams, rel, "\u22e1", "\\nsucceq", true); +defineSymbol(math, ams, rel, "\u22e9", "\\succnsim", true); +defineSymbol(math, ams, rel, "\u2aba", "\\succnapprox", true); // unicode-math maps \u2246 to \simneqq. We'll use the AMS synonym. + +defineSymbol(math, ams, rel, "\u2246", "\\ncong", true); +defineSymbol(math, ams, rel, "\ue007", "\\@nshortparallel"); +defineSymbol(math, ams, rel, "\u2226", "\\nparallel", true); +defineSymbol(math, ams, rel, "\u22af", "\\nVDash", true); +defineSymbol(math, ams, rel, "\u22eb", "\\ntriangleright"); +defineSymbol(math, ams, rel, "\u22ed", "\\ntrianglerighteq", true); +defineSymbol(math, ams, rel, "\ue018", "\\@nsupseteqq"); +defineSymbol(math, ams, rel, "\u228b", "\\supsetneq", true); +defineSymbol(math, ams, rel, "\ue01b", "\\@varsupsetneq"); +defineSymbol(math, ams, rel, "\u2acc", "\\supsetneqq", true); +defineSymbol(math, ams, rel, "\ue019", "\\@varsupsetneqq"); +defineSymbol(math, ams, rel, "\u22ae", "\\nVdash", true); +defineSymbol(math, ams, rel, "\u2ab5", "\\precneqq", true); +defineSymbol(math, ams, rel, "\u2ab6", "\\succneqq", true); +defineSymbol(math, ams, rel, "\ue016", "\\@nsubseteqq"); +defineSymbol(math, ams, bin, "\u22b4", "\\unlhd"); +defineSymbol(math, ams, bin, "\u22b5", "\\unrhd"); // AMS Negated Arrows + +defineSymbol(math, ams, rel, "\u219a", "\\nleftarrow", true); +defineSymbol(math, ams, rel, "\u219b", "\\nrightarrow", true); +defineSymbol(math, ams, rel, "\u21cd", "\\nLeftarrow", true); +defineSymbol(math, ams, rel, "\u21cf", "\\nRightarrow", true); +defineSymbol(math, ams, rel, "\u21ae", "\\nleftrightarrow", true); +defineSymbol(math, ams, rel, "\u21ce", "\\nLeftrightarrow", true); // AMS Misc + +defineSymbol(math, ams, rel, "\u25b3", "\\vartriangle"); +defineSymbol(math, ams, textord, "\u210f", "\\hslash"); +defineSymbol(math, ams, textord, "\u25bd", "\\triangledown"); +defineSymbol(math, ams, textord, "\u25ca", "\\lozenge"); +defineSymbol(math, ams, textord, "\u24c8", "\\circledS"); +defineSymbol(math, ams, textord, "\u00ae", "\\circledR"); +defineSymbol(text$1, ams, textord, "\u00ae", "\\circledR"); +defineSymbol(math, ams, textord, "\u2221", "\\measuredangle", true); +defineSymbol(math, ams, textord, "\u2204", "\\nexists"); +defineSymbol(math, ams, textord, "\u2127", "\\mho"); +defineSymbol(math, ams, textord, "\u2132", "\\Finv", true); +defineSymbol(math, ams, textord, "\u2141", "\\Game", true); +defineSymbol(math, ams, textord, "\u2035", "\\backprime"); +defineSymbol(math, ams, textord, "\u25b2", "\\blacktriangle"); +defineSymbol(math, ams, textord, "\u25bc", "\\blacktriangledown"); +defineSymbol(math, ams, textord, "\u25a0", "\\blacksquare"); +defineSymbol(math, ams, textord, "\u29eb", "\\blacklozenge"); +defineSymbol(math, ams, textord, "\u2605", "\\bigstar"); +defineSymbol(math, ams, textord, "\u2222", "\\sphericalangle", true); +defineSymbol(math, ams, textord, "\u2201", "\\complement", true); // unicode-math maps U+F0 (ð) to \matheth. We map to AMS function \eth + +defineSymbol(math, ams, textord, "\u00f0", "\\eth", true); +defineSymbol(math, ams, textord, "\u2571", "\\diagup"); +defineSymbol(math, ams, textord, "\u2572", "\\diagdown"); +defineSymbol(math, ams, textord, "\u25a1", "\\square"); +defineSymbol(math, ams, textord, "\u25a1", "\\Box"); +defineSymbol(math, ams, textord, "\u25ca", "\\Diamond"); // unicode-math maps U+A5 to \mathyen. We map to AMS function \yen + +defineSymbol(math, ams, textord, "\u00a5", "\\yen", true); +defineSymbol(text$1, ams, textord, "\u00a5", "\\yen", true); +defineSymbol(math, ams, textord, "\u2713", "\\checkmark", true); +defineSymbol(text$1, ams, textord, "\u2713", "\\checkmark"); // AMS Hebrew + +defineSymbol(math, ams, textord, "\u2136", "\\beth", true); +defineSymbol(math, ams, textord, "\u2138", "\\daleth", true); +defineSymbol(math, ams, textord, "\u2137", "\\gimel", true); // AMS Greek + +defineSymbol(math, ams, textord, "\u03dd", "\\digamma", true); +defineSymbol(math, ams, textord, "\u03f0", "\\varkappa"); // AMS Delimiters + +defineSymbol(math, ams, open, "\u250c", "\\ulcorner", true); +defineSymbol(math, ams, close, "\u2510", "\\urcorner", true); +defineSymbol(math, ams, open, "\u2514", "\\llcorner", true); +defineSymbol(math, ams, close, "\u2518", "\\lrcorner", true); // AMS Binary Relations + +defineSymbol(math, ams, rel, "\u2266", "\\leqq", true); +defineSymbol(math, ams, rel, "\u2a7d", "\\leqslant", true); +defineSymbol(math, ams, rel, "\u2a95", "\\eqslantless", true); +defineSymbol(math, ams, rel, "\u2272", "\\lesssim", true); +defineSymbol(math, ams, rel, "\u2a85", "\\lessapprox", true); +defineSymbol(math, ams, rel, "\u224a", "\\approxeq", true); +defineSymbol(math, ams, bin, "\u22d6", "\\lessdot"); +defineSymbol(math, ams, rel, "\u22d8", "\\lll", true); +defineSymbol(math, ams, rel, "\u2276", "\\lessgtr", true); +defineSymbol(math, ams, rel, "\u22da", "\\lesseqgtr", true); +defineSymbol(math, ams, rel, "\u2a8b", "\\lesseqqgtr", true); +defineSymbol(math, ams, rel, "\u2251", "\\doteqdot"); +defineSymbol(math, ams, rel, "\u2253", "\\risingdotseq", true); +defineSymbol(math, ams, rel, "\u2252", "\\fallingdotseq", true); +defineSymbol(math, ams, rel, "\u223d", "\\backsim", true); +defineSymbol(math, ams, rel, "\u22cd", "\\backsimeq", true); +defineSymbol(math, ams, rel, "\u2ac5", "\\subseteqq", true); +defineSymbol(math, ams, rel, "\u22d0", "\\Subset", true); +defineSymbol(math, ams, rel, "\u228f", "\\sqsubset", true); +defineSymbol(math, ams, rel, "\u227c", "\\preccurlyeq", true); +defineSymbol(math, ams, rel, "\u22de", "\\curlyeqprec", true); +defineSymbol(math, ams, rel, "\u227e", "\\precsim", true); +defineSymbol(math, ams, rel, "\u2ab7", "\\precapprox", true); +defineSymbol(math, ams, rel, "\u22b2", "\\vartriangleleft"); +defineSymbol(math, ams, rel, "\u22b4", "\\trianglelefteq"); +defineSymbol(math, ams, rel, "\u22a8", "\\vDash", true); +defineSymbol(math, ams, rel, "\u22aa", "\\Vvdash", true); +defineSymbol(math, ams, rel, "\u2323", "\\smallsmile"); +defineSymbol(math, ams, rel, "\u2322", "\\smallfrown"); +defineSymbol(math, ams, rel, "\u224f", "\\bumpeq", true); +defineSymbol(math, ams, rel, "\u224e", "\\Bumpeq", true); +defineSymbol(math, ams, rel, "\u2267", "\\geqq", true); +defineSymbol(math, ams, rel, "\u2a7e", "\\geqslant", true); +defineSymbol(math, ams, rel, "\u2a96", "\\eqslantgtr", true); +defineSymbol(math, ams, rel, "\u2273", "\\gtrsim", true); +defineSymbol(math, ams, rel, "\u2a86", "\\gtrapprox", true); +defineSymbol(math, ams, bin, "\u22d7", "\\gtrdot"); +defineSymbol(math, ams, rel, "\u22d9", "\\ggg", true); +defineSymbol(math, ams, rel, "\u2277", "\\gtrless", true); +defineSymbol(math, ams, rel, "\u22db", "\\gtreqless", true); +defineSymbol(math, ams, rel, "\u2a8c", "\\gtreqqless", true); +defineSymbol(math, ams, rel, "\u2256", "\\eqcirc", true); +defineSymbol(math, ams, rel, "\u2257", "\\circeq", true); +defineSymbol(math, ams, rel, "\u225c", "\\triangleq", true); +defineSymbol(math, ams, rel, "\u223c", "\\thicksim"); +defineSymbol(math, ams, rel, "\u2248", "\\thickapprox"); +defineSymbol(math, ams, rel, "\u2ac6", "\\supseteqq", true); +defineSymbol(math, ams, rel, "\u22d1", "\\Supset", true); +defineSymbol(math, ams, rel, "\u2290", "\\sqsupset", true); +defineSymbol(math, ams, rel, "\u227d", "\\succcurlyeq", true); +defineSymbol(math, ams, rel, "\u22df", "\\curlyeqsucc", true); +defineSymbol(math, ams, rel, "\u227f", "\\succsim", true); +defineSymbol(math, ams, rel, "\u2ab8", "\\succapprox", true); +defineSymbol(math, ams, rel, "\u22b3", "\\vartriangleright"); +defineSymbol(math, ams, rel, "\u22b5", "\\trianglerighteq"); +defineSymbol(math, ams, rel, "\u22a9", "\\Vdash", true); +defineSymbol(math, ams, rel, "\u2223", "\\shortmid"); +defineSymbol(math, ams, rel, "\u2225", "\\shortparallel"); +defineSymbol(math, ams, rel, "\u226c", "\\between", true); +defineSymbol(math, ams, rel, "\u22d4", "\\pitchfork", true); +defineSymbol(math, ams, rel, "\u221d", "\\varpropto"); +defineSymbol(math, ams, rel, "\u25c0", "\\blacktriangleleft"); // unicode-math says that \therefore is a mathord atom. +// We kept the amssymb atom type, which is rel. + +defineSymbol(math, ams, rel, "\u2234", "\\therefore", true); +defineSymbol(math, ams, rel, "\u220d", "\\backepsilon"); +defineSymbol(math, ams, rel, "\u25b6", "\\blacktriangleright"); // unicode-math says that \because is a mathord atom. +// We kept the amssymb atom type, which is rel. + +defineSymbol(math, ams, rel, "\u2235", "\\because", true); +defineSymbol(math, ams, rel, "\u22d8", "\\llless"); +defineSymbol(math, ams, rel, "\u22d9", "\\gggtr"); +defineSymbol(math, ams, bin, "\u22b2", "\\lhd"); +defineSymbol(math, ams, bin, "\u22b3", "\\rhd"); +defineSymbol(math, ams, rel, "\u2242", "\\eqsim", true); +defineSymbol(math, main, rel, "\u22c8", "\\Join"); +defineSymbol(math, ams, rel, "\u2251", "\\Doteq", true); // AMS Binary Operators + +defineSymbol(math, ams, bin, "\u2214", "\\dotplus", true); +defineSymbol(math, ams, bin, "\u2216", "\\smallsetminus"); +defineSymbol(math, ams, bin, "\u22d2", "\\Cap", true); +defineSymbol(math, ams, bin, "\u22d3", "\\Cup", true); +defineSymbol(math, ams, bin, "\u2a5e", "\\doublebarwedge", true); +defineSymbol(math, ams, bin, "\u229f", "\\boxminus", true); +defineSymbol(math, ams, bin, "\u229e", "\\boxplus", true); +defineSymbol(math, ams, bin, "\u22c7", "\\divideontimes", true); +defineSymbol(math, ams, bin, "\u22c9", "\\ltimes", true); +defineSymbol(math, ams, bin, "\u22ca", "\\rtimes", true); +defineSymbol(math, ams, bin, "\u22cb", "\\leftthreetimes", true); +defineSymbol(math, ams, bin, "\u22cc", "\\rightthreetimes", true); +defineSymbol(math, ams, bin, "\u22cf", "\\curlywedge", true); +defineSymbol(math, ams, bin, "\u22ce", "\\curlyvee", true); +defineSymbol(math, ams, bin, "\u229d", "\\circleddash", true); +defineSymbol(math, ams, bin, "\u229b", "\\circledast", true); +defineSymbol(math, ams, bin, "\u22c5", "\\centerdot"); +defineSymbol(math, ams, bin, "\u22ba", "\\intercal", true); +defineSymbol(math, ams, bin, "\u22d2", "\\doublecap"); +defineSymbol(math, ams, bin, "\u22d3", "\\doublecup"); +defineSymbol(math, ams, bin, "\u22a0", "\\boxtimes", true); // AMS Arrows +// Note: unicode-math maps \u21e2 to their own function \rightdasharrow. +// We'll map it to AMS function \dashrightarrow. It produces the same atom. + +defineSymbol(math, ams, rel, "\u21e2", "\\dashrightarrow", true); // unicode-math maps \u21e0 to \leftdasharrow. We'll use the AMS synonym. + +defineSymbol(math, ams, rel, "\u21e0", "\\dashleftarrow", true); +defineSymbol(math, ams, rel, "\u21c7", "\\leftleftarrows", true); +defineSymbol(math, ams, rel, "\u21c6", "\\leftrightarrows", true); +defineSymbol(math, ams, rel, "\u21da", "\\Lleftarrow", true); +defineSymbol(math, ams, rel, "\u219e", "\\twoheadleftarrow", true); +defineSymbol(math, ams, rel, "\u21a2", "\\leftarrowtail", true); +defineSymbol(math, ams, rel, "\u21ab", "\\looparrowleft", true); +defineSymbol(math, ams, rel, "\u21cb", "\\leftrightharpoons", true); +defineSymbol(math, ams, rel, "\u21b6", "\\curvearrowleft", true); // unicode-math maps \u21ba to \acwopencirclearrow. We'll use the AMS synonym. + +defineSymbol(math, ams, rel, "\u21ba", "\\circlearrowleft", true); +defineSymbol(math, ams, rel, "\u21b0", "\\Lsh", true); +defineSymbol(math, ams, rel, "\u21c8", "\\upuparrows", true); +defineSymbol(math, ams, rel, "\u21bf", "\\upharpoonleft", true); +defineSymbol(math, ams, rel, "\u21c3", "\\downharpoonleft", true); +defineSymbol(math, ams, rel, "\u22b8", "\\multimap", true); +defineSymbol(math, ams, rel, "\u21ad", "\\leftrightsquigarrow", true); +defineSymbol(math, ams, rel, "\u21c9", "\\rightrightarrows", true); +defineSymbol(math, ams, rel, "\u21c4", "\\rightleftarrows", true); +defineSymbol(math, ams, rel, "\u21a0", "\\twoheadrightarrow", true); +defineSymbol(math, ams, rel, "\u21a3", "\\rightarrowtail", true); +defineSymbol(math, ams, rel, "\u21ac", "\\looparrowright", true); +defineSymbol(math, ams, rel, "\u21b7", "\\curvearrowright", true); // unicode-math maps \u21bb to \cwopencirclearrow. We'll use the AMS synonym. + +defineSymbol(math, ams, rel, "\u21bb", "\\circlearrowright", true); +defineSymbol(math, ams, rel, "\u21b1", "\\Rsh", true); +defineSymbol(math, ams, rel, "\u21ca", "\\downdownarrows", true); +defineSymbol(math, ams, rel, "\u21be", "\\upharpoonright", true); +defineSymbol(math, ams, rel, "\u21c2", "\\downharpoonright", true); +defineSymbol(math, ams, rel, "\u21dd", "\\rightsquigarrow", true); +defineSymbol(math, ams, rel, "\u21dd", "\\leadsto"); +defineSymbol(math, ams, rel, "\u21db", "\\Rrightarrow", true); +defineSymbol(math, ams, rel, "\u21be", "\\restriction"); +defineSymbol(math, main, textord, "\u2018", "`"); +defineSymbol(math, main, textord, "$", "\\$"); +defineSymbol(text$1, main, textord, "$", "\\$"); +defineSymbol(text$1, main, textord, "$", "\\textdollar"); +defineSymbol(math, main, textord, "%", "\\%"); +defineSymbol(text$1, main, textord, "%", "\\%"); +defineSymbol(math, main, textord, "_", "\\_"); +defineSymbol(text$1, main, textord, "_", "\\_"); +defineSymbol(text$1, main, textord, "_", "\\textunderscore"); +defineSymbol(math, main, textord, "\u2220", "\\angle", true); +defineSymbol(math, main, textord, "\u221e", "\\infty", true); +defineSymbol(math, main, textord, "\u2032", "\\prime"); +defineSymbol(math, main, textord, "\u25b3", "\\triangle"); +defineSymbol(math, main, textord, "\u0393", "\\Gamma", true); +defineSymbol(math, main, textord, "\u0394", "\\Delta", true); +defineSymbol(math, main, textord, "\u0398", "\\Theta", true); +defineSymbol(math, main, textord, "\u039b", "\\Lambda", true); +defineSymbol(math, main, textord, "\u039e", "\\Xi", true); +defineSymbol(math, main, textord, "\u03a0", "\\Pi", true); +defineSymbol(math, main, textord, "\u03a3", "\\Sigma", true); +defineSymbol(math, main, textord, "\u03a5", "\\Upsilon", true); +defineSymbol(math, main, textord, "\u03a6", "\\Phi", true); +defineSymbol(math, main, textord, "\u03a8", "\\Psi", true); +defineSymbol(math, main, textord, "\u03a9", "\\Omega", true); +defineSymbol(math, main, textord, "A", "\u0391"); +defineSymbol(math, main, textord, "B", "\u0392"); +defineSymbol(math, main, textord, "E", "\u0395"); +defineSymbol(math, main, textord, "Z", "\u0396"); +defineSymbol(math, main, textord, "H", "\u0397"); +defineSymbol(math, main, textord, "I", "\u0399"); +defineSymbol(math, main, textord, "K", "\u039A"); +defineSymbol(math, main, textord, "M", "\u039C"); +defineSymbol(math, main, textord, "N", "\u039D"); +defineSymbol(math, main, textord, "O", "\u039F"); +defineSymbol(math, main, textord, "P", "\u03A1"); +defineSymbol(math, main, textord, "T", "\u03A4"); +defineSymbol(math, main, textord, "X", "\u03A7"); +defineSymbol(math, main, textord, "\u00ac", "\\neg", true); +defineSymbol(math, main, textord, "\u00ac", "\\lnot"); +defineSymbol(math, main, textord, "\u22a4", "\\top"); +defineSymbol(math, main, textord, "\u22a5", "\\bot"); +defineSymbol(math, main, textord, "\u2205", "\\emptyset"); +defineSymbol(math, ams, textord, "\u2205", "\\varnothing"); +defineSymbol(math, main, mathord, "\u03b1", "\\alpha", true); +defineSymbol(math, main, mathord, "\u03b2", "\\beta", true); +defineSymbol(math, main, mathord, "\u03b3", "\\gamma", true); +defineSymbol(math, main, mathord, "\u03b4", "\\delta", true); +defineSymbol(math, main, mathord, "\u03f5", "\\epsilon", true); +defineSymbol(math, main, mathord, "\u03b6", "\\zeta", true); +defineSymbol(math, main, mathord, "\u03b7", "\\eta", true); +defineSymbol(math, main, mathord, "\u03b8", "\\theta", true); +defineSymbol(math, main, mathord, "\u03b9", "\\iota", true); +defineSymbol(math, main, mathord, "\u03ba", "\\kappa", true); +defineSymbol(math, main, mathord, "\u03bb", "\\lambda", true); +defineSymbol(math, main, mathord, "\u03bc", "\\mu", true); +defineSymbol(math, main, mathord, "\u03bd", "\\nu", true); +defineSymbol(math, main, mathord, "\u03be", "\\xi", true); +defineSymbol(math, main, mathord, "\u03bf", "\\omicron", true); +defineSymbol(math, main, mathord, "\u03c0", "\\pi", true); +defineSymbol(math, main, mathord, "\u03c1", "\\rho", true); +defineSymbol(math, main, mathord, "\u03c3", "\\sigma", true); +defineSymbol(math, main, mathord, "\u03c4", "\\tau", true); +defineSymbol(math, main, mathord, "\u03c5", "\\upsilon", true); +defineSymbol(math, main, mathord, "\u03d5", "\\phi", true); +defineSymbol(math, main, mathord, "\u03c7", "\\chi", true); +defineSymbol(math, main, mathord, "\u03c8", "\\psi", true); +defineSymbol(math, main, mathord, "\u03c9", "\\omega", true); +defineSymbol(math, main, mathord, "\u03b5", "\\varepsilon", true); +defineSymbol(math, main, mathord, "\u03d1", "\\vartheta", true); +defineSymbol(math, main, mathord, "\u03d6", "\\varpi", true); +defineSymbol(math, main, mathord, "\u03f1", "\\varrho", true); +defineSymbol(math, main, mathord, "\u03c2", "\\varsigma", true); +defineSymbol(math, main, mathord, "\u03c6", "\\varphi", true); +defineSymbol(math, main, bin, "\u2217", "*"); +defineSymbol(math, main, bin, "+", "+"); +defineSymbol(math, main, bin, "\u2212", "-"); +defineSymbol(math, main, bin, "\u22c5", "\\cdot", true); +defineSymbol(math, main, bin, "\u2218", "\\circ"); +defineSymbol(math, main, bin, "\u00f7", "\\div", true); +defineSymbol(math, main, bin, "\u00b1", "\\pm", true); +defineSymbol(math, main, bin, "\u00d7", "\\times", true); +defineSymbol(math, main, bin, "\u2229", "\\cap", true); +defineSymbol(math, main, bin, "\u222a", "\\cup", true); +defineSymbol(math, main, bin, "\u2216", "\\setminus"); +defineSymbol(math, main, bin, "\u2227", "\\land"); +defineSymbol(math, main, bin, "\u2228", "\\lor"); +defineSymbol(math, main, bin, "\u2227", "\\wedge", true); +defineSymbol(math, main, bin, "\u2228", "\\vee", true); +defineSymbol(math, main, textord, "\u221a", "\\surd"); +defineSymbol(math, main, open, "(", "("); +defineSymbol(math, main, open, "[", "["); +defineSymbol(math, main, open, "\u27e8", "\\langle", true); +defineSymbol(math, main, open, "\u2223", "\\lvert"); +defineSymbol(math, main, open, "\u2225", "\\lVert"); +defineSymbol(math, main, close, ")", ")"); +defineSymbol(math, main, close, "]", "]"); +defineSymbol(math, main, close, "?", "?"); +defineSymbol(math, main, close, "!", "!"); +defineSymbol(math, main, close, "\u27e9", "\\rangle", true); +defineSymbol(math, main, close, "\u2223", "\\rvert"); +defineSymbol(math, main, close, "\u2225", "\\rVert"); +defineSymbol(math, main, rel, "=", "="); +defineSymbol(math, main, rel, "<", "<"); +defineSymbol(math, main, rel, ">", ">"); +defineSymbol(math, main, rel, ":", ":"); +defineSymbol(math, main, rel, "\u2248", "\\approx", true); +defineSymbol(math, main, rel, "\u2245", "\\cong", true); +defineSymbol(math, main, rel, "\u2265", "\\ge"); +defineSymbol(math, main, rel, "\u2265", "\\geq", true); +defineSymbol(math, main, rel, "\u2190", "\\gets"); +defineSymbol(math, main, rel, ">", "\\gt"); +defineSymbol(math, main, rel, "\u2208", "\\in", true); +defineSymbol(math, main, rel, "\ue020", "\\@not"); +defineSymbol(math, main, rel, "\u2282", "\\subset", true); +defineSymbol(math, main, rel, "\u2283", "\\supset", true); +defineSymbol(math, main, rel, "\u2286", "\\subseteq", true); +defineSymbol(math, main, rel, "\u2287", "\\supseteq", true); +defineSymbol(math, ams, rel, "\u2288", "\\nsubseteq", true); +defineSymbol(math, ams, rel, "\u2289", "\\nsupseteq", true); +defineSymbol(math, main, rel, "\u22a8", "\\models"); +defineSymbol(math, main, rel, "\u2190", "\\leftarrow", true); +defineSymbol(math, main, rel, "\u2264", "\\le"); +defineSymbol(math, main, rel, "\u2264", "\\leq", true); +defineSymbol(math, main, rel, "<", "\\lt"); +defineSymbol(math, main, rel, "\u2192", "\\rightarrow", true); +defineSymbol(math, main, rel, "\u2192", "\\to"); +defineSymbol(math, ams, rel, "\u2271", "\\ngeq", true); +defineSymbol(math, ams, rel, "\u2270", "\\nleq", true); +defineSymbol(math, main, spacing, "\u00a0", "\\ "); +defineSymbol(math, main, spacing, "\u00a0", "~"); +defineSymbol(math, main, spacing, "\u00a0", "\\space"); // Ref: LaTeX Source 2e: \DeclareRobustCommand{\nobreakspace}{% + +defineSymbol(math, main, spacing, "\u00a0", "\\nobreakspace"); +defineSymbol(text$1, main, spacing, "\u00a0", "\\ "); +defineSymbol(text$1, main, spacing, "\u00a0", "~"); +defineSymbol(text$1, main, spacing, "\u00a0", "\\space"); +defineSymbol(text$1, main, spacing, "\u00a0", "\\nobreakspace"); +defineSymbol(math, main, spacing, null, "\\nobreak"); +defineSymbol(math, main, spacing, null, "\\allowbreak"); +defineSymbol(math, main, punct, ",", ","); +defineSymbol(math, main, punct, ";", ";"); +defineSymbol(math, ams, bin, "\u22bc", "\\barwedge", true); +defineSymbol(math, ams, bin, "\u22bb", "\\veebar", true); +defineSymbol(math, main, bin, "\u2299", "\\odot", true); +defineSymbol(math, main, bin, "\u2295", "\\oplus", true); +defineSymbol(math, main, bin, "\u2297", "\\otimes", true); +defineSymbol(math, main, textord, "\u2202", "\\partial", true); +defineSymbol(math, main, bin, "\u2298", "\\oslash", true); +defineSymbol(math, ams, bin, "\u229a", "\\circledcirc", true); +defineSymbol(math, ams, bin, "\u22a1", "\\boxdot", true); +defineSymbol(math, main, bin, "\u25b3", "\\bigtriangleup"); +defineSymbol(math, main, bin, "\u25bd", "\\bigtriangledown"); +defineSymbol(math, main, bin, "\u2020", "\\dagger"); +defineSymbol(math, main, bin, "\u22c4", "\\diamond"); +defineSymbol(math, main, bin, "\u22c6", "\\star"); +defineSymbol(math, main, bin, "\u25c3", "\\triangleleft"); +defineSymbol(math, main, bin, "\u25b9", "\\triangleright"); +defineSymbol(math, main, open, "{", "\\{"); +defineSymbol(text$1, main, textord, "{", "\\{"); +defineSymbol(text$1, main, textord, "{", "\\textbraceleft"); +defineSymbol(math, main, close, "}", "\\}"); +defineSymbol(text$1, main, textord, "}", "\\}"); +defineSymbol(text$1, main, textord, "}", "\\textbraceright"); +defineSymbol(math, main, open, "{", "\\lbrace"); +defineSymbol(math, main, close, "}", "\\rbrace"); +defineSymbol(math, main, open, "[", "\\lbrack"); +defineSymbol(text$1, main, textord, "[", "\\lbrack"); +defineSymbol(math, main, close, "]", "\\rbrack"); +defineSymbol(text$1, main, textord, "]", "\\rbrack"); +defineSymbol(math, main, open, "(", "\\lparen"); +defineSymbol(math, main, close, ")", "\\rparen"); +defineSymbol(text$1, main, textord, "<", "\\textless"); // in T1 fontenc + +defineSymbol(text$1, main, textord, ">", "\\textgreater"); // in T1 fontenc + +defineSymbol(math, main, open, "\u230a", "\\lfloor", true); +defineSymbol(math, main, close, "\u230b", "\\rfloor", true); +defineSymbol(math, main, open, "\u2308", "\\lceil", true); +defineSymbol(math, main, close, "\u2309", "\\rceil", true); +defineSymbol(math, main, textord, "\\", "\\backslash"); +defineSymbol(math, main, textord, "\u2223", "|"); +defineSymbol(math, main, textord, "\u2223", "\\vert"); +defineSymbol(text$1, main, textord, "|", "\\textbar"); // in T1 fontenc + +defineSymbol(math, main, textord, "\u2225", "\\|"); +defineSymbol(math, main, textord, "\u2225", "\\Vert"); +defineSymbol(text$1, main, textord, "\u2225", "\\textbardbl"); +defineSymbol(text$1, main, textord, "~", "\\textasciitilde"); +defineSymbol(text$1, main, textord, "\\", "\\textbackslash"); +defineSymbol(text$1, main, textord, "^", "\\textasciicircum"); +defineSymbol(math, main, rel, "\u2191", "\\uparrow", true); +defineSymbol(math, main, rel, "\u21d1", "\\Uparrow", true); +defineSymbol(math, main, rel, "\u2193", "\\downarrow", true); +defineSymbol(math, main, rel, "\u21d3", "\\Downarrow", true); +defineSymbol(math, main, rel, "\u2195", "\\updownarrow", true); +defineSymbol(math, main, rel, "\u21d5", "\\Updownarrow", true); +defineSymbol(math, main, op, "\u2210", "\\coprod"); +defineSymbol(math, main, op, "\u22c1", "\\bigvee"); +defineSymbol(math, main, op, "\u22c0", "\\bigwedge"); +defineSymbol(math, main, op, "\u2a04", "\\biguplus"); +defineSymbol(math, main, op, "\u22c2", "\\bigcap"); +defineSymbol(math, main, op, "\u22c3", "\\bigcup"); +defineSymbol(math, main, op, "\u222b", "\\int"); +defineSymbol(math, main, op, "\u222b", "\\intop"); +defineSymbol(math, main, op, "\u222c", "\\iint"); +defineSymbol(math, main, op, "\u222d", "\\iiint"); +defineSymbol(math, main, op, "\u220f", "\\prod"); +defineSymbol(math, main, op, "\u2211", "\\sum"); +defineSymbol(math, main, op, "\u2a02", "\\bigotimes"); +defineSymbol(math, main, op, "\u2a01", "\\bigoplus"); +defineSymbol(math, main, op, "\u2a00", "\\bigodot"); +defineSymbol(math, main, op, "\u222e", "\\oint"); +defineSymbol(math, main, op, "\u222f", "\\oiint"); +defineSymbol(math, main, op, "\u2230", "\\oiiint"); +defineSymbol(math, main, op, "\u2a06", "\\bigsqcup"); +defineSymbol(math, main, op, "\u222b", "\\smallint"); +defineSymbol(text$1, main, inner, "\u2026", "\\textellipsis"); +defineSymbol(math, main, inner, "\u2026", "\\mathellipsis"); +defineSymbol(text$1, main, inner, "\u2026", "\\ldots", true); +defineSymbol(math, main, inner, "\u2026", "\\ldots", true); +defineSymbol(math, main, inner, "\u22ef", "\\@cdots", true); +defineSymbol(math, main, inner, "\u22f1", "\\ddots", true); +defineSymbol(math, main, textord, "\u22ee", "\\varvdots"); // \vdots is a macro + +defineSymbol(math, main, accent, "\u02ca", "\\acute"); +defineSymbol(math, main, accent, "\u02cb", "\\grave"); +defineSymbol(math, main, accent, "\u00a8", "\\ddot"); +defineSymbol(math, main, accent, "\u007e", "\\tilde"); +defineSymbol(math, main, accent, "\u02c9", "\\bar"); +defineSymbol(math, main, accent, "\u02d8", "\\breve"); +defineSymbol(math, main, accent, "\u02c7", "\\check"); +defineSymbol(math, main, accent, "\u005e", "\\hat"); +defineSymbol(math, main, accent, "\u20d7", "\\vec"); +defineSymbol(math, main, accent, "\u02d9", "\\dot"); +defineSymbol(math, main, accent, "\u02da", "\\mathring"); +defineSymbol(math, main, mathord, "\u0131", "\\imath", true); +defineSymbol(math, main, mathord, "\u0237", "\\jmath", true); +defineSymbol(text$1, main, textord, "\u0131", "\\i", true); +defineSymbol(text$1, main, textord, "\u0237", "\\j", true); +defineSymbol(text$1, main, textord, "\u00df", "\\ss", true); +defineSymbol(text$1, main, textord, "\u00e6", "\\ae", true); +defineSymbol(text$1, main, textord, "\u00e6", "\\ae", true); +defineSymbol(text$1, main, textord, "\u0153", "\\oe", true); +defineSymbol(text$1, main, textord, "\u00f8", "\\o", true); +defineSymbol(text$1, main, textord, "\u00c6", "\\AE", true); +defineSymbol(text$1, main, textord, "\u0152", "\\OE", true); +defineSymbol(text$1, main, textord, "\u00d8", "\\O", true); +defineSymbol(text$1, main, accent, "\u02ca", "\\'"); // acute + +defineSymbol(text$1, main, accent, "\u02cb", "\\`"); // grave + +defineSymbol(text$1, main, accent, "\u02c6", "\\^"); // circumflex + +defineSymbol(text$1, main, accent, "\u02dc", "\\~"); // tilde + +defineSymbol(text$1, main, accent, "\u02c9", "\\="); // macron + +defineSymbol(text$1, main, accent, "\u02d8", "\\u"); // breve + +defineSymbol(text$1, main, accent, "\u02d9", "\\."); // dot above + +defineSymbol(text$1, main, accent, "\u02da", "\\r"); // ring above + +defineSymbol(text$1, main, accent, "\u02c7", "\\v"); // caron + +defineSymbol(text$1, main, accent, "\u00a8", '\\"'); // diaresis + +defineSymbol(text$1, main, accent, "\u02dd", "\\H"); // double acute + +defineSymbol(text$1, main, accent, "\u25ef", "\\textcircled"); // \bigcirc glyph +// These ligatures are detected and created in Parser.js's `formLigatures`. + +const ligatures = { + "--": true, + "---": true, + "``": true, + "''": true +}; +defineSymbol(text$1, main, textord, "\u2013", "--"); +defineSymbol(text$1, main, textord, "\u2013", "\\textendash"); +defineSymbol(text$1, main, textord, "\u2014", "---"); +defineSymbol(text$1, main, textord, "\u2014", "\\textemdash"); +defineSymbol(text$1, main, textord, "\u2018", "`"); +defineSymbol(text$1, main, textord, "\u2018", "\\textquoteleft"); +defineSymbol(text$1, main, textord, "\u2019", "'"); +defineSymbol(text$1, main, textord, "\u2019", "\\textquoteright"); +defineSymbol(text$1, main, textord, "\u201c", "``"); +defineSymbol(text$1, main, textord, "\u201c", "\\textquotedblleft"); +defineSymbol(text$1, main, textord, "\u201d", "''"); +defineSymbol(text$1, main, textord, "\u201d", "\\textquotedblright"); // \degree from gensymb package + +defineSymbol(math, main, textord, "\u00b0", "\\degree", true); +defineSymbol(text$1, main, textord, "\u00b0", "\\degree"); // \textdegree from inputenc package + +defineSymbol(text$1, main, textord, "\u00b0", "\\textdegree", true); // TODO: In LaTeX, \pounds can generate a different character in text and math +// mode, but among our fonts, only Main-Italic defines this character "163". + +defineSymbol(math, main, mathord, "\u00a3", "\\pounds"); +defineSymbol(math, main, mathord, "\u00a3", "\\mathsterling", true); +defineSymbol(text$1, main, mathord, "\u00a3", "\\pounds"); +defineSymbol(text$1, main, mathord, "\u00a3", "\\textsterling", true); +defineSymbol(math, ams, textord, "\u2720", "\\maltese"); +defineSymbol(text$1, ams, textord, "\u2720", "\\maltese"); +defineSymbol(text$1, main, spacing, "\u00a0", "\\ "); +defineSymbol(text$1, main, spacing, "\u00a0", " "); +defineSymbol(text$1, main, spacing, "\u00a0", "~"); // There are lots of symbols which are the same, so we add them in afterwards. +// All of these are textords in math mode + +const mathTextSymbols = "0123456789/@.\""; + +for (let i = 0; i < mathTextSymbols.length; i++) { + const ch = mathTextSymbols.charAt(i); + defineSymbol(math, main, textord, ch, ch); +} // All of these are textords in text mode + + +const textSymbols = "0123456789!@*()-=+[]<>|\";:?/.,"; + +for (let i = 0; i < textSymbols.length; i++) { + const ch = textSymbols.charAt(i); + defineSymbol(text$1, main, textord, ch, ch); +} // All of these are textords in text mode, and mathords in math mode + + +const letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +for (let i = 0; i < letters.length; i++) { + const ch = letters.charAt(i); + defineSymbol(math, main, mathord, ch, ch); + defineSymbol(text$1, main, textord, ch, ch); +} // Blackboard bold and script letters in Unicode range + + +defineSymbol(math, ams, textord, "C", "\u2102"); // blackboard bold + +defineSymbol(text$1, ams, textord, "C", "\u2102"); +defineSymbol(math, ams, textord, "H", "\u210D"); +defineSymbol(text$1, ams, textord, "H", "\u210D"); +defineSymbol(math, ams, textord, "N", "\u2115"); +defineSymbol(text$1, ams, textord, "N", "\u2115"); +defineSymbol(math, ams, textord, "P", "\u2119"); +defineSymbol(text$1, ams, textord, "P", "\u2119"); +defineSymbol(math, ams, textord, "Q", "\u211A"); +defineSymbol(text$1, ams, textord, "Q", "\u211A"); +defineSymbol(math, ams, textord, "R", "\u211D"); +defineSymbol(text$1, ams, textord, "R", "\u211D"); +defineSymbol(math, ams, textord, "Z", "\u2124"); +defineSymbol(text$1, ams, textord, "Z", "\u2124"); +defineSymbol(math, main, mathord, "h", "\u210E"); // italic h, Planck constant + +defineSymbol(text$1, main, mathord, "h", "\u210E"); // The next loop loads wide (surrogate pair) characters. +// We support some letters in the Unicode range U+1D400 to U+1D7FF, +// Mathematical Alphanumeric Symbols. +// Some editors do not deal well with wide characters. So don't write the +// string into this file. Instead, create the string from the surrogate pair. + +let wideChar = ""; + +for (let i = 0; i < letters.length; i++) { + const ch = letters.charAt(i); // The hex numbers in the next line are a surrogate pair. + // 0xD835 is the high surrogate for all letters in the range we support. + // 0xDC00 is the low surrogate for bold A. + + wideChar = String.fromCharCode(0xD835, 0xDC00 + i); // A-Z a-z bold + + defineSymbol(math, main, mathord, ch, wideChar); + defineSymbol(text$1, main, textord, ch, wideChar); + wideChar = String.fromCharCode(0xD835, 0xDC34 + i); // A-Z a-z italic + + defineSymbol(math, main, mathord, ch, wideChar); + defineSymbol(text$1, main, textord, ch, wideChar); + wideChar = String.fromCharCode(0xD835, 0xDC68 + i); // A-Z a-z bold italic + + defineSymbol(math, main, mathord, ch, wideChar); + defineSymbol(text$1, main, textord, ch, wideChar); + wideChar = String.fromCharCode(0xD835, 0xDD04 + i); // A-Z a-z Fractur + + defineSymbol(math, main, mathord, ch, wideChar); + defineSymbol(text$1, main, textord, ch, wideChar); + wideChar = String.fromCharCode(0xD835, 0xDDA0 + i); // A-Z a-z sans-serif + + defineSymbol(math, main, mathord, ch, wideChar); + defineSymbol(text$1, main, textord, ch, wideChar); + wideChar = String.fromCharCode(0xD835, 0xDDD4 + i); // A-Z a-z sans bold + + defineSymbol(math, main, mathord, ch, wideChar); + defineSymbol(text$1, main, textord, ch, wideChar); + wideChar = String.fromCharCode(0xD835, 0xDE08 + i); // A-Z a-z sans italic + + defineSymbol(math, main, mathord, ch, wideChar); + defineSymbol(text$1, main, textord, ch, wideChar); + wideChar = String.fromCharCode(0xD835, 0xDE70 + i); // A-Z a-z monospace + + defineSymbol(math, main, mathord, ch, wideChar); + defineSymbol(text$1, main, textord, ch, wideChar); + + if (i < 26) { + // KaTeX fonts have only capital letters for blackboard bold and script. + // See exception for k below. + wideChar = String.fromCharCode(0xD835, 0xDD38 + i); // A-Z double struck + + defineSymbol(math, main, mathord, ch, wideChar); + defineSymbol(text$1, main, textord, ch, wideChar); + wideChar = String.fromCharCode(0xD835, 0xDC9C + i); // A-Z script + + defineSymbol(math, main, mathord, ch, wideChar); + defineSymbol(text$1, main, textord, ch, wideChar); + } // TODO: Add bold script when it is supported by a KaTeX font. + +} // "k" is the only double struck lower case letter in the KaTeX fonts. + + +wideChar = String.fromCharCode(0xD835, 0xDD5C); // k double struck + +defineSymbol(math, main, mathord, "k", wideChar); +defineSymbol(text$1, main, textord, "k", wideChar); // Next, some wide character numerals + +for (let i = 0; i < 10; i++) { + const ch = i.toString(); + wideChar = String.fromCharCode(0xD835, 0xDFCE + i); // 0-9 bold + + defineSymbol(math, main, mathord, ch, wideChar); + defineSymbol(text$1, main, textord, ch, wideChar); + wideChar = String.fromCharCode(0xD835, 0xDFE2 + i); // 0-9 sans serif + + defineSymbol(math, main, mathord, ch, wideChar); + defineSymbol(text$1, main, textord, ch, wideChar); + wideChar = String.fromCharCode(0xD835, 0xDFEC + i); // 0-9 bold sans + + defineSymbol(math, main, mathord, ch, wideChar); + defineSymbol(text$1, main, textord, ch, wideChar); + wideChar = String.fromCharCode(0xD835, 0xDFF6 + i); // 0-9 monospace + + defineSymbol(math, main, mathord, ch, wideChar); + defineSymbol(text$1, main, textord, ch, wideChar); +} // We add these Latin-1 letters as symbols for backwards-compatibility, +// but they are not actually in the font, nor are they supported by the +// Unicode accent mechanism, so they fall back to Times font and look ugly. +// TODO(edemaine): Fix this. + + +const extraLatin = "ÇÐÞçþ"; + +for (let i = 0; i < extraLatin.length; i++) { + const ch = extraLatin.charAt(i); + defineSymbol(math, main, mathord, ch, ch); + defineSymbol(text$1, main, textord, ch, ch); +} + +defineSymbol(text$1, main, textord, "ð", "ð"); // Unicode versions of existing characters + +defineSymbol(text$1, main, textord, "\u2013", "–"); +defineSymbol(text$1, main, textord, "\u2014", "—"); +defineSymbol(text$1, main, textord, "\u2018", "‘"); +defineSymbol(text$1, main, textord, "\u2019", "’"); +defineSymbol(text$1, main, textord, "\u201c", "“"); +defineSymbol(text$1, main, textord, "\u201d", "”"); + +/** + * This file provides support for Unicode range U+1D400 to U+1D7FF, + * Mathematical Alphanumeric Symbols. + * + * Function wideCharacterFont takes a wide character as input and returns + * the font information necessary to render it properly. + */ +/** + * Data below is from https://www.unicode.org/charts/PDF/U1D400.pdf + * That document sorts characters into groups by font type, say bold or italic. + * + * In the arrays below, each subarray consists three elements: + * * The CSS class of that group when in math mode. + * * The CSS class of that group when in text mode. + * * The font name, so that KaTeX can get font metrics. + */ + +const wideLatinLetterData = [["mathbf", "textbf", "Main-Bold"], // A-Z bold upright +["mathbf", "textbf", "Main-Bold"], // a-z bold upright +["mathdefault", "textit", "Math-Italic"], // A-Z italic +["mathdefault", "textit", "Math-Italic"], // a-z italic +["boldsymbol", "boldsymbol", "Main-BoldItalic"], // A-Z bold italic +["boldsymbol", "boldsymbol", "Main-BoldItalic"], // a-z bold italic +// Map fancy A-Z letters to script, not calligraphic. +// This aligns with unicode-math and math fonts (except Cambria Math). +["mathscr", "textscr", "Script-Regular"], // A-Z script +["", "", ""], // a-z script. No font +["", "", ""], // A-Z bold script. No font +["", "", ""], // a-z bold script. No font +["mathfrak", "textfrak", "Fraktur-Regular"], // A-Z Fraktur +["mathfrak", "textfrak", "Fraktur-Regular"], // a-z Fraktur +["mathbb", "textbb", "AMS-Regular"], // A-Z double-struck +["mathbb", "textbb", "AMS-Regular"], // k double-struck +["", "", ""], // A-Z bold Fraktur No font metrics +["", "", ""], // a-z bold Fraktur. No font. +["mathsf", "textsf", "SansSerif-Regular"], // A-Z sans-serif +["mathsf", "textsf", "SansSerif-Regular"], // a-z sans-serif +["mathboldsf", "textboldsf", "SansSerif-Bold"], // A-Z bold sans-serif +["mathboldsf", "textboldsf", "SansSerif-Bold"], // a-z bold sans-serif +["mathitsf", "textitsf", "SansSerif-Italic"], // A-Z italic sans-serif +["mathitsf", "textitsf", "SansSerif-Italic"], // a-z italic sans-serif +["", "", ""], // A-Z bold italic sans. No font +["", "", ""], // a-z bold italic sans. No font +["mathtt", "texttt", "Typewriter-Regular"], // A-Z monospace +["mathtt", "texttt", "Typewriter-Regular"]]; +const wideNumeralData = [["mathbf", "textbf", "Main-Bold"], // 0-9 bold +["", "", ""], // 0-9 double-struck. No KaTeX font. +["mathsf", "textsf", "SansSerif-Regular"], // 0-9 sans-serif +["mathboldsf", "textboldsf", "SansSerif-Bold"], // 0-9 bold sans-serif +["mathtt", "texttt", "Typewriter-Regular"]]; +const wideCharacterFont = function wideCharacterFont(wideChar, mode) { + // IE doesn't support codePointAt(). So work with the surrogate pair. + const H = wideChar.charCodeAt(0); // high surrogate + + const L = wideChar.charCodeAt(1); // low surrogate + + const codePoint = (H - 0xD800) * 0x400 + (L - 0xDC00) + 0x10000; + const j = mode === "math" ? 0 : 1; // column index for CSS class. + + if (0x1D400 <= codePoint && codePoint < 0x1D6A4) { + // wideLatinLetterData contains exactly 26 chars on each row. + // So we can calculate the relevant row. No traverse necessary. + const i = Math.floor((codePoint - 0x1D400) / 26); + return [wideLatinLetterData[i][2], wideLatinLetterData[i][j]]; + } else if (0x1D7CE <= codePoint && codePoint <= 0x1D7FF) { + // Numerals, ten per row. + const i = Math.floor((codePoint - 0x1D7CE) / 10); + return [wideNumeralData[i][2], wideNumeralData[i][j]]; + } else if (codePoint === 0x1D6A5 || codePoint === 0x1D6A6) { + // dotless i or j + return [wideLatinLetterData[0][2], wideLatinLetterData[0][j]]; + } else if (0x1D6A6 < codePoint && codePoint < 0x1D7CE) { + // Greek letters. Not supported, yet. + return ["", ""]; + } else { + // We don't support any wide characters outside 1D400–1D7FF. + throw new ParseError("Unsupported character: " + wideChar); + } +}; + +/** + * This file contains information about the options that the Parser carries + * around with it while parsing. Data is held in an `Options` object, and when + * recursing, a new `Options` object can be created with the `.with*` and + * `.reset` functions. + */ +const sizeStyleMap = [// Each element contains [textsize, scriptsize, scriptscriptsize]. +// The size mappings are taken from TeX with \normalsize=10pt. +[1, 1, 1], // size1: [5, 5, 5] \tiny +[2, 1, 1], // size2: [6, 5, 5] +[3, 1, 1], // size3: [7, 5, 5] \scriptsize +[4, 2, 1], // size4: [8, 6, 5] \footnotesize +[5, 2, 1], // size5: [9, 6, 5] \small +[6, 3, 1], // size6: [10, 7, 5] \normalsize +[7, 4, 2], // size7: [12, 8, 6] \large +[8, 6, 3], // size8: [14.4, 10, 7] \Large +[9, 7, 6], // size9: [17.28, 12, 10] \LARGE +[10, 8, 7], // size10: [20.74, 14.4, 12] \huge +[11, 10, 9]]; +const sizeMultipliers = [// fontMetrics.js:getGlobalMetrics also uses size indexes, so if +// you change size indexes, change that function. +0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.2, 1.44, 1.728, 2.074, 2.488]; + +const sizeAtStyle = function sizeAtStyle(size, style) { + return style.size < 2 ? size : sizeStyleMap[size - 1][style.size - 1]; +}; // In these types, "" (empty string) means "no change". + + +/** + * This is the main options class. It contains the current style, size, color, + * and font. + * + * Options objects should not be modified. To create a new Options with + * different properties, call a `.having*` method. + */ +class Options { + // A font family applies to a group of fonts (i.e. SansSerif), while a font + // represents a specific font (i.e. SansSerif Bold). + // See: https://tex.stackexchange.com/questions/22350/difference-between-textrm-and-mathrm + + /** + * The base size index. + */ + constructor(data) { + this.style = void 0; + this.color = void 0; + this.size = void 0; + this.textSize = void 0; + this.phantom = void 0; + this.font = void 0; + this.fontFamily = void 0; + this.fontWeight = void 0; + this.fontShape = void 0; + this.sizeMultiplier = void 0; + this.maxSize = void 0; + this.minRuleThickness = void 0; + this._fontMetrics = void 0; + this.style = data.style; + this.color = data.color; + this.size = data.size || Options.BASESIZE; + this.textSize = data.textSize || this.size; + this.phantom = !!data.phantom; + this.font = data.font || ""; + this.fontFamily = data.fontFamily || ""; + this.fontWeight = data.fontWeight || ''; + this.fontShape = data.fontShape || ''; + this.sizeMultiplier = sizeMultipliers[this.size - 1]; + this.maxSize = data.maxSize; + this.minRuleThickness = data.minRuleThickness; + this._fontMetrics = undefined; + } + /** + * Returns a new options object with the same properties as "this". Properties + * from "extension" will be copied to the new options object. + */ + + + extend(extension) { + const data = { + style: this.style, + size: this.size, + textSize: this.textSize, + color: this.color, + phantom: this.phantom, + font: this.font, + fontFamily: this.fontFamily, + fontWeight: this.fontWeight, + fontShape: this.fontShape, + maxSize: this.maxSize, + minRuleThickness: this.minRuleThickness + }; + + for (const key in extension) { + if (extension.hasOwnProperty(key)) { + data[key] = extension[key]; + } + } + + return new Options(data); + } + /** + * Return an options object with the given style. If `this.style === style`, + * returns `this`. + */ + + + havingStyle(style) { + if (this.style === style) { + return this; + } else { + return this.extend({ + style: style, + size: sizeAtStyle(this.textSize, style) + }); + } + } + /** + * Return an options object with a cramped version of the current style. If + * the current style is cramped, returns `this`. + */ + + + havingCrampedStyle() { + return this.havingStyle(this.style.cramp()); + } + /** + * Return an options object with the given size and in at least `\textstyle`. + * Returns `this` if appropriate. + */ + + + havingSize(size) { + if (this.size === size && this.textSize === size) { + return this; + } else { + return this.extend({ + style: this.style.text(), + size: size, + textSize: size, + sizeMultiplier: sizeMultipliers[size - 1] + }); + } + } + /** + * Like `this.havingSize(BASESIZE).havingStyle(style)`. If `style` is omitted, + * changes to at least `\textstyle`. + */ + + + havingBaseStyle(style) { + style = style || this.style.text(); + const wantSize = sizeAtStyle(Options.BASESIZE, style); + + if (this.size === wantSize && this.textSize === Options.BASESIZE && this.style === style) { + return this; + } else { + return this.extend({ + style: style, + size: wantSize + }); + } + } + /** + * Remove the effect of sizing changes such as \Huge. + * Keep the effect of the current style, such as \scriptstyle. + */ + + + havingBaseSizing() { + let size; + + switch (this.style.id) { + case 4: + case 5: + size = 3; // normalsize in scriptstyle + + break; + + case 6: + case 7: + size = 1; // normalsize in scriptscriptstyle + + break; + + default: + size = 6; + // normalsize in textstyle or displaystyle + } + + return this.extend({ + style: this.style.text(), + size: size + }); + } + /** + * Create a new options object with the given color. + */ + + + withColor(color) { + return this.extend({ + color: color + }); + } + /** + * Create a new options object with "phantom" set to true. + */ + + + withPhantom() { + return this.extend({ + phantom: true + }); + } + /** + * Creates a new options object with the given math font or old text font. + * @type {[type]} + */ + + + withFont(font) { + return this.extend({ + font + }); + } + /** + * Create a new options objects with the given fontFamily. + */ + + + withTextFontFamily(fontFamily) { + return this.extend({ + fontFamily, + font: "" + }); + } + /** + * Creates a new options object with the given font weight + */ + + + withTextFontWeight(fontWeight) { + return this.extend({ + fontWeight, + font: "" + }); + } + /** + * Creates a new options object with the given font weight + */ + + + withTextFontShape(fontShape) { + return this.extend({ + fontShape, + font: "" + }); + } + /** + * Return the CSS sizing classes required to switch from enclosing options + * `oldOptions` to `this`. Returns an array of classes. + */ + + + sizingClasses(oldOptions) { + if (oldOptions.size !== this.size) { + return ["sizing", "reset-size" + oldOptions.size, "size" + this.size]; + } else { + return []; + } + } + /** + * Return the CSS sizing classes required to switch to the base size. Like + * `this.havingSize(BASESIZE).sizingClasses(this)`. + */ + + + baseSizingClasses() { + if (this.size !== Options.BASESIZE) { + return ["sizing", "reset-size" + this.size, "size" + Options.BASESIZE]; + } else { + return []; + } + } + /** + * Return the font metrics for this size. + */ + + + fontMetrics() { + if (!this._fontMetrics) { + this._fontMetrics = getGlobalMetrics(this.size); + } + + return this._fontMetrics; + } + /** + * Gets the CSS color of the current options object + */ + + + getColor() { + if (this.phantom) { + return "transparent"; + } else { + return this.color; + } + } + +} + +Options.BASESIZE = 6; + +/** + * This file does conversion between units. In particular, it provides + * calculateSize to convert other units into ems. + */ +// Thus, multiplying a length by this number converts the length from units +// into pts. Dividing the result by ptPerEm gives the number of ems +// *assuming* a font size of ptPerEm (normal size, normal style). + +const ptPerUnit = { + // https://en.wikibooks.org/wiki/LaTeX/Lengths and + // https://tex.stackexchange.com/a/8263 + "pt": 1, + // TeX point + "mm": 7227 / 2540, + // millimeter + "cm": 7227 / 254, + // centimeter + "in": 72.27, + // inch + "bp": 803 / 800, + // big (PostScript) points + "pc": 12, + // pica + "dd": 1238 / 1157, + // didot + "cc": 14856 / 1157, + // cicero (12 didot) + "nd": 685 / 642, + // new didot + "nc": 1370 / 107, + // new cicero (12 new didot) + "sp": 1 / 65536, + // scaled point (TeX's internal smallest unit) + // https://tex.stackexchange.com/a/41371 + "px": 803 / 800 // \pdfpxdimen defaults to 1 bp in pdfTeX and LuaTeX + +}; // Dictionary of relative units, for fast validity testing. + +const relativeUnit = { + "ex": true, + "em": true, + "mu": true +}; + +/** + * Determine whether the specified unit (either a string defining the unit + * or a "size" parse node containing a unit field) is valid. + */ +const validUnit = function validUnit(unit) { + if (typeof unit !== "string") { + unit = unit.unit; + } + + return unit in ptPerUnit || unit in relativeUnit || unit === "ex"; +}; +/* + * Convert a "size" parse node (with numeric "number" and string "unit" fields, + * as parsed by functions.js argType "size") into a CSS em value for the + * current style/scale. `options` gives the current options. + */ + +const calculateSize = function calculateSize(sizeValue, options) { + let scale; + + if (sizeValue.unit in ptPerUnit) { + // Absolute units + scale = ptPerUnit[sizeValue.unit] // Convert unit to pt + / options.fontMetrics().ptPerEm // Convert pt to CSS em + / options.sizeMultiplier; // Unscale to make absolute units + } else if (sizeValue.unit === "mu") { + // `mu` units scale with scriptstyle/scriptscriptstyle. + scale = options.fontMetrics().cssEmPerMu; + } else { + // Other relative units always refer to the *textstyle* font + // in the current size. + let unitOptions; + + if (options.style.isTight()) { + // isTight() means current style is script/scriptscript. + unitOptions = options.havingStyle(options.style.text()); + } else { + unitOptions = options; + } // TODO: In TeX these units are relative to the quad of the current + // *text* font, e.g. cmr10. KaTeX instead uses values from the + // comparably-sized *Computer Modern symbol* font. At 10pt, these + // match. At 7pt and 5pt, they differ: cmr7=1.138894, cmsy7=1.170641; + // cmr5=1.361133, cmsy5=1.472241. Consider $\scriptsize a\kern1emb$. + // TeX \showlists shows a kern of 1.13889 * fontsize; + // KaTeX shows a kern of 1.171 * fontsize. + + + if (sizeValue.unit === "ex") { + scale = unitOptions.fontMetrics().xHeight; + } else if (sizeValue.unit === "em") { + scale = unitOptions.fontMetrics().quad; + } else { + throw new ParseError("Invalid unit: '" + sizeValue.unit + "'"); + } + + if (unitOptions !== options) { + scale *= unitOptions.sizeMultiplier / options.sizeMultiplier; + } + } + + return Math.min(sizeValue.number * scale, options.maxSize); +}; + +/* eslint no-console:0 */ +// The following have to be loaded from Main-Italic font, using class mathit +const mathitLetters = ["\\imath", "ı", // dotless i +"\\jmath", "ȷ", // dotless j +"\\pounds", "\\mathsterling", "\\textsterling", "£"]; +/** + * Looks up the given symbol in fontMetrics, after applying any symbol + * replacements defined in symbol.js + */ + +const lookupSymbol = function lookupSymbol(value, // TODO(#963): Use a union type for this. +fontName, mode) { + // Replace the value with its replaced value from symbol.js + if (symbols[mode][value] && symbols[mode][value].replace) { + value = symbols[mode][value].replace; + } + + return { + value: value, + metrics: getCharacterMetrics(value, fontName, mode) + }; +}; +/** + * Makes a symbolNode after translation via the list of symbols in symbols.js. + * Correctly pulls out metrics for the character, and optionally takes a list of + * classes to be attached to the node. + * + * TODO: make argument order closer to makeSpan + * TODO: add a separate argument for math class (e.g. `mop`, `mbin`), which + * should if present come first in `classes`. + * TODO(#953): Make `options` mandatory and always pass it in. + */ + + +const makeSymbol = function makeSymbol(value, fontName, mode, options, classes) { + const lookup = lookupSymbol(value, fontName, mode); + const metrics = lookup.metrics; + value = lookup.value; + let symbolNode; + + if (metrics) { + let italic = metrics.italic; + + if (mode === "text" || options && options.font === "mathit") { + italic = 0; + } + + symbolNode = new SymbolNode(value, metrics.height, metrics.depth, italic, metrics.skew, metrics.width, classes); + } else { + // TODO(emily): Figure out a good way to only print this in development + typeof console !== "undefined" && console.warn("No character metrics " + `for '${value}' in style '${fontName}' and mode '${mode}'`); + symbolNode = new SymbolNode(value, 0, 0, 0, 0, 0, classes); + } + + if (options) { + symbolNode.maxFontSize = options.sizeMultiplier; + + if (options.style.isTight()) { + symbolNode.classes.push("mtight"); + } + + const color = options.getColor(); + + if (color) { + symbolNode.style.color = color; + } + } + + return symbolNode; +}; +/** + * Makes a symbol in Main-Regular or AMS-Regular. + * Used for rel, bin, open, close, inner, and punct. + */ + + +const mathsym = function mathsym(value, mode, options, classes) { + if (classes === void 0) { + classes = []; + } + + // Decide what font to render the symbol in by its entry in the symbols + // table. + // Have a special case for when the value = \ because the \ is used as a + // textord in unsupported command errors but cannot be parsed as a regular + // text ordinal and is therefore not present as a symbol in the symbols + // table for text, as well as a special case for boldsymbol because it + // can be used for bold + and - + if (options.font === "boldsymbol" && lookupSymbol(value, "Main-Bold", mode).metrics) { + return makeSymbol(value, "Main-Bold", mode, options, classes.concat(["mathbf"])); + } else if (value === "\\" || symbols[mode][value].font === "main") { + return makeSymbol(value, "Main-Regular", mode, options, classes); + } else { + return makeSymbol(value, "AMS-Regular", mode, options, classes.concat(["amsrm"])); + } +}; +/** + * Determines which of the two font names (Main-Italic and Math-Italic) and + * corresponding style tags (maindefault or mathit) to use for default math font, + * depending on the symbol. + */ + + +const mathdefault = function mathdefault(value, mode, options, classes) { + if (/[0-9]/.test(value.charAt(0)) || // glyphs for \imath and \jmath do not exist in Math-Italic so we + // need to use Main-Italic instead + utils.contains(mathitLetters, value)) { + return { + fontName: "Main-Italic", + fontClass: "mathit" + }; + } else { + return { + fontName: "Math-Italic", + fontClass: "mathdefault" + }; + } +}; +/** + * Determines which of the font names (Main-Italic, Math-Italic, and Caligraphic) + * and corresponding style tags (mathit, mathdefault, or mathcal) to use for font + * "mathnormal", depending on the symbol. Use this function instead of fontMap for + * font "mathnormal". + */ + + +const mathnormal = function mathnormal(value, mode, options, classes) { + if (utils.contains(mathitLetters, value)) { + return { + fontName: "Main-Italic", + fontClass: "mathit" + }; + } else if (/[0-9]/.test(value.charAt(0))) { + return { + fontName: "Caligraphic-Regular", + fontClass: "mathcal" + }; + } else { + return { + fontName: "Math-Italic", + fontClass: "mathdefault" + }; + } +}; +/** + * Determines which of the two font names (Main-Bold and Math-BoldItalic) and + * corresponding style tags (mathbf or boldsymbol) to use for font "boldsymbol", + * depending on the symbol. Use this function instead of fontMap for font + * "boldsymbol". + */ + + +const boldsymbol = function boldsymbol(value, mode, options, classes) { + if (lookupSymbol(value, "Math-BoldItalic", mode).metrics) { + return { + fontName: "Math-BoldItalic", + fontClass: "boldsymbol" + }; + } else { + // Some glyphs do not exist in Math-BoldItalic so we need to use + // Main-Bold instead. + return { + fontName: "Main-Bold", + fontClass: "mathbf" + }; + } +}; +/** + * Makes either a mathord or textord in the correct font and color. + */ + + +const makeOrd = function makeOrd(group, options, type) { + const mode = group.mode; + const text = group.text; + const classes = ["mord"]; // Math mode or Old font (i.e. \rm) + + const isFont = mode === "math" || mode === "text" && options.font; + const fontOrFamily = isFont ? options.font : options.fontFamily; + + if (text.charCodeAt(0) === 0xD835) { + // surrogate pairs get special treatment + const _wideCharacterFont = wideCharacterFont(text, mode), + wideFontName = _wideCharacterFont[0], + wideFontClass = _wideCharacterFont[1]; + + return makeSymbol(text, wideFontName, mode, options, classes.concat(wideFontClass)); + } else if (fontOrFamily) { + let fontName; + let fontClasses; + + if (fontOrFamily === "boldsymbol" || fontOrFamily === "mathnormal") { + const fontData = fontOrFamily === "boldsymbol" ? boldsymbol(text, mode, options, classes) : mathnormal(text, mode, options, classes); + fontName = fontData.fontName; + fontClasses = [fontData.fontClass]; + } else if (utils.contains(mathitLetters, text)) { + fontName = "Main-Italic"; + fontClasses = ["mathit"]; + } else if (isFont) { + fontName = fontMap[fontOrFamily].fontName; + fontClasses = [fontOrFamily]; + } else { + fontName = retrieveTextFontName(fontOrFamily, options.fontWeight, options.fontShape); + fontClasses = [fontOrFamily, options.fontWeight, options.fontShape]; + } + + if (lookupSymbol(text, fontName, mode).metrics) { + return makeSymbol(text, fontName, mode, options, classes.concat(fontClasses)); + } else if (ligatures.hasOwnProperty(text) && fontName.substr(0, 10) === "Typewriter") { + // Deconstruct ligatures in monospace fonts (\texttt, \tt). + const parts = []; + + for (let i = 0; i < text.length; i++) { + parts.push(makeSymbol(text[i], fontName, mode, options, classes.concat(fontClasses))); + } + + return makeFragment(parts); + } + } // Makes a symbol in the default font for mathords and textords. + + + if (type === "mathord") { + const fontLookup = mathdefault(text, mode, options, classes); + return makeSymbol(text, fontLookup.fontName, mode, options, classes.concat([fontLookup.fontClass])); + } else if (type === "textord") { + const font = symbols[mode][text] && symbols[mode][text].font; + + if (font === "ams") { + const fontName = retrieveTextFontName("amsrm", options.fontWeight, options.fontShape); + return makeSymbol(text, fontName, mode, options, classes.concat("amsrm", options.fontWeight, options.fontShape)); + } else if (font === "main" || !font) { + const fontName = retrieveTextFontName("textrm", options.fontWeight, options.fontShape); + return makeSymbol(text, fontName, mode, options, classes.concat(options.fontWeight, options.fontShape)); + } else { + // fonts added by plugins + const fontName = retrieveTextFontName(font, options.fontWeight, options.fontShape); // We add font name as a css class + + return makeSymbol(text, fontName, mode, options, classes.concat(fontName, options.fontWeight, options.fontShape)); + } + } else { + throw new Error("unexpected type: " + type + " in makeOrd"); + } +}; +/** + * Returns true if subsequent symbolNodes have the same classes, skew, maxFont, + * and styles. + */ + + +const canCombine = (prev, next) => { + if (createClass(prev.classes) !== createClass(next.classes) || prev.skew !== next.skew || prev.maxFontSize !== next.maxFontSize) { + return false; + } + + for (const style in prev.style) { + if (prev.style.hasOwnProperty(style) && prev.style[style] !== next.style[style]) { + return false; + } + } + + for (const style in next.style) { + if (next.style.hasOwnProperty(style) && prev.style[style] !== next.style[style]) { + return false; + } + } + + return true; +}; +/** + * Combine consequetive domTree.symbolNodes into a single symbolNode. + * Note: this function mutates the argument. + */ + + +const tryCombineChars = chars => { + for (let i = 0; i < chars.length - 1; i++) { + const prev = chars[i]; + const next = chars[i + 1]; + + if (prev instanceof SymbolNode && next instanceof SymbolNode && canCombine(prev, next)) { + prev.text += next.text; + prev.height = Math.max(prev.height, next.height); + prev.depth = Math.max(prev.depth, next.depth); // Use the last character's italic correction since we use + // it to add padding to the right of the span created from + // the combined characters. + + prev.italic = next.italic; + chars.splice(i + 1, 1); + i--; + } + } + + return chars; +}; +/** + * Calculate the height, depth, and maxFontSize of an element based on its + * children. + */ + + +const sizeElementFromChildren = function sizeElementFromChildren(elem) { + let height = 0; + let depth = 0; + let maxFontSize = 0; + + for (let i = 0; i < elem.children.length; i++) { + const child = elem.children[i]; + + if (child.height > height) { + height = child.height; + } + + if (child.depth > depth) { + depth = child.depth; + } + + if (child.maxFontSize > maxFontSize) { + maxFontSize = child.maxFontSize; + } + } + + elem.height = height; + elem.depth = depth; + elem.maxFontSize = maxFontSize; +}; +/** + * Makes a span with the given list of classes, list of children, and options. + * + * TODO(#953): Ensure that `options` is always provided (currently some call + * sites don't pass it) and make the type below mandatory. + * TODO: add a separate argument for math class (e.g. `mop`, `mbin`), which + * should if present come first in `classes`. + */ + + +const makeSpan = function makeSpan(classes, children, options, style) { + const span = new Span(classes, children, options, style); + sizeElementFromChildren(span); + return span; +}; // SVG one is simpler -- doesn't require height, depth, max-font setting. +// This is also a separate method for typesafety. + + +const makeSvgSpan = (classes, children, options, style) => new Span(classes, children, options, style); + +const makeLineSpan = function makeLineSpan(className, options, thickness) { + const line = makeSpan([className], [], options); + line.height = Math.max(thickness || options.fontMetrics().defaultRuleThickness, options.minRuleThickness); + line.style.borderBottomWidth = line.height + "em"; + line.maxFontSize = 1.0; + return line; +}; +/** + * Makes an anchor with the given href, list of classes, list of children, + * and options. + */ + + +const makeAnchor = function makeAnchor(href, classes, children, options) { + const anchor = new Anchor(href, classes, children, options); + sizeElementFromChildren(anchor); + return anchor; +}; +/** + * Makes a document fragment with the given list of children. + */ + + +const makeFragment = function makeFragment(children) { + const fragment = new DocumentFragment(children); + sizeElementFromChildren(fragment); + return fragment; +}; +/** + * Wraps group in a span if it's a document fragment, allowing to apply classes + * and styles + */ + + +const wrapFragment = function wrapFragment(group, options) { + if (group instanceof DocumentFragment) { + return makeSpan([], [group], options); + } + + return group; +}; // These are exact object types to catch typos in the names of the optional fields. + + +// Computes the updated `children` list and the overall depth. +// +// This helper function for makeVList makes it easier to enforce type safety by +// allowing early exits (returns) in the logic. +const getVListChildrenAndDepth = function getVListChildrenAndDepth(params) { + if (params.positionType === "individualShift") { + const oldChildren = params.children; + const children = [oldChildren[0]]; // Add in kerns to the list of params.children to get each element to be + // shifted to the correct specified shift + + const depth = -oldChildren[0].shift - oldChildren[0].elem.depth; + let currPos = depth; + + for (let i = 1; i < oldChildren.length; i++) { + const diff = -oldChildren[i].shift - currPos - oldChildren[i].elem.depth; + const size = diff - (oldChildren[i - 1].elem.height + oldChildren[i - 1].elem.depth); + currPos = currPos + diff; + children.push({ + type: "kern", + size + }); + children.push(oldChildren[i]); + } + + return { + children, + depth + }; + } + + let depth; + + if (params.positionType === "top") { + // We always start at the bottom, so calculate the bottom by adding up + // all the sizes + let bottom = params.positionData; + + for (let i = 0; i < params.children.length; i++) { + const child = params.children[i]; + bottom -= child.type === "kern" ? child.size : child.elem.height + child.elem.depth; + } + + depth = bottom; + } else if (params.positionType === "bottom") { + depth = -params.positionData; + } else { + const firstChild = params.children[0]; + + if (firstChild.type !== "elem") { + throw new Error('First child must have type "elem".'); + } + + if (params.positionType === "shift") { + depth = -firstChild.elem.depth - params.positionData; + } else if (params.positionType === "firstBaseline") { + depth = -firstChild.elem.depth; + } else { + throw new Error(`Invalid positionType ${params.positionType}.`); + } + } + + return { + children: params.children, + depth + }; +}; +/** + * Makes a vertical list by stacking elements and kerns on top of each other. + * Allows for many different ways of specifying the positioning method. + * + * See VListParam documentation above. + */ + + +const makeVList = function makeVList(params, options) { + const _getVListChildrenAndD = getVListChildrenAndDepth(params), + children = _getVListChildrenAndD.children, + depth = _getVListChildrenAndD.depth; // Create a strut that is taller than any list item. The strut is added to + // each item, where it will determine the item's baseline. Since it has + // `overflow:hidden`, the strut's top edge will sit on the item's line box's + // top edge and the strut's bottom edge will sit on the item's baseline, + // with no additional line-height spacing. This allows the item baseline to + // be positioned precisely without worrying about font ascent and + // line-height. + + + let pstrutSize = 0; + + for (let i = 0; i < children.length; i++) { + const child = children[i]; + + if (child.type === "elem") { + const elem = child.elem; + pstrutSize = Math.max(pstrutSize, elem.maxFontSize, elem.height); + } + } + + pstrutSize += 2; + const pstrut = makeSpan(["pstrut"], []); + pstrut.style.height = pstrutSize + "em"; // Create a new list of actual children at the correct offsets + + const realChildren = []; + let minPos = depth; + let maxPos = depth; + let currPos = depth; + + for (let i = 0; i < children.length; i++) { + const child = children[i]; + + if (child.type === "kern") { + currPos += child.size; + } else { + const elem = child.elem; + const classes = child.wrapperClasses || []; + const style = child.wrapperStyle || {}; + const childWrap = makeSpan(classes, [pstrut, elem], undefined, style); + childWrap.style.top = -pstrutSize - currPos - elem.depth + "em"; + + if (child.marginLeft) { + childWrap.style.marginLeft = child.marginLeft; + } + + if (child.marginRight) { + childWrap.style.marginRight = child.marginRight; + } + + realChildren.push(childWrap); + currPos += elem.height + elem.depth; + } + + minPos = Math.min(minPos, currPos); + maxPos = Math.max(maxPos, currPos); + } // The vlist contents go in a table-cell with `vertical-align:bottom`. + // This cell's bottom edge will determine the containing table's baseline + // without overly expanding the containing line-box. + + + const vlist = makeSpan(["vlist"], realChildren); + vlist.style.height = maxPos + "em"; // A second row is used if necessary to represent the vlist's depth. + + let rows; + + if (minPos < 0) { + // We will define depth in an empty span with display: table-cell. + // It should render with the height that we define. But Chrome, in + // contenteditable mode only, treats that span as if it contains some + // text content. And that min-height over-rides our desired height. + // So we put another empty span inside the depth strut span. + const emptySpan = makeSpan([], []); + const depthStrut = makeSpan(["vlist"], [emptySpan]); + depthStrut.style.height = -minPos + "em"; // Safari wants the first row to have inline content; otherwise it + // puts the bottom of the *second* row on the baseline. + + const topStrut = makeSpan(["vlist-s"], [new SymbolNode("\u200b")]); + rows = [makeSpan(["vlist-r"], [vlist, topStrut]), makeSpan(["vlist-r"], [depthStrut])]; + } else { + rows = [makeSpan(["vlist-r"], [vlist])]; + } + + const vtable = makeSpan(["vlist-t"], rows); + + if (rows.length === 2) { + vtable.classes.push("vlist-t2"); + } + + vtable.height = maxPos; + vtable.depth = -minPos; + return vtable; +}; // Glue is a concept from TeX which is a flexible space between elements in +// either a vertical or horizontal list. In KaTeX, at least for now, it's +// static space between elements in a horizontal layout. + + +const makeGlue = (measurement, options) => { + // Make an empty span for the space + const rule = makeSpan(["mspace"], [], options); + const size = calculateSize(measurement, options); + rule.style.marginRight = `${size}em`; + return rule; +}; // Takes font options, and returns the appropriate fontLookup name + + +const retrieveTextFontName = function retrieveTextFontName(fontFamily, fontWeight, fontShape) { + let baseFontName = ""; + + switch (fontFamily) { + case "amsrm": + baseFontName = "AMS"; + break; + + case "textrm": + baseFontName = "Main"; + break; + + case "textsf": + baseFontName = "SansSerif"; + break; + + case "texttt": + baseFontName = "Typewriter"; + break; + + default: + baseFontName = fontFamily; + // use fonts added by a plugin + } + + let fontStylesName; + + if (fontWeight === "textbf" && fontShape === "textit") { + fontStylesName = "BoldItalic"; + } else if (fontWeight === "textbf") { + fontStylesName = "Bold"; + } else if (fontWeight === "textit") { + fontStylesName = "Italic"; + } else { + fontStylesName = "Regular"; + } + + return `${baseFontName}-${fontStylesName}`; +}; +/** + * Maps TeX font commands to objects containing: + * - variant: string used for "mathvariant" attribute in buildMathML.js + * - fontName: the "style" parameter to fontMetrics.getCharacterMetrics + */ +// A map between tex font commands an MathML mathvariant attribute values + + +const fontMap = { + // styles + "mathbf": { + variant: "bold", + fontName: "Main-Bold" + }, + "mathrm": { + variant: "normal", + fontName: "Main-Regular" + }, + "textit": { + variant: "italic", + fontName: "Main-Italic" + }, + "mathit": { + variant: "italic", + fontName: "Main-Italic" + }, + // Default math font, "mathnormal" and "boldsymbol" are missing because they + // require the use of several fonts: Main-Italic and Math-Italic for default + // math font, Main-Italic, Math-Italic, Caligraphic for "mathnormal", and + // Math-BoldItalic and Main-Bold for "boldsymbol". This is handled by a + // special case in makeOrd which ends up calling mathdefault, mathnormal, + // and boldsymbol. + // families + "mathbb": { + variant: "double-struck", + fontName: "AMS-Regular" + }, + "mathcal": { + variant: "script", + fontName: "Caligraphic-Regular" + }, + "mathfrak": { + variant: "fraktur", + fontName: "Fraktur-Regular" + }, + "mathscr": { + variant: "script", + fontName: "Script-Regular" + }, + "mathsf": { + variant: "sans-serif", + fontName: "SansSerif-Regular" + }, + "mathtt": { + variant: "monospace", + fontName: "Typewriter-Regular" + } +}; +const svgData = { + // path, width, height + vec: ["vec", 0.471, 0.714], + // values from the font glyph + oiintSize1: ["oiintSize1", 0.957, 0.499], + // oval to overlay the integrand + oiintSize2: ["oiintSize2", 1.472, 0.659], + oiiintSize1: ["oiiintSize1", 1.304, 0.499], + oiiintSize2: ["oiiintSize2", 1.98, 0.659] +}; + +const staticSvg = function staticSvg(value, options) { + // Create a span with inline SVG for the element. + const _svgData$value = svgData[value], + pathName = _svgData$value[0], + width = _svgData$value[1], + height = _svgData$value[2]; + const path = new PathNode(pathName); + const svgNode = new SvgNode([path], { + "width": width + "em", + "height": height + "em", + // Override CSS rule `.katex svg { width: 100% }` + "style": "width:" + width + "em", + "viewBox": "0 0 " + 1000 * width + " " + 1000 * height, + "preserveAspectRatio": "xMinYMin" + }); + const span = makeSvgSpan(["overlay"], [svgNode], options); + span.height = height; + span.style.height = height + "em"; + span.style.width = width + "em"; + return span; +}; + +var buildCommon = { + fontMap, + makeSymbol, + mathsym, + makeSpan, + makeSvgSpan, + makeLineSpan, + makeAnchor, + makeFragment, + wrapFragment, + makeVList, + makeOrd, + makeGlue, + staticSvg, + svgData, + tryCombineChars +}; + +/** + * Asserts that the node is of the given type and returns it with stricter + * typing. Throws if the node's type does not match. + */ +function assertNodeType(node, type) { + const typedNode = checkNodeType(node, type); + + if (!typedNode) { + throw new Error(`Expected node of type ${type}, but got ` + (node ? `node of type ${node.type}` : String(node))); + } // $FlowFixMe: Unsure why. + + + return typedNode; +} +/** + * Returns the node more strictly typed iff it is of the given type. Otherwise, + * returns null. + */ + +function checkNodeType(node, type) { + if (node && node.type === type) { + // The definition of ParseNode doesn't communicate to flow that + // `type: TYPE` (as that's not explicitly mentioned anywhere), though that + // happens to be true for all our value types. + // $FlowFixMe + return node; + } + + return null; +} +/** + * Asserts that the node is of the given type and returns it with stricter + * typing. Throws if the node's type does not match. + */ + +function assertAtomFamily(node, family) { + const typedNode = checkAtomFamily(node, family); + + if (!typedNode) { + throw new Error(`Expected node of type "atom" and family "${family}", but got ` + (node ? node.type === "atom" ? `atom of family ${node.family}` : `node of type ${node.type}` : String(node))); + } + + return typedNode; +} +/** + * Returns the node more strictly typed iff it is of the given type. Otherwise, + * returns null. + */ + +function checkAtomFamily(node, family) { + return node && node.type === "atom" && node.family === family ? node : null; +} +/** + * Returns the node more strictly typed iff it is of the given type. Otherwise, + * returns null. + */ + +function assertSymbolNodeType(node) { + const typedNode = checkSymbolNodeType(node); + + if (!typedNode) { + throw new Error(`Expected node of symbol group type, but got ` + (node ? `node of type ${node.type}` : String(node))); + } + + return typedNode; +} +/** + * Returns the node more strictly typed iff it is of the given type. Otherwise, + * returns null. + */ + +function checkSymbolNodeType(node) { + if (node && (node.type === "atom" || NON_ATOMS.hasOwnProperty(node.type))) { + // $FlowFixMe + return node; + } + + return null; +} + +/** + * Describes spaces between different classes of atoms. + */ +const thinspace = { + number: 3, + unit: "mu" +}; +const mediumspace = { + number: 4, + unit: "mu" +}; +const thickspace = { + number: 5, + unit: "mu" +}; // Making the type below exact with all optional fields doesn't work due to +// - https://github.com/facebook/flow/issues/4582 +// - https://github.com/facebook/flow/issues/5688 +// However, since *all* fields are optional, $Shape<> works as suggested in 5688 +// above. + +// Spacing relationships for display and text styles +const spacings = { + mord: { + mop: thinspace, + mbin: mediumspace, + mrel: thickspace, + minner: thinspace + }, + mop: { + mord: thinspace, + mop: thinspace, + mrel: thickspace, + minner: thinspace + }, + mbin: { + mord: mediumspace, + mop: mediumspace, + mopen: mediumspace, + minner: mediumspace + }, + mrel: { + mord: thickspace, + mop: thickspace, + mopen: thickspace, + minner: thickspace + }, + mopen: {}, + mclose: { + mop: thinspace, + mbin: mediumspace, + mrel: thickspace, + minner: thinspace + }, + mpunct: { + mord: thinspace, + mop: thinspace, + mrel: thickspace, + mopen: thinspace, + mclose: thinspace, + mpunct: thinspace, + minner: thinspace + }, + minner: { + mord: thinspace, + mop: thinspace, + mbin: mediumspace, + mrel: thickspace, + mopen: thinspace, + mpunct: thinspace, + minner: thinspace + } +}; // Spacing relationships for script and scriptscript styles + +const tightSpacings = { + mord: { + mop: thinspace + }, + mop: { + mord: thinspace, + mop: thinspace + }, + mbin: {}, + mrel: {}, + mopen: {}, + mclose: { + mop: thinspace + }, + mpunct: {}, + minner: { + mop: thinspace + } +}; + +/** + * All registered functions. + * `functions.js` just exports this same dictionary again and makes it public. + * `Parser.js` requires this dictionary. + */ +const _functions = {}; +/** + * All HTML builders. Should be only used in the `define*` and the `build*ML` + * functions. + */ + +const _htmlGroupBuilders = {}; +/** + * All MathML builders. Should be only used in the `define*` and the `build*ML` + * functions. + */ + +const _mathmlGroupBuilders = {}; +function defineFunction(_ref) { + let type = _ref.type, + names = _ref.names, + props = _ref.props, + handler = _ref.handler, + htmlBuilder = _ref.htmlBuilder, + mathmlBuilder = _ref.mathmlBuilder; + // Set default values of functions + const data = { + type, + numArgs: props.numArgs, + argTypes: props.argTypes, + greediness: props.greediness === undefined ? 1 : props.greediness, + allowedInText: !!props.allowedInText, + allowedInMath: props.allowedInMath === undefined ? true : props.allowedInMath, + numOptionalArgs: props.numOptionalArgs || 0, + infix: !!props.infix, + handler: handler + }; + + for (let i = 0; i < names.length; ++i) { + _functions[names[i]] = data; + } + + if (type) { + if (htmlBuilder) { + _htmlGroupBuilders[type] = htmlBuilder; + } + + if (mathmlBuilder) { + _mathmlGroupBuilders[type] = mathmlBuilder; + } + } +} +/** + * Use this to register only the HTML and MathML builders for a function (e.g. + * if the function's ParseNode is generated in Parser.js rather than via a + * stand-alone handler provided to `defineFunction`). + */ + +function defineFunctionBuilders(_ref2) { + let type = _ref2.type, + htmlBuilder = _ref2.htmlBuilder, + mathmlBuilder = _ref2.mathmlBuilder; + defineFunction({ + type, + names: [], + props: { + numArgs: 0 + }, + + handler() { + throw new Error('Should never be called.'); + }, + + htmlBuilder, + mathmlBuilder + }); +} // Since the corresponding buildHTML/buildMathML function expects a +// list of elements, we normalize for different kinds of arguments + +const ordargument = function ordargument(arg) { + const node = checkNodeType(arg, "ordgroup"); + return node ? node.body : [arg]; +}; + +/** + * This file does the main work of building a domTree structure from a parse + * tree. The entry point is the `buildHTML` function, which takes a parse tree. + * Then, the buildExpression, buildGroup, and various groupBuilders functions + * are called, to produce a final HTML tree. + */ +const makeSpan$1 = buildCommon.makeSpan; // Binary atoms (first class `mbin`) change into ordinary atoms (`mord`) +// depending on their surroundings. See TeXbook pg. 442-446, Rules 5 and 6, +// and the text before Rule 19. + +const binLeftCanceller = ["leftmost", "mbin", "mopen", "mrel", "mop", "mpunct"]; +const binRightCanceller = ["rightmost", "mrel", "mclose", "mpunct"]; +const styleMap = { + "display": Style$1.DISPLAY, + "text": Style$1.TEXT, + "script": Style$1.SCRIPT, + "scriptscript": Style$1.SCRIPTSCRIPT +}; +const DomEnum = { + mord: "mord", + mop: "mop", + mbin: "mbin", + mrel: "mrel", + mopen: "mopen", + mclose: "mclose", + mpunct: "mpunct", + minner: "minner" +}; + +/** + * Take a list of nodes, build them in order, and return a list of the built + * nodes. documentFragments are flattened into their contents, so the + * returned list contains no fragments. `isRealGroup` is true if `expression` + * is a real group (no atoms will be added on either side), as opposed to + * a partial group (e.g. one created by \color). `surrounding` is an array + * consisting type of nodes that will be added to the left and right. + */ +const buildExpression = function buildExpression(expression, options, isRealGroup, surrounding) { + if (surrounding === void 0) { + surrounding = [null, null]; + } + + // Parse expressions into `groups`. + const groups = []; + + for (let i = 0; i < expression.length; i++) { + const output = buildGroup(expression[i], options); + + if (output instanceof DocumentFragment) { + const children = output.children; + groups.push(...children); + } else { + groups.push(output); + } + } // If `expression` is a partial group, let the parent handle spacings + // to avoid processing groups multiple times. + + + if (!isRealGroup) { + return groups; + } + + let glueOptions = options; + + if (expression.length === 1) { + const node = checkNodeType(expression[0], "sizing") || checkNodeType(expression[0], "styling"); + + if (!node) ; else if (node.type === "sizing") { + glueOptions = options.havingSize(node.size); + } else if (node.type === "styling") { + glueOptions = options.havingStyle(styleMap[node.style]); + } + } // Dummy spans for determining spacings between surrounding atoms. + // If `expression` has no atoms on the left or right, class "leftmost" + // or "rightmost", respectively, is used to indicate it. + + + const dummyPrev = makeSpan$1([surrounding[0] || "leftmost"], [], options); + const dummyNext = makeSpan$1([surrounding[1] || "rightmost"], [], options); // TODO: These code assumes that a node's math class is the first element + // of its `classes` array. A later cleanup should ensure this, for + // instance by changing the signature of `makeSpan`. + // Before determining what spaces to insert, perform bin cancellation. + // Binary operators change to ordinary symbols in some contexts. + + traverseNonSpaceNodes(groups, (node, prev) => { + const prevType = prev.classes[0]; + const type = node.classes[0]; + + if (prevType === "mbin" && utils.contains(binRightCanceller, type)) { + prev.classes[0] = "mord"; + } else if (type === "mbin" && utils.contains(binLeftCanceller, prevType)) { + node.classes[0] = "mord"; + } + }, { + node: dummyPrev + }, dummyNext); + traverseNonSpaceNodes(groups, (node, prev) => { + const prevType = getTypeOfDomTree(prev); + const type = getTypeOfDomTree(node); // 'mtight' indicates that the node is script or scriptscript style. + + const space = prevType && type ? node.hasClass("mtight") ? tightSpacings[prevType][type] : spacings[prevType][type] : null; + + if (space) { + // Insert glue (spacing) after the `prev`. + return buildCommon.makeGlue(space, glueOptions); + } + }, { + node: dummyPrev + }, dummyNext); + return groups; +}; // Depth-first traverse non-space `nodes`, calling `callback` with the current and +// previous node as arguments, optionally returning a node to insert after the +// previous node. `prev` is an object with the previous node and `insertAfter` +// function to insert after it. `next` is a node that will be added to the right. +// Used for bin cancellation and inserting spacings. + +const traverseNonSpaceNodes = function traverseNonSpaceNodes(nodes, callback, prev, next) { + if (next) { + // temporarily append the right node, if exists + nodes.push(next); + } + + let i = 0; + + for (; i < nodes.length; i++) { + const node = nodes[i]; + const partialGroup = checkPartialGroup(node); + + if (partialGroup) { + // Recursive DFS + // $FlowFixMe: make nodes a $ReadOnlyArray by returning a new array + traverseNonSpaceNodes(partialGroup.children, callback, prev); + continue; + } // Ignore explicit spaces (e.g., \;, \,) when determining what implicit + // spacing should go between atoms of different classes + + + if (node.classes[0] === "mspace") { + continue; + } + + const result = callback(node, prev.node); + + if (result) { + if (prev.insertAfter) { + prev.insertAfter(result); + } else { + // insert at front + nodes.unshift(result); + i++; + } + } + + prev.node = node; + + prev.insertAfter = (index => n => { + nodes.splice(index + 1, 0, n); + i++; + })(i); + } + + if (next) { + nodes.pop(); + } +}; // Check if given node is a partial group, i.e., does not affect spacing around. + + +const checkPartialGroup = function checkPartialGroup(node) { + if (node instanceof DocumentFragment || node instanceof Anchor) { + return node; + } + + return null; +}; // Return the outermost node of a domTree. + + +const getOutermostNode = function getOutermostNode(node, side) { + const partialGroup = checkPartialGroup(node); + + if (partialGroup) { + const children = partialGroup.children; + + if (children.length) { + if (side === "right") { + return getOutermostNode(children[children.length - 1], "right"); + } else if (side === "left") { + return getOutermostNode(children[0], "left"); + } + } + } + + return node; +}; // Return math atom class (mclass) of a domTree. +// If `side` is given, it will get the type of the outermost node at given side. + + +const getTypeOfDomTree = function getTypeOfDomTree(node, side) { + if (!node) { + return null; + } + + if (side) { + node = getOutermostNode(node, side); + } // This makes a lot of assumptions as to where the type of atom + // appears. We should do a better job of enforcing this. + + + return DomEnum[node.classes[0]] || null; +}; +const makeNullDelimiter = function makeNullDelimiter(options, classes) { + const moreClasses = ["nulldelimiter"].concat(options.baseSizingClasses()); + return makeSpan$1(classes.concat(moreClasses)); +}; +/** + * buildGroup is the function that takes a group and calls the correct groupType + * function for it. It also handles the interaction of size and style changes + * between parents and children. + */ + +const buildGroup = function buildGroup(group, options, baseOptions) { + if (!group) { + return makeSpan$1(); + } + + if (_htmlGroupBuilders[group.type]) { + // Call the groupBuilders function + let groupNode = _htmlGroupBuilders[group.type](group, options); // If the size changed between the parent and the current group, account + // for that size difference. + + if (baseOptions && options.size !== baseOptions.size) { + groupNode = makeSpan$1(options.sizingClasses(baseOptions), [groupNode], options); + const multiplier = options.sizeMultiplier / baseOptions.sizeMultiplier; + groupNode.height *= multiplier; + groupNode.depth *= multiplier; + } + + return groupNode; + } else { + throw new ParseError("Got group of unknown type: '" + group.type + "'"); + } +}; +/** + * Combine an array of HTML DOM nodes (e.g., the output of `buildExpression`) + * into an unbreakable HTML node of class .base, with proper struts to + * guarantee correct vertical extent. `buildHTML` calls this repeatedly to + * make up the entire expression as a sequence of unbreakable units. + */ + +function buildHTMLUnbreakable(children, options) { + // Compute height and depth of this chunk. + const body = makeSpan$1(["base"], children, options); // Add strut, which ensures that the top of the HTML element falls at + // the height of the expression, and the bottom of the HTML element + // falls at the depth of the expression. + // We used to have separate top and bottom struts, where the bottom strut + // would like to use `vertical-align: top`, but in IE 9 this lowers the + // baseline of the box to the bottom of this strut (instead of staying in + // the normal place) so we use an absolute value for vertical-align instead. + + const strut = makeSpan$1(["strut"]); + strut.style.height = body.height + body.depth + "em"; + strut.style.verticalAlign = -body.depth + "em"; + body.children.unshift(strut); + return body; +} +/** + * Take an entire parse tree, and build it into an appropriate set of HTML + * nodes. + */ + + +function buildHTML(tree, options) { + // Strip off outer tag wrapper for processing below. + let tag = null; + + if (tree.length === 1 && tree[0].type === "tag") { + tag = tree[0].tag; + tree = tree[0].body; + } // Build the expression contained in the tree + + + const expression = buildExpression(tree, options, true); + const children = []; // Create one base node for each chunk between potential line breaks. + // The TeXBook [p.173] says "A formula will be broken only after a + // relation symbol like $=$ or $<$ or $\rightarrow$, or after a binary + // operation symbol like $+$ or $-$ or $\times$, where the relation or + // binary operation is on the ``outer level'' of the formula (i.e., not + // enclosed in {...} and not part of an \over construction)." + + let parts = []; + + for (let i = 0; i < expression.length; i++) { + parts.push(expression[i]); + + if (expression[i].hasClass("mbin") || expression[i].hasClass("mrel") || expression[i].hasClass("allowbreak")) { + // Put any post-operator glue on same line as operator. + // Watch for \nobreak along the way, and stop at \newline. + let nobreak = false; + + while (i < expression.length - 1 && expression[i + 1].hasClass("mspace") && !expression[i + 1].hasClass("newline")) { + i++; + parts.push(expression[i]); + + if (expression[i].hasClass("nobreak")) { + nobreak = true; + } + } // Don't allow break if \nobreak among the post-operator glue. + + + if (!nobreak) { + children.push(buildHTMLUnbreakable(parts, options)); + parts = []; + } + } else if (expression[i].hasClass("newline")) { + // Write the line except the newline + parts.pop(); + + if (parts.length > 0) { + children.push(buildHTMLUnbreakable(parts, options)); + parts = []; + } // Put the newline at the top level + + + children.push(expression[i]); + } + } + + if (parts.length > 0) { + children.push(buildHTMLUnbreakable(parts, options)); + } // Now, if there was a tag, build it too and append it as a final child. + + + let tagChild; + + if (tag) { + tagChild = buildHTMLUnbreakable(buildExpression(tag, options, true)); + tagChild.classes = ["tag"]; + children.push(tagChild); + } + + const htmlNode = makeSpan$1(["katex-html"], children); + htmlNode.setAttribute("aria-hidden", "true"); // Adjust the strut of the tag to be the maximum height of all children + // (the height of the enclosing htmlNode) for proper vertical alignment. + + if (tagChild) { + const strut = tagChild.children[0]; + strut.style.height = htmlNode.height + htmlNode.depth + "em"; + strut.style.verticalAlign = -htmlNode.depth + "em"; + } + + return htmlNode; +} + +/** + * These objects store data about MathML nodes. This is the MathML equivalent + * of the types in domTree.js. Since MathML handles its own rendering, and + * since we're mainly using MathML to improve accessibility, we don't manage + * any of the styling state that the plain DOM nodes do. + * + * The `toNode` and `toMarkup` functions work simlarly to how they do in + * domTree.js, creating namespaced DOM nodes and HTML text markup respectively. + */ +function newDocumentFragment(children) { + return new DocumentFragment(children); +} +/** + * This node represents a general purpose MathML node of any type. The + * constructor requires the type of node to create (for example, `"mo"` or + * `"mspace"`, corresponding to `` and `` tags). + */ + +class MathNode { + constructor(type, children) { + this.type = void 0; + this.attributes = void 0; + this.children = void 0; + this.type = type; + this.attributes = {}; + this.children = children || []; + } + /** + * Sets an attribute on a MathML node. MathML depends on attributes to convey a + * semantic content, so this is used heavily. + */ + + + setAttribute(name, value) { + this.attributes[name] = value; + } + /** + * Gets an attribute on a MathML node. + */ + + + getAttribute(name) { + return this.attributes[name]; + } + /** + * Converts the math node into a MathML-namespaced DOM element. + */ + + + toNode() { + const node = document.createElementNS("http://www.w3.org/1998/Math/MathML", this.type); + + for (const attr in this.attributes) { + if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) { + node.setAttribute(attr, this.attributes[attr]); + } + } + + for (let i = 0; i < this.children.length; i++) { + node.appendChild(this.children[i].toNode()); + } + + return node; + } + /** + * Converts the math node into an HTML markup string. + */ + + + toMarkup() { + let markup = "<" + this.type; // Add the attributes + + for (const attr in this.attributes) { + if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) { + markup += " " + attr + "=\""; + markup += utils.escape(this.attributes[attr]); + markup += "\""; + } + } + + markup += ">"; + + for (let i = 0; i < this.children.length; i++) { + markup += this.children[i].toMarkup(); + } + + markup += ""; + return markup; + } + /** + * Converts the math node into a string, similar to innerText, but escaped. + */ + + + toText() { + return this.children.map(child => child.toText()).join(""); + } + +} +/** + * This node represents a piece of text. + */ + +class TextNode { + constructor(text) { + this.text = void 0; + this.text = text; + } + /** + * Converts the text node into a DOM text node. + */ + + + toNode() { + return document.createTextNode(this.text); + } + /** + * Converts the text node into escaped HTML markup + * (representing the text itself). + */ + + + toMarkup() { + return utils.escape(this.toText()); + } + /** + * Converts the text node into a string + * (representing the text iteself). + */ + + + toText() { + return this.text; + } + +} +/** + * This node represents a space, but may render as or as text, + * depending on the width. + */ + +class SpaceNode { + /** + * Create a Space node with width given in CSS ems. + */ + constructor(width) { + this.width = void 0; + this.character = void 0; + this.width = width; // See https://www.w3.org/TR/2000/WD-MathML2-20000328/chapter6.html + // for a table of space-like characters. We use Unicode + // representations instead of &LongNames; as it's not clear how to + // make the latter via document.createTextNode. + + if (width >= 0.05555 && width <= 0.05556) { + this.character = "\u200a"; //   + } else if (width >= 0.1666 && width <= 0.1667) { + this.character = "\u2009"; //   + } else if (width >= 0.2222 && width <= 0.2223) { + this.character = "\u2005"; //   + } else if (width >= 0.2777 && width <= 0.2778) { + this.character = "\u2005\u200a"; //    + } else if (width >= -0.05556 && width <= -0.05555) { + this.character = "\u200a\u2063"; // ​ + } else if (width >= -0.1667 && width <= -0.1666) { + this.character = "\u2009\u2063"; // ​ + } else if (width >= -0.2223 && width <= -0.2222) { + this.character = "\u205f\u2063"; // ​ + } else if (width >= -0.2778 && width <= -0.2777) { + this.character = "\u2005\u2063"; // ​ + } else { + this.character = null; + } + } + /** + * Converts the math node into a MathML-namespaced DOM element. + */ + + + toNode() { + if (this.character) { + return document.createTextNode(this.character); + } else { + const node = document.createElementNS("http://www.w3.org/1998/Math/MathML", "mspace"); + node.setAttribute("width", this.width + "em"); + return node; + } + } + /** + * Converts the math node into an HTML markup string. + */ + + + toMarkup() { + if (this.character) { + return `${this.character}`; + } else { + return ``; + } + } + /** + * Converts the math node into a string, similar to innerText. + */ + + + toText() { + if (this.character) { + return this.character; + } else { + return " "; + } + } + +} + +var mathMLTree = { + MathNode, + TextNode, + SpaceNode, + newDocumentFragment +}; + +/** + * This file converts a parse tree into a cooresponding MathML tree. The main + * entry point is the `buildMathML` function, which takes a parse tree from the + * parser. + */ + +/** + * Takes a symbol and converts it into a MathML text node after performing + * optional replacement from symbols.js. + */ +const makeText = function makeText(text, mode, options) { + if (symbols[mode][text] && symbols[mode][text].replace && text.charCodeAt(0) !== 0xD835 && !(ligatures.hasOwnProperty(text) && options && (options.fontFamily && options.fontFamily.substr(4, 2) === "tt" || options.font && options.font.substr(4, 2) === "tt"))) { + text = symbols[mode][text].replace; + } + + return new mathMLTree.TextNode(text); +}; +/** + * Wrap the given array of nodes in an node if needed, i.e., + * unless the array has length 1. Always returns a single node. + */ + +const makeRow = function makeRow(body) { + if (body.length === 1) { + return body[0]; + } else { + return new mathMLTree.MathNode("mrow", body); + } +}; +/** + * Returns the math variant as a string or null if none is required. + */ + +const getVariant = function getVariant(group, options) { + // Handle \text... font specifiers as best we can. + // MathML has a limited list of allowable mathvariant specifiers; see + // https://www.w3.org/TR/MathML3/chapter3.html#presm.commatt + if (options.fontFamily === "texttt") { + return "monospace"; + } else if (options.fontFamily === "textsf") { + if (options.fontShape === "textit" && options.fontWeight === "textbf") { + return "sans-serif-bold-italic"; + } else if (options.fontShape === "textit") { + return "sans-serif-italic"; + } else if (options.fontWeight === "textbf") { + return "bold-sans-serif"; + } else { + return "sans-serif"; + } + } else if (options.fontShape === "textit" && options.fontWeight === "textbf") { + return "bold-italic"; + } else if (options.fontShape === "textit") { + return "italic"; + } else if (options.fontWeight === "textbf") { + return "bold"; + } + + const font = options.font; + + if (!font || font === "mathnormal") { + return null; + } + + const mode = group.mode; + + if (font === "mathit") { + return "italic"; + } else if (font === "boldsymbol") { + return "bold-italic"; + } else if (font === "mathbf") { + return "bold"; + } else if (font === "mathbb") { + return "double-struck"; + } else if (font === "mathfrak") { + return "fraktur"; + } else if (font === "mathscr" || font === "mathcal") { + // MathML makes no distinction between script and caligrahpic + return "script"; + } else if (font === "mathsf") { + return "sans-serif"; + } else if (font === "mathtt") { + return "monospace"; + } + + let text = group.text; + + if (utils.contains(["\\imath", "\\jmath"], text)) { + return null; + } + + if (symbols[mode][text] && symbols[mode][text].replace) { + text = symbols[mode][text].replace; + } + + const fontName = buildCommon.fontMap[font].fontName; + + if (getCharacterMetrics(text, fontName, mode)) { + return buildCommon.fontMap[font].variant; + } + + return null; +}; +/** + * Takes a list of nodes, builds them, and returns a list of the generated + * MathML nodes. Also combine consecutive outputs into a single + * tag. + */ + +const buildExpression$1 = function buildExpression(expression, options, isOrdgroup) { + if (expression.length === 1) { + const group = buildGroup$1(expression[0], options); + + if (isOrdgroup && group instanceof MathNode && group.type === "mo") { + // When TeX writers want to suppress spacing on an operator, + // they often put the operator by itself inside braces. + group.setAttribute("lspace", "0em"); + group.setAttribute("rspace", "0em"); + } + + return [group]; + } + + const groups = []; + let lastGroup; + + for (let i = 0; i < expression.length; i++) { + const group = buildGroup$1(expression[i], options); + + if (group instanceof MathNode && lastGroup instanceof MathNode) { + // Concatenate adjacent s + if (group.type === 'mtext' && lastGroup.type === 'mtext' && group.getAttribute('mathvariant') === lastGroup.getAttribute('mathvariant')) { + lastGroup.children.push(...group.children); + continue; // Concatenate adjacent s + } else if (group.type === 'mn' && lastGroup.type === 'mn') { + lastGroup.children.push(...group.children); + continue; // Concatenate ... followed by . + } else if (group.type === 'mi' && group.children.length === 1 && lastGroup.type === 'mn') { + const child = group.children[0]; + + if (child instanceof TextNode && child.text === '.') { + lastGroup.children.push(...group.children); + continue; + } + } else if (lastGroup.type === 'mi' && lastGroup.children.length === 1) { + const lastChild = lastGroup.children[0]; + + if (lastChild instanceof TextNode && lastChild.text === '\u0338' && (group.type === 'mo' || group.type === 'mi' || group.type === 'mn')) { + const child = group.children[0]; + + if (child instanceof TextNode && child.text.length > 0) { + // Overlay with combining character long solidus + child.text = child.text.slice(0, 1) + "\u0338" + child.text.slice(1); + groups.pop(); + } + } + } + } + + groups.push(group); + lastGroup = group; + } + + return groups; +}; +/** + * Equivalent to buildExpression, but wraps the elements in an + * if there's more than one. Returns a single node instead of an array. + */ + +const buildExpressionRow = function buildExpressionRow(expression, options, isOrdgroup) { + return makeRow(buildExpression$1(expression, options, isOrdgroup)); +}; +/** + * Takes a group from the parser and calls the appropriate groupBuilders function + * on it to produce a MathML node. + */ + +const buildGroup$1 = function buildGroup(group, options) { + if (!group) { + return new mathMLTree.MathNode("mrow"); + } + + if (_mathmlGroupBuilders[group.type]) { + // Call the groupBuilders function + const result = _mathmlGroupBuilders[group.type](group, options); + return result; + } else { + throw new ParseError("Got group of unknown type: '" + group.type + "'"); + } +}; +/** + * Takes a full parse tree and settings and builds a MathML representation of + * it. In particular, we put the elements from building the parse tree into a + * tag so we can also include that TeX source as an annotation. + * + * Note that we actually return a domTree element with a `` inside it so + * we can do appropriate styling. + */ + +function buildMathML(tree, texExpression, options, forMathmlOnly) { + const expression = buildExpression$1(tree, options); // Wrap up the expression in an mrow so it is presented in the semantics + // tag correctly, unless it's a single or . + + let wrapper; + + if (expression.length === 1 && expression[0] instanceof MathNode && utils.contains(["mrow", "mtable"], expression[0].type)) { + wrapper = expression[0]; + } else { + wrapper = new mathMLTree.MathNode("mrow", expression); + } // Build a TeX annotation of the source + + + const annotation = new mathMLTree.MathNode("annotation", [new mathMLTree.TextNode(texExpression)]); + annotation.setAttribute("encoding", "application/x-tex"); + const semantics = new mathMLTree.MathNode("semantics", [wrapper, annotation]); + const math = new mathMLTree.MathNode("math", [semantics]); + math.setAttribute("xmlns", "http://www.w3.org/1998/Math/MathML"); // You can't style nodes, so we wrap the node in a span. + // NOTE: The span class is not typed to have nodes as children, and + // we don't want to make the children type more generic since the children + // of span are expected to have more fields in `buildHtml` contexts. + + const wrapperClass = forMathmlOnly ? "katex" : "katex-mathml"; // $FlowFixMe + + return buildCommon.makeSpan([wrapperClass], [math]); +} + +const optionsFromSettings = function optionsFromSettings(settings) { + return new Options({ + style: settings.displayMode ? Style$1.DISPLAY : Style$1.TEXT, + maxSize: settings.maxSize, + minRuleThickness: settings.minRuleThickness + }); +}; + +const displayWrap = function displayWrap(node, settings) { + if (settings.displayMode) { + const classes = ["katex-display"]; + + if (settings.leqno) { + classes.push("leqno"); + } + + if (settings.fleqn) { + classes.push("fleqn"); + } + + node = buildCommon.makeSpan(classes, [node]); + } + + return node; +}; + +const buildTree = function buildTree(tree, expression, settings) { + const options = optionsFromSettings(settings); + let katexNode; + + if (settings.output === "mathml") { + return buildMathML(tree, expression, options, true); + } else if (settings.output === "html") { + const htmlNode = buildHTML(tree, options); + katexNode = buildCommon.makeSpan(["katex"], [htmlNode]); + } else { + const mathMLNode = buildMathML(tree, expression, options, false); + const htmlNode = buildHTML(tree, options); + katexNode = buildCommon.makeSpan(["katex"], [mathMLNode, htmlNode]); + } + + return displayWrap(katexNode, settings); +}; +const buildHTMLTree = function buildHTMLTree(tree, expression, settings) { + const options = optionsFromSettings(settings); + const htmlNode = buildHTML(tree, options); + const katexNode = buildCommon.makeSpan(["katex"], [htmlNode]); + return displayWrap(katexNode, settings); +}; + +/** + * This file provides support to buildMathML.js and buildHTML.js + * for stretchy wide elements rendered from SVG files + * and other CSS trickery. + */ +const stretchyCodePoint = { + widehat: "^", + widecheck: "ˇ", + widetilde: "~", + utilde: "~", + overleftarrow: "\u2190", + underleftarrow: "\u2190", + xleftarrow: "\u2190", + overrightarrow: "\u2192", + underrightarrow: "\u2192", + xrightarrow: "\u2192", + underbrace: "\u23df", + overbrace: "\u23de", + overgroup: "\u23e0", + undergroup: "\u23e1", + overleftrightarrow: "\u2194", + underleftrightarrow: "\u2194", + xleftrightarrow: "\u2194", + Overrightarrow: "\u21d2", + xRightarrow: "\u21d2", + overleftharpoon: "\u21bc", + xleftharpoonup: "\u21bc", + overrightharpoon: "\u21c0", + xrightharpoonup: "\u21c0", + xLeftarrow: "\u21d0", + xLeftrightarrow: "\u21d4", + xhookleftarrow: "\u21a9", + xhookrightarrow: "\u21aa", + xmapsto: "\u21a6", + xrightharpoondown: "\u21c1", + xleftharpoondown: "\u21bd", + xrightleftharpoons: "\u21cc", + xleftrightharpoons: "\u21cb", + xtwoheadleftarrow: "\u219e", + xtwoheadrightarrow: "\u21a0", + xlongequal: "=", + xtofrom: "\u21c4", + xrightleftarrows: "\u21c4", + xrightequilibrium: "\u21cc", + // Not a perfect match. + xleftequilibrium: "\u21cb" // None better available. + +}; + +const mathMLnode = function mathMLnode(label) { + const node = new mathMLTree.MathNode("mo", [new mathMLTree.TextNode(stretchyCodePoint[label.substr(1)])]); + node.setAttribute("stretchy", "true"); + return node; +}; // Many of the KaTeX SVG images have been adapted from glyphs in KaTeX fonts. +// Copyright (c) 2009-2010, Design Science, Inc. () +// Copyright (c) 2014-2017 Khan Academy () +// Licensed under the SIL Open Font License, Version 1.1. +// See \nhttp://scripts.sil.org/OFL +// Very Long SVGs +// Many of the KaTeX stretchy wide elements use a long SVG image and an +// overflow: hidden tactic to achieve a stretchy image while avoiding +// distortion of arrowheads or brace corners. +// The SVG typically contains a very long (400 em) arrow. +// The SVG is in a container span that has overflow: hidden, so the span +// acts like a window that exposes only part of the SVG. +// The SVG always has a longer, thinner aspect ratio than the container span. +// After the SVG fills 100% of the height of the container span, +// there is a long arrow shaft left over. That left-over shaft is not shown. +// Instead, it is sliced off because the span's CSS has overflow: hidden. +// Thus, the reader sees an arrow that matches the subject matter width +// without distortion. +// Some functions, such as \cancel, need to vary their aspect ratio. These +// functions do not get the overflow SVG treatment. +// Second Brush Stroke +// Low resolution monitors struggle to display images in fine detail. +// So browsers apply anti-aliasing. A long straight arrow shaft therefore +// will sometimes appear as if it has a blurred edge. +// To mitigate this, these SVG files contain a second "brush-stroke" on the +// arrow shafts. That is, a second long thin rectangular SVG path has been +// written directly on top of each arrow shaft. This reinforcement causes +// some of the screen pixels to display as black instead of the anti-aliased +// gray pixel that a single path would generate. So we get arrow shafts +// whose edges appear to be sharper. +// In the katexImagesData object just below, the dimensions all +// correspond to path geometry inside the relevant SVG. +// For example, \overrightarrow uses the same arrowhead as glyph U+2192 +// from the KaTeX Main font. The scaling factor is 1000. +// That is, inside the font, that arrowhead is 522 units tall, which +// corresponds to 0.522 em inside the document. + + +const katexImagesData = { + // path(s), minWidth, height, align + overrightarrow: [["rightarrow"], 0.888, 522, "xMaxYMin"], + overleftarrow: [["leftarrow"], 0.888, 522, "xMinYMin"], + underrightarrow: [["rightarrow"], 0.888, 522, "xMaxYMin"], + underleftarrow: [["leftarrow"], 0.888, 522, "xMinYMin"], + xrightarrow: [["rightarrow"], 1.469, 522, "xMaxYMin"], + xleftarrow: [["leftarrow"], 1.469, 522, "xMinYMin"], + Overrightarrow: [["doublerightarrow"], 0.888, 560, "xMaxYMin"], + xRightarrow: [["doublerightarrow"], 1.526, 560, "xMaxYMin"], + xLeftarrow: [["doubleleftarrow"], 1.526, 560, "xMinYMin"], + overleftharpoon: [["leftharpoon"], 0.888, 522, "xMinYMin"], + xleftharpoonup: [["leftharpoon"], 0.888, 522, "xMinYMin"], + xleftharpoondown: [["leftharpoondown"], 0.888, 522, "xMinYMin"], + overrightharpoon: [["rightharpoon"], 0.888, 522, "xMaxYMin"], + xrightharpoonup: [["rightharpoon"], 0.888, 522, "xMaxYMin"], + xrightharpoondown: [["rightharpoondown"], 0.888, 522, "xMaxYMin"], + xlongequal: [["longequal"], 0.888, 334, "xMinYMin"], + xtwoheadleftarrow: [["twoheadleftarrow"], 0.888, 334, "xMinYMin"], + xtwoheadrightarrow: [["twoheadrightarrow"], 0.888, 334, "xMaxYMin"], + overleftrightarrow: [["leftarrow", "rightarrow"], 0.888, 522], + overbrace: [["leftbrace", "midbrace", "rightbrace"], 1.6, 548], + underbrace: [["leftbraceunder", "midbraceunder", "rightbraceunder"], 1.6, 548], + underleftrightarrow: [["leftarrow", "rightarrow"], 0.888, 522], + xleftrightarrow: [["leftarrow", "rightarrow"], 1.75, 522], + xLeftrightarrow: [["doubleleftarrow", "doublerightarrow"], 1.75, 560], + xrightleftharpoons: [["leftharpoondownplus", "rightharpoonplus"], 1.75, 716], + xleftrightharpoons: [["leftharpoonplus", "rightharpoondownplus"], 1.75, 716], + xhookleftarrow: [["leftarrow", "righthook"], 1.08, 522], + xhookrightarrow: [["lefthook", "rightarrow"], 1.08, 522], + overlinesegment: [["leftlinesegment", "rightlinesegment"], 0.888, 522], + underlinesegment: [["leftlinesegment", "rightlinesegment"], 0.888, 522], + overgroup: [["leftgroup", "rightgroup"], 0.888, 342], + undergroup: [["leftgroupunder", "rightgroupunder"], 0.888, 342], + xmapsto: [["leftmapsto", "rightarrow"], 1.5, 522], + xtofrom: [["leftToFrom", "rightToFrom"], 1.75, 528], + // The next three arrows are from the mhchem package. + // In mhchem.sty, min-length is 2.0em. But these arrows might appear in the + // document as \xrightarrow or \xrightleftharpoons. Those have + // min-length = 1.75em, so we set min-length on these next three to match. + xrightleftarrows: [["baraboveleftarrow", "rightarrowabovebar"], 1.75, 901], + xrightequilibrium: [["baraboveshortleftharpoon", "rightharpoonaboveshortbar"], 1.75, 716], + xleftequilibrium: [["shortbaraboveleftharpoon", "shortrightharpoonabovebar"], 1.75, 716] +}; + +const groupLength = function groupLength(arg) { + if (arg.type === "ordgroup") { + return arg.body.length; + } else { + return 1; + } +}; + +const svgSpan = function svgSpan(group, options) { + // Create a span with inline SVG for the element. + function buildSvgSpan_() { + let viewBoxWidth = 400000; // default + + const label = group.label.substr(1); + + if (utils.contains(["widehat", "widecheck", "widetilde", "utilde"], label)) { + // Each type in the `if` statement corresponds to one of the ParseNode + // types below. This narrowing is required to access `grp.base`. + const grp = group; // There are four SVG images available for each function. + // Choose a taller image when there are more characters. + + const numChars = groupLength(grp.base); + let viewBoxHeight; + let pathName; + let height; + + if (numChars > 5) { + if (label === "widehat" || label === "widecheck") { + viewBoxHeight = 420; + viewBoxWidth = 2364; + height = 0.42; + pathName = label + "4"; + } else { + viewBoxHeight = 312; + viewBoxWidth = 2340; + height = 0.34; + pathName = "tilde4"; + } + } else { + const imgIndex = [1, 1, 2, 2, 3, 3][numChars]; + + if (label === "widehat" || label === "widecheck") { + viewBoxWidth = [0, 1062, 2364, 2364, 2364][imgIndex]; + viewBoxHeight = [0, 239, 300, 360, 420][imgIndex]; + height = [0, 0.24, 0.3, 0.3, 0.36, 0.42][imgIndex]; + pathName = label + imgIndex; + } else { + viewBoxWidth = [0, 600, 1033, 2339, 2340][imgIndex]; + viewBoxHeight = [0, 260, 286, 306, 312][imgIndex]; + height = [0, 0.26, 0.286, 0.3, 0.306, 0.34][imgIndex]; + pathName = "tilde" + imgIndex; + } + } + + const path = new PathNode(pathName); + const svgNode = new SvgNode([path], { + "width": "100%", + "height": height + "em", + "viewBox": `0 0 ${viewBoxWidth} ${viewBoxHeight}`, + "preserveAspectRatio": "none" + }); + return { + span: buildCommon.makeSvgSpan([], [svgNode], options), + minWidth: 0, + height + }; + } else { + const spans = []; + const data = katexImagesData[label]; + const paths = data[0], + minWidth = data[1], + viewBoxHeight = data[2]; + const height = viewBoxHeight / 1000; + const numSvgChildren = paths.length; + let widthClasses; + let aligns; + + if (numSvgChildren === 1) { + // $FlowFixMe: All these cases must be of the 4-tuple type. + const align1 = data[3]; + widthClasses = ["hide-tail"]; + aligns = [align1]; + } else if (numSvgChildren === 2) { + widthClasses = ["halfarrow-left", "halfarrow-right"]; + aligns = ["xMinYMin", "xMaxYMin"]; + } else if (numSvgChildren === 3) { + widthClasses = ["brace-left", "brace-center", "brace-right"]; + aligns = ["xMinYMin", "xMidYMin", "xMaxYMin"]; + } else { + throw new Error(`Correct katexImagesData or update code here to support + ${numSvgChildren} children.`); + } + + for (let i = 0; i < numSvgChildren; i++) { + const path = new PathNode(paths[i]); + const svgNode = new SvgNode([path], { + "width": "400em", + "height": height + "em", + "viewBox": `0 0 ${viewBoxWidth} ${viewBoxHeight}`, + "preserveAspectRatio": aligns[i] + " slice" + }); + const span = buildCommon.makeSvgSpan([widthClasses[i]], [svgNode], options); + + if (numSvgChildren === 1) { + return { + span, + minWidth, + height + }; + } else { + span.style.height = height + "em"; + spans.push(span); + } + } + + return { + span: buildCommon.makeSpan(["stretchy"], spans, options), + minWidth, + height + }; + } + } // buildSvgSpan_() + + + const _buildSvgSpan_ = buildSvgSpan_(), + span = _buildSvgSpan_.span, + minWidth = _buildSvgSpan_.minWidth, + height = _buildSvgSpan_.height; // Note that we are returning span.depth = 0. + // Any adjustments relative to the baseline must be done in buildHTML. + + + span.height = height; + span.style.height = height + "em"; + + if (minWidth > 0) { + span.style.minWidth = minWidth + "em"; + } + + return span; +}; + +const encloseSpan = function encloseSpan(inner, label, pad, options) { + // Return an image span for \cancel, \bcancel, \xcancel, or \fbox + let img; + const totalHeight = inner.height + inner.depth + 2 * pad; + + if (/fbox|color/.test(label)) { + img = buildCommon.makeSpan(["stretchy", label], [], options); + + if (label === "fbox") { + const color = options.color && options.getColor(); + + if (color) { + img.style.borderColor = color; + } + } + } else { + // \cancel, \bcancel, or \xcancel + // Since \cancel's SVG is inline and it omits the viewBox attribute, + // its stroke-width will not vary with span area. + const lines = []; + + if (/^[bx]cancel$/.test(label)) { + lines.push(new LineNode({ + "x1": "0", + "y1": "0", + "x2": "100%", + "y2": "100%", + "stroke-width": "0.046em" + })); + } + + if (/^x?cancel$/.test(label)) { + lines.push(new LineNode({ + "x1": "0", + "y1": "100%", + "x2": "100%", + "y2": "0", + "stroke-width": "0.046em" + })); + } + + const svgNode = new SvgNode(lines, { + "width": "100%", + "height": totalHeight + "em" + }); + img = buildCommon.makeSvgSpan([], [svgNode], options); + } + + img.height = totalHeight; + img.style.height = totalHeight + "em"; + return img; +}; + +var stretchy = { + encloseSpan, + mathMLnode, + svgSpan +}; + +// NOTE: Unlike most `htmlBuilder`s, this one handles not only "accent", but +const htmlBuilder = (grp, options) => { + // Accents are handled in the TeXbook pg. 443, rule 12. + let base; + let group; + const supSub = checkNodeType(grp, "supsub"); + let supSubGroup; + + if (supSub) { + // If our base is a character box, and we have superscripts and + // subscripts, the supsub will defer to us. In particular, we want + // to attach the superscripts and subscripts to the inner body (so + // that the position of the superscripts and subscripts won't be + // affected by the height of the accent). We accomplish this by + // sticking the base of the accent into the base of the supsub, and + // rendering that, while keeping track of where the accent is. + // The real accent group is the base of the supsub group + group = assertNodeType(supSub.base, "accent"); // The character box is the base of the accent group + + base = group.base; // Stick the character box into the base of the supsub group + + supSub.base = base; // Rerender the supsub group with its new base, and store that + // result. + + supSubGroup = assertSpan(buildGroup(supSub, options)); // reset original base + + supSub.base = group; + } else { + group = assertNodeType(grp, "accent"); + base = group.base; + } // Build the base group + + + const body = buildGroup(base, options.havingCrampedStyle()); // Does the accent need to shift for the skew of a character? + + const mustShift = group.isShifty && utils.isCharacterBox(base); // Calculate the skew of the accent. This is based on the line "If the + // nucleus is not a single character, let s = 0; otherwise set s to the + // kern amount for the nucleus followed by the \skewchar of its font." + // Note that our skew metrics are just the kern between each character + // and the skewchar. + + let skew = 0; + + if (mustShift) { + // If the base is a character box, then we want the skew of the + // innermost character. To do that, we find the innermost character: + const baseChar = utils.getBaseElem(base); // Then, we render its group to get the symbol inside it + + const baseGroup = buildGroup(baseChar, options.havingCrampedStyle()); // Finally, we pull the skew off of the symbol. + + skew = assertSymbolDomNode(baseGroup).skew; // Note that we now throw away baseGroup, because the layers we + // removed with getBaseElem might contain things like \color which + // we can't get rid of. + // TODO(emily): Find a better way to get the skew + } // calculate the amount of space between the body and the accent + + + let clearance = Math.min(body.height, options.fontMetrics().xHeight); // Build the accent + + let accentBody; + + if (!group.isStretchy) { + let accent; + let width; + + if (group.label === "\\vec") { + // Before version 0.9, \vec used the combining font glyph U+20D7. + // But browsers, especially Safari, are not consistent in how they + // render combining characters when not preceded by a character. + // So now we use an SVG. + // If Safari reforms, we should consider reverting to the glyph. + accent = buildCommon.staticSvg("vec", options); + width = buildCommon.svgData.vec[1]; + } else { + accent = buildCommon.makeOrd({ + mode: group.mode, + text: group.label + }, options, "textord"); + accent = assertSymbolDomNode(accent); // Remove the italic correction of the accent, because it only serves to + // shift the accent over to a place we don't want. + + accent.italic = 0; + width = accent.width; + } + + accentBody = buildCommon.makeSpan(["accent-body"], [accent]); // "Full" accents expand the width of the resulting symbol to be + // at least the width of the accent, and overlap directly onto the + // character without any vertical offset. + + const accentFull = group.label === "\\textcircled"; + + if (accentFull) { + accentBody.classes.push('accent-full'); + clearance = body.height; + } // Shift the accent over by the skew. + + + let left = skew; // CSS defines `.katex .accent .accent-body:not(.accent-full) { width: 0 }` + // so that the accent doesn't contribute to the bounding box. + // We need to shift the character by its width (effectively half + // its width) to compensate. + + if (!accentFull) { + left -= width / 2; + } + + accentBody.style.left = left + "em"; // \textcircled uses the \bigcirc glyph, so it needs some + // vertical adjustment to match LaTeX. + + if (group.label === "\\textcircled") { + accentBody.style.top = ".2em"; + } + + accentBody = buildCommon.makeVList({ + positionType: "firstBaseline", + children: [{ + type: "elem", + elem: body + }, { + type: "kern", + size: -clearance + }, { + type: "elem", + elem: accentBody + }] + }, options); + } else { + accentBody = stretchy.svgSpan(group, options); + accentBody = buildCommon.makeVList({ + positionType: "firstBaseline", + children: [{ + type: "elem", + elem: body + }, { + type: "elem", + elem: accentBody, + wrapperClasses: ["svg-align"], + wrapperStyle: skew > 0 ? { + width: `calc(100% - ${2 * skew}em)`, + marginLeft: `${2 * skew}em` + } : undefined + }] + }, options); + } + + const accentWrap = buildCommon.makeSpan(["mord", "accent"], [accentBody], options); + + if (supSubGroup) { + // Here, we replace the "base" child of the supsub with our newly + // generated accent. + supSubGroup.children[0] = accentWrap; // Since we don't rerun the height calculation after replacing the + // accent, we manually recalculate height. + + supSubGroup.height = Math.max(accentWrap.height, supSubGroup.height); // Accents should always be ords, even when their innards are not. + + supSubGroup.classes[0] = "mord"; + return supSubGroup; + } else { + return accentWrap; + } +}; + +const mathmlBuilder = (group, options) => { + const accentNode = group.isStretchy ? stretchy.mathMLnode(group.label) : new mathMLTree.MathNode("mo", [makeText(group.label, group.mode)]); + const node = new mathMLTree.MathNode("mover", [buildGroup$1(group.base, options), accentNode]); + node.setAttribute("accent", "true"); + return node; +}; + +const NON_STRETCHY_ACCENT_REGEX = new RegExp(["\\acute", "\\grave", "\\ddot", "\\tilde", "\\bar", "\\breve", "\\check", "\\hat", "\\vec", "\\dot", "\\mathring"].map(accent => `\\${accent}`).join("|")); // Accents + +defineFunction({ + type: "accent", + names: ["\\acute", "\\grave", "\\ddot", "\\tilde", "\\bar", "\\breve", "\\check", "\\hat", "\\vec", "\\dot", "\\mathring", "\\widecheck", "\\widehat", "\\widetilde", "\\overrightarrow", "\\overleftarrow", "\\Overrightarrow", "\\overleftrightarrow", "\\overgroup", "\\overlinesegment", "\\overleftharpoon", "\\overrightharpoon"], + props: { + numArgs: 1 + }, + handler: (context, args) => { + const base = args[0]; + const isStretchy = !NON_STRETCHY_ACCENT_REGEX.test(context.funcName); + const isShifty = !isStretchy || context.funcName === "\\widehat" || context.funcName === "\\widetilde" || context.funcName === "\\widecheck"; + return { + type: "accent", + mode: context.parser.mode, + label: context.funcName, + isStretchy: isStretchy, + isShifty: isShifty, + base: base + }; + }, + htmlBuilder, + mathmlBuilder +}); // Text-mode accents + +defineFunction({ + type: "accent", + names: ["\\'", "\\`", "\\^", "\\~", "\\=", "\\u", "\\.", '\\"', "\\r", "\\H", "\\v", "\\textcircled"], + props: { + numArgs: 1, + allowedInText: true, + allowedInMath: false + }, + handler: (context, args) => { + const base = args[0]; + return { + type: "accent", + mode: context.parser.mode, + label: context.funcName, + isStretchy: false, + isShifty: true, + base: base + }; + }, + htmlBuilder, + mathmlBuilder +}); + +// Horizontal overlap functions +defineFunction({ + type: "accentUnder", + names: ["\\underleftarrow", "\\underrightarrow", "\\underleftrightarrow", "\\undergroup", "\\underlinesegment", "\\utilde"], + props: { + numArgs: 1 + }, + handler: (_ref, args) => { + let parser = _ref.parser, + funcName = _ref.funcName; + const base = args[0]; + return { + type: "accentUnder", + mode: parser.mode, + label: funcName, + base: base + }; + }, + htmlBuilder: (group, options) => { + // Treat under accents much like underlines. + const innerGroup = buildGroup(group.base, options); + const accentBody = stretchy.svgSpan(group, options); + const kern = group.label === "\\utilde" ? 0.12 : 0; // Generate the vlist, with the appropriate kerns + + const vlist = buildCommon.makeVList({ + positionType: "bottom", + positionData: accentBody.height + kern, + children: [{ + type: "elem", + elem: accentBody, + wrapperClasses: ["svg-align"] + }, { + type: "kern", + size: kern + }, { + type: "elem", + elem: innerGroup + }] + }, options); + return buildCommon.makeSpan(["mord", "accentunder"], [vlist], options); + }, + mathmlBuilder: (group, options) => { + const accentNode = stretchy.mathMLnode(group.label); + const node = new mathMLTree.MathNode("munder", [buildGroup$1(group.base, options), accentNode]); + node.setAttribute("accentunder", "true"); + return node; + } +}); + +// Helper function +const paddedNode = group => { + const node = new mathMLTree.MathNode("mpadded", group ? [group] : []); + node.setAttribute("width", "+0.6em"); + node.setAttribute("lspace", "0.3em"); + return node; +}; // Stretchy arrows with an optional argument + + +defineFunction({ + type: "xArrow", + names: ["\\xleftarrow", "\\xrightarrow", "\\xLeftarrow", "\\xRightarrow", "\\xleftrightarrow", "\\xLeftrightarrow", "\\xhookleftarrow", "\\xhookrightarrow", "\\xmapsto", "\\xrightharpoondown", "\\xrightharpoonup", "\\xleftharpoondown", "\\xleftharpoonup", "\\xrightleftharpoons", "\\xleftrightharpoons", "\\xlongequal", "\\xtwoheadrightarrow", "\\xtwoheadleftarrow", "\\xtofrom", // The next 3 functions are here to support the mhchem extension. + // Direct use of these functions is discouraged and may break someday. + "\\xrightleftarrows", "\\xrightequilibrium", "\\xleftequilibrium"], + props: { + numArgs: 1, + numOptionalArgs: 1 + }, + + handler(_ref, args, optArgs) { + let parser = _ref.parser, + funcName = _ref.funcName; + return { + type: "xArrow", + mode: parser.mode, + label: funcName, + body: args[0], + below: optArgs[0] + }; + }, + + // Flow is unable to correctly infer the type of `group`, even though it's + // unamibiguously determined from the passed-in `type` above. + htmlBuilder(group, options) { + const style = options.style; // Build the argument groups in the appropriate style. + // Ref: amsmath.dtx: \hbox{$\scriptstyle\mkern#3mu{#6}\mkern#4mu$}% + // Some groups can return document fragments. Handle those by wrapping + // them in a span. + + let newOptions = options.havingStyle(style.sup()); + const upperGroup = buildCommon.wrapFragment(buildGroup(group.body, newOptions, options), options); + upperGroup.classes.push("x-arrow-pad"); + let lowerGroup; + + if (group.below) { + // Build the lower group + newOptions = options.havingStyle(style.sub()); + lowerGroup = buildCommon.wrapFragment(buildGroup(group.below, newOptions, options), options); + lowerGroup.classes.push("x-arrow-pad"); + } + + const arrowBody = stretchy.svgSpan(group, options); // Re shift: Note that stretchy.svgSpan returned arrowBody.depth = 0. + // The point we want on the math axis is at 0.5 * arrowBody.height. + + const arrowShift = -options.fontMetrics().axisHeight + 0.5 * arrowBody.height; // 2 mu kern. Ref: amsmath.dtx: #7\if0#2\else\mkern#2mu\fi + + let upperShift = -options.fontMetrics().axisHeight - 0.5 * arrowBody.height - 0.111; // 0.111 em = 2 mu + + if (upperGroup.depth > 0.25 || group.label === "\\xleftequilibrium") { + upperShift -= upperGroup.depth; // shift up if depth encroaches + } // Generate the vlist + + + let vlist; + + if (lowerGroup) { + const lowerShift = -options.fontMetrics().axisHeight + lowerGroup.height + 0.5 * arrowBody.height + 0.111; + vlist = buildCommon.makeVList({ + positionType: "individualShift", + children: [{ + type: "elem", + elem: upperGroup, + shift: upperShift + }, { + type: "elem", + elem: arrowBody, + shift: arrowShift + }, { + type: "elem", + elem: lowerGroup, + shift: lowerShift + }] + }, options); + } else { + vlist = buildCommon.makeVList({ + positionType: "individualShift", + children: [{ + type: "elem", + elem: upperGroup, + shift: upperShift + }, { + type: "elem", + elem: arrowBody, + shift: arrowShift + }] + }, options); + } // $FlowFixMe: Replace this with passing "svg-align" into makeVList. + + + vlist.children[0].children[0].children[1].classes.push("svg-align"); + return buildCommon.makeSpan(["mrel", "x-arrow"], [vlist], options); + }, + + mathmlBuilder(group, options) { + const arrowNode = stretchy.mathMLnode(group.label); + let node; + + if (group.body) { + const upperNode = paddedNode(buildGroup$1(group.body, options)); + + if (group.below) { + const lowerNode = paddedNode(buildGroup$1(group.below, options)); + node = new mathMLTree.MathNode("munderover", [arrowNode, lowerNode, upperNode]); + } else { + node = new mathMLTree.MathNode("mover", [arrowNode, upperNode]); + } + } else if (group.below) { + const lowerNode = paddedNode(buildGroup$1(group.below, options)); + node = new mathMLTree.MathNode("munder", [arrowNode, lowerNode]); + } else { + // This should never happen. + // Parser.js throws an error if there is no argument. + node = paddedNode(); + node = new mathMLTree.MathNode("mover", [arrowNode, node]); + } + + return node; + } + +}); + +// {123} and converts into symbol with code 123. It is used by the *macro* +// \char defined in macros.js. + +defineFunction({ + type: "textord", + names: ["\\@char"], + props: { + numArgs: 1, + allowedInText: true + }, + + handler(_ref, args) { + let parser = _ref.parser; + const arg = assertNodeType(args[0], "ordgroup"); + const group = arg.body; + let number = ""; + + for (let i = 0; i < group.length; i++) { + const node = assertNodeType(group[i], "textord"); + number += node.text; + } + + const code = parseInt(number); + + if (isNaN(code)) { + throw new ParseError(`\\@char has non-numeric argument ${number}`); + } + + return { + type: "textord", + mode: parser.mode, + text: String.fromCharCode(code) + }; + } + +}); + +const htmlBuilder$1 = (group, options) => { + const elements = buildExpression(group.body, options.withColor(group.color), false); // \color isn't supposed to affect the type of the elements it contains. + // To accomplish this, we wrap the results in a fragment, so the inner + // elements will be able to directly interact with their neighbors. For + // example, `\color{red}{2 +} 3` has the same spacing as `2 + 3` + + return buildCommon.makeFragment(elements); +}; + +const mathmlBuilder$1 = (group, options) => { + const inner = buildExpression$1(group.body, options.withColor(group.color)); + const node = new mathMLTree.MathNode("mstyle", inner); + node.setAttribute("mathcolor", group.color); + return node; +}; + +defineFunction({ + type: "color", + names: ["\\textcolor"], + props: { + numArgs: 2, + allowedInText: true, + greediness: 3, + argTypes: ["color", "original"] + }, + + handler(_ref, args) { + let parser = _ref.parser; + const color = assertNodeType(args[0], "color-token").color; + const body = args[1]; + return { + type: "color", + mode: parser.mode, + color, + body: ordargument(body) + }; + }, + + htmlBuilder: htmlBuilder$1, + mathmlBuilder: mathmlBuilder$1 +}); +defineFunction({ + type: "color", + names: ["\\color"], + props: { + numArgs: 1, + allowedInText: true, + greediness: 3, + argTypes: ["color"] + }, + + handler(_ref2, args) { + let parser = _ref2.parser, + breakOnTokenText = _ref2.breakOnTokenText; + const color = assertNodeType(args[0], "color-token").color; // Set macro \current@color in current namespace to store the current + // color, mimicking the behavior of color.sty. + // This is currently used just to correctly color a \right + // that follows a \color command. + + parser.gullet.macros.set("\\current@color", color); // Parse out the implicit body that should be colored. + + const body = parser.parseExpression(true, breakOnTokenText); + return { + type: "color", + mode: parser.mode, + color, + body + }; + }, + + htmlBuilder: htmlBuilder$1, + mathmlBuilder: mathmlBuilder$1 +}); + +// Row breaks within tabular environments, and line breaks at top level +// same signature, we implement them as one megafunction, with newRow +// indicating whether we're in the \cr case, and newLine indicating whether +// to break the line in the \newline case. + +defineFunction({ + type: "cr", + names: ["\\cr", "\\newline"], + props: { + numArgs: 0, + numOptionalArgs: 1, + argTypes: ["size"], + allowedInText: true + }, + + handler(_ref, args, optArgs) { + let parser = _ref.parser, + funcName = _ref.funcName; + const size = optArgs[0]; + const newRow = funcName === "\\cr"; + let newLine = false; + + if (!newRow) { + if (parser.settings.displayMode && parser.settings.useStrictBehavior("newLineInDisplayMode", "In LaTeX, \\\\ or \\newline " + "does nothing in display mode")) { + newLine = false; + } else { + newLine = true; + } + } + + return { + type: "cr", + mode: parser.mode, + newLine, + newRow, + size: size && assertNodeType(size, "size").value + }; + }, + + // The following builders are called only at the top level, + // not within tabular/array environments. + htmlBuilder(group, options) { + if (group.newRow) { + throw new ParseError("\\cr valid only within a tabular/array environment"); + } + + const span = buildCommon.makeSpan(["mspace"], [], options); + + if (group.newLine) { + span.classes.push("newline"); + + if (group.size) { + span.style.marginTop = calculateSize(group.size, options) + "em"; + } + } + + return span; + }, + + mathmlBuilder(group, options) { + const node = new mathMLTree.MathNode("mspace"); + + if (group.newLine) { + node.setAttribute("linebreak", "newline"); + + if (group.size) { + node.setAttribute("height", calculateSize(group.size, options) + "em"); + } + } + + return node; + } + +}); + +/** + * This file deals with creating delimiters of various sizes. The TeXbook + * discusses these routines on page 441-442, in the "Another subroutine sets box + * x to a specified variable delimiter" paragraph. + * + * There are three main routines here. `makeSmallDelim` makes a delimiter in the + * normal font, but in either text, script, or scriptscript style. + * `makeLargeDelim` makes a delimiter in textstyle, but in one of the Size1, + * Size2, Size3, or Size4 fonts. `makeStackedDelim` makes a delimiter out of + * smaller pieces that are stacked on top of one another. + * + * The functions take a parameter `center`, which determines if the delimiter + * should be centered around the axis. + * + * Then, there are three exposed functions. `sizedDelim` makes a delimiter in + * one of the given sizes. This is used for things like `\bigl`. + * `customSizedDelim` makes a delimiter with a given total height+depth. It is + * called in places like `\sqrt`. `leftRightDelim` makes an appropriate + * delimiter which surrounds an expression of a given height an depth. It is + * used in `\left` and `\right`. + */ + +/** + * Get the metrics for a given symbol and font, after transformation (i.e. + * after following replacement from symbols.js) + */ +const getMetrics = function getMetrics(symbol, font, mode) { + const replace = symbols.math[symbol] && symbols.math[symbol].replace; + const metrics = getCharacterMetrics(replace || symbol, font, mode); + + if (!metrics) { + throw new Error(`Unsupported symbol ${symbol} and font size ${font}.`); + } + + return metrics; +}; +/** + * Puts a delimiter span in a given style, and adds appropriate height, depth, + * and maxFontSizes. + */ + + +const styleWrap = function styleWrap(delim, toStyle, options, classes) { + const newOptions = options.havingBaseStyle(toStyle); + const span = buildCommon.makeSpan(classes.concat(newOptions.sizingClasses(options)), [delim], options); + const delimSizeMultiplier = newOptions.sizeMultiplier / options.sizeMultiplier; + span.height *= delimSizeMultiplier; + span.depth *= delimSizeMultiplier; + span.maxFontSize = newOptions.sizeMultiplier; + return span; +}; + +const centerSpan = function centerSpan(span, options, style) { + const newOptions = options.havingBaseStyle(style); + const shift = (1 - options.sizeMultiplier / newOptions.sizeMultiplier) * options.fontMetrics().axisHeight; + span.classes.push("delimcenter"); + span.style.top = shift + "em"; + span.height -= shift; + span.depth += shift; +}; +/** + * Makes a small delimiter. This is a delimiter that comes in the Main-Regular + * font, but is restyled to either be in textstyle, scriptstyle, or + * scriptscriptstyle. + */ + + +const makeSmallDelim = function makeSmallDelim(delim, style, center, options, mode, classes) { + const text = buildCommon.makeSymbol(delim, "Main-Regular", mode, options); + const span = styleWrap(text, style, options, classes); + + if (center) { + centerSpan(span, options, style); + } + + return span; +}; +/** + * Builds a symbol in the given font size (note size is an integer) + */ + + +const mathrmSize = function mathrmSize(value, size, mode, options) { + return buildCommon.makeSymbol(value, "Size" + size + "-Regular", mode, options); +}; +/** + * Makes a large delimiter. This is a delimiter that comes in the Size1, Size2, + * Size3, or Size4 fonts. It is always rendered in textstyle. + */ + + +const makeLargeDelim = function makeLargeDelim(delim, size, center, options, mode, classes) { + const inner = mathrmSize(delim, size, mode, options); + const span = styleWrap(buildCommon.makeSpan(["delimsizing", "size" + size], [inner], options), Style$1.TEXT, options, classes); + + if (center) { + centerSpan(span, options, Style$1.TEXT); + } + + return span; +}; +/** + * Make an inner span with the given offset and in the given font. This is used + * in `makeStackedDelim` to make the stacking pieces for the delimiter. + */ + + +const makeInner = function makeInner(symbol, font, mode) { + let sizeClass; // Apply the correct CSS class to choose the right font. + + if (font === "Size1-Regular") { + sizeClass = "delim-size1"; + } else + /* if (font === "Size4-Regular") */ + { + sizeClass = "delim-size4"; + } + + const inner = buildCommon.makeSpan(["delimsizinginner", sizeClass], [buildCommon.makeSpan([], [buildCommon.makeSymbol(symbol, font, mode)])]); // Since this will be passed into `makeVList` in the end, wrap the element + // in the appropriate tag that VList uses. + + return { + type: "elem", + elem: inner + }; +}; // Helper for makeStackedDelim + + +const lap = { + type: "kern", + size: -0.005 +}; +/** + * Make a stacked delimiter out of a given delimiter, with the total height at + * least `heightTotal`. This routine is mentioned on page 442 of the TeXbook. + */ + +const makeStackedDelim = function makeStackedDelim(delim, heightTotal, center, options, mode, classes) { + // There are four parts, the top, an optional middle, a repeated part, and a + // bottom. + let top; + let middle; + let repeat; + let bottom; + top = repeat = bottom = delim; + middle = null; // Also keep track of what font the delimiters are in + + let font = "Size1-Regular"; // We set the parts and font based on the symbol. Note that we use + // '\u23d0' instead of '|' and '\u2016' instead of '\\|' for the + // repeats of the arrows + + if (delim === "\\uparrow") { + repeat = bottom = "\u23d0"; + } else if (delim === "\\Uparrow") { + repeat = bottom = "\u2016"; + } else if (delim === "\\downarrow") { + top = repeat = "\u23d0"; + } else if (delim === "\\Downarrow") { + top = repeat = "\u2016"; + } else if (delim === "\\updownarrow") { + top = "\\uparrow"; + repeat = "\u23d0"; + bottom = "\\downarrow"; + } else if (delim === "\\Updownarrow") { + top = "\\Uparrow"; + repeat = "\u2016"; + bottom = "\\Downarrow"; + } else if (delim === "[" || delim === "\\lbrack") { + top = "\u23a1"; + repeat = "\u23a2"; + bottom = "\u23a3"; + font = "Size4-Regular"; + } else if (delim === "]" || delim === "\\rbrack") { + top = "\u23a4"; + repeat = "\u23a5"; + bottom = "\u23a6"; + font = "Size4-Regular"; + } else if (delim === "\\lfloor" || delim === "\u230a") { + repeat = top = "\u23a2"; + bottom = "\u23a3"; + font = "Size4-Regular"; + } else if (delim === "\\lceil" || delim === "\u2308") { + top = "\u23a1"; + repeat = bottom = "\u23a2"; + font = "Size4-Regular"; + } else if (delim === "\\rfloor" || delim === "\u230b") { + repeat = top = "\u23a5"; + bottom = "\u23a6"; + font = "Size4-Regular"; + } else if (delim === "\\rceil" || delim === "\u2309") { + top = "\u23a4"; + repeat = bottom = "\u23a5"; + font = "Size4-Regular"; + } else if (delim === "(" || delim === "\\lparen") { + top = "\u239b"; + repeat = "\u239c"; + bottom = "\u239d"; + font = "Size4-Regular"; + } else if (delim === ")" || delim === "\\rparen") { + top = "\u239e"; + repeat = "\u239f"; + bottom = "\u23a0"; + font = "Size4-Regular"; + } else if (delim === "\\{" || delim === "\\lbrace") { + top = "\u23a7"; + middle = "\u23a8"; + bottom = "\u23a9"; + repeat = "\u23aa"; + font = "Size4-Regular"; + } else if (delim === "\\}" || delim === "\\rbrace") { + top = "\u23ab"; + middle = "\u23ac"; + bottom = "\u23ad"; + repeat = "\u23aa"; + font = "Size4-Regular"; + } else if (delim === "\\lgroup" || delim === "\u27ee") { + top = "\u23a7"; + bottom = "\u23a9"; + repeat = "\u23aa"; + font = "Size4-Regular"; + } else if (delim === "\\rgroup" || delim === "\u27ef") { + top = "\u23ab"; + bottom = "\u23ad"; + repeat = "\u23aa"; + font = "Size4-Regular"; + } else if (delim === "\\lmoustache" || delim === "\u23b0") { + top = "\u23a7"; + bottom = "\u23ad"; + repeat = "\u23aa"; + font = "Size4-Regular"; + } else if (delim === "\\rmoustache" || delim === "\u23b1") { + top = "\u23ab"; + bottom = "\u23a9"; + repeat = "\u23aa"; + font = "Size4-Regular"; + } // Get the metrics of the four sections + + + const topMetrics = getMetrics(top, font, mode); + const topHeightTotal = topMetrics.height + topMetrics.depth; + const repeatMetrics = getMetrics(repeat, font, mode); + const repeatHeightTotal = repeatMetrics.height + repeatMetrics.depth; + const bottomMetrics = getMetrics(bottom, font, mode); + const bottomHeightTotal = bottomMetrics.height + bottomMetrics.depth; + let middleHeightTotal = 0; + let middleFactor = 1; + + if (middle !== null) { + const middleMetrics = getMetrics(middle, font, mode); + middleHeightTotal = middleMetrics.height + middleMetrics.depth; + middleFactor = 2; // repeat symmetrically above and below middle + } // Calcuate the minimal height that the delimiter can have. + // It is at least the size of the top, bottom, and optional middle combined. + + + const minHeight = topHeightTotal + bottomHeightTotal + middleHeightTotal; // Compute the number of copies of the repeat symbol we will need + + const repeatCount = Math.max(0, Math.ceil((heightTotal - minHeight) / (middleFactor * repeatHeightTotal))); // Compute the total height of the delimiter including all the symbols + + const realHeightTotal = minHeight + repeatCount * middleFactor * repeatHeightTotal; // The center of the delimiter is placed at the center of the axis. Note + // that in this context, "center" means that the delimiter should be + // centered around the axis in the current style, while normally it is + // centered around the axis in textstyle. + + let axisHeight = options.fontMetrics().axisHeight; + + if (center) { + axisHeight *= options.sizeMultiplier; + } // Calculate the depth + + + const depth = realHeightTotal / 2 - axisHeight; // This function differs from the TeX procedure in one way. + // We shift each repeat element downwards by 0.005em, to prevent a gap + // due to browser floating point rounding error. + // Then, at the last element-to element joint, we add one extra repeat + // element to cover the gap created by the shifts. + // Find the shift needed to align the upper end of the extra element at a point + // 0.005em above the lower end of the top element. + + const shiftOfExtraElement = (repeatCount + 1) * 0.005 - repeatHeightTotal; // Now, we start building the pieces that will go into the vlist + // Keep a list of the inner pieces + + const inners = []; // Add the bottom symbol + + inners.push(makeInner(bottom, font, mode)); + + if (middle === null) { + // Add that many symbols + for (let i = 0; i < repeatCount; i++) { + inners.push(lap); // overlap + + inners.push(makeInner(repeat, font, mode)); + } + } else { + // When there is a middle bit, we need the middle part and two repeated + // sections + for (let i = 0; i < repeatCount; i++) { + inners.push(lap); + inners.push(makeInner(repeat, font, mode)); + } // Insert one extra repeat element. + + + inners.push({ + type: "kern", + size: shiftOfExtraElement + }); + inners.push(makeInner(repeat, font, mode)); + inners.push(lap); // Now insert the middle of the brace. + + inners.push(makeInner(middle, font, mode)); + + for (let i = 0; i < repeatCount; i++) { + inners.push(lap); + inners.push(makeInner(repeat, font, mode)); + } + } // To cover the gap create by the overlaps, insert one more repeat element, + // at a position that juts 0.005 above the bottom of the top element. + + + inners.push({ + type: "kern", + size: shiftOfExtraElement + }); + inners.push(makeInner(repeat, font, mode)); + inners.push(lap); // Add the top symbol + + inners.push(makeInner(top, font, mode)); // Finally, build the vlist + + const newOptions = options.havingBaseStyle(Style$1.TEXT); + const inner = buildCommon.makeVList({ + positionType: "bottom", + positionData: depth, + children: inners + }, newOptions); + return styleWrap(buildCommon.makeSpan(["delimsizing", "mult"], [inner], newOptions), Style$1.TEXT, options, classes); +}; // All surds have 0.08em padding above the viniculum inside the SVG. +// That keeps browser span height rounding error from pinching the line. + + +const vbPad = 80; // padding above the surd, measured inside the viewBox. + +const emPad = 0.08; // padding, in ems, measured in the document. + +const sqrtSvg = function sqrtSvg(sqrtName, height, viewBoxHeight, extraViniculum, options) { + const path = sqrtPath(sqrtName, extraViniculum, viewBoxHeight); + const pathNode = new PathNode(sqrtName, path); + const svg = new SvgNode([pathNode], { + // Note: 1000:1 ratio of viewBox to document em width. + "width": "400em", + "height": height + "em", + "viewBox": "0 0 400000 " + viewBoxHeight, + "preserveAspectRatio": "xMinYMin slice" + }); + return buildCommon.makeSvgSpan(["hide-tail"], [svg], options); +}; +/** + * Make a sqrt image of the given height, + */ + + +const makeSqrtImage = function makeSqrtImage(height, options) { + // Define a newOptions that removes the effect of size changes such as \Huge. + // We don't pick different a height surd for \Huge. For it, we scale up. + const newOptions = options.havingBaseSizing(); // Pick the desired surd glyph from a sequence of surds. + + const delim = traverseSequence("\\surd", height * newOptions.sizeMultiplier, stackLargeDelimiterSequence, newOptions); + let sizeMultiplier = newOptions.sizeMultiplier; // default + // The standard sqrt SVGs each have a 0.04em thick viniculum. + // If Settings.minRuleThickness is larger than that, we add extraViniculum. + + const extraViniculum = Math.max(0, options.minRuleThickness - options.fontMetrics().sqrtRuleThickness); // Create a span containing an SVG image of a sqrt symbol. + + let span; + let spanHeight = 0; + let texHeight = 0; + let viewBoxHeight = 0; + let advanceWidth; // We create viewBoxes with 80 units of "padding" above each surd. + // Then browser rounding error on the parent span height will not + // encroach on the ink of the viniculum. But that padding is not + // included in the TeX-like `height` used for calculation of + // vertical alignment. So texHeight = span.height < span.style.height. + + if (delim.type === "small") { + // Get an SVG that is derived from glyph U+221A in font KaTeX-Main. + // 1000 unit normal glyph height. + viewBoxHeight = 1000 + 1000 * extraViniculum + vbPad; + + if (height < 1.0) { + sizeMultiplier = 1.0; // mimic a \textfont radical + } else if (height < 1.4) { + sizeMultiplier = 0.7; // mimic a \scriptfont radical + } + + spanHeight = (1.0 + extraViniculum + emPad) / sizeMultiplier; + texHeight = (1.00 + extraViniculum) / sizeMultiplier; + span = sqrtSvg("sqrtMain", spanHeight, viewBoxHeight, extraViniculum, options); + span.style.minWidth = "0.853em"; + advanceWidth = 0.833 / sizeMultiplier; // from the font. + } else if (delim.type === "large") { + // These SVGs come from fonts: KaTeX_Size1, _Size2, etc. + viewBoxHeight = (1000 + vbPad) * sizeToMaxHeight[delim.size]; + texHeight = (sizeToMaxHeight[delim.size] + extraViniculum) / sizeMultiplier; + spanHeight = (sizeToMaxHeight[delim.size] + extraViniculum + emPad) / sizeMultiplier; + span = sqrtSvg("sqrtSize" + delim.size, spanHeight, viewBoxHeight, extraViniculum, options); + span.style.minWidth = "1.02em"; + advanceWidth = 1.0 / sizeMultiplier; // 1.0 from the font. + } else { + // Tall sqrt. In TeX, this would be stacked using multiple glyphs. + // We'll use a single SVG to accomplish the same thing. + spanHeight = height + extraViniculum + emPad; + texHeight = height + extraViniculum; + viewBoxHeight = Math.floor(1000 * height + extraViniculum) + vbPad; + span = sqrtSvg("sqrtTall", spanHeight, viewBoxHeight, extraViniculum, options); + span.style.minWidth = "0.742em"; + advanceWidth = 1.056; + } + + span.height = texHeight; + span.style.height = spanHeight + "em"; + return { + span, + advanceWidth, + // Calculate the actual line width. + // This actually should depend on the chosen font -- e.g. \boldmath + // should use the thicker surd symbols from e.g. KaTeX_Main-Bold, and + // have thicker rules. + ruleWidth: (options.fontMetrics().sqrtRuleThickness + extraViniculum) * sizeMultiplier + }; +}; // There are three kinds of delimiters, delimiters that stack when they become +// too large + + +const stackLargeDelimiters = ["(", "\\lparen", ")", "\\rparen", "[", "\\lbrack", "]", "\\rbrack", "\\{", "\\lbrace", "\\}", "\\rbrace", "\\lfloor", "\\rfloor", "\u230a", "\u230b", "\\lceil", "\\rceil", "\u2308", "\u2309", "\\surd"]; // delimiters that always stack + +const stackAlwaysDelimiters = ["\\uparrow", "\\downarrow", "\\updownarrow", "\\Uparrow", "\\Downarrow", "\\Updownarrow", "|", "\\|", "\\vert", "\\Vert", "\\lvert", "\\rvert", "\\lVert", "\\rVert", "\\lgroup", "\\rgroup", "\u27ee", "\u27ef", "\\lmoustache", "\\rmoustache", "\u23b0", "\u23b1"]; // and delimiters that never stack + +const stackNeverDelimiters = ["<", ">", "\\langle", "\\rangle", "/", "\\backslash", "\\lt", "\\gt"]; // Metrics of the different sizes. Found by looking at TeX's output of +// $\bigl| // \Bigl| \biggl| \Biggl| \showlists$ +// Used to create stacked delimiters of appropriate sizes in makeSizedDelim. + +const sizeToMaxHeight = [0, 1.2, 1.8, 2.4, 3.0]; +/** + * Used to create a delimiter of a specific size, where `size` is 1, 2, 3, or 4. + */ + +const makeSizedDelim = function makeSizedDelim(delim, size, options, mode, classes) { + // < and > turn into \langle and \rangle in delimiters + if (delim === "<" || delim === "\\lt" || delim === "\u27e8") { + delim = "\\langle"; + } else if (delim === ">" || delim === "\\gt" || delim === "\u27e9") { + delim = "\\rangle"; + } // Sized delimiters are never centered. + + + if (utils.contains(stackLargeDelimiters, delim) || utils.contains(stackNeverDelimiters, delim)) { + return makeLargeDelim(delim, size, false, options, mode, classes); + } else if (utils.contains(stackAlwaysDelimiters, delim)) { + return makeStackedDelim(delim, sizeToMaxHeight[size], false, options, mode, classes); + } else { + throw new ParseError("Illegal delimiter: '" + delim + "'"); + } +}; +/** + * There are three different sequences of delimiter sizes that the delimiters + * follow depending on the kind of delimiter. This is used when creating custom + * sized delimiters to decide whether to create a small, large, or stacked + * delimiter. + * + * In real TeX, these sequences aren't explicitly defined, but are instead + * defined inside the font metrics. Since there are only three sequences that + * are possible for the delimiters that TeX defines, it is easier to just encode + * them explicitly here. + */ + + +// Delimiters that never stack try small delimiters and large delimiters only +const stackNeverDelimiterSequence = [{ + type: "small", + style: Style$1.SCRIPTSCRIPT +}, { + type: "small", + style: Style$1.SCRIPT +}, { + type: "small", + style: Style$1.TEXT +}, { + type: "large", + size: 1 +}, { + type: "large", + size: 2 +}, { + type: "large", + size: 3 +}, { + type: "large", + size: 4 +}]; // Delimiters that always stack try the small delimiters first, then stack + +const stackAlwaysDelimiterSequence = [{ + type: "small", + style: Style$1.SCRIPTSCRIPT +}, { + type: "small", + style: Style$1.SCRIPT +}, { + type: "small", + style: Style$1.TEXT +}, { + type: "stack" +}]; // Delimiters that stack when large try the small and then large delimiters, and +// stack afterwards + +const stackLargeDelimiterSequence = [{ + type: "small", + style: Style$1.SCRIPTSCRIPT +}, { + type: "small", + style: Style$1.SCRIPT +}, { + type: "small", + style: Style$1.TEXT +}, { + type: "large", + size: 1 +}, { + type: "large", + size: 2 +}, { + type: "large", + size: 3 +}, { + type: "large", + size: 4 +}, { + type: "stack" +}]; +/** + * Get the font used in a delimiter based on what kind of delimiter it is. + * TODO(#963) Use more specific font family return type once that is introduced. + */ + +const delimTypeToFont = function delimTypeToFont(type) { + if (type.type === "small") { + return "Main-Regular"; + } else if (type.type === "large") { + return "Size" + type.size + "-Regular"; + } else if (type.type === "stack") { + return "Size4-Regular"; + } else { + throw new Error(`Add support for delim type '${type.type}' here.`); + } +}; +/** + * Traverse a sequence of types of delimiters to decide what kind of delimiter + * should be used to create a delimiter of the given height+depth. + */ + + +const traverseSequence = function traverseSequence(delim, height, sequence, options) { + // Here, we choose the index we should start at in the sequences. In smaller + // sizes (which correspond to larger numbers in style.size) we start earlier + // in the sequence. Thus, scriptscript starts at index 3-3=0, script starts + // at index 3-2=1, text starts at 3-1=2, and display starts at min(2,3-0)=2 + const start = Math.min(2, 3 - options.style.size); + + for (let i = start; i < sequence.length; i++) { + if (sequence[i].type === "stack") { + // This is always the last delimiter, so we just break the loop now. + break; + } + + const metrics = getMetrics(delim, delimTypeToFont(sequence[i]), "math"); + let heightDepth = metrics.height + metrics.depth; // Small delimiters are scaled down versions of the same font, so we + // account for the style change size. + + if (sequence[i].type === "small") { + const newOptions = options.havingBaseStyle(sequence[i].style); + heightDepth *= newOptions.sizeMultiplier; + } // Check if the delimiter at this size works for the given height. + + + if (heightDepth > height) { + return sequence[i]; + } + } // If we reached the end of the sequence, return the last sequence element. + + + return sequence[sequence.length - 1]; +}; +/** + * Make a delimiter of a given height+depth, with optional centering. Here, we + * traverse the sequences, and create a delimiter that the sequence tells us to. + */ + + +const makeCustomSizedDelim = function makeCustomSizedDelim(delim, height, center, options, mode, classes) { + if (delim === "<" || delim === "\\lt" || delim === "\u27e8") { + delim = "\\langle"; + } else if (delim === ">" || delim === "\\gt" || delim === "\u27e9") { + delim = "\\rangle"; + } // Decide what sequence to use + + + let sequence; + + if (utils.contains(stackNeverDelimiters, delim)) { + sequence = stackNeverDelimiterSequence; + } else if (utils.contains(stackLargeDelimiters, delim)) { + sequence = stackLargeDelimiterSequence; + } else { + sequence = stackAlwaysDelimiterSequence; + } // Look through the sequence + + + const delimType = traverseSequence(delim, height, sequence, options); // Get the delimiter from font glyphs. + // Depending on the sequence element we decided on, call the + // appropriate function. + + if (delimType.type === "small") { + return makeSmallDelim(delim, delimType.style, center, options, mode, classes); + } else if (delimType.type === "large") { + return makeLargeDelim(delim, delimType.size, center, options, mode, classes); + } else + /* if (delimType.type === "stack") */ + { + return makeStackedDelim(delim, height, center, options, mode, classes); + } +}; +/** + * Make a delimiter for use with `\left` and `\right`, given a height and depth + * of an expression that the delimiters surround. + */ + + +const makeLeftRightDelim = function makeLeftRightDelim(delim, height, depth, options, mode, classes) { + // We always center \left/\right delimiters, so the axis is always shifted + const axisHeight = options.fontMetrics().axisHeight * options.sizeMultiplier; // Taken from TeX source, tex.web, function make_left_right + + const delimiterFactor = 901; + const delimiterExtend = 5.0 / options.fontMetrics().ptPerEm; + const maxDistFromAxis = Math.max(height - axisHeight, depth + axisHeight); + const totalHeight = Math.max( // In real TeX, calculations are done using integral values which are + // 65536 per pt, or 655360 per em. So, the division here truncates in + // TeX but doesn't here, producing different results. If we wanted to + // exactly match TeX's calculation, we could do + // Math.floor(655360 * maxDistFromAxis / 500) * + // delimiterFactor / 655360 + // (To see the difference, compare + // x^{x^{\left(\rule{0.1em}{0.68em}\right)}} + // in TeX and KaTeX) + maxDistFromAxis / 500 * delimiterFactor, 2 * maxDistFromAxis - delimiterExtend); // Finally, we defer to `makeCustomSizedDelim` with our calculated total + // height + + return makeCustomSizedDelim(delim, totalHeight, true, options, mode, classes); +}; + +var delimiter = { + sqrtImage: makeSqrtImage, + sizedDelim: makeSizedDelim, + customSizedDelim: makeCustomSizedDelim, + leftRightDelim: makeLeftRightDelim +}; + +// Extra data needed for the delimiter handler down below +const delimiterSizes = { + "\\bigl": { + mclass: "mopen", + size: 1 + }, + "\\Bigl": { + mclass: "mopen", + size: 2 + }, + "\\biggl": { + mclass: "mopen", + size: 3 + }, + "\\Biggl": { + mclass: "mopen", + size: 4 + }, + "\\bigr": { + mclass: "mclose", + size: 1 + }, + "\\Bigr": { + mclass: "mclose", + size: 2 + }, + "\\biggr": { + mclass: "mclose", + size: 3 + }, + "\\Biggr": { + mclass: "mclose", + size: 4 + }, + "\\bigm": { + mclass: "mrel", + size: 1 + }, + "\\Bigm": { + mclass: "mrel", + size: 2 + }, + "\\biggm": { + mclass: "mrel", + size: 3 + }, + "\\Biggm": { + mclass: "mrel", + size: 4 + }, + "\\big": { + mclass: "mord", + size: 1 + }, + "\\Big": { + mclass: "mord", + size: 2 + }, + "\\bigg": { + mclass: "mord", + size: 3 + }, + "\\Bigg": { + mclass: "mord", + size: 4 + } +}; +const delimiters = ["(", "\\lparen", ")", "\\rparen", "[", "\\lbrack", "]", "\\rbrack", "\\{", "\\lbrace", "\\}", "\\rbrace", "\\lfloor", "\\rfloor", "\u230a", "\u230b", "\\lceil", "\\rceil", "\u2308", "\u2309", "<", ">", "\\langle", "\u27e8", "\\rangle", "\u27e9", "\\lt", "\\gt", "\\lvert", "\\rvert", "\\lVert", "\\rVert", "\\lgroup", "\\rgroup", "\u27ee", "\u27ef", "\\lmoustache", "\\rmoustache", "\u23b0", "\u23b1", "/", "\\backslash", "|", "\\vert", "\\|", "\\Vert", "\\uparrow", "\\Uparrow", "\\downarrow", "\\Downarrow", "\\updownarrow", "\\Updownarrow", "."]; + +// Delimiter functions +function checkDelimiter(delim, context) { + const symDelim = checkSymbolNodeType(delim); + + if (symDelim && utils.contains(delimiters, symDelim.text)) { + return symDelim; + } else { + throw new ParseError("Invalid delimiter: '" + (symDelim ? symDelim.text : JSON.stringify(delim)) + "' after '" + context.funcName + "'", delim); + } +} + +defineFunction({ + type: "delimsizing", + names: ["\\bigl", "\\Bigl", "\\biggl", "\\Biggl", "\\bigr", "\\Bigr", "\\biggr", "\\Biggr", "\\bigm", "\\Bigm", "\\biggm", "\\Biggm", "\\big", "\\Big", "\\bigg", "\\Bigg"], + props: { + numArgs: 1 + }, + handler: (context, args) => { + const delim = checkDelimiter(args[0], context); + return { + type: "delimsizing", + mode: context.parser.mode, + size: delimiterSizes[context.funcName].size, + mclass: delimiterSizes[context.funcName].mclass, + delim: delim.text + }; + }, + htmlBuilder: (group, options) => { + if (group.delim === ".") { + // Empty delimiters still count as elements, even though they don't + // show anything. + return buildCommon.makeSpan([group.mclass]); + } // Use delimiter.sizedDelim to generate the delimiter. + + + return delimiter.sizedDelim(group.delim, group.size, options, group.mode, [group.mclass]); + }, + mathmlBuilder: group => { + const children = []; + + if (group.delim !== ".") { + children.push(makeText(group.delim, group.mode)); + } + + const node = new mathMLTree.MathNode("mo", children); + + if (group.mclass === "mopen" || group.mclass === "mclose") { + // Only some of the delimsizing functions act as fences, and they + // return "mopen" or "mclose" mclass. + node.setAttribute("fence", "true"); + } else { + // Explicitly disable fencing if it's not a fence, to override the + // defaults. + node.setAttribute("fence", "false"); + } + + return node; + } +}); + +function assertParsed(group) { + if (!group.body) { + throw new Error("Bug: The leftright ParseNode wasn't fully parsed."); + } +} + +defineFunction({ + type: "leftright-right", + names: ["\\right"], + props: { + numArgs: 1 + }, + handler: (context, args) => { + // \left case below triggers parsing of \right in + // `const right = parser.parseFunction();` + // uses this return value. + const color = context.parser.gullet.macros.get("\\current@color"); + + if (color && typeof color !== "string") { + throw new ParseError("\\current@color set to non-string in \\right"); + } + + return { + type: "leftright-right", + mode: context.parser.mode, + delim: checkDelimiter(args[0], context).text, + color // undefined if not set via \color + + }; + } +}); +defineFunction({ + type: "leftright", + names: ["\\left"], + props: { + numArgs: 1 + }, + handler: (context, args) => { + const delim = checkDelimiter(args[0], context); + const parser = context.parser; // Parse out the implicit body + + ++parser.leftrightDepth; // parseExpression stops before '\\right' + + const body = parser.parseExpression(false); + --parser.leftrightDepth; // Check the next token + + parser.expect("\\right", false); + const right = assertNodeType(parser.parseFunction(), "leftright-right"); + return { + type: "leftright", + mode: parser.mode, + body, + left: delim.text, + right: right.delim, + rightColor: right.color + }; + }, + htmlBuilder: (group, options) => { + assertParsed(group); // Build the inner expression + + const inner = buildExpression(group.body, options, true, ["mopen", "mclose"]); + let innerHeight = 0; + let innerDepth = 0; + let hadMiddle = false; // Calculate its height and depth + + for (let i = 0; i < inner.length; i++) { + // Property `isMiddle` not defined on `span`. See comment in + // "middle"'s htmlBuilder. + // $FlowFixMe + if (inner[i].isMiddle) { + hadMiddle = true; + } else { + innerHeight = Math.max(inner[i].height, innerHeight); + innerDepth = Math.max(inner[i].depth, innerDepth); + } + } // The size of delimiters is the same, regardless of what style we are + // in. Thus, to correctly calculate the size of delimiter we need around + // a group, we scale down the inner size based on the size. + + + innerHeight *= options.sizeMultiplier; + innerDepth *= options.sizeMultiplier; + let leftDelim; + + if (group.left === ".") { + // Empty delimiters in \left and \right make null delimiter spaces. + leftDelim = makeNullDelimiter(options, ["mopen"]); + } else { + // Otherwise, use leftRightDelim to generate the correct sized + // delimiter. + leftDelim = delimiter.leftRightDelim(group.left, innerHeight, innerDepth, options, group.mode, ["mopen"]); + } // Add it to the beginning of the expression + + + inner.unshift(leftDelim); // Handle middle delimiters + + if (hadMiddle) { + for (let i = 1; i < inner.length; i++) { + const middleDelim = inner[i]; // Property `isMiddle` not defined on `span`. See comment in + // "middle"'s htmlBuilder. + // $FlowFixMe + + const isMiddle = middleDelim.isMiddle; + + if (isMiddle) { + // Apply the options that were active when \middle was called + inner[i] = delimiter.leftRightDelim(isMiddle.delim, innerHeight, innerDepth, isMiddle.options, group.mode, []); + } + } + } + + let rightDelim; // Same for the right delimiter, but using color specified by \color + + if (group.right === ".") { + rightDelim = makeNullDelimiter(options, ["mclose"]); + } else { + const colorOptions = group.rightColor ? options.withColor(group.rightColor) : options; + rightDelim = delimiter.leftRightDelim(group.right, innerHeight, innerDepth, colorOptions, group.mode, ["mclose"]); + } // Add it to the end of the expression. + + + inner.push(rightDelim); + return buildCommon.makeSpan(["minner"], inner, options); + }, + mathmlBuilder: (group, options) => { + assertParsed(group); + const inner = buildExpression$1(group.body, options); + + if (group.left !== ".") { + const leftNode = new mathMLTree.MathNode("mo", [makeText(group.left, group.mode)]); + leftNode.setAttribute("fence", "true"); + inner.unshift(leftNode); + } + + if (group.right !== ".") { + const rightNode = new mathMLTree.MathNode("mo", [makeText(group.right, group.mode)]); + rightNode.setAttribute("fence", "true"); + + if (group.rightColor) { + rightNode.setAttribute("mathcolor", group.rightColor); + } + + inner.push(rightNode); + } + + return makeRow(inner); + } +}); +defineFunction({ + type: "middle", + names: ["\\middle"], + props: { + numArgs: 1 + }, + handler: (context, args) => { + const delim = checkDelimiter(args[0], context); + + if (!context.parser.leftrightDepth) { + throw new ParseError("\\middle without preceding \\left", delim); + } + + return { + type: "middle", + mode: context.parser.mode, + delim: delim.text + }; + }, + htmlBuilder: (group, options) => { + let middleDelim; + + if (group.delim === ".") { + middleDelim = makeNullDelimiter(options, []); + } else { + middleDelim = delimiter.sizedDelim(group.delim, 1, options, group.mode, []); + const isMiddle = { + delim: group.delim, + options + }; // Property `isMiddle` not defined on `span`. It is only used in + // this file above. + // TODO: Fix this violation of the `span` type and possibly rename + // things since `isMiddle` sounds like a boolean, but is a struct. + // $FlowFixMe + + middleDelim.isMiddle = isMiddle; + } + + return middleDelim; + }, + mathmlBuilder: (group, options) => { + // A Firefox \middle will strech a character vertically only if it + // is in the fence part of the operator dictionary at: + // https://www.w3.org/TR/MathML3/appendixc.html. + // So we need to avoid U+2223 and use plain "|" instead. + const textNode = group.delim === "\\vert" || group.delim === "|" ? makeText("|", "text") : makeText(group.delim, group.mode); + const middleNode = new mathMLTree.MathNode("mo", [textNode]); + middleNode.setAttribute("fence", "true"); // MathML gives 5/18em spacing to each element. + // \middle should get delimiter spacing instead. + + middleNode.setAttribute("lspace", "0.05em"); + middleNode.setAttribute("rspace", "0.05em"); + return middleNode; + } +}); + +const htmlBuilder$2 = (group, options) => { + // \cancel, \bcancel, \xcancel, \sout, \fbox, \colorbox, \fcolorbox + // Some groups can return document fragments. Handle those by wrapping + // them in a span. + const inner = buildCommon.wrapFragment(buildGroup(group.body, options), options); + const label = group.label.substr(1); + const scale = options.sizeMultiplier; + let img; + let imgShift = 0; // In the LaTeX cancel package, line geometry is slightly different + // depending on whether the subject is wider than it is tall, or vice versa. + // We don't know the width of a group, so as a proxy, we test if + // the subject is a single character. This captures most of the + // subjects that should get the "tall" treatment. + + const isSingleChar = utils.isCharacterBox(group.body); + + if (label === "sout") { + img = buildCommon.makeSpan(["stretchy", "sout"]); + img.height = options.fontMetrics().defaultRuleThickness / scale; + imgShift = -0.5 * options.fontMetrics().xHeight; + } else { + // Add horizontal padding + if (/cancel/.test(label)) { + if (!isSingleChar) { + inner.classes.push("cancel-pad"); + } + } else { + inner.classes.push("boxpad"); + } // Add vertical padding + + + let vertPad = 0; + let ruleThickness = 0; // ref: cancel package: \advance\totalheight2\p@ % "+2" + + if (/box/.test(label)) { + ruleThickness = Math.max(options.fontMetrics().fboxrule, // default + options.minRuleThickness // User override. + ); + vertPad = options.fontMetrics().fboxsep + (label === "colorbox" ? 0 : ruleThickness); + } else { + vertPad = isSingleChar ? 0.2 : 0; + } + + img = stretchy.encloseSpan(inner, label, vertPad, options); + + if (/fbox|boxed|fcolorbox/.test(label)) { + img.style.borderStyle = "solid"; + img.style.borderWidth = `${ruleThickness}em`; + } + + imgShift = inner.depth + vertPad; + + if (group.backgroundColor) { + img.style.backgroundColor = group.backgroundColor; + + if (group.borderColor) { + img.style.borderColor = group.borderColor; + } + } + } + + let vlist; + + if (group.backgroundColor) { + vlist = buildCommon.makeVList({ + positionType: "individualShift", + children: [// Put the color background behind inner; + { + type: "elem", + elem: img, + shift: imgShift + }, { + type: "elem", + elem: inner, + shift: 0 + }] + }, options); + } else { + vlist = buildCommon.makeVList({ + positionType: "individualShift", + children: [// Write the \cancel stroke on top of inner. + { + type: "elem", + elem: inner, + shift: 0 + }, { + type: "elem", + elem: img, + shift: imgShift, + wrapperClasses: /cancel/.test(label) ? ["svg-align"] : [] + }] + }, options); + } + + if (/cancel/.test(label)) { + // The cancel package documentation says that cancel lines add their height + // to the expression, but tests show that isn't how it actually works. + vlist.height = inner.height; + vlist.depth = inner.depth; + } + + if (/cancel/.test(label) && !isSingleChar) { + // cancel does not create horiz space for its line extension. + return buildCommon.makeSpan(["mord", "cancel-lap"], [vlist], options); + } else { + return buildCommon.makeSpan(["mord"], [vlist], options); + } +}; + +const mathmlBuilder$2 = (group, options) => { + let fboxsep = 0; + const node = new mathMLTree.MathNode(group.label.indexOf("colorbox") > -1 ? "mpadded" : "menclose", [buildGroup$1(group.body, options)]); + + switch (group.label) { + case "\\cancel": + node.setAttribute("notation", "updiagonalstrike"); + break; + + case "\\bcancel": + node.setAttribute("notation", "downdiagonalstrike"); + break; + + case "\\sout": + node.setAttribute("notation", "horizontalstrike"); + break; + + case "\\fbox": + node.setAttribute("notation", "box"); + break; + + case "\\fcolorbox": + case "\\colorbox": + // doesn't have a good notation option. So use + // instead. Set some attributes that come included with . + fboxsep = options.fontMetrics().fboxsep * options.fontMetrics().ptPerEm; + node.setAttribute("width", `+${2 * fboxsep}pt`); + node.setAttribute("height", `+${2 * fboxsep}pt`); + node.setAttribute("lspace", `${fboxsep}pt`); // + + node.setAttribute("voffset", `${fboxsep}pt`); + + if (group.label === "\\fcolorbox") { + const thk = Math.max(options.fontMetrics().fboxrule, // default + options.minRuleThickness // user override + ); + node.setAttribute("style", "border: " + thk + "em solid " + String(group.borderColor)); + } + + break; + + case "\\xcancel": + node.setAttribute("notation", "updiagonalstrike downdiagonalstrike"); + break; + } + + if (group.backgroundColor) { + node.setAttribute("mathbackground", group.backgroundColor); + } + + return node; +}; + +defineFunction({ + type: "enclose", + names: ["\\colorbox"], + props: { + numArgs: 2, + allowedInText: true, + greediness: 3, + argTypes: ["color", "text"] + }, + + handler(_ref, args, optArgs) { + let parser = _ref.parser, + funcName = _ref.funcName; + const color = assertNodeType(args[0], "color-token").color; + const body = args[1]; + return { + type: "enclose", + mode: parser.mode, + label: funcName, + backgroundColor: color, + body + }; + }, + + htmlBuilder: htmlBuilder$2, + mathmlBuilder: mathmlBuilder$2 +}); +defineFunction({ + type: "enclose", + names: ["\\fcolorbox"], + props: { + numArgs: 3, + allowedInText: true, + greediness: 3, + argTypes: ["color", "color", "text"] + }, + + handler(_ref2, args, optArgs) { + let parser = _ref2.parser, + funcName = _ref2.funcName; + const borderColor = assertNodeType(args[0], "color-token").color; + const backgroundColor = assertNodeType(args[1], "color-token").color; + const body = args[2]; + return { + type: "enclose", + mode: parser.mode, + label: funcName, + backgroundColor, + borderColor, + body + }; + }, + + htmlBuilder: htmlBuilder$2, + mathmlBuilder: mathmlBuilder$2 +}); +defineFunction({ + type: "enclose", + names: ["\\fbox"], + props: { + numArgs: 1, + argTypes: ["hbox"], + allowedInText: true + }, + + handler(_ref3, args) { + let parser = _ref3.parser; + return { + type: "enclose", + mode: parser.mode, + label: "\\fbox", + body: args[0] + }; + } + +}); +defineFunction({ + type: "enclose", + names: ["\\cancel", "\\bcancel", "\\xcancel", "\\sout"], + props: { + numArgs: 1 + }, + + handler(_ref4, args, optArgs) { + let parser = _ref4.parser, + funcName = _ref4.funcName; + const body = args[0]; + return { + type: "enclose", + mode: parser.mode, + label: funcName, + body + }; + }, + + htmlBuilder: htmlBuilder$2, + mathmlBuilder: mathmlBuilder$2 +}); + +/** + * All registered environments. + * `environments.js` exports this same dictionary again and makes it public. + * `Parser.js` requires this dictionary via `environments.js`. + */ +const _environments = {}; +function defineEnvironment(_ref) { + let type = _ref.type, + names = _ref.names, + props = _ref.props, + handler = _ref.handler, + htmlBuilder = _ref.htmlBuilder, + mathmlBuilder = _ref.mathmlBuilder; + // Set default values of environments. + const data = { + type, + numArgs: props.numArgs || 0, + greediness: 1, + allowedInText: false, + numOptionalArgs: 0, + handler + }; + + for (let i = 0; i < names.length; ++i) { + // TODO: The value type of _environments should be a type union of all + // possible `EnvSpec<>` possibilities instead of `EnvSpec<*>`, which is + // an existential type. + // $FlowFixMe + _environments[names[i]] = data; + } + + if (htmlBuilder) { + _htmlGroupBuilders[type] = htmlBuilder; + } + + if (mathmlBuilder) { + _mathmlGroupBuilders[type] = mathmlBuilder; + } +} + +function getHLines(parser) { + // Return an array. The array length = number of hlines. + // Each element in the array tells if the line is dashed. + const hlineInfo = []; + parser.consumeSpaces(); + let nxt = parser.fetch().text; + + while (nxt === "\\hline" || nxt === "\\hdashline") { + parser.consume(); + hlineInfo.push(nxt === "\\hdashline"); + parser.consumeSpaces(); + nxt = parser.fetch().text; + } + + return hlineInfo; +} +/** + * Parse the body of the environment, with rows delimited by \\ and + * columns delimited by &, and create a nested list in row-major order + * with one group per cell. If given an optional argument style + * ("text", "display", etc.), then each cell is cast into that style. + */ + + +function parseArray(parser, _ref, style) { + let hskipBeforeAndAfter = _ref.hskipBeforeAndAfter, + addJot = _ref.addJot, + cols = _ref.cols, + arraystretch = _ref.arraystretch, + colSeparationType = _ref.colSeparationType; + // Parse body of array with \\ temporarily mapped to \cr + parser.gullet.beginGroup(); + parser.gullet.macros.set("\\\\", "\\cr"); // Get current arraystretch if it's not set by the environment + + if (!arraystretch) { + const stretch = parser.gullet.expandMacroAsText("\\arraystretch"); + + if (stretch == null) { + // Default \arraystretch from lttab.dtx + arraystretch = 1; + } else { + arraystretch = parseFloat(stretch); + + if (!arraystretch || arraystretch < 0) { + throw new ParseError(`Invalid \\arraystretch: ${stretch}`); + } + } + } // Start group for first cell + + + parser.gullet.beginGroup(); + let row = []; + const body = [row]; + const rowGaps = []; + const hLinesBeforeRow = []; // Test for \hline at the top of the array. + + hLinesBeforeRow.push(getHLines(parser)); + + while (true) { + // eslint-disable-line no-constant-condition + // Parse each cell in its own group (namespace) + let cell = parser.parseExpression(false, "\\cr"); + parser.gullet.endGroup(); + parser.gullet.beginGroup(); + cell = { + type: "ordgroup", + mode: parser.mode, + body: cell + }; + + if (style) { + cell = { + type: "styling", + mode: parser.mode, + style, + body: [cell] + }; + } + + row.push(cell); + const next = parser.fetch().text; + + if (next === "&") { + parser.consume(); + } else if (next === "\\end") { + // Arrays terminate newlines with `\crcr` which consumes a `\cr` if + // the last line is empty. + // NOTE: Currently, `cell` is the last item added into `row`. + if (row.length === 1 && cell.type === "styling" && cell.body[0].body.length === 0) { + body.pop(); + } + + if (hLinesBeforeRow.length < body.length + 1) { + hLinesBeforeRow.push([]); + } + + break; + } else if (next === "\\cr") { + const cr = assertNodeType(parser.parseFunction(), "cr"); + rowGaps.push(cr.size); // check for \hline(s) following the row separator + + hLinesBeforeRow.push(getHLines(parser)); + row = []; + body.push(row); + } else { + throw new ParseError("Expected & or \\\\ or \\cr or \\end", parser.nextToken); + } + } // End cell group + + + parser.gullet.endGroup(); // End array group defining \\ + + parser.gullet.endGroup(); + return { + type: "array", + mode: parser.mode, + addJot, + arraystretch, + body, + cols, + rowGaps, + hskipBeforeAndAfter, + hLinesBeforeRow, + colSeparationType + }; +} // Decides on a style for cells in an array according to whether the given +// environment name starts with the letter 'd'. + + +function dCellStyle(envName) { + if (envName.substr(0, 1) === "d") { + return "display"; + } else { + return "text"; + } +} + +const htmlBuilder$3 = function htmlBuilder(group, options) { + let r; + let c; + const nr = group.body.length; + const hLinesBeforeRow = group.hLinesBeforeRow; + let nc = 0; + let body = new Array(nr); + const hlines = []; + const ruleThickness = Math.max( // From LaTeX \showthe\arrayrulewidth. Equals 0.04 em. + options.fontMetrics().arrayRuleWidth, options.minRuleThickness // User override. + ); // Horizontal spacing + + const pt = 1 / options.fontMetrics().ptPerEm; + let arraycolsep = 5 * pt; // default value, i.e. \arraycolsep in article.cls + + if (group.colSeparationType && group.colSeparationType === "small") { + // We're in a {smallmatrix}. Default column space is \thickspace, + // i.e. 5/18em = 0.2778em, per amsmath.dtx for {smallmatrix}. + // But that needs adjustment because LaTeX applies \scriptstyle to the + // entire array, including the colspace, but this function applies + // \scriptstyle only inside each element. + const localMultiplier = options.havingStyle(Style$1.SCRIPT).sizeMultiplier; + arraycolsep = 0.2778 * (localMultiplier / options.sizeMultiplier); + } // Vertical spacing + + + const baselineskip = 12 * pt; // see size10.clo + // Default \jot from ltmath.dtx + // TODO(edemaine): allow overriding \jot via \setlength (#687) + + const jot = 3 * pt; + const arrayskip = group.arraystretch * baselineskip; + const arstrutHeight = 0.7 * arrayskip; // \strutbox in ltfsstrc.dtx and + + const arstrutDepth = 0.3 * arrayskip; // \@arstrutbox in lttab.dtx + + let totalHeight = 0; // Set a position for \hline(s) at the top of the array, if any. + + function setHLinePos(hlinesInGap) { + for (let i = 0; i < hlinesInGap.length; ++i) { + if (i > 0) { + totalHeight += 0.25; + } + + hlines.push({ + pos: totalHeight, + isDashed: hlinesInGap[i] + }); + } + } + + setHLinePos(hLinesBeforeRow[0]); + + for (r = 0; r < group.body.length; ++r) { + const inrow = group.body[r]; + let height = arstrutHeight; // \@array adds an \@arstrut + + let depth = arstrutDepth; // to each tow (via the template) + + if (nc < inrow.length) { + nc = inrow.length; + } + + const outrow = new Array(inrow.length); + + for (c = 0; c < inrow.length; ++c) { + const elt = buildGroup(inrow[c], options); + + if (depth < elt.depth) { + depth = elt.depth; + } + + if (height < elt.height) { + height = elt.height; + } + + outrow[c] = elt; + } + + const rowGap = group.rowGaps[r]; + let gap = 0; + + if (rowGap) { + gap = calculateSize(rowGap, options); + + if (gap > 0) { + // \@argarraycr + gap += arstrutDepth; + + if (depth < gap) { + depth = gap; // \@xargarraycr + } + + gap = 0; + } + } // In AMS multiline environments such as aligned and gathered, rows + // correspond to lines that have additional \jot added to the + // \baselineskip via \openup. + + + if (group.addJot) { + depth += jot; + } + + outrow.height = height; + outrow.depth = depth; + totalHeight += height; + outrow.pos = totalHeight; + totalHeight += depth + gap; // \@yargarraycr + + body[r] = outrow; // Set a position for \hline(s), if any. + + setHLinePos(hLinesBeforeRow[r + 1]); + } + + const offset = totalHeight / 2 + options.fontMetrics().axisHeight; + const colDescriptions = group.cols || []; + const cols = []; + let colSep; + let colDescrNum; + + for (c = 0, colDescrNum = 0; // Continue while either there are more columns or more column + // descriptions, so trailing separators don't get lost. + c < nc || colDescrNum < colDescriptions.length; ++c, ++colDescrNum) { + let colDescr = colDescriptions[colDescrNum] || {}; + let firstSeparator = true; + + while (colDescr.type === "separator") { + // If there is more than one separator in a row, add a space + // between them. + if (!firstSeparator) { + colSep = buildCommon.makeSpan(["arraycolsep"], []); + colSep.style.width = options.fontMetrics().doubleRuleSep + "em"; + cols.push(colSep); + } + + if (colDescr.separator === "|" || colDescr.separator === ":") { + const lineType = colDescr.separator === "|" ? "solid" : "dashed"; + const separator = buildCommon.makeSpan(["vertical-separator"], [], options); + separator.style.height = totalHeight + "em"; + separator.style.borderRightWidth = `${ruleThickness}em`; + separator.style.borderRightStyle = lineType; + separator.style.margin = `0 -${ruleThickness / 2}em`; + separator.style.verticalAlign = -(totalHeight - offset) + "em"; + cols.push(separator); + } else { + throw new ParseError("Invalid separator type: " + colDescr.separator); + } + + colDescrNum++; + colDescr = colDescriptions[colDescrNum] || {}; + firstSeparator = false; + } + + if (c >= nc) { + continue; + } + + let sepwidth; + + if (c > 0 || group.hskipBeforeAndAfter) { + sepwidth = utils.deflt(colDescr.pregap, arraycolsep); + + if (sepwidth !== 0) { + colSep = buildCommon.makeSpan(["arraycolsep"], []); + colSep.style.width = sepwidth + "em"; + cols.push(colSep); + } + } + + let col = []; + + for (r = 0; r < nr; ++r) { + const row = body[r]; + const elem = row[c]; + + if (!elem) { + continue; + } + + const shift = row.pos - offset; + elem.depth = row.depth; + elem.height = row.height; + col.push({ + type: "elem", + elem: elem, + shift: shift + }); + } + + col = buildCommon.makeVList({ + positionType: "individualShift", + children: col + }, options); + col = buildCommon.makeSpan(["col-align-" + (colDescr.align || "c")], [col]); + cols.push(col); + + if (c < nc - 1 || group.hskipBeforeAndAfter) { + sepwidth = utils.deflt(colDescr.postgap, arraycolsep); + + if (sepwidth !== 0) { + colSep = buildCommon.makeSpan(["arraycolsep"], []); + colSep.style.width = sepwidth + "em"; + cols.push(colSep); + } + } + } + + body = buildCommon.makeSpan(["mtable"], cols); // Add \hline(s), if any. + + if (hlines.length > 0) { + const line = buildCommon.makeLineSpan("hline", options, ruleThickness); + const dashes = buildCommon.makeLineSpan("hdashline", options, ruleThickness); + const vListElems = [{ + type: "elem", + elem: body, + shift: 0 + }]; + + while (hlines.length > 0) { + const hline = hlines.pop(); + const lineShift = hline.pos - offset; + + if (hline.isDashed) { + vListElems.push({ + type: "elem", + elem: dashes, + shift: lineShift + }); + } else { + vListElems.push({ + type: "elem", + elem: line, + shift: lineShift + }); + } + } + + body = buildCommon.makeVList({ + positionType: "individualShift", + children: vListElems + }, options); + } + + return buildCommon.makeSpan(["mord"], [body], options); +}; + +const alignMap = { + c: "center ", + l: "left ", + r: "right " +}; + +const mathmlBuilder$3 = function mathmlBuilder(group, options) { + let table = new mathMLTree.MathNode("mtable", group.body.map(function (row) { + return new mathMLTree.MathNode("mtr", row.map(function (cell) { + return new mathMLTree.MathNode("mtd", [buildGroup$1(cell, options)]); + })); + })); // Set column alignment, row spacing, column spacing, and + // array lines by setting attributes on the table element. + // Set the row spacing. In MathML, we specify a gap distance. + // We do not use rowGap[] because MathML automatically increases + // cell height with the height/depth of the element content. + // LaTeX \arraystretch multiplies the row baseline-to-baseline distance. + // We simulate this by adding (arraystretch - 1)em to the gap. This + // does a reasonable job of adjusting arrays containing 1 em tall content. + // The 0.16 and 0.09 values are found emprically. They produce an array + // similar to LaTeX and in which content does not interfere with \hines. + + const gap = group.arraystretch === 0.5 ? 0.1 // {smallmatrix}, {subarray} + : 0.16 + group.arraystretch - 1 + (group.addJot ? 0.09 : 0); + table.setAttribute("rowspacing", gap + "em"); // MathML table lines go only between cells. + // To place a line on an edge we'll use , if necessary. + + let menclose = ""; + let align = ""; + + if (group.cols) { + // Find column alignment, column spacing, and vertical lines. + const cols = group.cols; + let columnLines = ""; + let prevTypeWasAlign = false; + let iStart = 0; + let iEnd = cols.length; + + if (cols[0].type === "separator") { + menclose += "top "; + iStart = 1; + } + + if (cols[cols.length - 1].type === "separator") { + menclose += "bottom "; + iEnd -= 1; + } + + for (let i = iStart; i < iEnd; i++) { + if (cols[i].type === "align") { + align += alignMap[cols[i].align]; + + if (prevTypeWasAlign) { + columnLines += "none "; + } + + prevTypeWasAlign = true; + } else if (cols[i].type === "separator") { + // MathML accepts only single lines between cells. + // So we read only the first of consecutive separators. + if (prevTypeWasAlign) { + columnLines += cols[i].separator === "|" ? "solid " : "dashed "; + prevTypeWasAlign = false; + } + } + } + + table.setAttribute("columnalign", align.trim()); + + if (/[sd]/.test(columnLines)) { + table.setAttribute("columnlines", columnLines.trim()); + } + } // Set column spacing. + + + if (group.colSeparationType === "align") { + const cols = group.cols || []; + let spacing = ""; + + for (let i = 1; i < cols.length; i++) { + spacing += i % 2 ? "0em " : "1em "; + } + + table.setAttribute("columnspacing", spacing.trim()); + } else if (group.colSeparationType === "alignat") { + table.setAttribute("columnspacing", "0em"); + } else if (group.colSeparationType === "small") { + table.setAttribute("columnspacing", "0.2778em"); + } else { + table.setAttribute("columnspacing", "1em"); + } // Address \hline and \hdashline + + + let rowLines = ""; + const hlines = group.hLinesBeforeRow; + menclose += hlines[0].length > 0 ? "left " : ""; + menclose += hlines[hlines.length - 1].length > 0 ? "right " : ""; + + for (let i = 1; i < hlines.length - 1; i++) { + rowLines += hlines[i].length === 0 ? "none " // MathML accepts only a single line between rows. Read one element. + : hlines[i][0] ? "dashed " : "solid "; + } + + if (/[sd]/.test(rowLines)) { + table.setAttribute("rowlines", rowLines.trim()); + } + + if (menclose !== "") { + table = new mathMLTree.MathNode("menclose", [table]); + table.setAttribute("notation", menclose.trim()); + } + + if (group.arraystretch && group.arraystretch < 1) { + // A small array. Wrap in scriptstyle so row gap is not too large. + table = new mathMLTree.MathNode("mstyle", [table]); + table.setAttribute("scriptlevel", "1"); + } + + return table; +}; // Convenience function for aligned and alignedat environments. + + +const alignedHandler = function alignedHandler(context, args) { + const cols = []; + const res = parseArray(context.parser, { + cols, + addJot: true + }, "display"); // Determining number of columns. + // 1. If the first argument is given, we use it as a number of columns, + // and makes sure that each row doesn't exceed that number. + // 2. Otherwise, just count number of columns = maximum number + // of cells in each row ("aligned" mode -- isAligned will be true). + // + // At the same time, prepend empty group {} at beginning of every second + // cell in each row (starting with second cell) so that operators become + // binary. This behavior is implemented in amsmath's \start@aligned. + + let numMaths; + let numCols = 0; + const emptyGroup = { + type: "ordgroup", + mode: context.mode, + body: [] + }; + const ordgroup = checkNodeType(args[0], "ordgroup"); + + if (ordgroup) { + let arg0 = ""; + + for (let i = 0; i < ordgroup.body.length; i++) { + const textord = assertNodeType(ordgroup.body[i], "textord"); + arg0 += textord.text; + } + + numMaths = Number(arg0); + numCols = numMaths * 2; + } + + const isAligned = !numCols; + res.body.forEach(function (row) { + for (let i = 1; i < row.length; i += 2) { + // Modify ordgroup node within styling node + const styling = assertNodeType(row[i], "styling"); + const ordgroup = assertNodeType(styling.body[0], "ordgroup"); + ordgroup.body.unshift(emptyGroup); + } + + if (!isAligned) { + // Case 1 + const curMaths = row.length / 2; + + if (numMaths < curMaths) { + throw new ParseError("Too many math in a row: " + `expected ${numMaths}, but got ${curMaths}`, row[0]); + } + } else if (numCols < row.length) { + // Case 2 + numCols = row.length; + } + }); // Adjusting alignment. + // In aligned mode, we add one \qquad between columns; + // otherwise we add nothing. + + for (let i = 0; i < numCols; ++i) { + let align = "r"; + let pregap = 0; + + if (i % 2 === 1) { + align = "l"; + } else if (i > 0 && isAligned) { + // "aligned" mode. + pregap = 1; // add one \quad + } + + cols[i] = { + type: "align", + align: align, + pregap: pregap, + postgap: 0 + }; + } + + res.colSeparationType = isAligned ? "align" : "alignat"; + return res; +}; // Arrays are part of LaTeX, defined in lttab.dtx so its documentation +// is part of the source2e.pdf file of LaTeX2e source documentation. +// {darray} is an {array} environment where cells are set in \displaystyle, +// as defined in nccmath.sty. + + +defineEnvironment({ + type: "array", + names: ["array", "darray"], + props: { + numArgs: 1 + }, + + handler(context, args) { + // Since no types are specified above, the two possibilities are + // - The argument is wrapped in {} or [], in which case Parser's + // parseGroup() returns an "ordgroup" wrapping some symbol node. + // - The argument is a bare symbol node. + const symNode = checkSymbolNodeType(args[0]); + const colalign = symNode ? [args[0]] : assertNodeType(args[0], "ordgroup").body; + const cols = colalign.map(function (nde) { + const node = assertSymbolNodeType(nde); + const ca = node.text; + + if ("lcr".indexOf(ca) !== -1) { + return { + type: "align", + align: ca + }; + } else if (ca === "|") { + return { + type: "separator", + separator: "|" + }; + } else if (ca === ":") { + return { + type: "separator", + separator: ":" + }; + } + + throw new ParseError("Unknown column alignment: " + ca, nde); + }); + const res = { + cols, + hskipBeforeAndAfter: true // \@preamble in lttab.dtx + + }; + return parseArray(context.parser, res, dCellStyle(context.envName)); + }, + + htmlBuilder: htmlBuilder$3, + mathmlBuilder: mathmlBuilder$3 +}); // The matrix environments of amsmath builds on the array environment +// of LaTeX, which is discussed above. + +defineEnvironment({ + type: "array", + names: ["matrix", "pmatrix", "bmatrix", "Bmatrix", "vmatrix", "Vmatrix"], + props: { + numArgs: 0 + }, + + handler(context) { + const delimiters = { + "matrix": null, + "pmatrix": ["(", ")"], + "bmatrix": ["[", "]"], + "Bmatrix": ["\\{", "\\}"], + "vmatrix": ["|", "|"], + "Vmatrix": ["\\Vert", "\\Vert"] + }[context.envName]; // \hskip -\arraycolsep in amsmath + + const payload = { + hskipBeforeAndAfter: false + }; + const res = parseArray(context.parser, payload, dCellStyle(context.envName)); + return delimiters ? { + type: "leftright", + mode: context.mode, + body: [res], + left: delimiters[0], + right: delimiters[1], + rightColor: undefined // \right uninfluenced by \color in array + + } : res; + }, + + htmlBuilder: htmlBuilder$3, + mathmlBuilder: mathmlBuilder$3 +}); +defineEnvironment({ + type: "array", + names: ["smallmatrix"], + props: { + numArgs: 0 + }, + + handler(context) { + const payload = { + arraystretch: 0.5 + }; + const res = parseArray(context.parser, payload, "script"); + res.colSeparationType = "small"; + return res; + }, + + htmlBuilder: htmlBuilder$3, + mathmlBuilder: mathmlBuilder$3 +}); +defineEnvironment({ + type: "array", + names: ["subarray"], + props: { + numArgs: 1 + }, + + handler(context, args) { + // Parsing of {subarray} is similar to {array} + const symNode = checkSymbolNodeType(args[0]); + const colalign = symNode ? [args[0]] : assertNodeType(args[0], "ordgroup").body; + const cols = colalign.map(function (nde) { + const node = assertSymbolNodeType(nde); + const ca = node.text; // {subarray} only recognizes "l" & "c" + + if ("lc".indexOf(ca) !== -1) { + return { + type: "align", + align: ca + }; + } + + throw new ParseError("Unknown column alignment: " + ca, nde); + }); + + if (cols.length > 1) { + throw new ParseError("{subarray} can contain only one column"); + } + + let res = { + cols, + hskipBeforeAndAfter: false, + arraystretch: 0.5 + }; + res = parseArray(context.parser, res, "script"); + + if (res.body[0].length > 1) { + throw new ParseError("{subarray} can contain only one column"); + } + + return res; + }, + + htmlBuilder: htmlBuilder$3, + mathmlBuilder: mathmlBuilder$3 +}); // A cases environment (in amsmath.sty) is almost equivalent to +// \def\arraystretch{1.2}% +// \left\{\begin{array}{@{}l@{\quad}l@{}} … \end{array}\right. +// {dcases} is a {cases} environment where cells are set in \displaystyle, +// as defined in mathtools.sty. + +defineEnvironment({ + type: "array", + names: ["cases", "dcases"], + props: { + numArgs: 0 + }, + + handler(context) { + const payload = { + arraystretch: 1.2, + cols: [{ + type: "align", + align: "l", + pregap: 0, + // TODO(kevinb) get the current style. + // For now we use the metrics for TEXT style which is what we were + // doing before. Before attempting to get the current style we + // should look at TeX's behavior especially for \over and matrices. + postgap: 1.0 + /* 1em quad */ + + }, { + type: "align", + align: "l", + pregap: 0, + postgap: 0 + }] + }; + const res = parseArray(context.parser, payload, dCellStyle(context.envName)); + return { + type: "leftright", + mode: context.mode, + body: [res], + left: "\\{", + right: ".", + rightColor: undefined + }; + }, + + htmlBuilder: htmlBuilder$3, + mathmlBuilder: mathmlBuilder$3 +}); // An aligned environment is like the align* environment +// except it operates within math mode. +// Note that we assume \nomallineskiplimit to be zero, +// so that \strut@ is the same as \strut. + +defineEnvironment({ + type: "array", + names: ["aligned"], + props: { + numArgs: 0 + }, + handler: alignedHandler, + htmlBuilder: htmlBuilder$3, + mathmlBuilder: mathmlBuilder$3 +}); // A gathered environment is like an array environment with one centered +// column, but where rows are considered lines so get \jot line spacing +// and contents are set in \displaystyle. + +defineEnvironment({ + type: "array", + names: ["gathered"], + props: { + numArgs: 0 + }, + + handler(context) { + const res = { + cols: [{ + type: "align", + align: "c" + }], + addJot: true + }; + return parseArray(context.parser, res, "display"); + }, + + htmlBuilder: htmlBuilder$3, + mathmlBuilder: mathmlBuilder$3 +}); // alignat environment is like an align environment, but one must explicitly +// specify maximum number of columns in each row, and can adjust spacing between +// each columns. + +defineEnvironment({ + type: "array", + names: ["alignedat"], + // One for numbered and for unnumbered; + // but, KaTeX doesn't supports math numbering yet, + // they make no difference for now. + props: { + numArgs: 1 + }, + handler: alignedHandler, + htmlBuilder: htmlBuilder$3, + mathmlBuilder: mathmlBuilder$3 +}); // Catch \hline outside array environment + +defineFunction({ + type: "text", + // Doesn't matter what this is. + names: ["\\hline", "\\hdashline"], + props: { + numArgs: 0, + allowedInText: true, + allowedInMath: true + }, + + handler(context, args) { + throw new ParseError(`${context.funcName} valid only within array environment`); + } + +}); + +const environments = _environments; + +// defineEnvironment definitions. +// $FlowFixMe, "environment" handler returns an environment ParseNode + +defineFunction({ + type: "environment", + names: ["\\begin", "\\end"], + props: { + numArgs: 1, + argTypes: ["text"] + }, + + handler(_ref, args) { + let parser = _ref.parser, + funcName = _ref.funcName; + const nameGroup = args[0]; + + if (nameGroup.type !== "ordgroup") { + throw new ParseError("Invalid environment name", nameGroup); + } + + let envName = ""; + + for (let i = 0; i < nameGroup.body.length; ++i) { + envName += assertNodeType(nameGroup.body[i], "textord").text; + } + + if (funcName === "\\begin") { + // begin...end is similar to left...right + if (!environments.hasOwnProperty(envName)) { + throw new ParseError("No such environment: " + envName, nameGroup); + } // Build the environment object. Arguments and other information will + // be made available to the begin and end methods using properties. + + + const env = environments[envName]; + + const _parser$parseArgument = parser.parseArguments("\\begin{" + envName + "}", env), + args = _parser$parseArgument.args, + optArgs = _parser$parseArgument.optArgs; + + const context = { + mode: parser.mode, + envName, + parser + }; + const result = env.handler(context, args, optArgs); + parser.expect("\\end", false); + const endNameToken = parser.nextToken; + const end = assertNodeType(parser.parseFunction(), "environment"); + + if (end.name !== envName) { + throw new ParseError(`Mismatch: \\begin{${envName}} matched by \\end{${end.name}}`, endNameToken); + } + + return result; + } + + return { + type: "environment", + mode: parser.mode, + name: envName, + nameGroup + }; + } + +}); + +const makeSpan$2 = buildCommon.makeSpan; + +function htmlBuilder$4(group, options) { + const elements = buildExpression(group.body, options, true); + return makeSpan$2([group.mclass], elements, options); +} + +function mathmlBuilder$4(group, options) { + let node; + const inner = buildExpression$1(group.body, options); + + if (group.mclass === "minner") { + return mathMLTree.newDocumentFragment(inner); + } else if (group.mclass === "mord") { + if (group.isCharacterBox) { + node = inner[0]; + node.type = "mi"; + } else { + node = new mathMLTree.MathNode("mi", inner); + } + } else { + if (group.isCharacterBox) { + node = inner[0]; + node.type = "mo"; + } else { + node = new mathMLTree.MathNode("mo", inner); + } // Set spacing based on what is the most likely adjacent atom type. + // See TeXbook p170. + + + if (group.mclass === "mbin") { + node.attributes.lspace = "0.22em"; // medium space + + node.attributes.rspace = "0.22em"; + } else if (group.mclass === "mpunct") { + node.attributes.lspace = "0em"; + node.attributes.rspace = "0.17em"; // thinspace + } else if (group.mclass === "mopen" || group.mclass === "mclose") { + node.attributes.lspace = "0em"; + node.attributes.rspace = "0em"; + } // MathML default space is 5/18 em, so needs no action. + // Ref: https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mo + + } + + return node; +} // Math class commands except \mathop + + +defineFunction({ + type: "mclass", + names: ["\\mathord", "\\mathbin", "\\mathrel", "\\mathopen", "\\mathclose", "\\mathpunct", "\\mathinner"], + props: { + numArgs: 1 + }, + + handler(_ref, args) { + let parser = _ref.parser, + funcName = _ref.funcName; + const body = args[0]; + return { + type: "mclass", + mode: parser.mode, + mclass: "m" + funcName.substr(5), + // TODO(kevinb): don't prefix with 'm' + body: ordargument(body), + isCharacterBox: utils.isCharacterBox(body) + }; + }, + + htmlBuilder: htmlBuilder$4, + mathmlBuilder: mathmlBuilder$4 +}); +const binrelClass = arg => { + // \binrel@ spacing varies with (bin|rel|ord) of the atom in the argument. + // (by rendering separately and with {}s before and after, and measuring + // the change in spacing). We'll do roughly the same by detecting the + // atom type directly. + const atom = arg.type === "ordgroup" && arg.body.length ? arg.body[0] : arg; + + if (atom.type === "atom" && (atom.family === "bin" || atom.family === "rel")) { + return "m" + atom.family; + } else { + return "mord"; + } +}; // \@binrel{x}{y} renders like y but as mbin/mrel/mord if x is mbin/mrel/mord. +// This is equivalent to \binrel@{x}\binrel@@{y} in AMSTeX. + +defineFunction({ + type: "mclass", + names: ["\\@binrel"], + props: { + numArgs: 2 + }, + + handler(_ref2, args) { + let parser = _ref2.parser; + return { + type: "mclass", + mode: parser.mode, + mclass: binrelClass(args[0]), + body: [args[1]], + isCharacterBox: utils.isCharacterBox(args[1]) + }; + } + +}); // Build a relation or stacked op by placing one symbol on top of another + +defineFunction({ + type: "mclass", + names: ["\\stackrel", "\\overset", "\\underset"], + props: { + numArgs: 2 + }, + + handler(_ref3, args) { + let parser = _ref3.parser, + funcName = _ref3.funcName; + const baseArg = args[1]; + const shiftedArg = args[0]; + let mclass; + + if (funcName !== "\\stackrel") { + // LaTeX applies \binrel spacing to \overset and \underset. + mclass = binrelClass(baseArg); + } else { + mclass = "mrel"; // for \stackrel + } + + const baseOp = { + type: "op", + mode: baseArg.mode, + limits: true, + alwaysHandleSupSub: true, + parentIsSupSub: false, + symbol: false, + suppressBaseShift: funcName !== "\\stackrel", + body: ordargument(baseArg) + }; + const supsub = { + type: "supsub", + mode: shiftedArg.mode, + base: baseOp, + sup: funcName === "\\underset" ? null : shiftedArg, + sub: funcName === "\\underset" ? shiftedArg : null + }; + return { + type: "mclass", + mode: parser.mode, + mclass, + body: [supsub], + isCharacterBox: utils.isCharacterBox(supsub) + }; + }, + + htmlBuilder: htmlBuilder$4, + mathmlBuilder: mathmlBuilder$4 +}); + +// TODO(kevinb): implement \\sl and \\sc + +const htmlBuilder$5 = (group, options) => { + const font = group.font; + const newOptions = options.withFont(font); + return buildGroup(group.body, newOptions); +}; + +const mathmlBuilder$5 = (group, options) => { + const font = group.font; + const newOptions = options.withFont(font); + return buildGroup$1(group.body, newOptions); +}; + +const fontAliases = { + "\\Bbb": "\\mathbb", + "\\bold": "\\mathbf", + "\\frak": "\\mathfrak", + "\\bm": "\\boldsymbol" +}; +defineFunction({ + type: "font", + names: [// styles, except \boldsymbol defined below + "\\mathrm", "\\mathit", "\\mathbf", "\\mathnormal", // families + "\\mathbb", "\\mathcal", "\\mathfrak", "\\mathscr", "\\mathsf", "\\mathtt", // aliases, except \bm defined below + "\\Bbb", "\\bold", "\\frak"], + props: { + numArgs: 1, + greediness: 2 + }, + handler: (_ref, args) => { + let parser = _ref.parser, + funcName = _ref.funcName; + const body = args[0]; + let func = funcName; + + if (func in fontAliases) { + func = fontAliases[func]; + } + + return { + type: "font", + mode: parser.mode, + font: func.slice(1), + body + }; + }, + htmlBuilder: htmlBuilder$5, + mathmlBuilder: mathmlBuilder$5 +}); +defineFunction({ + type: "mclass", + names: ["\\boldsymbol", "\\bm"], + props: { + numArgs: 1, + greediness: 2 + }, + handler: (_ref2, args) => { + let parser = _ref2.parser; + const body = args[0]; + const isCharacterBox = utils.isCharacterBox(body); // amsbsy.sty's \boldsymbol uses \binrel spacing to inherit the + // argument's bin|rel|ord status + + return { + type: "mclass", + mode: parser.mode, + mclass: binrelClass(body), + body: [{ + type: "font", + mode: parser.mode, + font: "boldsymbol", + body + }], + isCharacterBox: isCharacterBox + }; + } +}); // Old font changing functions + +defineFunction({ + type: "font", + names: ["\\rm", "\\sf", "\\tt", "\\bf", "\\it"], + props: { + numArgs: 0, + allowedInText: true + }, + handler: (_ref3, args) => { + let parser = _ref3.parser, + funcName = _ref3.funcName, + breakOnTokenText = _ref3.breakOnTokenText; + const mode = parser.mode; + const body = parser.parseExpression(true, breakOnTokenText); + const style = `math${funcName.slice(1)}`; + return { + type: "font", + mode: mode, + font: style, + body: { + type: "ordgroup", + mode: parser.mode, + body + } + }; + }, + htmlBuilder: htmlBuilder$5, + mathmlBuilder: mathmlBuilder$5 +}); + +const adjustStyle = (size, originalStyle) => { + // Figure out what style this fraction should be in based on the + // function used + let style = originalStyle; + + if (size === "display") { + // Get display style as a default. + // If incoming style is sub/sup, use style.text() to get correct size. + style = style.id >= Style$1.SCRIPT.id ? style.text() : Style$1.DISPLAY; + } else if (size === "text" && style.size === Style$1.DISPLAY.size) { + // We're in a \tfrac but incoming style is displaystyle, so: + style = Style$1.TEXT; + } else if (size === "script") { + style = Style$1.SCRIPT; + } else if (size === "scriptscript") { + style = Style$1.SCRIPTSCRIPT; + } + + return style; +}; + +const htmlBuilder$6 = (group, options) => { + // Fractions are handled in the TeXbook on pages 444-445, rules 15(a-e). + const style = adjustStyle(group.size, options.style); + const nstyle = style.fracNum(); + const dstyle = style.fracDen(); + let newOptions; + newOptions = options.havingStyle(nstyle); + const numerm = buildGroup(group.numer, newOptions, options); + + if (group.continued) { + // \cfrac inserts a \strut into the numerator. + // Get \strut dimensions from TeXbook page 353. + const hStrut = 8.5 / options.fontMetrics().ptPerEm; + const dStrut = 3.5 / options.fontMetrics().ptPerEm; + numerm.height = numerm.height < hStrut ? hStrut : numerm.height; + numerm.depth = numerm.depth < dStrut ? dStrut : numerm.depth; + } + + newOptions = options.havingStyle(dstyle); + const denomm = buildGroup(group.denom, newOptions, options); + let rule; + let ruleWidth; + let ruleSpacing; + + if (group.hasBarLine) { + if (group.barSize) { + ruleWidth = calculateSize(group.barSize, options); + rule = buildCommon.makeLineSpan("frac-line", options, ruleWidth); + } else { + rule = buildCommon.makeLineSpan("frac-line", options); + } + + ruleWidth = rule.height; + ruleSpacing = rule.height; + } else { + rule = null; + ruleWidth = 0; + ruleSpacing = options.fontMetrics().defaultRuleThickness; + } // Rule 15b + + + let numShift; + let clearance; + let denomShift; + + if (style.size === Style$1.DISPLAY.size || group.size === "display") { + numShift = options.fontMetrics().num1; + + if (ruleWidth > 0) { + clearance = 3 * ruleSpacing; + } else { + clearance = 7 * ruleSpacing; + } + + denomShift = options.fontMetrics().denom1; + } else { + if (ruleWidth > 0) { + numShift = options.fontMetrics().num2; + clearance = ruleSpacing; + } else { + numShift = options.fontMetrics().num3; + clearance = 3 * ruleSpacing; + } + + denomShift = options.fontMetrics().denom2; + } + + let frac; + + if (!rule) { + // Rule 15c + const candidateClearance = numShift - numerm.depth - (denomm.height - denomShift); + + if (candidateClearance < clearance) { + numShift += 0.5 * (clearance - candidateClearance); + denomShift += 0.5 * (clearance - candidateClearance); + } + + frac = buildCommon.makeVList({ + positionType: "individualShift", + children: [{ + type: "elem", + elem: denomm, + shift: denomShift + }, { + type: "elem", + elem: numerm, + shift: -numShift + }] + }, options); + } else { + // Rule 15d + const axisHeight = options.fontMetrics().axisHeight; + + if (numShift - numerm.depth - (axisHeight + 0.5 * ruleWidth) < clearance) { + numShift += clearance - (numShift - numerm.depth - (axisHeight + 0.5 * ruleWidth)); + } + + if (axisHeight - 0.5 * ruleWidth - (denomm.height - denomShift) < clearance) { + denomShift += clearance - (axisHeight - 0.5 * ruleWidth - (denomm.height - denomShift)); + } + + const midShift = -(axisHeight - 0.5 * ruleWidth); + frac = buildCommon.makeVList({ + positionType: "individualShift", + children: [{ + type: "elem", + elem: denomm, + shift: denomShift + }, { + type: "elem", + elem: rule, + shift: midShift + }, { + type: "elem", + elem: numerm, + shift: -numShift + }] + }, options); + } // Since we manually change the style sometimes (with \dfrac or \tfrac), + // account for the possible size change here. + + + newOptions = options.havingStyle(style); + frac.height *= newOptions.sizeMultiplier / options.sizeMultiplier; + frac.depth *= newOptions.sizeMultiplier / options.sizeMultiplier; // Rule 15e + + let delimSize; + + if (style.size === Style$1.DISPLAY.size) { + delimSize = options.fontMetrics().delim1; + } else { + delimSize = options.fontMetrics().delim2; + } + + let leftDelim; + let rightDelim; + + if (group.leftDelim == null) { + leftDelim = makeNullDelimiter(options, ["mopen"]); + } else { + leftDelim = delimiter.customSizedDelim(group.leftDelim, delimSize, true, options.havingStyle(style), group.mode, ["mopen"]); + } + + if (group.continued) { + rightDelim = buildCommon.makeSpan([]); // zero width for \cfrac + } else if (group.rightDelim == null) { + rightDelim = makeNullDelimiter(options, ["mclose"]); + } else { + rightDelim = delimiter.customSizedDelim(group.rightDelim, delimSize, true, options.havingStyle(style), group.mode, ["mclose"]); + } + + return buildCommon.makeSpan(["mord"].concat(newOptions.sizingClasses(options)), [leftDelim, buildCommon.makeSpan(["mfrac"], [frac]), rightDelim], options); +}; + +const mathmlBuilder$6 = (group, options) => { + let node = new mathMLTree.MathNode("mfrac", [buildGroup$1(group.numer, options), buildGroup$1(group.denom, options)]); + + if (!group.hasBarLine) { + node.setAttribute("linethickness", "0px"); + } else if (group.barSize) { + const ruleWidth = calculateSize(group.barSize, options); + node.setAttribute("linethickness", ruleWidth + "em"); + } + + const style = adjustStyle(group.size, options.style); + + if (style.size !== options.style.size) { + node = new mathMLTree.MathNode("mstyle", [node]); + const isDisplay = style.size === Style$1.DISPLAY.size ? "true" : "false"; + node.setAttribute("displaystyle", isDisplay); + node.setAttribute("scriptlevel", "0"); + } + + if (group.leftDelim != null || group.rightDelim != null) { + const withDelims = []; + + if (group.leftDelim != null) { + const leftOp = new mathMLTree.MathNode("mo", [new mathMLTree.TextNode(group.leftDelim.replace("\\", ""))]); + leftOp.setAttribute("fence", "true"); + withDelims.push(leftOp); + } + + withDelims.push(node); + + if (group.rightDelim != null) { + const rightOp = new mathMLTree.MathNode("mo", [new mathMLTree.TextNode(group.rightDelim.replace("\\", ""))]); + rightOp.setAttribute("fence", "true"); + withDelims.push(rightOp); + } + + return makeRow(withDelims); + } + + return node; +}; + +defineFunction({ + type: "genfrac", + names: ["\\cfrac", "\\dfrac", "\\frac", "\\tfrac", "\\dbinom", "\\binom", "\\tbinom", "\\\\atopfrac", // can’t be entered directly + "\\\\bracefrac", "\\\\brackfrac"], + props: { + numArgs: 2, + greediness: 2 + }, + handler: (_ref, args) => { + let parser = _ref.parser, + funcName = _ref.funcName; + const numer = args[0]; + const denom = args[1]; + let hasBarLine; + let leftDelim = null; + let rightDelim = null; + let size = "auto"; + + switch (funcName) { + case "\\cfrac": + case "\\dfrac": + case "\\frac": + case "\\tfrac": + hasBarLine = true; + break; + + case "\\\\atopfrac": + hasBarLine = false; + break; + + case "\\dbinom": + case "\\binom": + case "\\tbinom": + hasBarLine = false; + leftDelim = "("; + rightDelim = ")"; + break; + + case "\\\\bracefrac": + hasBarLine = false; + leftDelim = "\\{"; + rightDelim = "\\}"; + break; + + case "\\\\brackfrac": + hasBarLine = false; + leftDelim = "["; + rightDelim = "]"; + break; + + default: + throw new Error("Unrecognized genfrac command"); + } + + switch (funcName) { + case "\\cfrac": + case "\\dfrac": + case "\\dbinom": + size = "display"; + break; + + case "\\tfrac": + case "\\tbinom": + size = "text"; + break; + } + + return { + type: "genfrac", + mode: parser.mode, + continued: funcName === "\\cfrac", + numer, + denom, + hasBarLine, + leftDelim, + rightDelim, + size, + barSize: null + }; + }, + htmlBuilder: htmlBuilder$6, + mathmlBuilder: mathmlBuilder$6 +}); // Infix generalized fractions -- these are not rendered directly, but replaced +// immediately by one of the variants above. + +defineFunction({ + type: "infix", + names: ["\\over", "\\choose", "\\atop", "\\brace", "\\brack"], + props: { + numArgs: 0, + infix: true + }, + + handler(_ref2) { + let parser = _ref2.parser, + funcName = _ref2.funcName, + token = _ref2.token; + let replaceWith; + + switch (funcName) { + case "\\over": + replaceWith = "\\frac"; + break; + + case "\\choose": + replaceWith = "\\binom"; + break; + + case "\\atop": + replaceWith = "\\\\atopfrac"; + break; + + case "\\brace": + replaceWith = "\\\\bracefrac"; + break; + + case "\\brack": + replaceWith = "\\\\brackfrac"; + break; + + default: + throw new Error("Unrecognized infix genfrac command"); + } + + return { + type: "infix", + mode: parser.mode, + replaceWith, + token + }; + } + +}); +const stylArray = ["display", "text", "script", "scriptscript"]; + +const delimFromValue = function delimFromValue(delimString) { + let delim = null; + + if (delimString.length > 0) { + delim = delimString; + delim = delim === "." ? null : delim; + } + + return delim; +}; + +defineFunction({ + type: "genfrac", + names: ["\\genfrac"], + props: { + numArgs: 6, + greediness: 6, + argTypes: ["math", "math", "size", "text", "math", "math"] + }, + + handler(_ref3, args) { + let parser = _ref3.parser; + const numer = args[4]; + const denom = args[5]; // Look into the parse nodes to get the desired delimiters. + + let leftNode = checkNodeType(args[0], "atom"); + + if (leftNode) { + leftNode = assertAtomFamily(args[0], "open"); + } + + const leftDelim = leftNode ? delimFromValue(leftNode.text) : null; + let rightNode = checkNodeType(args[1], "atom"); + + if (rightNode) { + rightNode = assertAtomFamily(args[1], "close"); + } + + const rightDelim = rightNode ? delimFromValue(rightNode.text) : null; + const barNode = assertNodeType(args[2], "size"); + let hasBarLine; + let barSize = null; + + if (barNode.isBlank) { + // \genfrac acts differently than \above. + // \genfrac treats an empty size group as a signal to use a + // standard bar size. \above would see size = 0 and omit the bar. + hasBarLine = true; + } else { + barSize = barNode.value; + hasBarLine = barSize.number > 0; + } // Find out if we want displaystyle, textstyle, etc. + + + let size = "auto"; + let styl = checkNodeType(args[3], "ordgroup"); + + if (styl) { + if (styl.body.length > 0) { + const textOrd = assertNodeType(styl.body[0], "textord"); + size = stylArray[Number(textOrd.text)]; + } + } else { + styl = assertNodeType(args[3], "textord"); + size = stylArray[Number(styl.text)]; + } + + return { + type: "genfrac", + mode: parser.mode, + numer, + denom, + continued: false, + hasBarLine, + barSize, + leftDelim, + rightDelim, + size + }; + }, + + htmlBuilder: htmlBuilder$6, + mathmlBuilder: mathmlBuilder$6 +}); // \above is an infix fraction that also defines a fraction bar size. + +defineFunction({ + type: "infix", + names: ["\\above"], + props: { + numArgs: 1, + argTypes: ["size"], + infix: true + }, + + handler(_ref4, args) { + let parser = _ref4.parser, + funcName = _ref4.funcName, + token = _ref4.token; + return { + type: "infix", + mode: parser.mode, + replaceWith: "\\\\abovefrac", + size: assertNodeType(args[0], "size").value, + token + }; + } + +}); +defineFunction({ + type: "genfrac", + names: ["\\\\abovefrac"], + props: { + numArgs: 3, + argTypes: ["math", "size", "math"] + }, + handler: (_ref5, args) => { + let parser = _ref5.parser, + funcName = _ref5.funcName; + const numer = args[0]; + const barSize = assert(assertNodeType(args[1], "infix").size); + const denom = args[2]; + const hasBarLine = barSize.number > 0; + return { + type: "genfrac", + mode: parser.mode, + numer, + denom, + continued: false, + hasBarLine, + barSize, + leftDelim: null, + rightDelim: null, + size: "auto" + }; + }, + htmlBuilder: htmlBuilder$6, + mathmlBuilder: mathmlBuilder$6 +}); + +// NOTE: Unlike most `htmlBuilder`s, this one handles not only "horizBrace", but +const htmlBuilder$7 = (grp, options) => { + const style = options.style; // Pull out the `ParseNode<"horizBrace">` if `grp` is a "supsub" node. + + let supSubGroup; + let group; + const supSub = checkNodeType(grp, "supsub"); + + if (supSub) { + // Ref: LaTeX source2e: }}}}\limits} + // i.e. LaTeX treats the brace similar to an op and passes it + // with \limits, so we need to assign supsub style. + supSubGroup = supSub.sup ? buildGroup(supSub.sup, options.havingStyle(style.sup()), options) : buildGroup(supSub.sub, options.havingStyle(style.sub()), options); + group = assertNodeType(supSub.base, "horizBrace"); + } else { + group = assertNodeType(grp, "horizBrace"); + } // Build the base group + + + const body = buildGroup(group.base, options.havingBaseStyle(Style$1.DISPLAY)); // Create the stretchy element + + const braceBody = stretchy.svgSpan(group, options); // Generate the vlist, with the appropriate kerns ┏━━━━━━━━┓ + // This first vlist contains the content and the brace: equation + + let vlist; + + if (group.isOver) { + vlist = buildCommon.makeVList({ + positionType: "firstBaseline", + children: [{ + type: "elem", + elem: body + }, { + type: "kern", + size: 0.1 + }, { + type: "elem", + elem: braceBody + }] + }, options); // $FlowFixMe: Replace this with passing "svg-align" into makeVList. + + vlist.children[0].children[0].children[1].classes.push("svg-align"); + } else { + vlist = buildCommon.makeVList({ + positionType: "bottom", + positionData: body.depth + 0.1 + braceBody.height, + children: [{ + type: "elem", + elem: braceBody + }, { + type: "kern", + size: 0.1 + }, { + type: "elem", + elem: body + }] + }, options); // $FlowFixMe: Replace this with passing "svg-align" into makeVList. + + vlist.children[0].children[0].children[0].classes.push("svg-align"); + } + + if (supSubGroup) { + // To write the supsub, wrap the first vlist in another vlist: + // They can't all go in the same vlist, because the note might be + // wider than the equation. We want the equation to control the + // brace width. + // note long note long note + // ┏━━━━━━━━┓ or ┏━━━┓ not ┏━━━━━━━━━┓ + // equation eqn eqn + const vSpan = buildCommon.makeSpan(["mord", group.isOver ? "mover" : "munder"], [vlist], options); + + if (group.isOver) { + vlist = buildCommon.makeVList({ + positionType: "firstBaseline", + children: [{ + type: "elem", + elem: vSpan + }, { + type: "kern", + size: 0.2 + }, { + type: "elem", + elem: supSubGroup + }] + }, options); + } else { + vlist = buildCommon.makeVList({ + positionType: "bottom", + positionData: vSpan.depth + 0.2 + supSubGroup.height + supSubGroup.depth, + children: [{ + type: "elem", + elem: supSubGroup + }, { + type: "kern", + size: 0.2 + }, { + type: "elem", + elem: vSpan + }] + }, options); + } + } + + return buildCommon.makeSpan(["mord", group.isOver ? "mover" : "munder"], [vlist], options); +}; + +const mathmlBuilder$7 = (group, options) => { + const accentNode = stretchy.mathMLnode(group.label); + return new mathMLTree.MathNode(group.isOver ? "mover" : "munder", [buildGroup$1(group.base, options), accentNode]); +}; // Horizontal stretchy braces + + +defineFunction({ + type: "horizBrace", + names: ["\\overbrace", "\\underbrace"], + props: { + numArgs: 1 + }, + + handler(_ref, args) { + let parser = _ref.parser, + funcName = _ref.funcName; + return { + type: "horizBrace", + mode: parser.mode, + label: funcName, + isOver: /^\\over/.test(funcName), + base: args[0] + }; + }, + + htmlBuilder: htmlBuilder$7, + mathmlBuilder: mathmlBuilder$7 +}); + +defineFunction({ + type: "href", + names: ["\\href"], + props: { + numArgs: 2, + argTypes: ["url", "original"], + allowedInText: true + }, + handler: (_ref, args) => { + let parser = _ref.parser; + const body = args[1]; + const href = assertNodeType(args[0], "url").url; + + if (!parser.settings.isTrusted({ + command: "\\href", + url: href + })) { + return parser.formatUnsupportedCmd("\\href"); + } + + return { + type: "href", + mode: parser.mode, + href, + body: ordargument(body) + }; + }, + htmlBuilder: (group, options) => { + const elements = buildExpression(group.body, options, false); + return buildCommon.makeAnchor(group.href, [], elements, options); + }, + mathmlBuilder: (group, options) => { + let math = buildExpressionRow(group.body, options); + + if (!(math instanceof MathNode)) { + math = new MathNode("mrow", [math]); + } + + math.setAttribute("href", group.href); + return math; + } +}); +defineFunction({ + type: "href", + names: ["\\url"], + props: { + numArgs: 1, + argTypes: ["url"], + allowedInText: true + }, + handler: (_ref2, args) => { + let parser = _ref2.parser; + const href = assertNodeType(args[0], "url").url; + + if (!parser.settings.isTrusted({ + command: "\\url", + url: href + })) { + return parser.formatUnsupportedCmd("\\url"); + } + + const chars = []; + + for (let i = 0; i < href.length; i++) { + let c = href[i]; + + if (c === "~") { + c = "\\textasciitilde"; + } + + chars.push({ + type: "textord", + mode: "text", + text: c + }); + } + + const body = { + type: "text", + mode: parser.mode, + font: "\\texttt", + body: chars + }; + return { + type: "href", + mode: parser.mode, + href, + body: ordargument(body) + }; + } +}); + +defineFunction({ + type: "htmlmathml", + names: ["\\html@mathml"], + props: { + numArgs: 2, + allowedInText: true + }, + handler: (_ref, args) => { + let parser = _ref.parser; + return { + type: "htmlmathml", + mode: parser.mode, + html: ordargument(args[0]), + mathml: ordargument(args[1]) + }; + }, + htmlBuilder: (group, options) => { + const elements = buildExpression(group.html, options, false); + return buildCommon.makeFragment(elements); + }, + mathmlBuilder: (group, options) => { + return buildExpressionRow(group.mathml, options); + } +}); + +const sizeData = function sizeData(str) { + if (/^[-+]? *(\d+(\.\d*)?|\.\d+)$/.test(str)) { + // str is a number with no unit specified. + // default unit is bp, per graphix package. + return { + number: +str, + unit: "bp" + }; + } else { + const match = /([-+]?) *(\d+(?:\.\d*)?|\.\d+) *([a-z]{2})/.exec(str); + + if (!match) { + throw new ParseError("Invalid size: '" + str + "' in \\includegraphics"); + } + + const data = { + number: +(match[1] + match[2]), + // sign + magnitude, cast to number + unit: match[3] + }; + + if (!validUnit(data)) { + throw new ParseError("Invalid unit: '" + data.unit + "' in \\includegraphics."); + } + + return data; + } +}; + +defineFunction({ + type: "includegraphics", + names: ["\\includegraphics"], + props: { + numArgs: 1, + numOptionalArgs: 1, + argTypes: ["raw", "url"], + allowedInText: false + }, + handler: (_ref, args, optArgs) => { + let parser = _ref.parser; + let width = { + number: 0, + unit: "em" + }; + let height = { + number: 0.9, + unit: "em" + }; // sorta character sized. + + let totalheight = { + number: 0, + unit: "em" + }; + let alt = ""; + + if (optArgs[0]) { + const attributeStr = assertNodeType(optArgs[0], "raw").string; // Parser.js does not parse key/value pairs. We get a string. + + const attributes = attributeStr.split(","); + + for (let i = 0; i < attributes.length; i++) { + const keyVal = attributes[i].split("="); + + if (keyVal.length === 2) { + const str = keyVal[1].trim(); + + switch (keyVal[0].trim()) { + case "alt": + alt = str; + break; + + case "width": + width = sizeData(str); + break; + + case "height": + height = sizeData(str); + break; + + case "totalheight": + totalheight = sizeData(str); + break; + + default: + throw new ParseError("Invalid key: '" + keyVal[0] + "' in \\includegraphics."); + } + } + } + } + + const src = assertNodeType(args[0], "url").url; + + if (alt === "") { + // No alt given. Use the file name. Strip away the path. + alt = src; + alt = alt.replace(/^.*[\\/]/, ''); + alt = alt.substring(0, alt.lastIndexOf('.')); + } + + if (!parser.settings.isTrusted({ + command: "\\includegraphics", + url: src + })) { + return parser.formatUnsupportedCmd("\\includegraphics"); + } + + return { + type: "includegraphics", + mode: parser.mode, + alt: alt, + width: width, + height: height, + totalheight: totalheight, + src: src + }; + }, + htmlBuilder: (group, options) => { + const height = calculateSize(group.height, options); + let depth = 0; + + if (group.totalheight.number > 0) { + depth = calculateSize(group.totalheight, options) - height; + depth = Number(depth.toFixed(2)); + } + + let width = 0; + + if (group.width.number > 0) { + width = calculateSize(group.width, options); + } + + const style = { + height: height + depth + "em" + }; + + if (width > 0) { + style.width = width + "em"; + } + + if (depth > 0) { + style.verticalAlign = -depth + "em"; + } + + const node = new Img(group.src, group.alt, style); + node.height = height; + node.depth = depth; + return node; + }, + mathmlBuilder: (group, options) => { + const node = new mathMLTree.MathNode("mglyph", []); + node.setAttribute("alt", group.alt); + const height = calculateSize(group.height, options); + let depth = 0; + + if (group.totalheight.number > 0) { + depth = calculateSize(group.totalheight, options) - height; + depth = depth.toFixed(2); + node.setAttribute("valign", "-" + depth + "em"); + } + + node.setAttribute("height", height + depth + "em"); + + if (group.width.number > 0) { + const width = calculateSize(group.width, options); + node.setAttribute("width", width + "em"); + } + + node.setAttribute("src", group.src); + return node; + } +}); + +// Horizontal spacing commands + +defineFunction({ + type: "kern", + names: ["\\kern", "\\mkern", "\\hskip", "\\mskip"], + props: { + numArgs: 1, + argTypes: ["size"], + allowedInText: true + }, + + handler(_ref, args) { + let parser = _ref.parser, + funcName = _ref.funcName; + const size = assertNodeType(args[0], "size"); + + if (parser.settings.strict) { + const mathFunction = funcName[1] === 'm'; // \mkern, \mskip + + const muUnit = size.value.unit === 'mu'; + + if (mathFunction) { + if (!muUnit) { + parser.settings.reportNonstrict("mathVsTextUnits", `LaTeX's ${funcName} supports only mu units, ` + `not ${size.value.unit} units`); + } + + if (parser.mode !== "math") { + parser.settings.reportNonstrict("mathVsTextUnits", `LaTeX's ${funcName} works only in math mode`); + } + } else { + // !mathFunction + if (muUnit) { + parser.settings.reportNonstrict("mathVsTextUnits", `LaTeX's ${funcName} doesn't support mu units`); + } + } + } + + return { + type: "kern", + mode: parser.mode, + dimension: size.value + }; + }, + + htmlBuilder(group, options) { + return buildCommon.makeGlue(group.dimension, options); + }, + + mathmlBuilder(group, options) { + const dimension = calculateSize(group.dimension, options); + return new mathMLTree.SpaceNode(dimension); + } + +}); + +// Horizontal overlap functions +defineFunction({ + type: "lap", + names: ["\\mathllap", "\\mathrlap", "\\mathclap"], + props: { + numArgs: 1, + allowedInText: true + }, + handler: (_ref, args) => { + let parser = _ref.parser, + funcName = _ref.funcName; + const body = args[0]; + return { + type: "lap", + mode: parser.mode, + alignment: funcName.slice(5), + body + }; + }, + htmlBuilder: (group, options) => { + // mathllap, mathrlap, mathclap + let inner; + + if (group.alignment === "clap") { + // ref: https://www.math.lsu.edu/~aperlis/publications/mathclap/ + inner = buildCommon.makeSpan([], [buildGroup(group.body, options)]); // wrap, since CSS will center a .clap > .inner > span + + inner = buildCommon.makeSpan(["inner"], [inner], options); + } else { + inner = buildCommon.makeSpan(["inner"], [buildGroup(group.body, options)]); + } + + const fix = buildCommon.makeSpan(["fix"], []); + let node = buildCommon.makeSpan([group.alignment], [inner, fix], options); // At this point, we have correctly set horizontal alignment of the + // two items involved in the lap. + // Next, use a strut to set the height of the HTML bounding box. + // Otherwise, a tall argument may be misplaced. + + const strut = buildCommon.makeSpan(["strut"]); + strut.style.height = node.height + node.depth + "em"; + strut.style.verticalAlign = -node.depth + "em"; + node.children.unshift(strut); // Next, prevent vertical misplacement when next to something tall. + + node = buildCommon.makeVList({ + positionType: "firstBaseline", + children: [{ + type: "elem", + elem: node + }] + }, options); // Get the horizontal spacing correct relative to adjacent items. + + return buildCommon.makeSpan(["mord"], [node], options); + }, + mathmlBuilder: (group, options) => { + // mathllap, mathrlap, mathclap + const node = new mathMLTree.MathNode("mpadded", [buildGroup$1(group.body, options)]); + + if (group.alignment !== "rlap") { + const offset = group.alignment === "llap" ? "-1" : "-0.5"; + node.setAttribute("lspace", offset + "width"); + } + + node.setAttribute("width", "0px"); + return node; + } +}); + +defineFunction({ + type: "styling", + names: ["\\(", "$"], + props: { + numArgs: 0, + allowedInText: true, + allowedInMath: false + }, + + handler(_ref, args) { + let funcName = _ref.funcName, + parser = _ref.parser; + const outerMode = parser.mode; + parser.switchMode("math"); + const close = funcName === "\\(" ? "\\)" : "$"; + const body = parser.parseExpression(false, close); + parser.expect(close); + parser.switchMode(outerMode); + return { + type: "styling", + mode: parser.mode, + style: "text", + body + }; + } + +}); // Check for extra closing math delimiters + +defineFunction({ + type: "text", + // Doesn't matter what this is. + names: ["\\)", "\\]"], + props: { + numArgs: 0, + allowedInText: true, + allowedInMath: false + }, + + handler(context, args) { + throw new ParseError(`Mismatched ${context.funcName}`); + } + +}); + +const chooseMathStyle = (group, options) => { + switch (options.style.size) { + case Style$1.DISPLAY.size: + return group.display; + + case Style$1.TEXT.size: + return group.text; + + case Style$1.SCRIPT.size: + return group.script; + + case Style$1.SCRIPTSCRIPT.size: + return group.scriptscript; + + default: + return group.text; + } +}; + +defineFunction({ + type: "mathchoice", + names: ["\\mathchoice"], + props: { + numArgs: 4 + }, + handler: (_ref, args) => { + let parser = _ref.parser; + return { + type: "mathchoice", + mode: parser.mode, + display: ordargument(args[0]), + text: ordargument(args[1]), + script: ordargument(args[2]), + scriptscript: ordargument(args[3]) + }; + }, + htmlBuilder: (group, options) => { + const body = chooseMathStyle(group, options); + const elements = buildExpression(body, options, false); + return buildCommon.makeFragment(elements); + }, + mathmlBuilder: (group, options) => { + const body = chooseMathStyle(group, options); + return buildExpressionRow(body, options); + } +}); + +// For an operator with limits, assemble the base, sup, and sub into a span. +const assembleSupSub = (base, supGroup, subGroup, options, style, slant, baseShift) => { + // IE 8 clips \int if it is in a display: inline-block. We wrap it + // in a new span so it is an inline, and works. + base = buildCommon.makeSpan([], [base]); + let sub; + let sup; // We manually have to handle the superscripts and subscripts. This, + // aside from the kern calculations, is copied from supsub. + + if (supGroup) { + const elem = buildGroup(supGroup, options.havingStyle(style.sup()), options); + sup = { + elem, + kern: Math.max(options.fontMetrics().bigOpSpacing1, options.fontMetrics().bigOpSpacing3 - elem.depth) + }; + } + + if (subGroup) { + const elem = buildGroup(subGroup, options.havingStyle(style.sub()), options); + sub = { + elem, + kern: Math.max(options.fontMetrics().bigOpSpacing2, options.fontMetrics().bigOpSpacing4 - elem.height) + }; + } // Build the final group as a vlist of the possible subscript, base, + // and possible superscript. + + + let finalGroup; + + if (sup && sub) { + const bottom = options.fontMetrics().bigOpSpacing5 + sub.elem.height + sub.elem.depth + sub.kern + base.depth + baseShift; + finalGroup = buildCommon.makeVList({ + positionType: "bottom", + positionData: bottom, + children: [{ + type: "kern", + size: options.fontMetrics().bigOpSpacing5 + }, { + type: "elem", + elem: sub.elem, + marginLeft: -slant + "em" + }, { + type: "kern", + size: sub.kern + }, { + type: "elem", + elem: base + }, { + type: "kern", + size: sup.kern + }, { + type: "elem", + elem: sup.elem, + marginLeft: slant + "em" + }, { + type: "kern", + size: options.fontMetrics().bigOpSpacing5 + }] + }, options); + } else if (sub) { + const top = base.height - baseShift; // Shift the limits by the slant of the symbol. Note + // that we are supposed to shift the limits by 1/2 of the slant, + // but since we are centering the limits adding a full slant of + // margin will shift by 1/2 that. + + finalGroup = buildCommon.makeVList({ + positionType: "top", + positionData: top, + children: [{ + type: "kern", + size: options.fontMetrics().bigOpSpacing5 + }, { + type: "elem", + elem: sub.elem, + marginLeft: -slant + "em" + }, { + type: "kern", + size: sub.kern + }, { + type: "elem", + elem: base + }] + }, options); + } else if (sup) { + const bottom = base.depth + baseShift; + finalGroup = buildCommon.makeVList({ + positionType: "bottom", + positionData: bottom, + children: [{ + type: "elem", + elem: base + }, { + type: "kern", + size: sup.kern + }, { + type: "elem", + elem: sup.elem, + marginLeft: slant + "em" + }, { + type: "kern", + size: options.fontMetrics().bigOpSpacing5 + }] + }, options); + } else { + // This case probably shouldn't occur (this would mean the + // supsub was sending us a group with no superscript or + // subscript) but be safe. + return base; + } + + return buildCommon.makeSpan(["mop", "op-limits"], [finalGroup], options); +}; + +// Limits, symbols +// Most operators have a large successor symbol, but these don't. +const noSuccessor = ["\\smallint"]; // NOTE: Unlike most `htmlBuilder`s, this one handles not only "op", but also +// "supsub" since some of them (like \int) can affect super/subscripting. + +const htmlBuilder$8 = (grp, options) => { + // Operators are handled in the TeXbook pg. 443-444, rule 13(a). + let supGroup; + let subGroup; + let hasLimits = false; + let group; + const supSub = checkNodeType(grp, "supsub"); + + if (supSub) { + // If we have limits, supsub will pass us its group to handle. Pull + // out the superscript and subscript and set the group to the op in + // its base. + supGroup = supSub.sup; + subGroup = supSub.sub; + group = assertNodeType(supSub.base, "op"); + hasLimits = true; + } else { + group = assertNodeType(grp, "op"); + } + + const style = options.style; + let large = false; + + if (style.size === Style$1.DISPLAY.size && group.symbol && !utils.contains(noSuccessor, group.name)) { + // Most symbol operators get larger in displaystyle (rule 13) + large = true; + } + + let base; + + if (group.symbol) { + // If this is a symbol, create the symbol. + const fontName = large ? "Size2-Regular" : "Size1-Regular"; + let stash = ""; + + if (group.name === "\\oiint" || group.name === "\\oiiint") { + // No font glyphs yet, so use a glyph w/o the oval. + // TODO: When font glyphs are available, delete this code. + stash = group.name.substr(1); // $FlowFixMe + + group.name = stash === "oiint" ? "\\iint" : "\\iiint"; + } + + base = buildCommon.makeSymbol(group.name, fontName, "math", options, ["mop", "op-symbol", large ? "large-op" : "small-op"]); + + if (stash.length > 0) { + // We're in \oiint or \oiiint. Overlay the oval. + // TODO: When font glyphs are available, delete this code. + const italic = base.italic; + const oval = buildCommon.staticSvg(stash + "Size" + (large ? "2" : "1"), options); + base = buildCommon.makeVList({ + positionType: "individualShift", + children: [{ + type: "elem", + elem: base, + shift: 0 + }, { + type: "elem", + elem: oval, + shift: large ? 0.08 : 0 + }] + }, options); // $FlowFixMe + + group.name = "\\" + stash; + base.classes.unshift("mop"); // $FlowFixMe + + base.italic = italic; + } + } else if (group.body) { + // If this is a list, compose that list. + const inner = buildExpression(group.body, options, true); + + if (inner.length === 1 && inner[0] instanceof SymbolNode) { + base = inner[0]; + base.classes[0] = "mop"; // replace old mclass + } else { + base = buildCommon.makeSpan(["mop"], buildCommon.tryCombineChars(inner), options); + } + } else { + // Otherwise, this is a text operator. Build the text from the + // operator's name. + // TODO(emily): Add a space in the middle of some of these + // operators, like \limsup + const output = []; + + for (let i = 1; i < group.name.length; i++) { + output.push(buildCommon.mathsym(group.name[i], group.mode, options)); + } + + base = buildCommon.makeSpan(["mop"], output, options); + } // If content of op is a single symbol, shift it vertically. + + + let baseShift = 0; + let slant = 0; + + if ((base instanceof SymbolNode || group.name === "\\oiint" || group.name === "\\oiiint") && !group.suppressBaseShift) { + // We suppress the shift of the base of \overset and \underset. Otherwise, + // shift the symbol so its center lies on the axis (rule 13). It + // appears that our fonts have the centers of the symbols already + // almost on the axis, so these numbers are very small. Note we + // don't actually apply this here, but instead it is used either in + // the vlist creation or separately when there are no limits. + baseShift = (base.height - base.depth) / 2 - options.fontMetrics().axisHeight; // The slant of the symbol is just its italic correction. + // $FlowFixMe + + slant = base.italic; + } + + if (hasLimits) { + return assembleSupSub(base, supGroup, subGroup, options, style, slant, baseShift); + } else { + if (baseShift) { + base.style.position = "relative"; + base.style.top = baseShift + "em"; + } + + return base; + } +}; + +const mathmlBuilder$8 = (group, options) => { + let node; + + if (group.symbol) { + // This is a symbol. Just add the symbol. + node = new MathNode("mo", [makeText(group.name, group.mode)]); + + if (utils.contains(noSuccessor, group.name)) { + node.setAttribute("largeop", "false"); + } + } else if (group.body) { + // This is an operator with children. Add them. + node = new MathNode("mo", buildExpression$1(group.body, options)); + } else { + // This is a text operator. Add all of the characters from the + // operator's name. + node = new MathNode("mi", [new TextNode(group.name.slice(1))]); // Append an . + // ref: https://www.w3.org/TR/REC-MathML/chap3_2.html#sec3.2.4 + + const operator = new MathNode("mo", [makeText("\u2061", "text")]); + + if (group.parentIsSupSub) { + node = new MathNode("mo", [node, operator]); + } else { + node = newDocumentFragment([node, operator]); + } + } + + return node; +}; + +const singleCharBigOps = { + "\u220F": "\\prod", + "\u2210": "\\coprod", + "\u2211": "\\sum", + "\u22c0": "\\bigwedge", + "\u22c1": "\\bigvee", + "\u22c2": "\\bigcap", + "\u22c3": "\\bigcup", + "\u2a00": "\\bigodot", + "\u2a01": "\\bigoplus", + "\u2a02": "\\bigotimes", + "\u2a04": "\\biguplus", + "\u2a06": "\\bigsqcup" +}; +defineFunction({ + type: "op", + names: ["\\coprod", "\\bigvee", "\\bigwedge", "\\biguplus", "\\bigcap", "\\bigcup", "\\intop", "\\prod", "\\sum", "\\bigotimes", "\\bigoplus", "\\bigodot", "\\bigsqcup", "\\smallint", "\u220F", "\u2210", "\u2211", "\u22c0", "\u22c1", "\u22c2", "\u22c3", "\u2a00", "\u2a01", "\u2a02", "\u2a04", "\u2a06"], + props: { + numArgs: 0 + }, + handler: (_ref, args) => { + let parser = _ref.parser, + funcName = _ref.funcName; + let fName = funcName; + + if (fName.length === 1) { + fName = singleCharBigOps[fName]; + } + + return { + type: "op", + mode: parser.mode, + limits: true, + parentIsSupSub: false, + symbol: true, + name: fName + }; + }, + htmlBuilder: htmlBuilder$8, + mathmlBuilder: mathmlBuilder$8 +}); // Note: calling defineFunction with a type that's already been defined only +// works because the same htmlBuilder and mathmlBuilder are being used. + +defineFunction({ + type: "op", + names: ["\\mathop"], + props: { + numArgs: 1 + }, + handler: (_ref2, args) => { + let parser = _ref2.parser; + const body = args[0]; + return { + type: "op", + mode: parser.mode, + limits: false, + parentIsSupSub: false, + symbol: false, + body: ordargument(body) + }; + }, + htmlBuilder: htmlBuilder$8, + mathmlBuilder: mathmlBuilder$8 +}); // There are 2 flags for operators; whether they produce limits in +// displaystyle, and whether they are symbols and should grow in +// displaystyle. These four groups cover the four possible choices. + +const singleCharIntegrals = { + "\u222b": "\\int", + "\u222c": "\\iint", + "\u222d": "\\iiint", + "\u222e": "\\oint", + "\u222f": "\\oiint", + "\u2230": "\\oiiint" +}; // No limits, not symbols + +defineFunction({ + type: "op", + names: ["\\arcsin", "\\arccos", "\\arctan", "\\arctg", "\\arcctg", "\\arg", "\\ch", "\\cos", "\\cosec", "\\cosh", "\\cot", "\\cotg", "\\coth", "\\csc", "\\ctg", "\\cth", "\\deg", "\\dim", "\\exp", "\\hom", "\\ker", "\\lg", "\\ln", "\\log", "\\sec", "\\sin", "\\sinh", "\\sh", "\\tan", "\\tanh", "\\tg", "\\th"], + props: { + numArgs: 0 + }, + + handler(_ref3) { + let parser = _ref3.parser, + funcName = _ref3.funcName; + return { + type: "op", + mode: parser.mode, + limits: false, + parentIsSupSub: false, + symbol: false, + name: funcName + }; + }, + + htmlBuilder: htmlBuilder$8, + mathmlBuilder: mathmlBuilder$8 +}); // Limits, not symbols + +defineFunction({ + type: "op", + names: ["\\det", "\\gcd", "\\inf", "\\lim", "\\max", "\\min", "\\Pr", "\\sup"], + props: { + numArgs: 0 + }, + + handler(_ref4) { + let parser = _ref4.parser, + funcName = _ref4.funcName; + return { + type: "op", + mode: parser.mode, + limits: true, + parentIsSupSub: false, + symbol: false, + name: funcName + }; + }, + + htmlBuilder: htmlBuilder$8, + mathmlBuilder: mathmlBuilder$8 +}); // No limits, symbols + +defineFunction({ + type: "op", + names: ["\\int", "\\iint", "\\iiint", "\\oint", "\\oiint", "\\oiiint", "\u222b", "\u222c", "\u222d", "\u222e", "\u222f", "\u2230"], + props: { + numArgs: 0 + }, + + handler(_ref5) { + let parser = _ref5.parser, + funcName = _ref5.funcName; + let fName = funcName; + + if (fName.length === 1) { + fName = singleCharIntegrals[fName]; + } + + return { + type: "op", + mode: parser.mode, + limits: false, + parentIsSupSub: false, + symbol: true, + name: fName + }; + }, + + htmlBuilder: htmlBuilder$8, + mathmlBuilder: mathmlBuilder$8 +}); + +// NOTE: Unlike most `htmlBuilder`s, this one handles not only +// "operatorname", but also "supsub" since \operatorname* can +const htmlBuilder$9 = (grp, options) => { + // Operators are handled in the TeXbook pg. 443-444, rule 13(a). + let supGroup; + let subGroup; + let hasLimits = false; + let group; + const supSub = checkNodeType(grp, "supsub"); + + if (supSub) { + // If we have limits, supsub will pass us its group to handle. Pull + // out the superscript and subscript and set the group to the op in + // its base. + supGroup = supSub.sup; + subGroup = supSub.sub; + group = assertNodeType(supSub.base, "operatorname"); + hasLimits = true; + } else { + group = assertNodeType(grp, "operatorname"); + } + + let base; + + if (group.body.length > 0) { + const body = group.body.map(child => { + // $FlowFixMe: Check if the node has a string `text` property. + const childText = child.text; + + if (typeof childText === "string") { + return { + type: "textord", + mode: child.mode, + text: childText + }; + } else { + return child; + } + }); // Consolidate function names into symbol characters. + + const expression = buildExpression(body, options.withFont("mathrm"), true); + + for (let i = 0; i < expression.length; i++) { + const child = expression[i]; + + if (child instanceof SymbolNode) { + // Per amsopn package, + // change minus to hyphen and \ast to asterisk + child.text = child.text.replace(/\u2212/, "-").replace(/\u2217/, "*"); + } + } + + base = buildCommon.makeSpan(["mop"], expression, options); + } else { + base = buildCommon.makeSpan(["mop"], [], options); + } + + if (hasLimits) { + return assembleSupSub(base, supGroup, subGroup, options, options.style, 0, 0); + } else { + return base; + } +}; + +const mathmlBuilder$9 = (group, options) => { + // The steps taken here are similar to the html version. + let expression = buildExpression$1(group.body, options.withFont("mathrm")); // Is expression a string or has it something like a fraction? + + let isAllString = true; // default + + for (let i = 0; i < expression.length; i++) { + const node = expression[i]; + + if (node instanceof mathMLTree.SpaceNode) ; else if (node instanceof mathMLTree.MathNode) { + switch (node.type) { + case "mi": + case "mn": + case "ms": + case "mspace": + case "mtext": + break; + // Do nothing yet. + + case "mo": + { + const child = node.children[0]; + + if (node.children.length === 1 && child instanceof mathMLTree.TextNode) { + child.text = child.text.replace(/\u2212/, "-").replace(/\u2217/, "*"); + } else { + isAllString = false; + } + + break; + } + + default: + isAllString = false; + } + } else { + isAllString = false; + } + } + + if (isAllString) { + // Write a single TextNode instead of multiple nested tags. + const word = expression.map(node => node.toText()).join(""); + expression = [new mathMLTree.TextNode(word)]; + } + + const identifier = new mathMLTree.MathNode("mi", expression); + identifier.setAttribute("mathvariant", "normal"); // \u2061 is the same as ⁡ + // ref: https://www.w3schools.com/charsets/ref_html_entities_a.asp + + const operator = new mathMLTree.MathNode("mo", [makeText("\u2061", "text")]); + + if (group.parentIsSupSub) { + return new mathMLTree.MathNode("mo", [identifier, operator]); + } else { + return mathMLTree.newDocumentFragment([identifier, operator]); + } +}; // \operatorname +// amsopn.dtx: \mathop{#1\kern\z@\operator@font#3}\newmcodes@ + + +defineFunction({ + type: "operatorname", + names: ["\\operatorname", "\\operatorname*"], + props: { + numArgs: 1 + }, + handler: (_ref, args) => { + let parser = _ref.parser, + funcName = _ref.funcName; + const body = args[0]; + return { + type: "operatorname", + mode: parser.mode, + body: ordargument(body), + alwaysHandleSupSub: funcName === "\\operatorname*", + limits: false, + parentIsSupSub: false + }; + }, + htmlBuilder: htmlBuilder$9, + mathmlBuilder: mathmlBuilder$9 +}); + +defineFunctionBuilders({ + type: "ordgroup", + + htmlBuilder(group, options) { + if (group.semisimple) { + return buildCommon.makeFragment(buildExpression(group.body, options, false)); + } + + return buildCommon.makeSpan(["mord"], buildExpression(group.body, options, true), options); + }, + + mathmlBuilder(group, options) { + return buildExpressionRow(group.body, options, true); + } + +}); + +defineFunction({ + type: "overline", + names: ["\\overline"], + props: { + numArgs: 1 + }, + + handler(_ref, args) { + let parser = _ref.parser; + const body = args[0]; + return { + type: "overline", + mode: parser.mode, + body + }; + }, + + htmlBuilder(group, options) { + // Overlines are handled in the TeXbook pg 443, Rule 9. + // Build the inner group in the cramped style. + const innerGroup = buildGroup(group.body, options.havingCrampedStyle()); // Create the line above the body + + const line = buildCommon.makeLineSpan("overline-line", options); // Generate the vlist, with the appropriate kerns + + const defaultRuleThickness = options.fontMetrics().defaultRuleThickness; + const vlist = buildCommon.makeVList({ + positionType: "firstBaseline", + children: [{ + type: "elem", + elem: innerGroup + }, { + type: "kern", + size: 3 * defaultRuleThickness + }, { + type: "elem", + elem: line + }, { + type: "kern", + size: defaultRuleThickness + }] + }, options); + return buildCommon.makeSpan(["mord", "overline"], [vlist], options); + }, + + mathmlBuilder(group, options) { + const operator = new mathMLTree.MathNode("mo", [new mathMLTree.TextNode("\u203e")]); + operator.setAttribute("stretchy", "true"); + const node = new mathMLTree.MathNode("mover", [buildGroup$1(group.body, options), operator]); + node.setAttribute("accent", "true"); + return node; + } + +}); + +defineFunction({ + type: "phantom", + names: ["\\phantom"], + props: { + numArgs: 1, + allowedInText: true + }, + handler: (_ref, args) => { + let parser = _ref.parser; + const body = args[0]; + return { + type: "phantom", + mode: parser.mode, + body: ordargument(body) + }; + }, + htmlBuilder: (group, options) => { + const elements = buildExpression(group.body, options.withPhantom(), false); // \phantom isn't supposed to affect the elements it contains. + // See "color" for more details. + + return buildCommon.makeFragment(elements); + }, + mathmlBuilder: (group, options) => { + const inner = buildExpression$1(group.body, options); + return new mathMLTree.MathNode("mphantom", inner); + } +}); +defineFunction({ + type: "hphantom", + names: ["\\hphantom"], + props: { + numArgs: 1, + allowedInText: true + }, + handler: (_ref2, args) => { + let parser = _ref2.parser; + const body = args[0]; + return { + type: "hphantom", + mode: parser.mode, + body + }; + }, + htmlBuilder: (group, options) => { + let node = buildCommon.makeSpan([], [buildGroup(group.body, options.withPhantom())]); + node.height = 0; + node.depth = 0; + + if (node.children) { + for (let i = 0; i < node.children.length; i++) { + node.children[i].height = 0; + node.children[i].depth = 0; + } + } // See smash for comment re: use of makeVList + + + node = buildCommon.makeVList({ + positionType: "firstBaseline", + children: [{ + type: "elem", + elem: node + }] + }, options); // For spacing, TeX treats \smash as a math group (same spacing as ord). + + return buildCommon.makeSpan(["mord"], [node], options); + }, + mathmlBuilder: (group, options) => { + const inner = buildExpression$1(ordargument(group.body), options); + const phantom = new mathMLTree.MathNode("mphantom", inner); + const node = new mathMLTree.MathNode("mpadded", [phantom]); + node.setAttribute("height", "0px"); + node.setAttribute("depth", "0px"); + return node; + } +}); +defineFunction({ + type: "vphantom", + names: ["\\vphantom"], + props: { + numArgs: 1, + allowedInText: true + }, + handler: (_ref3, args) => { + let parser = _ref3.parser; + const body = args[0]; + return { + type: "vphantom", + mode: parser.mode, + body + }; + }, + htmlBuilder: (group, options) => { + const inner = buildCommon.makeSpan(["inner"], [buildGroup(group.body, options.withPhantom())]); + const fix = buildCommon.makeSpan(["fix"], []); + return buildCommon.makeSpan(["mord", "rlap"], [inner, fix], options); + }, + mathmlBuilder: (group, options) => { + const inner = buildExpression$1(ordargument(group.body), options); + const phantom = new mathMLTree.MathNode("mphantom", inner); + const node = new mathMLTree.MathNode("mpadded", [phantom]); + node.setAttribute("width", "0px"); + return node; + } +}); + +defineFunction({ + type: "raisebox", + names: ["\\raisebox"], + props: { + numArgs: 2, + argTypes: ["size", "hbox"], + allowedInText: true + }, + + handler(_ref, args) { + let parser = _ref.parser; + const amount = assertNodeType(args[0], "size").value; + const body = args[1]; + return { + type: "raisebox", + mode: parser.mode, + dy: amount, + body + }; + }, + + htmlBuilder(group, options) { + const body = buildGroup(group.body, options); + const dy = calculateSize(group.dy, options); + return buildCommon.makeVList({ + positionType: "shift", + positionData: -dy, + children: [{ + type: "elem", + elem: body + }] + }, options); + }, + + mathmlBuilder(group, options) { + const node = new mathMLTree.MathNode("mpadded", [buildGroup$1(group.body, options)]); + const dy = group.dy.number + group.dy.unit; + node.setAttribute("voffset", dy); + return node; + } + +}); + +defineFunction({ + type: "rule", + names: ["\\rule"], + props: { + numArgs: 2, + numOptionalArgs: 1, + argTypes: ["size", "size", "size"] + }, + + handler(_ref, args, optArgs) { + let parser = _ref.parser; + const shift = optArgs[0]; + const width = assertNodeType(args[0], "size"); + const height = assertNodeType(args[1], "size"); + return { + type: "rule", + mode: parser.mode, + shift: shift && assertNodeType(shift, "size").value, + width: width.value, + height: height.value + }; + }, + + htmlBuilder(group, options) { + // Make an empty span for the rule + const rule = buildCommon.makeSpan(["mord", "rule"], [], options); // Calculate the shift, width, and height of the rule, and account for units + + const width = calculateSize(group.width, options); + const height = calculateSize(group.height, options); + const shift = group.shift ? calculateSize(group.shift, options) : 0; // Style the rule to the right size + + rule.style.borderRightWidth = width + "em"; + rule.style.borderTopWidth = height + "em"; + rule.style.bottom = shift + "em"; // Record the height and width + + rule.width = width; + rule.height = height + shift; + rule.depth = -shift; // Font size is the number large enough that the browser will + // reserve at least `absHeight` space above the baseline. + // The 1.125 factor was empirically determined + + rule.maxFontSize = height * 1.125 * options.sizeMultiplier; + return rule; + }, + + mathmlBuilder(group, options) { + const width = calculateSize(group.width, options); + const height = calculateSize(group.height, options); + const shift = group.shift ? calculateSize(group.shift, options) : 0; + const color = options.color && options.getColor() || "black"; + const rule = new mathMLTree.MathNode("mspace"); + rule.setAttribute("mathbackground", color); + rule.setAttribute("width", width + "em"); + rule.setAttribute("height", height + "em"); + const wrapper = new mathMLTree.MathNode("mpadded", [rule]); + + if (shift >= 0) { + wrapper.setAttribute("height", "+" + shift + "em"); + } else { + wrapper.setAttribute("height", shift + "em"); + wrapper.setAttribute("depth", "+" + -shift + "em"); + } + + wrapper.setAttribute("voffset", shift + "em"); + return wrapper; + } + +}); + +function sizingGroup(value, options, baseOptions) { + const inner = buildExpression(value, options, false); + const multiplier = options.sizeMultiplier / baseOptions.sizeMultiplier; // Add size-resetting classes to the inner list and set maxFontSize + // manually. Handle nested size changes. + + for (let i = 0; i < inner.length; i++) { + const pos = inner[i].classes.indexOf("sizing"); + + if (pos < 0) { + Array.prototype.push.apply(inner[i].classes, options.sizingClasses(baseOptions)); + } else if (inner[i].classes[pos + 1] === "reset-size" + options.size) { + // This is a nested size change: e.g., inner[i] is the "b" in + // `\Huge a \small b`. Override the old size (the `reset-` class) + // but not the new size. + inner[i].classes[pos + 1] = "reset-size" + baseOptions.size; + } + + inner[i].height *= multiplier; + inner[i].depth *= multiplier; + } + + return buildCommon.makeFragment(inner); +} +const sizeFuncs = ["\\tiny", "\\sixptsize", "\\scriptsize", "\\footnotesize", "\\small", "\\normalsize", "\\large", "\\Large", "\\LARGE", "\\huge", "\\Huge"]; +const htmlBuilder$a = (group, options) => { + // Handle sizing operators like \Huge. Real TeX doesn't actually allow + // these functions inside of math expressions, so we do some special + // handling. + const newOptions = options.havingSize(group.size); + return sizingGroup(group.body, newOptions, options); +}; +defineFunction({ + type: "sizing", + names: sizeFuncs, + props: { + numArgs: 0, + allowedInText: true + }, + handler: (_ref, args) => { + let breakOnTokenText = _ref.breakOnTokenText, + funcName = _ref.funcName, + parser = _ref.parser; + const body = parser.parseExpression(false, breakOnTokenText); + return { + type: "sizing", + mode: parser.mode, + // Figure out what size to use based on the list of functions above + size: sizeFuncs.indexOf(funcName) + 1, + body + }; + }, + htmlBuilder: htmlBuilder$a, + mathmlBuilder: (group, options) => { + const newOptions = options.havingSize(group.size); + const inner = buildExpression$1(group.body, newOptions); + const node = new mathMLTree.MathNode("mstyle", inner); // TODO(emily): This doesn't produce the correct size for nested size + // changes, because we don't keep state of what style we're currently + // in, so we can't reset the size to normal before changing it. Now + // that we're passing an options parameter we should be able to fix + // this. + + node.setAttribute("mathsize", newOptions.sizeMultiplier + "em"); + return node; + } +}); + +// smash, with optional [tb], as in AMS +defineFunction({ + type: "smash", + names: ["\\smash"], + props: { + numArgs: 1, + numOptionalArgs: 1, + allowedInText: true + }, + handler: (_ref, args, optArgs) => { + let parser = _ref.parser; + let smashHeight = false; + let smashDepth = false; + const tbArg = optArgs[0] && assertNodeType(optArgs[0], "ordgroup"); + + if (tbArg) { + // Optional [tb] argument is engaged. + // ref: amsmath: \renewcommand{\smash}[1][tb]{% + // def\mb@t{\ht}\def\mb@b{\dp}\def\mb@tb{\ht\z@\z@\dp}% + let letter = ""; + + for (let i = 0; i < tbArg.body.length; ++i) { + const node = tbArg.body[i]; // $FlowFixMe: Not every node type has a `text` property. + + letter = node.text; + + if (letter === "t") { + smashHeight = true; + } else if (letter === "b") { + smashDepth = true; + } else { + smashHeight = false; + smashDepth = false; + break; + } + } + } else { + smashHeight = true; + smashDepth = true; + } + + const body = args[0]; + return { + type: "smash", + mode: parser.mode, + body, + smashHeight, + smashDepth + }; + }, + htmlBuilder: (group, options) => { + const node = buildCommon.makeSpan([], [buildGroup(group.body, options)]); + + if (!group.smashHeight && !group.smashDepth) { + return node; + } + + if (group.smashHeight) { + node.height = 0; // In order to influence makeVList, we have to reset the children. + + if (node.children) { + for (let i = 0; i < node.children.length; i++) { + node.children[i].height = 0; + } + } + } + + if (group.smashDepth) { + node.depth = 0; + + if (node.children) { + for (let i = 0; i < node.children.length; i++) { + node.children[i].depth = 0; + } + } + } // At this point, we've reset the TeX-like height and depth values. + // But the span still has an HTML line height. + // makeVList applies "display: table-cell", which prevents the browser + // from acting on that line height. So we'll call makeVList now. + + + const smashedNode = buildCommon.makeVList({ + positionType: "firstBaseline", + children: [{ + type: "elem", + elem: node + }] + }, options); // For spacing, TeX treats \hphantom as a math group (same spacing as ord). + + return buildCommon.makeSpan(["mord"], [smashedNode], options); + }, + mathmlBuilder: (group, options) => { + const node = new mathMLTree.MathNode("mpadded", [buildGroup$1(group.body, options)]); + + if (group.smashHeight) { + node.setAttribute("height", "0px"); + } + + if (group.smashDepth) { + node.setAttribute("depth", "0px"); + } + + return node; + } +}); + +defineFunction({ + type: "sqrt", + names: ["\\sqrt"], + props: { + numArgs: 1, + numOptionalArgs: 1 + }, + + handler(_ref, args, optArgs) { + let parser = _ref.parser; + const index = optArgs[0]; + const body = args[0]; + return { + type: "sqrt", + mode: parser.mode, + body, + index + }; + }, + + htmlBuilder(group, options) { + // Square roots are handled in the TeXbook pg. 443, Rule 11. + // First, we do the same steps as in overline to build the inner group + // and line + let inner = buildGroup(group.body, options.havingCrampedStyle()); + + if (inner.height === 0) { + // Render a small surd. + inner.height = options.fontMetrics().xHeight; + } // Some groups can return document fragments. Handle those by wrapping + // them in a span. + + + inner = buildCommon.wrapFragment(inner, options); // Calculate the minimum size for the \surd delimiter + + const metrics = options.fontMetrics(); + const theta = metrics.defaultRuleThickness; + let phi = theta; + + if (options.style.id < Style$1.TEXT.id) { + phi = options.fontMetrics().xHeight; + } // Calculate the clearance between the body and line + + + let lineClearance = theta + phi / 4; + const minDelimiterHeight = inner.height + inner.depth + lineClearance + theta; // Create a sqrt SVG of the required minimum size + + const _delimiter$sqrtImage = delimiter.sqrtImage(minDelimiterHeight, options), + img = _delimiter$sqrtImage.span, + ruleWidth = _delimiter$sqrtImage.ruleWidth, + advanceWidth = _delimiter$sqrtImage.advanceWidth; + + const delimDepth = img.height - ruleWidth; // Adjust the clearance based on the delimiter size + + if (delimDepth > inner.height + inner.depth + lineClearance) { + lineClearance = (lineClearance + delimDepth - inner.height - inner.depth) / 2; + } // Shift the sqrt image + + + const imgShift = img.height - inner.height - lineClearance - ruleWidth; + inner.style.paddingLeft = advanceWidth + "em"; // Overlay the image and the argument. + + const body = buildCommon.makeVList({ + positionType: "firstBaseline", + children: [{ + type: "elem", + elem: inner, + wrapperClasses: ["svg-align"] + }, { + type: "kern", + size: -(inner.height + imgShift) + }, { + type: "elem", + elem: img + }, { + type: "kern", + size: ruleWidth + }] + }, options); + + if (!group.index) { + return buildCommon.makeSpan(["mord", "sqrt"], [body], options); + } else { + // Handle the optional root index + // The index is always in scriptscript style + const newOptions = options.havingStyle(Style$1.SCRIPTSCRIPT); + const rootm = buildGroup(group.index, newOptions, options); // The amount the index is shifted by. This is taken from the TeX + // source, in the definition of `\r@@t`. + + const toShift = 0.6 * (body.height - body.depth); // Build a VList with the superscript shifted up correctly + + const rootVList = buildCommon.makeVList({ + positionType: "shift", + positionData: -toShift, + children: [{ + type: "elem", + elem: rootm + }] + }, options); // Add a class surrounding it so we can add on the appropriate + // kerning + + const rootVListWrap = buildCommon.makeSpan(["root"], [rootVList]); + return buildCommon.makeSpan(["mord", "sqrt"], [rootVListWrap, body], options); + } + }, + + mathmlBuilder(group, options) { + const body = group.body, + index = group.index; + return index ? new mathMLTree.MathNode("mroot", [buildGroup$1(body, options), buildGroup$1(index, options)]) : new mathMLTree.MathNode("msqrt", [buildGroup$1(body, options)]); + } + +}); + +const styleMap$1 = { + "display": Style$1.DISPLAY, + "text": Style$1.TEXT, + "script": Style$1.SCRIPT, + "scriptscript": Style$1.SCRIPTSCRIPT +}; +defineFunction({ + type: "styling", + names: ["\\displaystyle", "\\textstyle", "\\scriptstyle", "\\scriptscriptstyle"], + props: { + numArgs: 0, + allowedInText: true + }, + + handler(_ref, args) { + let breakOnTokenText = _ref.breakOnTokenText, + funcName = _ref.funcName, + parser = _ref.parser; + // parse out the implicit body + const body = parser.parseExpression(true, breakOnTokenText); // TODO: Refactor to avoid duplicating styleMap in multiple places (e.g. + // here and in buildHTML and de-dupe the enumeration of all the styles). + // $FlowFixMe: The names above exactly match the styles. + + const style = funcName.slice(1, funcName.length - 5); + return { + type: "styling", + mode: parser.mode, + // Figure out what style to use by pulling out the style from + // the function name + style, + body + }; + }, + + htmlBuilder(group, options) { + // Style changes are handled in the TeXbook on pg. 442, Rule 3. + const newStyle = styleMap$1[group.style]; + const newOptions = options.havingStyle(newStyle).withFont(''); + return sizingGroup(group.body, newOptions, options); + }, + + mathmlBuilder(group, options) { + // Figure out what style we're changing to. + const newStyle = styleMap$1[group.style]; + const newOptions = options.havingStyle(newStyle); + const inner = buildExpression$1(group.body, newOptions); + const node = new mathMLTree.MathNode("mstyle", inner); + const styleAttributes = { + "display": ["0", "true"], + "text": ["0", "false"], + "script": ["1", "false"], + "scriptscript": ["2", "false"] + }; + const attr = styleAttributes[group.style]; + node.setAttribute("scriptlevel", attr[0]); + node.setAttribute("displaystyle", attr[1]); + return node; + } + +}); + +/** + * Sometimes, groups perform special rules when they have superscripts or + * subscripts attached to them. This function lets the `supsub` group know that + * Sometimes, groups perform special rules when they have superscripts or + * its inner element should handle the superscripts and subscripts instead of + * handling them itself. + */ +const htmlBuilderDelegate = function htmlBuilderDelegate(group, options) { + const base = group.base; + + if (!base) { + return null; + } else if (base.type === "op") { + // Operators handle supsubs differently when they have limits + // (e.g. `\displaystyle\sum_2^3`) + const delegate = base.limits && (options.style.size === Style$1.DISPLAY.size || base.alwaysHandleSupSub); + return delegate ? htmlBuilder$8 : null; + } else if (base.type === "operatorname") { + const delegate = base.alwaysHandleSupSub && (options.style.size === Style$1.DISPLAY.size || base.limits); + return delegate ? htmlBuilder$9 : null; + } else if (base.type === "accent") { + return utils.isCharacterBox(base.base) ? htmlBuilder : null; + } else if (base.type === "horizBrace") { + const isSup = !group.sub; + return isSup === base.isOver ? htmlBuilder$7 : null; + } else { + return null; + } +}; // Super scripts and subscripts, whose precise placement can depend on other +// functions that precede them. + + +defineFunctionBuilders({ + type: "supsub", + + htmlBuilder(group, options) { + // Superscript and subscripts are handled in the TeXbook on page + // 445-446, rules 18(a-f). + // Here is where we defer to the inner group if it should handle + // superscripts and subscripts itself. + const builderDelegate = htmlBuilderDelegate(group, options); + + if (builderDelegate) { + return builderDelegate(group, options); + } + + const valueBase = group.base, + valueSup = group.sup, + valueSub = group.sub; + const base = buildGroup(valueBase, options); + let supm; + let subm; + const metrics = options.fontMetrics(); // Rule 18a + + let supShift = 0; + let subShift = 0; + const isCharacterBox = valueBase && utils.isCharacterBox(valueBase); + + if (valueSup) { + const newOptions = options.havingStyle(options.style.sup()); + supm = buildGroup(valueSup, newOptions, options); + + if (!isCharacterBox) { + supShift = base.height - newOptions.fontMetrics().supDrop * newOptions.sizeMultiplier / options.sizeMultiplier; + } + } + + if (valueSub) { + const newOptions = options.havingStyle(options.style.sub()); + subm = buildGroup(valueSub, newOptions, options); + + if (!isCharacterBox) { + subShift = base.depth + newOptions.fontMetrics().subDrop * newOptions.sizeMultiplier / options.sizeMultiplier; + } + } // Rule 18c + + + let minSupShift; + + if (options.style === Style$1.DISPLAY) { + minSupShift = metrics.sup1; + } else if (options.style.cramped) { + minSupShift = metrics.sup3; + } else { + minSupShift = metrics.sup2; + } // scriptspace is a font-size-independent size, so scale it + // appropriately for use as the marginRight. + + + const multiplier = options.sizeMultiplier; + const marginRight = 0.5 / metrics.ptPerEm / multiplier + "em"; + let marginLeft = null; + + if (subm) { + // Subscripts shouldn't be shifted by the base's italic correction. + // Account for that by shifting the subscript back the appropriate + // amount. Note we only do this when the base is a single symbol. + const isOiint = group.base && group.base.type === "op" && group.base.name && (group.base.name === "\\oiint" || group.base.name === "\\oiiint"); + + if (base instanceof SymbolNode || isOiint) { + // $FlowFixMe + marginLeft = -base.italic + "em"; + } + } + + let supsub; + + if (supm && subm) { + supShift = Math.max(supShift, minSupShift, supm.depth + 0.25 * metrics.xHeight); + subShift = Math.max(subShift, metrics.sub2); + const ruleWidth = metrics.defaultRuleThickness; // Rule 18e + + const maxWidth = 4 * ruleWidth; + + if (supShift - supm.depth - (subm.height - subShift) < maxWidth) { + subShift = maxWidth - (supShift - supm.depth) + subm.height; + const psi = 0.8 * metrics.xHeight - (supShift - supm.depth); + + if (psi > 0) { + supShift += psi; + subShift -= psi; + } + } + + const vlistElem = [{ + type: "elem", + elem: subm, + shift: subShift, + marginRight, + marginLeft + }, { + type: "elem", + elem: supm, + shift: -supShift, + marginRight + }]; + supsub = buildCommon.makeVList({ + positionType: "individualShift", + children: vlistElem + }, options); + } else if (subm) { + // Rule 18b + subShift = Math.max(subShift, metrics.sub1, subm.height - 0.8 * metrics.xHeight); + const vlistElem = [{ + type: "elem", + elem: subm, + marginLeft, + marginRight + }]; + supsub = buildCommon.makeVList({ + positionType: "shift", + positionData: subShift, + children: vlistElem + }, options); + } else if (supm) { + // Rule 18c, d + supShift = Math.max(supShift, minSupShift, supm.depth + 0.25 * metrics.xHeight); + supsub = buildCommon.makeVList({ + positionType: "shift", + positionData: -supShift, + children: [{ + type: "elem", + elem: supm, + marginRight + }] + }, options); + } else { + throw new Error("supsub must have either sup or sub."); + } // Wrap the supsub vlist in a span.msupsub to reset text-align. + + + const mclass = getTypeOfDomTree(base, "right") || "mord"; + return buildCommon.makeSpan([mclass], [base, buildCommon.makeSpan(["msupsub"], [supsub])], options); + }, + + mathmlBuilder(group, options) { + // Is the inner group a relevant horizonal brace? + let isBrace = false; + let isOver; + let isSup; + const horizBrace = checkNodeType(group.base, "horizBrace"); + + if (horizBrace) { + isSup = !!group.sup; + + if (isSup === horizBrace.isOver) { + isBrace = true; + isOver = horizBrace.isOver; + } + } + + if (group.base && (group.base.type === "op" || group.base.type === "operatorname")) { + group.base.parentIsSupSub = true; + } + + const children = [buildGroup$1(group.base, options)]; + + if (group.sub) { + children.push(buildGroup$1(group.sub, options)); + } + + if (group.sup) { + children.push(buildGroup$1(group.sup, options)); + } + + let nodeType; + + if (isBrace) { + nodeType = isOver ? "mover" : "munder"; + } else if (!group.sub) { + const base = group.base; + + if (base && base.type === "op" && base.limits && (options.style === Style$1.DISPLAY || base.alwaysHandleSupSub)) { + nodeType = "mover"; + } else if (base && base.type === "operatorname" && base.alwaysHandleSupSub && (base.limits || options.style === Style$1.DISPLAY)) { + nodeType = "mover"; + } else { + nodeType = "msup"; + } + } else if (!group.sup) { + const base = group.base; + + if (base && base.type === "op" && base.limits && (options.style === Style$1.DISPLAY || base.alwaysHandleSupSub)) { + nodeType = "munder"; + } else if (base && base.type === "operatorname" && base.alwaysHandleSupSub && (base.limits || options.style === Style$1.DISPLAY)) { + nodeType = "munder"; + } else { + nodeType = "msub"; + } + } else { + const base = group.base; + + if (base && base.type === "op" && base.limits && options.style === Style$1.DISPLAY) { + nodeType = "munderover"; + } else if (base && base.type === "operatorname" && base.alwaysHandleSupSub && (options.style === Style$1.DISPLAY || base.limits)) { + nodeType = "munderover"; + } else { + nodeType = "msubsup"; + } + } + + const node = new mathMLTree.MathNode(nodeType, children); + return node; + } + +}); + +defineFunctionBuilders({ + type: "atom", + + htmlBuilder(group, options) { + return buildCommon.mathsym(group.text, group.mode, options, ["m" + group.family]); + }, + + mathmlBuilder(group, options) { + const node = new mathMLTree.MathNode("mo", [makeText(group.text, group.mode)]); + + if (group.family === "bin") { + const variant = getVariant(group, options); + + if (variant === "bold-italic") { + node.setAttribute("mathvariant", variant); + } + } else if (group.family === "punct") { + node.setAttribute("separator", "true"); + } else if (group.family === "open" || group.family === "close") { + // Delims built here should not stretch vertically. + // See delimsizing.js for stretchy delims. + node.setAttribute("stretchy", "false"); + } + + return node; + } + +}); + +// "mathord" and "textord" ParseNodes created in Parser.js from symbol Groups in +const defaultVariant = { + "mi": "italic", + "mn": "normal", + "mtext": "normal" +}; +defineFunctionBuilders({ + type: "mathord", + + htmlBuilder(group, options) { + return buildCommon.makeOrd(group, options, "mathord"); + }, + + mathmlBuilder(group, options) { + const node = new mathMLTree.MathNode("mi", [makeText(group.text, group.mode, options)]); + const variant = getVariant(group, options) || "italic"; + + if (variant !== defaultVariant[node.type]) { + node.setAttribute("mathvariant", variant); + } + + return node; + } + +}); +defineFunctionBuilders({ + type: "textord", + + htmlBuilder(group, options) { + return buildCommon.makeOrd(group, options, "textord"); + }, + + mathmlBuilder(group, options) { + const text = makeText(group.text, group.mode, options); + const variant = getVariant(group, options) || "normal"; + let node; + + if (group.mode === 'text') { + node = new mathMLTree.MathNode("mtext", [text]); + } else if (/[0-9]/.test(group.text)) { + // TODO(kevinb) merge adjacent nodes + // do it as a post processing step + node = new mathMLTree.MathNode("mn", [text]); + } else if (group.text === "\\prime") { + node = new mathMLTree.MathNode("mo", [text]); + } else { + node = new mathMLTree.MathNode("mi", [text]); + } + + if (variant !== defaultVariant[node.type]) { + node.setAttribute("mathvariant", variant); + } + + return node; + } + +}); + +const cssSpace = { + "\\nobreak": "nobreak", + "\\allowbreak": "allowbreak" +}; // A lookup table to determine whether a spacing function/symbol should be +// treated like a regular space character. If a symbol or command is a key +// in this table, then it should be a regular space character. Furthermore, +// the associated value may have a `className` specifying an extra CSS class +// to add to the created `span`. + +const regularSpace = { + " ": {}, + "\\ ": {}, + "~": { + className: "nobreak" + }, + "\\space": {}, + "\\nobreakspace": { + className: "nobreak" + } +}; // ParseNode<"spacing"> created in Parser.js from the "spacing" symbol Groups in +// src/symbols.js. + +defineFunctionBuilders({ + type: "spacing", + + htmlBuilder(group, options) { + if (regularSpace.hasOwnProperty(group.text)) { + const className = regularSpace[group.text].className || ""; // Spaces are generated by adding an actual space. Each of these + // things has an entry in the symbols table, so these will be turned + // into appropriate outputs. + + if (group.mode === "text") { + const ord = buildCommon.makeOrd(group, options, "textord"); + ord.classes.push(className); + return ord; + } else { + return buildCommon.makeSpan(["mspace", className], [buildCommon.mathsym(group.text, group.mode, options)], options); + } + } else if (cssSpace.hasOwnProperty(group.text)) { + // Spaces based on just a CSS class. + return buildCommon.makeSpan(["mspace", cssSpace[group.text]], [], options); + } else { + throw new ParseError(`Unknown type of space "${group.text}"`); + } + }, + + mathmlBuilder(group, options) { + let node; + + if (regularSpace.hasOwnProperty(group.text)) { + node = new mathMLTree.MathNode("mtext", [new mathMLTree.TextNode("\u00a0")]); + } else if (cssSpace.hasOwnProperty(group.text)) { + // CSS-based MathML spaces (\nobreak, \allowbreak) are ignored + return new mathMLTree.MathNode("mspace"); + } else { + throw new ParseError(`Unknown type of space "${group.text}"`); + } + + return node; + } + +}); + +const pad = () => { + const padNode = new mathMLTree.MathNode("mtd", []); + padNode.setAttribute("width", "50%"); + return padNode; +}; + +defineFunctionBuilders({ + type: "tag", + + mathmlBuilder(group, options) { + const table = new mathMLTree.MathNode("mtable", [new mathMLTree.MathNode("mtr", [pad(), new mathMLTree.MathNode("mtd", [buildExpressionRow(group.body, options)]), pad(), new mathMLTree.MathNode("mtd", [buildExpressionRow(group.tag, options)])])]); + table.setAttribute("width", "100%"); + return table; // TODO: Left-aligned tags. + // Currently, the group and options passed here do not contain + // enough info to set tag alignment. `leqno` is in Settings but it is + // not passed to Options. On the HTML side, leqno is + // set by a CSS class applied in buildTree.js. That would have worked + // in MathML if browsers supported . Since they don't, we + // need to rewrite the way this function is called. + } + +}); + +const textFontFamilies = { + "\\text": undefined, + "\\textrm": "textrm", + "\\textsf": "textsf", + "\\texttt": "texttt", + "\\textnormal": "textrm" +}; +const textFontWeights = { + "\\textbf": "textbf", + "\\textmd": "textmd" +}; +const textFontShapes = { + "\\textit": "textit", + "\\textup": "textup" +}; + +const optionsWithFont = (group, options) => { + const font = group.font; // Checks if the argument is a font family or a font style. + + if (!font) { + return options; + } else if (textFontFamilies[font]) { + return options.withTextFontFamily(textFontFamilies[font]); + } else if (textFontWeights[font]) { + return options.withTextFontWeight(textFontWeights[font]); + } else { + return options.withTextFontShape(textFontShapes[font]); + } +}; + +defineFunction({ + type: "text", + names: [// Font families + "\\text", "\\textrm", "\\textsf", "\\texttt", "\\textnormal", // Font weights + "\\textbf", "\\textmd", // Font Shapes + "\\textit", "\\textup"], + props: { + numArgs: 1, + argTypes: ["text"], + greediness: 2, + allowedInText: true + }, + + handler(_ref, args) { + let parser = _ref.parser, + funcName = _ref.funcName; + const body = args[0]; + return { + type: "text", + mode: parser.mode, + body: ordargument(body), + font: funcName + }; + }, + + htmlBuilder(group, options) { + const newOptions = optionsWithFont(group, options); + const inner = buildExpression(group.body, newOptions, true); + return buildCommon.makeSpan(["mord", "text"], buildCommon.tryCombineChars(inner), newOptions); + }, + + mathmlBuilder(group, options) { + const newOptions = optionsWithFont(group, options); + return buildExpressionRow(group.body, newOptions); + } + +}); + +defineFunction({ + type: "underline", + names: ["\\underline"], + props: { + numArgs: 1, + allowedInText: true + }, + + handler(_ref, args) { + let parser = _ref.parser; + return { + type: "underline", + mode: parser.mode, + body: args[0] + }; + }, + + htmlBuilder(group, options) { + // Underlines are handled in the TeXbook pg 443, Rule 10. + // Build the inner group. + const innerGroup = buildGroup(group.body, options); // Create the line to go below the body + + const line = buildCommon.makeLineSpan("underline-line", options); // Generate the vlist, with the appropriate kerns + + const defaultRuleThickness = options.fontMetrics().defaultRuleThickness; + const vlist = buildCommon.makeVList({ + positionType: "top", + positionData: innerGroup.height, + children: [{ + type: "kern", + size: defaultRuleThickness + }, { + type: "elem", + elem: line + }, { + type: "kern", + size: 3 * defaultRuleThickness + }, { + type: "elem", + elem: innerGroup + }] + }, options); + return buildCommon.makeSpan(["mord", "underline"], [vlist], options); + }, + + mathmlBuilder(group, options) { + const operator = new mathMLTree.MathNode("mo", [new mathMLTree.TextNode("\u203e")]); + operator.setAttribute("stretchy", "true"); + const node = new mathMLTree.MathNode("munder", [buildGroup$1(group.body, options), operator]); + node.setAttribute("accentunder", "true"); + return node; + } + +}); + +defineFunction({ + type: "verb", + names: ["\\verb"], + props: { + numArgs: 0, + allowedInText: true + }, + + handler(context, args, optArgs) { + // \verb and \verb* are dealt with directly in Parser.js. + // If we end up here, it's because of a failure to match the two delimiters + // in the regex in Lexer.js. LaTeX raises the following error when \verb is + // terminated by end of line (or file). + throw new ParseError("\\verb ended by end of line instead of matching delimiter"); + }, + + htmlBuilder(group, options) { + const text = makeVerb(group); + const body = []; // \verb enters text mode and therefore is sized like \textstyle + + const newOptions = options.havingStyle(options.style.text()); + + for (let i = 0; i < text.length; i++) { + let c = text[i]; + + if (c === '~') { + c = '\\textasciitilde'; + } + + body.push(buildCommon.makeSymbol(c, "Typewriter-Regular", group.mode, newOptions, ["mord", "texttt"])); + } + + return buildCommon.makeSpan(["mord", "text"].concat(newOptions.sizingClasses(options)), buildCommon.tryCombineChars(body), newOptions); + }, + + mathmlBuilder(group, options) { + const text = new mathMLTree.TextNode(makeVerb(group)); + const node = new mathMLTree.MathNode("mtext", [text]); + node.setAttribute("mathvariant", "monospace"); + return node; + } + +}); +/** + * Converts verb group into body string. + * + * \verb* replaces each space with an open box \u2423 + * \verb replaces each space with a no-break space \xA0 + */ + +const makeVerb = group => group.body.replace(/ /g, group.star ? '\u2423' : '\xA0'); + +/** Include this to ensure that all functions are defined. */ +const functions = _functions; + +/** + * The Lexer class handles tokenizing the input in various ways. Since our + * parser expects us to be able to backtrack, the lexer allows lexing from any + * given starting point. + * + * Its main exposed function is the `lex` function, which takes a position to + * lex from and a type of token to lex. It defers to the appropriate `_innerLex` + * function. + * + * The various `_innerLex` functions perform the actual lexing of different + * kinds. + */ + +/* The following tokenRegex + * - matches typical whitespace (but not NBSP etc.) using its first group + * - does not match any control character \x00-\x1f except whitespace + * - does not match a bare backslash + * - matches any ASCII character except those just mentioned + * - does not match the BMP private use area \uE000-\uF8FF + * - does not match bare surrogate code units + * - matches any BMP character except for those just described + * - matches any valid Unicode surrogate pair + * - matches a backslash followed by one or more letters + * - matches a backslash followed by any BMP character, including newline + * Just because the Lexer matches something doesn't mean it's valid input: + * If there is no matching function or symbol definition, the Parser will + * still reject the input. + */ +const spaceRegexString = "[ \r\n\t]"; +const controlWordRegexString = "\\\\[a-zA-Z@]+"; +const controlSymbolRegexString = "\\\\[^\uD800-\uDFFF]"; +const controlWordWhitespaceRegexString = `${controlWordRegexString}${spaceRegexString}*`; +const controlWordWhitespaceRegex = new RegExp(`^(${controlWordRegexString})${spaceRegexString}*$`); +const combiningDiacriticalMarkString = "[\u0300-\u036f]"; +const combiningDiacriticalMarksEndRegex = new RegExp(`${combiningDiacriticalMarkString}+$`); +const tokenRegexString = `(${spaceRegexString}+)|` + // whitespace +"([!-\\[\\]-\u2027\u202A-\uD7FF\uF900-\uFFFF]" + // single codepoint +`${combiningDiacriticalMarkString}*` + // ...plus accents +"|[\uD800-\uDBFF][\uDC00-\uDFFF]" + // surrogate pair +`${combiningDiacriticalMarkString}*` + // ...plus accents +"|\\\\verb\\*([^]).*?\\3" + // \verb* +"|\\\\verb([^*a-zA-Z]).*?\\4" + // \verb unstarred +"|\\\\operatorname\\*" + // \operatorname* +`|${controlWordWhitespaceRegexString}` + // \macroName + spaces +`|${controlSymbolRegexString})`; // \\, \', etc. + +/** Main Lexer class */ + +class Lexer { + // category codes, only supports comment characters (14) for now + constructor(input, settings) { + this.input = void 0; + this.settings = void 0; + this.tokenRegex = void 0; + this.catcodes = void 0; + // Separate accents from characters + this.input = input; + this.settings = settings; + this.tokenRegex = new RegExp(tokenRegexString, 'g'); + this.catcodes = { + "%": 14 // comment character + + }; + } + + setCatcode(char, code) { + this.catcodes[char] = code; + } + /** + * This function lexes a single token. + */ + + + lex() { + const input = this.input; + const pos = this.tokenRegex.lastIndex; + + if (pos === input.length) { + return new Token("EOF", new SourceLocation(this, pos, pos)); + } + + const match = this.tokenRegex.exec(input); + + if (match === null || match.index !== pos) { + throw new ParseError(`Unexpected character: '${input[pos]}'`, new Token(input[pos], new SourceLocation(this, pos, pos + 1))); + } + + let text = match[2] || " "; + + if (this.catcodes[text] === 14) { + // comment character + const nlIndex = input.indexOf('\n', this.tokenRegex.lastIndex); + + if (nlIndex === -1) { + this.tokenRegex.lastIndex = input.length; // EOF + + this.settings.reportNonstrict("commentAtEnd", "% comment has no terminating newline; LaTeX would " + "fail because of commenting the end of math mode (e.g. $)"); + } else { + this.tokenRegex.lastIndex = nlIndex + 1; + } + + return this.lex(); + } // Trim any trailing whitespace from control word match + + + const controlMatch = text.match(controlWordWhitespaceRegex); + + if (controlMatch) { + text = controlMatch[1]; + } + + return new Token(text, new SourceLocation(this, pos, this.tokenRegex.lastIndex)); + } + +} + +/** + * A `Namespace` refers to a space of nameable things like macros or lengths, + * which can be `set` either globally or local to a nested group, using an + * undo stack similar to how TeX implements this functionality. + * Performance-wise, `get` and local `set` take constant time, while global + * `set` takes time proportional to the depth of group nesting. + */ +class Namespace { + /** + * Both arguments are optional. The first argument is an object of + * built-in mappings which never change. The second argument is an object + * of initial (global-level) mappings, which will constantly change + * according to any global/top-level `set`s done. + */ + constructor(builtins, globalMacros) { + if (builtins === void 0) { + builtins = {}; + } + + if (globalMacros === void 0) { + globalMacros = {}; + } + + this.current = void 0; + this.builtins = void 0; + this.undefStack = void 0; + this.current = globalMacros; + this.builtins = builtins; + this.undefStack = []; + } + /** + * Start a new nested group, affecting future local `set`s. + */ + + + beginGroup() { + this.undefStack.push({}); + } + /** + * End current nested group, restoring values before the group began. + */ + + + endGroup() { + if (this.undefStack.length === 0) { + throw new ParseError("Unbalanced namespace destruction: attempt " + "to pop global namespace; please report this as a bug"); + } + + const undefs = this.undefStack.pop(); + + for (const undef in undefs) { + if (undefs.hasOwnProperty(undef)) { + if (undefs[undef] === undefined) { + delete this.current[undef]; + } else { + this.current[undef] = undefs[undef]; + } + } + } + } + /** + * Detect whether `name` has a definition. Equivalent to + * `get(name) != null`. + */ + + + has(name) { + return this.current.hasOwnProperty(name) || this.builtins.hasOwnProperty(name); + } + /** + * Get the current value of a name, or `undefined` if there is no value. + * + * Note: Do not use `if (namespace.get(...))` to detect whether a macro + * is defined, as the definition may be the empty string which evaluates + * to `false` in JavaScript. Use `if (namespace.get(...) != null)` or + * `if (namespace.has(...))`. + */ + + + get(name) { + if (this.current.hasOwnProperty(name)) { + return this.current[name]; + } else { + return this.builtins[name]; + } + } + /** + * Set the current value of a name, and optionally set it globally too. + * Local set() sets the current value and (when appropriate) adds an undo + * operation to the undo stack. Global set() may change the undo + * operation at every level, so takes time linear in their number. + */ + + + set(name, value, global) { + if (global === void 0) { + global = false; + } + + if (global) { + // Global set is equivalent to setting in all groups. Simulate this + // by destroying any undos currently scheduled for this name, + // and adding an undo with the *new* value (in case it later gets + // locally reset within this environment). + for (let i = 0; i < this.undefStack.length; i++) { + delete this.undefStack[i][name]; + } + + if (this.undefStack.length > 0) { + this.undefStack[this.undefStack.length - 1][name] = value; + } + } else { + // Undo this set at end of this group (possibly to `undefined`), + // unless an undo is already in place, in which case that older + // value is the correct one. + const top = this.undefStack[this.undefStack.length - 1]; + + if (top && !top.hasOwnProperty(name)) { + top[name] = this.current[name]; + } + } + + this.current[name] = value; + } + +} + +/** + * Predefined macros for KaTeX. + * This can be used to define some commands in terms of others. + */ +const builtinMacros = {}; + +function defineMacro(name, body) { + builtinMacros[name] = body; +} ////////////////////////////////////////////////////////////////////// +// macro tools +// LaTeX's \@firstoftwo{#1}{#2} expands to #1, skipping #2 +// TeX source: \long\def\@firstoftwo#1#2{#1} + +defineMacro("\\@firstoftwo", function (context) { + const args = context.consumeArgs(2); + return { + tokens: args[0], + numArgs: 0 + }; +}); // LaTeX's \@secondoftwo{#1}{#2} expands to #2, skipping #1 +// TeX source: \long\def\@secondoftwo#1#2{#2} + +defineMacro("\\@secondoftwo", function (context) { + const args = context.consumeArgs(2); + return { + tokens: args[1], + numArgs: 0 + }; +}); // LaTeX's \@ifnextchar{#1}{#2}{#3} looks ahead to the next (unexpanded) +// symbol. If it matches #1, then the macro expands to #2; otherwise, #3. +// Note, however, that it does not consume the next symbol in either case. + +defineMacro("\\@ifnextchar", function (context) { + const args = context.consumeArgs(3); // symbol, if, else + + const nextToken = context.future(); + + if (args[0].length === 1 && args[0][0].text === nextToken.text) { + return { + tokens: args[1], + numArgs: 0 + }; + } else { + return { + tokens: args[2], + numArgs: 0 + }; + } +}); // LaTeX's \@ifstar{#1}{#2} looks ahead to the next (unexpanded) symbol. +// If it is `*`, then it consumes the symbol, and the macro expands to #1; +// otherwise, the macro expands to #2 (without consuming the symbol). +// TeX source: \def\@ifstar#1{\@ifnextchar *{\@firstoftwo{#1}}} + +defineMacro("\\@ifstar", "\\@ifnextchar *{\\@firstoftwo{#1}}"); // LaTeX's \TextOrMath{#1}{#2} expands to #1 in text mode, #2 in math mode + +defineMacro("\\TextOrMath", function (context) { + const args = context.consumeArgs(2); + + if (context.mode === 'text') { + return { + tokens: args[0], + numArgs: 0 + }; + } else { + return { + tokens: args[1], + numArgs: 0 + }; + } +}); // Lookup table for parsing numbers in base 8 through 16 + +const digitToNumber = { + "0": 0, + "1": 1, + "2": 2, + "3": 3, + "4": 4, + "5": 5, + "6": 6, + "7": 7, + "8": 8, + "9": 9, + "a": 10, + "A": 10, + "b": 11, + "B": 11, + "c": 12, + "C": 12, + "d": 13, + "D": 13, + "e": 14, + "E": 14, + "f": 15, + "F": 15 +}; // TeX \char makes a literal character (catcode 12) using the following forms: +// (see The TeXBook, p. 43) +// \char123 -- decimal +// \char'123 -- octal +// \char"123 -- hex +// \char`x -- character that can be written (i.e. isn't active) +// \char`\x -- character that cannot be written (e.g. %) +// These all refer to characters from the font, so we turn them into special +// calls to a function \@char dealt with in the Parser. + +defineMacro("\\char", function (context) { + let token = context.popToken(); + let base; + let number = ''; + + if (token.text === "'") { + base = 8; + token = context.popToken(); + } else if (token.text === '"') { + base = 16; + token = context.popToken(); + } else if (token.text === "`") { + token = context.popToken(); + + if (token.text[0] === "\\") { + number = token.text.charCodeAt(1); + } else if (token.text === "EOF") { + throw new ParseError("\\char` missing argument"); + } else { + number = token.text.charCodeAt(0); + } + } else { + base = 10; + } + + if (base) { + // Parse a number in the given base, starting with first `token`. + number = digitToNumber[token.text]; + + if (number == null || number >= base) { + throw new ParseError(`Invalid base-${base} digit ${token.text}`); + } + + let digit; + + while ((digit = digitToNumber[context.future().text]) != null && digit < base) { + number *= base; + number += digit; + context.popToken(); + } + } + + return `\\@char{${number}}`; +}); // Basic support for macro definitions: +// \def\macro{expansion} +// \def\macro#1{expansion} +// \def\macro#1#2{expansion} +// \def\macro#1#2#3#4#5#6#7#8#9{expansion} +// Also the \gdef and \global\def equivalents + +const def = (context, global) => { + let arg = context.consumeArgs(1)[0]; + + if (arg.length !== 1) { + throw new ParseError("\\gdef's first argument must be a macro name"); + } + + const name = arg[0].text; // Count argument specifiers, and check they are in the order #1 #2 ... + + let numArgs = 0; + arg = context.consumeArgs(1)[0]; + + while (arg.length === 1 && arg[0].text === "#") { + arg = context.consumeArgs(1)[0]; + + if (arg.length !== 1) { + throw new ParseError(`Invalid argument number length "${arg.length}"`); + } + + if (!/^[1-9]$/.test(arg[0].text)) { + throw new ParseError(`Invalid argument number "${arg[0].text}"`); + } + + numArgs++; + + if (parseInt(arg[0].text) !== numArgs) { + throw new ParseError(`Argument number "${arg[0].text}" out of order`); + } + + arg = context.consumeArgs(1)[0]; + } // Final arg is the expansion of the macro + + + context.macros.set(name, { + tokens: arg, + numArgs + }, global); + return ''; +}; + +defineMacro("\\gdef", context => def(context, true)); +defineMacro("\\def", context => def(context, false)); +defineMacro("\\global", context => { + const next = context.consumeArgs(1)[0]; + + if (next.length !== 1) { + throw new ParseError("Invalid command after \\global"); + } + + const command = next[0].text; // TODO: Should expand command + + if (command === "\\def") { + // \global\def is equivalent to \gdef + return def(context, true); + } else { + throw new ParseError(`Invalid command '${command}' after \\global`); + } +}); // \newcommand{\macro}[args]{definition} +// \renewcommand{\macro}[args]{definition} +// TODO: Optional arguments: \newcommand{\macro}[args][default]{definition} + +const newcommand = (context, existsOK, nonexistsOK) => { + let arg = context.consumeArgs(1)[0]; + + if (arg.length !== 1) { + throw new ParseError("\\newcommand's first argument must be a macro name"); + } + + const name = arg[0].text; + const exists = context.isDefined(name); + + if (exists && !existsOK) { + throw new ParseError(`\\newcommand{${name}} attempting to redefine ` + `${name}; use \\renewcommand`); + } + + if (!exists && !nonexistsOK) { + throw new ParseError(`\\renewcommand{${name}} when command ${name} ` + `does not yet exist; use \\newcommand`); + } + + let numArgs = 0; + arg = context.consumeArgs(1)[0]; + + if (arg.length === 1 && arg[0].text === "[") { + let argText = ''; + let token = context.expandNextToken(); + + while (token.text !== "]" && token.text !== "EOF") { + // TODO: Should properly expand arg, e.g., ignore {}s + argText += token.text; + token = context.expandNextToken(); + } + + if (!argText.match(/^\s*[0-9]+\s*$/)) { + throw new ParseError(`Invalid number of arguments: ${argText}`); + } + + numArgs = parseInt(argText); + arg = context.consumeArgs(1)[0]; + } // Final arg is the expansion of the macro + + + context.macros.set(name, { + tokens: arg, + numArgs + }); + return ''; +}; + +defineMacro("\\newcommand", context => newcommand(context, false, true)); +defineMacro("\\renewcommand", context => newcommand(context, true, false)); +defineMacro("\\providecommand", context => newcommand(context, true, true)); ////////////////////////////////////////////////////////////////////// +// Grouping +// \let\bgroup={ \let\egroup=} + +defineMacro("\\bgroup", "{"); +defineMacro("\\egroup", "}"); // Symbols from latex.ltx: +// \def\lq{`} +// \def\rq{'} +// \def \aa {\r a} +// \def \AA {\r A} + +defineMacro("\\lq", "`"); +defineMacro("\\rq", "'"); +defineMacro("\\aa", "\\r a"); +defineMacro("\\AA", "\\r A"); // Copyright (C) and registered (R) symbols. Use raw symbol in MathML. +// \DeclareTextCommandDefault{\textcopyright}{\textcircled{c}} +// \DeclareTextCommandDefault{\textregistered}{\textcircled{% +// \check@mathfonts\fontsize\sf@size\z@\math@fontsfalse\selectfont R}} +// \DeclareRobustCommand{\copyright}{% +// \ifmmode{\nfss@text{\textcopyright}}\else\textcopyright\fi} + +defineMacro("\\textcopyright", "\\html@mathml{\\textcircled{c}}{\\char`©}"); +defineMacro("\\copyright", "\\TextOrMath{\\textcopyright}{\\text{\\textcopyright}}"); +defineMacro("\\textregistered", "\\html@mathml{\\textcircled{\\scriptsize R}}{\\char`®}"); // Characters omitted from Unicode range 1D400–1D7FF + +defineMacro("\u212C", "\\mathscr{B}"); // script + +defineMacro("\u2130", "\\mathscr{E}"); +defineMacro("\u2131", "\\mathscr{F}"); +defineMacro("\u210B", "\\mathscr{H}"); +defineMacro("\u2110", "\\mathscr{I}"); +defineMacro("\u2112", "\\mathscr{L}"); +defineMacro("\u2133", "\\mathscr{M}"); +defineMacro("\u211B", "\\mathscr{R}"); +defineMacro("\u212D", "\\mathfrak{C}"); // Fraktur + +defineMacro("\u210C", "\\mathfrak{H}"); +defineMacro("\u2128", "\\mathfrak{Z}"); // Define \Bbbk with a macro that works in both HTML and MathML. + +defineMacro("\\Bbbk", "\\Bbb{k}"); // Unicode middle dot +// The KaTeX fonts do not contain U+00B7. Instead, \cdotp displays +// the dot at U+22C5 and gives it punct spacing. + +defineMacro("\u00b7", "\\cdotp"); // \llap and \rlap render their contents in text mode + +defineMacro("\\llap", "\\mathllap{\\textrm{#1}}"); +defineMacro("\\rlap", "\\mathrlap{\\textrm{#1}}"); +defineMacro("\\clap", "\\mathclap{\\textrm{#1}}"); // \not is defined by base/fontmath.ltx via +// \DeclareMathSymbol{\not}{\mathrel}{symbols}{"36} +// It's thus treated like a \mathrel, but defined by a symbol that has zero +// width but extends to the right. We use \rlap to get that spacing. +// For MathML we write U+0338 here. buildMathML.js will then do the overlay. + +defineMacro("\\not", '\\html@mathml{\\mathrel{\\mathrlap\\@not}}{\\char"338}'); // Negated symbols from base/fontmath.ltx: +// \def\neq{\not=} \let\ne=\neq +// \DeclareRobustCommand +// \notin{\mathrel{\m@th\mathpalette\c@ncel\in}} +// \def\c@ncel#1#2{\m@th\ooalign{$\hfil#1\mkern1mu/\hfil$\crcr$#1#2$}} + +defineMacro("\\neq", "\\html@mathml{\\mathrel{\\not=}}{\\mathrel{\\char`≠}}"); +defineMacro("\\ne", "\\neq"); +defineMacro("\u2260", "\\neq"); +defineMacro("\\notin", "\\html@mathml{\\mathrel{{\\in}\\mathllap{/\\mskip1mu}}}" + "{\\mathrel{\\char`∉}}"); +defineMacro("\u2209", "\\notin"); // Unicode stacked relations + +defineMacro("\u2258", "\\html@mathml{" + "\\mathrel{=\\kern{-1em}\\raisebox{0.4em}{$\\scriptsize\\frown$}}" + "}{\\mathrel{\\char`\u2258}}"); +defineMacro("\u2259", "\\html@mathml{\\stackrel{\\tiny\\wedge}{=}}{\\mathrel{\\char`\u2258}}"); +defineMacro("\u225A", "\\html@mathml{\\stackrel{\\tiny\\vee}{=}}{\\mathrel{\\char`\u225A}}"); +defineMacro("\u225B", "\\html@mathml{\\stackrel{\\scriptsize\\star}{=}}" + "{\\mathrel{\\char`\u225B}}"); +defineMacro("\u225D", "\\html@mathml{\\stackrel{\\tiny\\mathrm{def}}{=}}" + "{\\mathrel{\\char`\u225D}}"); +defineMacro("\u225E", "\\html@mathml{\\stackrel{\\tiny\\mathrm{m}}{=}}" + "{\\mathrel{\\char`\u225E}}"); +defineMacro("\u225F", "\\html@mathml{\\stackrel{\\tiny?}{=}}{\\mathrel{\\char`\u225F}}"); // Misc Unicode + +defineMacro("\u27C2", "\\perp"); +defineMacro("\u203C", "\\mathclose{!\\mkern-0.8mu!}"); +defineMacro("\u220C", "\\notni"); +defineMacro("\u231C", "\\ulcorner"); +defineMacro("\u231D", "\\urcorner"); +defineMacro("\u231E", "\\llcorner"); +defineMacro("\u231F", "\\lrcorner"); +defineMacro("\u00A9", "\\copyright"); +defineMacro("\u00AE", "\\textregistered"); +defineMacro("\uFE0F", "\\textregistered"); ////////////////////////////////////////////////////////////////////// +// LaTeX_2ε +// \vdots{\vbox{\baselineskip4\p@ \lineskiplimit\z@ +// \kern6\p@\hbox{.}\hbox{.}\hbox{.}}} +// We'll call \varvdots, which gets a glyph from symbols.js. +// The zero-width rule gets us an equivalent to the vertical 6pt kern. + +defineMacro("\\vdots", "\\mathord{\\varvdots\\rule{0pt}{15pt}}"); +defineMacro("\u22ee", "\\vdots"); ////////////////////////////////////////////////////////////////////// +// amsmath.sty +// http://mirrors.concertpass.com/tex-archive/macros/latex/required/amsmath/amsmath.pdf +// Italic Greek capital letters. AMS defines these with \DeclareMathSymbol, +// but they are equivalent to \mathit{\Letter}. + +defineMacro("\\varGamma", "\\mathit{\\Gamma}"); +defineMacro("\\varDelta", "\\mathit{\\Delta}"); +defineMacro("\\varTheta", "\\mathit{\\Theta}"); +defineMacro("\\varLambda", "\\mathit{\\Lambda}"); +defineMacro("\\varXi", "\\mathit{\\Xi}"); +defineMacro("\\varPi", "\\mathit{\\Pi}"); +defineMacro("\\varSigma", "\\mathit{\\Sigma}"); +defineMacro("\\varUpsilon", "\\mathit{\\Upsilon}"); +defineMacro("\\varPhi", "\\mathit{\\Phi}"); +defineMacro("\\varPsi", "\\mathit{\\Psi}"); +defineMacro("\\varOmega", "\\mathit{\\Omega}"); //\newcommand{\substack}[1]{\subarray{c}#1\endsubarray} + +defineMacro("\\substack", "\\begin{subarray}{c}#1\\end{subarray}"); // \renewcommand{\colon}{\nobreak\mskip2mu\mathpunct{}\nonscript +// \mkern-\thinmuskip{:}\mskip6muplus1mu\relax} + +defineMacro("\\colon", "\\nobreak\\mskip2mu\\mathpunct{}" + "\\mathchoice{\\mkern-3mu}{\\mkern-3mu}{}{}{:}\\mskip6mu"); // \newcommand{\boxed}[1]{\fbox{\m@th$\displaystyle#1$}} + +defineMacro("\\boxed", "\\fbox{$\\displaystyle{#1}$}"); // \def\iff{\DOTSB\;\Longleftrightarrow\;} +// \def\implies{\DOTSB\;\Longrightarrow\;} +// \def\impliedby{\DOTSB\;\Longleftarrow\;} + +defineMacro("\\iff", "\\DOTSB\\;\\Longleftrightarrow\\;"); +defineMacro("\\implies", "\\DOTSB\\;\\Longrightarrow\\;"); +defineMacro("\\impliedby", "\\DOTSB\\;\\Longleftarrow\\;"); // AMSMath's automatic \dots, based on \mdots@@ macro. + +const dotsByToken = { + ',': '\\dotsc', + '\\not': '\\dotsb', + // \keybin@ checks for the following: + '+': '\\dotsb', + '=': '\\dotsb', + '<': '\\dotsb', + '>': '\\dotsb', + '-': '\\dotsb', + '*': '\\dotsb', + ':': '\\dotsb', + // Symbols whose definition starts with \DOTSB: + '\\DOTSB': '\\dotsb', + '\\coprod': '\\dotsb', + '\\bigvee': '\\dotsb', + '\\bigwedge': '\\dotsb', + '\\biguplus': '\\dotsb', + '\\bigcap': '\\dotsb', + '\\bigcup': '\\dotsb', + '\\prod': '\\dotsb', + '\\sum': '\\dotsb', + '\\bigotimes': '\\dotsb', + '\\bigoplus': '\\dotsb', + '\\bigodot': '\\dotsb', + '\\bigsqcup': '\\dotsb', + '\\And': '\\dotsb', + '\\longrightarrow': '\\dotsb', + '\\Longrightarrow': '\\dotsb', + '\\longleftarrow': '\\dotsb', + '\\Longleftarrow': '\\dotsb', + '\\longleftrightarrow': '\\dotsb', + '\\Longleftrightarrow': '\\dotsb', + '\\mapsto': '\\dotsb', + '\\longmapsto': '\\dotsb', + '\\hookrightarrow': '\\dotsb', + '\\doteq': '\\dotsb', + // Symbols whose definition starts with \mathbin: + '\\mathbin': '\\dotsb', + // Symbols whose definition starts with \mathrel: + '\\mathrel': '\\dotsb', + '\\relbar': '\\dotsb', + '\\Relbar': '\\dotsb', + '\\xrightarrow': '\\dotsb', + '\\xleftarrow': '\\dotsb', + // Symbols whose definition starts with \DOTSI: + '\\DOTSI': '\\dotsi', + '\\int': '\\dotsi', + '\\oint': '\\dotsi', + '\\iint': '\\dotsi', + '\\iiint': '\\dotsi', + '\\iiiint': '\\dotsi', + '\\idotsint': '\\dotsi', + // Symbols whose definition starts with \DOTSX: + '\\DOTSX': '\\dotsx' +}; +defineMacro("\\dots", function (context) { + // TODO: If used in text mode, should expand to \textellipsis. + // However, in KaTeX, \textellipsis and \ldots behave the same + // (in text mode), and it's unlikely we'd see any of the math commands + // that affect the behavior of \dots when in text mode. So fine for now + // (until we support \ifmmode ... \else ... \fi). + let thedots = '\\dotso'; + const next = context.expandAfterFuture().text; + + if (next in dotsByToken) { + thedots = dotsByToken[next]; + } else if (next.substr(0, 4) === '\\not') { + thedots = '\\dotsb'; + } else if (next in symbols.math) { + if (utils.contains(['bin', 'rel'], symbols.math[next].group)) { + thedots = '\\dotsb'; + } + } + + return thedots; +}); +const spaceAfterDots = { + // \rightdelim@ checks for the following: + ')': true, + ']': true, + '\\rbrack': true, + '\\}': true, + '\\rbrace': true, + '\\rangle': true, + '\\rceil': true, + '\\rfloor': true, + '\\rgroup': true, + '\\rmoustache': true, + '\\right': true, + '\\bigr': true, + '\\biggr': true, + '\\Bigr': true, + '\\Biggr': true, + // \extra@ also tests for the following: + '$': true, + // \extrap@ checks for the following: + ';': true, + '.': true, + ',': true +}; +defineMacro("\\dotso", function (context) { + const next = context.future().text; + + if (next in spaceAfterDots) { + return "\\ldots\\,"; + } else { + return "\\ldots"; + } +}); +defineMacro("\\dotsc", function (context) { + const next = context.future().text; // \dotsc uses \extra@ but not \extrap@, instead specially checking for + // ';' and '.', but doesn't check for ','. + + if (next in spaceAfterDots && next !== ',') { + return "\\ldots\\,"; + } else { + return "\\ldots"; + } +}); +defineMacro("\\cdots", function (context) { + const next = context.future().text; + + if (next in spaceAfterDots) { + return "\\@cdots\\,"; + } else { + return "\\@cdots"; + } +}); +defineMacro("\\dotsb", "\\cdots"); +defineMacro("\\dotsm", "\\cdots"); +defineMacro("\\dotsi", "\\!\\cdots"); // amsmath doesn't actually define \dotsx, but \dots followed by a macro +// starting with \DOTSX implies \dotso, and then \extra@ detects this case +// and forces the added `\,`. + +defineMacro("\\dotsx", "\\ldots\\,"); // \let\DOTSI\relax +// \let\DOTSB\relax +// \let\DOTSX\relax + +defineMacro("\\DOTSI", "\\relax"); +defineMacro("\\DOTSB", "\\relax"); +defineMacro("\\DOTSX", "\\relax"); // Spacing, based on amsmath.sty's override of LaTeX defaults +// \DeclareRobustCommand{\tmspace}[3]{% +// \ifmmode\mskip#1#2\else\kern#1#3\fi\relax} + +defineMacro("\\tmspace", "\\TextOrMath{\\kern#1#3}{\\mskip#1#2}\\relax"); // \renewcommand{\,}{\tmspace+\thinmuskip{.1667em}} +// TODO: math mode should use \thinmuskip + +defineMacro("\\,", "\\tmspace+{3mu}{.1667em}"); // \let\thinspace\, + +defineMacro("\\thinspace", "\\,"); // \def\>{\mskip\medmuskip} +// \renewcommand{\:}{\tmspace+\medmuskip{.2222em}} +// TODO: \> and math mode of \: should use \medmuskip = 4mu plus 2mu minus 4mu + +defineMacro("\\>", "\\mskip{4mu}"); +defineMacro("\\:", "\\tmspace+{4mu}{.2222em}"); // \let\medspace\: + +defineMacro("\\medspace", "\\:"); // \renewcommand{\;}{\tmspace+\thickmuskip{.2777em}} +// TODO: math mode should use \thickmuskip = 5mu plus 5mu + +defineMacro("\\;", "\\tmspace+{5mu}{.2777em}"); // \let\thickspace\; + +defineMacro("\\thickspace", "\\;"); // \renewcommand{\!}{\tmspace-\thinmuskip{.1667em}} +// TODO: math mode should use \thinmuskip + +defineMacro("\\!", "\\tmspace-{3mu}{.1667em}"); // \let\negthinspace\! + +defineMacro("\\negthinspace", "\\!"); // \newcommand{\negmedspace}{\tmspace-\medmuskip{.2222em}} +// TODO: math mode should use \medmuskip + +defineMacro("\\negmedspace", "\\tmspace-{4mu}{.2222em}"); // \newcommand{\negthickspace}{\tmspace-\thickmuskip{.2777em}} +// TODO: math mode should use \thickmuskip + +defineMacro("\\negthickspace", "\\tmspace-{5mu}{.277em}"); // \def\enspace{\kern.5em } + +defineMacro("\\enspace", "\\kern.5em "); // \def\enskip{\hskip.5em\relax} + +defineMacro("\\enskip", "\\hskip.5em\\relax"); // \def\quad{\hskip1em\relax} + +defineMacro("\\quad", "\\hskip1em\\relax"); // \def\qquad{\hskip2em\relax} + +defineMacro("\\qquad", "\\hskip2em\\relax"); // \tag@in@display form of \tag + +defineMacro("\\tag", "\\@ifstar\\tag@literal\\tag@paren"); +defineMacro("\\tag@paren", "\\tag@literal{({#1})}"); +defineMacro("\\tag@literal", context => { + if (context.macros.get("\\df@tag")) { + throw new ParseError("Multiple \\tag"); + } + + return "\\gdef\\df@tag{\\text{#1}}"; +}); // \renewcommand{\bmod}{\nonscript\mskip-\medmuskip\mkern5mu\mathbin +// {\operator@font mod}\penalty900 +// \mkern5mu\nonscript\mskip-\medmuskip} +// \newcommand{\pod}[1]{\allowbreak +// \if@display\mkern18mu\else\mkern8mu\fi(#1)} +// \renewcommand{\pmod}[1]{\pod{{\operator@font mod}\mkern6mu#1}} +// \newcommand{\mod}[1]{\allowbreak\if@display\mkern18mu +// \else\mkern12mu\fi{\operator@font mod}\,\,#1} +// TODO: math mode should use \medmuskip = 4mu plus 2mu minus 4mu + +defineMacro("\\bmod", "\\mathchoice{\\mskip1mu}{\\mskip1mu}{\\mskip5mu}{\\mskip5mu}" + "\\mathbin{\\rm mod}" + "\\mathchoice{\\mskip1mu}{\\mskip1mu}{\\mskip5mu}{\\mskip5mu}"); +defineMacro("\\pod", "\\allowbreak" + "\\mathchoice{\\mkern18mu}{\\mkern8mu}{\\mkern8mu}{\\mkern8mu}(#1)"); +defineMacro("\\pmod", "\\pod{{\\rm mod}\\mkern6mu#1}"); +defineMacro("\\mod", "\\allowbreak" + "\\mathchoice{\\mkern18mu}{\\mkern12mu}{\\mkern12mu}{\\mkern12mu}" + "{\\rm mod}\\,\\,#1"); // \pmb -- A simulation of bold. +// The version in ambsy.sty works by typesetting three copies of the argument +// with small offsets. We use two copies. We omit the vertical offset because +// of rendering problems that makeVList encounters in Safari. + +defineMacro("\\pmb", "\\html@mathml{" + "\\@binrel{#1}{\\mathrlap{#1}\\kern0.5px#1}}" + "{\\mathbf{#1}}"); ////////////////////////////////////////////////////////////////////// +// LaTeX source2e +// \\ defaults to \newline, but changes to \cr within array environment + +defineMacro("\\\\", "\\newline"); // \def\TeX{T\kern-.1667em\lower.5ex\hbox{E}\kern-.125emX\@} +// TODO: Doesn't normally work in math mode because \@ fails. KaTeX doesn't +// support \@ yet, so that's omitted, and we add \text so that the result +// doesn't look funny in math mode. + +defineMacro("\\TeX", "\\textrm{\\html@mathml{" + "T\\kern-.1667em\\raisebox{-.5ex}{E}\\kern-.125emX" + "}{TeX}}"); // \DeclareRobustCommand{\LaTeX}{L\kern-.36em% +// {\sbox\z@ T% +// \vbox to\ht\z@{\hbox{\check@mathfonts +// \fontsize\sf@size\z@ +// \math@fontsfalse\selectfont +// A}% +// \vss}% +// }% +// \kern-.15em% +// \TeX} +// This code aligns the top of the A with the T (from the perspective of TeX's +// boxes, though visually the A appears to extend above slightly). +// We compute the corresponding \raisebox when A is rendered in \normalsize +// \scriptstyle, which has a scale factor of 0.7 (see Options.js). + +const latexRaiseA = metricMap['Main-Regular']["T".charCodeAt(0)][1] - 0.7 * metricMap['Main-Regular']["A".charCodeAt(0)][1] + "em"; +defineMacro("\\LaTeX", "\\textrm{\\html@mathml{" + `L\\kern-.36em\\raisebox{${latexRaiseA}}{\\scriptstyle A}` + "\\kern-.15em\\TeX}{LaTeX}}"); // New KaTeX logo based on tweaking LaTeX logo + +defineMacro("\\KaTeX", "\\textrm{\\html@mathml{" + `K\\kern-.17em\\raisebox{${latexRaiseA}}{\\scriptstyle A}` + "\\kern-.15em\\TeX}{KaTeX}}"); // \DeclareRobustCommand\hspace{\@ifstar\@hspacer\@hspace} +// \def\@hspace#1{\hskip #1\relax} +// \def\@hspacer#1{\vrule \@width\z@\nobreak +// \hskip #1\hskip \z@skip} + +defineMacro("\\hspace", "\\@ifstar\\@hspacer\\@hspace"); +defineMacro("\\@hspace", "\\hskip #1\\relax"); +defineMacro("\\@hspacer", "\\rule{0pt}{0pt}\\hskip #1\\relax"); ////////////////////////////////////////////////////////////////////// +// mathtools.sty +//\providecommand\ordinarycolon{:} + +defineMacro("\\ordinarycolon", ":"); //\def\vcentcolon{\mathrel{\mathop\ordinarycolon}} +//TODO(edemaine): Not yet centered. Fix via \raisebox or #726 + +defineMacro("\\vcentcolon", "\\mathrel{\\mathop\\ordinarycolon}"); // \providecommand*\dblcolon{\vcentcolon\mathrel{\mkern-.9mu}\vcentcolon} + +defineMacro("\\dblcolon", "\\html@mathml{" + "\\mathrel{\\vcentcolon\\mathrel{\\mkern-.9mu}\\vcentcolon}}" + "{\\mathop{\\char\"2237}}"); // \providecommand*\coloneqq{\vcentcolon\mathrel{\mkern-1.2mu}=} + +defineMacro("\\coloneqq", "\\html@mathml{" + "\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}=}}" + "{\\mathop{\\char\"2254}}"); // ≔ +// \providecommand*\Coloneqq{\dblcolon\mathrel{\mkern-1.2mu}=} + +defineMacro("\\Coloneqq", "\\html@mathml{" + "\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}=}}" + "{\\mathop{\\char\"2237\\char\"3d}}"); // \providecommand*\coloneq{\vcentcolon\mathrel{\mkern-1.2mu}\mathrel{-}} + +defineMacro("\\coloneq", "\\html@mathml{" + "\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}\\mathrel{-}}}" + "{\\mathop{\\char\"3a\\char\"2212}}"); // \providecommand*\Coloneq{\dblcolon\mathrel{\mkern-1.2mu}\mathrel{-}} + +defineMacro("\\Coloneq", "\\html@mathml{" + "\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}\\mathrel{-}}}" + "{\\mathop{\\char\"2237\\char\"2212}}"); // \providecommand*\eqqcolon{=\mathrel{\mkern-1.2mu}\vcentcolon} + +defineMacro("\\eqqcolon", "\\html@mathml{" + "\\mathrel{=\\mathrel{\\mkern-1.2mu}\\vcentcolon}}" + "{\\mathop{\\char\"2255}}"); // ≕ +// \providecommand*\Eqqcolon{=\mathrel{\mkern-1.2mu}\dblcolon} + +defineMacro("\\Eqqcolon", "\\html@mathml{" + "\\mathrel{=\\mathrel{\\mkern-1.2mu}\\dblcolon}}" + "{\\mathop{\\char\"3d\\char\"2237}}"); // \providecommand*\eqcolon{\mathrel{-}\mathrel{\mkern-1.2mu}\vcentcolon} + +defineMacro("\\eqcolon", "\\html@mathml{" + "\\mathrel{\\mathrel{-}\\mathrel{\\mkern-1.2mu}\\vcentcolon}}" + "{\\mathop{\\char\"2239}}"); // \providecommand*\Eqcolon{\mathrel{-}\mathrel{\mkern-1.2mu}\dblcolon} + +defineMacro("\\Eqcolon", "\\html@mathml{" + "\\mathrel{\\mathrel{-}\\mathrel{\\mkern-1.2mu}\\dblcolon}}" + "{\\mathop{\\char\"2212\\char\"2237}}"); // \providecommand*\colonapprox{\vcentcolon\mathrel{\mkern-1.2mu}\approx} + +defineMacro("\\colonapprox", "\\html@mathml{" + "\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}\\approx}}" + "{\\mathop{\\char\"3a\\char\"2248}}"); // \providecommand*\Colonapprox{\dblcolon\mathrel{\mkern-1.2mu}\approx} + +defineMacro("\\Colonapprox", "\\html@mathml{" + "\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}\\approx}}" + "{\\mathop{\\char\"2237\\char\"2248}}"); // \providecommand*\colonsim{\vcentcolon\mathrel{\mkern-1.2mu}\sim} + +defineMacro("\\colonsim", "\\html@mathml{" + "\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}\\sim}}" + "{\\mathop{\\char\"3a\\char\"223c}}"); // \providecommand*\Colonsim{\dblcolon\mathrel{\mkern-1.2mu}\sim} + +defineMacro("\\Colonsim", "\\html@mathml{" + "\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}\\sim}}" + "{\\mathop{\\char\"2237\\char\"223c}}"); // Some Unicode characters are implemented with macros to mathtools functions. + +defineMacro("\u2237", "\\dblcolon"); // :: + +defineMacro("\u2239", "\\eqcolon"); // -: + +defineMacro("\u2254", "\\coloneqq"); // := + +defineMacro("\u2255", "\\eqqcolon"); // =: + +defineMacro("\u2A74", "\\Coloneqq"); // ::= +////////////////////////////////////////////////////////////////////// +// colonequals.sty +// Alternate names for mathtools's macros: + +defineMacro("\\ratio", "\\vcentcolon"); +defineMacro("\\coloncolon", "\\dblcolon"); +defineMacro("\\colonequals", "\\coloneqq"); +defineMacro("\\coloncolonequals", "\\Coloneqq"); +defineMacro("\\equalscolon", "\\eqqcolon"); +defineMacro("\\equalscoloncolon", "\\Eqqcolon"); +defineMacro("\\colonminus", "\\coloneq"); +defineMacro("\\coloncolonminus", "\\Coloneq"); +defineMacro("\\minuscolon", "\\eqcolon"); +defineMacro("\\minuscoloncolon", "\\Eqcolon"); // \colonapprox name is same in mathtools and colonequals. + +defineMacro("\\coloncolonapprox", "\\Colonapprox"); // \colonsim name is same in mathtools and colonequals. + +defineMacro("\\coloncolonsim", "\\Colonsim"); // Additional macros, implemented by analogy with mathtools definitions: + +defineMacro("\\simcolon", "\\mathrel{\\sim\\mathrel{\\mkern-1.2mu}\\vcentcolon}"); +defineMacro("\\simcoloncolon", "\\mathrel{\\sim\\mathrel{\\mkern-1.2mu}\\dblcolon}"); +defineMacro("\\approxcolon", "\\mathrel{\\approx\\mathrel{\\mkern-1.2mu}\\vcentcolon}"); +defineMacro("\\approxcoloncolon", "\\mathrel{\\approx\\mathrel{\\mkern-1.2mu}\\dblcolon}"); // Present in newtxmath, pxfonts and txfonts + +defineMacro("\\notni", "\\html@mathml{\\not\\ni}{\\mathrel{\\char`\u220C}}"); +defineMacro("\\limsup", "\\DOTSB\\operatorname*{lim\\,sup}"); +defineMacro("\\liminf", "\\DOTSB\\operatorname*{lim\\,inf}"); ////////////////////////////////////////////////////////////////////// +// MathML alternates for KaTeX glyphs in the Unicode private area + +defineMacro("\\gvertneqq", "\\html@mathml{\\@gvertneqq}{\u2269}"); +defineMacro("\\lvertneqq", "\\html@mathml{\\@lvertneqq}{\u2268}"); +defineMacro("\\ngeqq", "\\html@mathml{\\@ngeqq}{\u2271}"); +defineMacro("\\ngeqslant", "\\html@mathml{\\@ngeqslant}{\u2271}"); +defineMacro("\\nleqq", "\\html@mathml{\\@nleqq}{\u2270}"); +defineMacro("\\nleqslant", "\\html@mathml{\\@nleqslant}{\u2270}"); +defineMacro("\\nshortmid", "\\html@mathml{\\@nshortmid}{∤}"); +defineMacro("\\nshortparallel", "\\html@mathml{\\@nshortparallel}{∦}"); +defineMacro("\\nsubseteqq", "\\html@mathml{\\@nsubseteqq}{\u2288}"); +defineMacro("\\nsupseteqq", "\\html@mathml{\\@nsupseteqq}{\u2289}"); +defineMacro("\\varsubsetneq", "\\html@mathml{\\@varsubsetneq}{⊊}"); +defineMacro("\\varsubsetneqq", "\\html@mathml{\\@varsubsetneqq}{⫋}"); +defineMacro("\\varsupsetneq", "\\html@mathml{\\@varsupsetneq}{⊋}"); +defineMacro("\\varsupsetneqq", "\\html@mathml{\\@varsupsetneqq}{⫌}"); ////////////////////////////////////////////////////////////////////// +// stmaryrd and semantic +// The stmaryrd and semantic packages render the next four items by calling a +// glyph. Those glyphs do not exist in the KaTeX fonts. Hence the macros. + +defineMacro("\\llbracket", "\\html@mathml{" + "\\mathopen{[\\mkern-3.2mu[}}" + "{\\mathopen{\\char`\u27e6}}"); +defineMacro("\\rrbracket", "\\html@mathml{" + "\\mathclose{]\\mkern-3.2mu]}}" + "{\\mathclose{\\char`\u27e7}}"); +defineMacro("\u27e6", "\\llbracket"); // blackboard bold [ + +defineMacro("\u27e7", "\\rrbracket"); // blackboard bold ] + +defineMacro("\\lBrace", "\\html@mathml{" + "\\mathopen{\\{\\mkern-3.2mu[}}" + "{\\mathopen{\\char`\u2983}}"); +defineMacro("\\rBrace", "\\html@mathml{" + "\\mathclose{]\\mkern-3.2mu\\}}}" + "{\\mathclose{\\char`\u2984}}"); +defineMacro("\u2983", "\\lBrace"); // blackboard bold { + +defineMacro("\u2984", "\\rBrace"); // blackboard bold } +// TODO: Create variable sized versions of the last two items. I believe that +// will require new font glyphs. +////////////////////////////////////////////////////////////////////// +// texvc.sty +// The texvc package contains macros available in mediawiki pages. +// We omit the functions deprecated at +// https://en.wikipedia.org/wiki/Help:Displaying_a_formula#Deprecated_syntax +// We also omit texvc's \O, which conflicts with \text{\O} + +defineMacro("\\darr", "\\downarrow"); +defineMacro("\\dArr", "\\Downarrow"); +defineMacro("\\Darr", "\\Downarrow"); +defineMacro("\\lang", "\\langle"); +defineMacro("\\rang", "\\rangle"); +defineMacro("\\uarr", "\\uparrow"); +defineMacro("\\uArr", "\\Uparrow"); +defineMacro("\\Uarr", "\\Uparrow"); +defineMacro("\\N", "\\mathbb{N}"); +defineMacro("\\R", "\\mathbb{R}"); +defineMacro("\\Z", "\\mathbb{Z}"); +defineMacro("\\alef", "\\aleph"); +defineMacro("\\alefsym", "\\aleph"); +defineMacro("\\Alpha", "\\mathrm{A}"); +defineMacro("\\Beta", "\\mathrm{B}"); +defineMacro("\\bull", "\\bullet"); +defineMacro("\\Chi", "\\mathrm{X}"); +defineMacro("\\clubs", "\\clubsuit"); +defineMacro("\\cnums", "\\mathbb{C}"); +defineMacro("\\Complex", "\\mathbb{C}"); +defineMacro("\\Dagger", "\\ddagger"); +defineMacro("\\diamonds", "\\diamondsuit"); +defineMacro("\\empty", "\\emptyset"); +defineMacro("\\Epsilon", "\\mathrm{E}"); +defineMacro("\\Eta", "\\mathrm{H}"); +defineMacro("\\exist", "\\exists"); +defineMacro("\\harr", "\\leftrightarrow"); +defineMacro("\\hArr", "\\Leftrightarrow"); +defineMacro("\\Harr", "\\Leftrightarrow"); +defineMacro("\\hearts", "\\heartsuit"); +defineMacro("\\image", "\\Im"); +defineMacro("\\infin", "\\infty"); +defineMacro("\\Iota", "\\mathrm{I}"); +defineMacro("\\isin", "\\in"); +defineMacro("\\Kappa", "\\mathrm{K}"); +defineMacro("\\larr", "\\leftarrow"); +defineMacro("\\lArr", "\\Leftarrow"); +defineMacro("\\Larr", "\\Leftarrow"); +defineMacro("\\lrarr", "\\leftrightarrow"); +defineMacro("\\lrArr", "\\Leftrightarrow"); +defineMacro("\\Lrarr", "\\Leftrightarrow"); +defineMacro("\\Mu", "\\mathrm{M}"); +defineMacro("\\natnums", "\\mathbb{N}"); +defineMacro("\\Nu", "\\mathrm{N}"); +defineMacro("\\Omicron", "\\mathrm{O}"); +defineMacro("\\plusmn", "\\pm"); +defineMacro("\\rarr", "\\rightarrow"); +defineMacro("\\rArr", "\\Rightarrow"); +defineMacro("\\Rarr", "\\Rightarrow"); +defineMacro("\\real", "\\Re"); +defineMacro("\\reals", "\\mathbb{R}"); +defineMacro("\\Reals", "\\mathbb{R}"); +defineMacro("\\Rho", "\\mathrm{P}"); +defineMacro("\\sdot", "\\cdot"); +defineMacro("\\sect", "\\S"); +defineMacro("\\spades", "\\spadesuit"); +defineMacro("\\sub", "\\subset"); +defineMacro("\\sube", "\\subseteq"); +defineMacro("\\supe", "\\supseteq"); +defineMacro("\\Tau", "\\mathrm{T}"); +defineMacro("\\thetasym", "\\vartheta"); // TODO: defineMacro("\\varcoppa", "\\\mbox{\\coppa}"); + +defineMacro("\\weierp", "\\wp"); +defineMacro("\\Zeta", "\\mathrm{Z}"); ////////////////////////////////////////////////////////////////////// +// statmath.sty +// https://ctan.math.illinois.edu/macros/latex/contrib/statmath/statmath.pdf + +defineMacro("\\argmin", "\\DOTSB\\operatorname*{arg\\,min}"); +defineMacro("\\argmax", "\\DOTSB\\operatorname*{arg\\,max}"); +defineMacro("\\plim", "\\DOTSB\\mathop{\\operatorname{plim}}\\limits"); // Custom Khan Academy colors, should be moved to an optional package + +defineMacro("\\blue", "\\textcolor{##6495ed}{#1}"); +defineMacro("\\orange", "\\textcolor{##ffa500}{#1}"); +defineMacro("\\pink", "\\textcolor{##ff00af}{#1}"); +defineMacro("\\red", "\\textcolor{##df0030}{#1}"); +defineMacro("\\green", "\\textcolor{##28ae7b}{#1}"); +defineMacro("\\gray", "\\textcolor{gray}{#1}"); +defineMacro("\\purple", "\\textcolor{##9d38bd}{#1}"); +defineMacro("\\blueA", "\\textcolor{##ccfaff}{#1}"); +defineMacro("\\blueB", "\\textcolor{##80f6ff}{#1}"); +defineMacro("\\blueC", "\\textcolor{##63d9ea}{#1}"); +defineMacro("\\blueD", "\\textcolor{##11accd}{#1}"); +defineMacro("\\blueE", "\\textcolor{##0c7f99}{#1}"); +defineMacro("\\tealA", "\\textcolor{##94fff5}{#1}"); +defineMacro("\\tealB", "\\textcolor{##26edd5}{#1}"); +defineMacro("\\tealC", "\\textcolor{##01d1c1}{#1}"); +defineMacro("\\tealD", "\\textcolor{##01a995}{#1}"); +defineMacro("\\tealE", "\\textcolor{##208170}{#1}"); +defineMacro("\\greenA", "\\textcolor{##b6ffb0}{#1}"); +defineMacro("\\greenB", "\\textcolor{##8af281}{#1}"); +defineMacro("\\greenC", "\\textcolor{##74cf70}{#1}"); +defineMacro("\\greenD", "\\textcolor{##1fab54}{#1}"); +defineMacro("\\greenE", "\\textcolor{##0d923f}{#1}"); +defineMacro("\\goldA", "\\textcolor{##ffd0a9}{#1}"); +defineMacro("\\goldB", "\\textcolor{##ffbb71}{#1}"); +defineMacro("\\goldC", "\\textcolor{##ff9c39}{#1}"); +defineMacro("\\goldD", "\\textcolor{##e07d10}{#1}"); +defineMacro("\\goldE", "\\textcolor{##a75a05}{#1}"); +defineMacro("\\redA", "\\textcolor{##fca9a9}{#1}"); +defineMacro("\\redB", "\\textcolor{##ff8482}{#1}"); +defineMacro("\\redC", "\\textcolor{##f9685d}{#1}"); +defineMacro("\\redD", "\\textcolor{##e84d39}{#1}"); +defineMacro("\\redE", "\\textcolor{##bc2612}{#1}"); +defineMacro("\\maroonA", "\\textcolor{##ffbde0}{#1}"); +defineMacro("\\maroonB", "\\textcolor{##ff92c6}{#1}"); +defineMacro("\\maroonC", "\\textcolor{##ed5fa6}{#1}"); +defineMacro("\\maroonD", "\\textcolor{##ca337c}{#1}"); +defineMacro("\\maroonE", "\\textcolor{##9e034e}{#1}"); +defineMacro("\\purpleA", "\\textcolor{##ddd7ff}{#1}"); +defineMacro("\\purpleB", "\\textcolor{##c6b9fc}{#1}"); +defineMacro("\\purpleC", "\\textcolor{##aa87ff}{#1}"); +defineMacro("\\purpleD", "\\textcolor{##7854ab}{#1}"); +defineMacro("\\purpleE", "\\textcolor{##543b78}{#1}"); +defineMacro("\\mintA", "\\textcolor{##f5f9e8}{#1}"); +defineMacro("\\mintB", "\\textcolor{##edf2df}{#1}"); +defineMacro("\\mintC", "\\textcolor{##e0e5cc}{#1}"); +defineMacro("\\grayA", "\\textcolor{##f6f7f7}{#1}"); +defineMacro("\\grayB", "\\textcolor{##f0f1f2}{#1}"); +defineMacro("\\grayC", "\\textcolor{##e3e5e6}{#1}"); +defineMacro("\\grayD", "\\textcolor{##d6d8da}{#1}"); +defineMacro("\\grayE", "\\textcolor{##babec2}{#1}"); +defineMacro("\\grayF", "\\textcolor{##888d93}{#1}"); +defineMacro("\\grayG", "\\textcolor{##626569}{#1}"); +defineMacro("\\grayH", "\\textcolor{##3b3e40}{#1}"); +defineMacro("\\grayI", "\\textcolor{##21242c}{#1}"); +defineMacro("\\kaBlue", "\\textcolor{##314453}{#1}"); +defineMacro("\\kaGreen", "\\textcolor{##71B307}{#1}"); + +/** + * This file contains the “gullet” where macros are expanded + * until only non-macro tokens remain. + */ +// List of commands that act like macros but aren't defined as a macro, +// function, or symbol. Used in `isDefined`. +const implicitCommands = { + "\\relax": true, + // MacroExpander.js + "^": true, + // Parser.js + "_": true, + // Parser.js + "\\limits": true, + // Parser.js + "\\nolimits": true // Parser.js + +}; +class MacroExpander { + constructor(input, settings, mode) { + this.settings = void 0; + this.expansionCount = void 0; + this.lexer = void 0; + this.macros = void 0; + this.stack = void 0; + this.mode = void 0; + this.settings = settings; + this.expansionCount = 0; + this.feed(input); // Make new global namespace + + this.macros = new Namespace(builtinMacros, settings.macros); + this.mode = mode; + this.stack = []; // contains tokens in REVERSE order + } + /** + * Feed a new input string to the same MacroExpander + * (with existing macros etc.). + */ + + + feed(input) { + this.lexer = new Lexer(input, this.settings); + } + /** + * Switches between "text" and "math" modes. + */ + + + switchMode(newMode) { + this.mode = newMode; + } + /** + * Start a new group nesting within all namespaces. + */ + + + beginGroup() { + this.macros.beginGroup(); + } + /** + * End current group nesting within all namespaces. + */ + + + endGroup() { + this.macros.endGroup(); + } + /** + * Returns the topmost token on the stack, without expanding it. + * Similar in behavior to TeX's `\futurelet`. + */ + + + future() { + if (this.stack.length === 0) { + this.pushToken(this.lexer.lex()); + } + + return this.stack[this.stack.length - 1]; + } + /** + * Remove and return the next unexpanded token. + */ + + + popToken() { + this.future(); // ensure non-empty stack + + return this.stack.pop(); + } + /** + * Add a given token to the token stack. In particular, this get be used + * to put back a token returned from one of the other methods. + */ + + + pushToken(token) { + this.stack.push(token); + } + /** + * Append an array of tokens to the token stack. + */ + + + pushTokens(tokens) { + this.stack.push(...tokens); + } + /** + * Consume all following space tokens, without expansion. + */ + + + consumeSpaces() { + for (;;) { + const token = this.future(); + + if (token.text === " ") { + this.stack.pop(); + } else { + break; + } + } + } + /** + * Consume the specified number of arguments from the token stream, + * and return the resulting array of arguments. + */ + + + consumeArgs(numArgs) { + const args = []; // obtain arguments, either single token or balanced {…} group + + for (let i = 0; i < numArgs; ++i) { + this.consumeSpaces(); // ignore spaces before each argument + + const startOfArg = this.popToken(); + + if (startOfArg.text === "{") { + const arg = []; + let depth = 1; + + while (depth !== 0) { + const tok = this.popToken(); + arg.push(tok); + + if (tok.text === "{") { + ++depth; + } else if (tok.text === "}") { + --depth; + } else if (tok.text === "EOF") { + throw new ParseError("End of input in macro argument", startOfArg); + } + } + + arg.pop(); // remove last } + + arg.reverse(); // like above, to fit in with stack order + + args[i] = arg; + } else if (startOfArg.text === "EOF") { + throw new ParseError("End of input expecting macro argument"); + } else { + args[i] = [startOfArg]; + } + } + + return args; + } + /** + * Expand the next token only once if possible. + * + * If the token is expanded, the resulting tokens will be pushed onto + * the stack in reverse order and will be returned as an array, + * also in reverse order. + * + * If not, the next token will be returned without removing it + * from the stack. This case can be detected by a `Token` return value + * instead of an `Array` return value. + * + * In either case, the next token will be on the top of the stack, + * or the stack will be empty. + * + * Used to implement `expandAfterFuture` and `expandNextToken`. + * + * At the moment, macro expansion doesn't handle delimited macros, + * i.e. things like those defined by \def\foo#1\end{…}. + * See the TeX book page 202ff. for details on how those should behave. + */ + + + expandOnce() { + const topToken = this.popToken(); + const name = topToken.text; + + const expansion = this._getExpansion(name); + + if (expansion == null) { + // mainly checking for undefined here + // Fully expanded + this.pushToken(topToken); + return topToken; + } + + this.expansionCount++; + + if (this.expansionCount > this.settings.maxExpand) { + throw new ParseError("Too many expansions: infinite loop or " + "need to increase maxExpand setting"); + } + + let tokens = expansion.tokens; + + if (expansion.numArgs) { + const args = this.consumeArgs(expansion.numArgs); // paste arguments in place of the placeholders + + tokens = tokens.slice(); // make a shallow copy + + for (let i = tokens.length - 1; i >= 0; --i) { + let tok = tokens[i]; + + if (tok.text === "#") { + if (i === 0) { + throw new ParseError("Incomplete placeholder at end of macro body", tok); + } + + tok = tokens[--i]; // next token on stack + + if (tok.text === "#") { + // ## → # + tokens.splice(i + 1, 1); // drop first # + } else if (/^[1-9]$/.test(tok.text)) { + // replace the placeholder with the indicated argument + tokens.splice(i, 2, ...args[+tok.text - 1]); + } else { + throw new ParseError("Not a valid argument number", tok); + } + } + } + } // Concatenate expansion onto top of stack. + + + this.pushTokens(tokens); + return tokens; + } + /** + * Expand the next token only once (if possible), and return the resulting + * top token on the stack (without removing anything from the stack). + * Similar in behavior to TeX's `\expandafter\futurelet`. + * Equivalent to expandOnce() followed by future(). + */ + + + expandAfterFuture() { + this.expandOnce(); + return this.future(); + } + /** + * Recursively expand first token, then return first non-expandable token. + */ + + + expandNextToken() { + for (;;) { + const expanded = this.expandOnce(); // expandOnce returns Token if and only if it's fully expanded. + + if (expanded instanceof Token) { + // \relax stops the expansion, but shouldn't get returned (a + // null return value couldn't get implemented as a function). + if (expanded.text === "\\relax") { + this.stack.pop(); + } else { + return this.stack.pop(); // === expanded + } + } + } // Flow unable to figure out that this pathway is impossible. + // https://github.com/facebook/flow/issues/4808 + + + throw new Error(); // eslint-disable-line no-unreachable + } + /** + * Fully expand the given macro name and return the resulting list of + * tokens, or return `undefined` if no such macro is defined. + */ + + + expandMacro(name) { + if (!this.macros.get(name)) { + return undefined; + } + + const output = []; + const oldStackLength = this.stack.length; + this.pushToken(new Token(name)); + + while (this.stack.length > oldStackLength) { + const expanded = this.expandOnce(); // expandOnce returns Token if and only if it's fully expanded. + + if (expanded instanceof Token) { + output.push(this.stack.pop()); + } + } + + return output; + } + /** + * Fully expand the given macro name and return the result as a string, + * or return `undefined` if no such macro is defined. + */ + + + expandMacroAsText(name) { + const tokens = this.expandMacro(name); + + if (tokens) { + return tokens.map(token => token.text).join(""); + } else { + return tokens; + } + } + /** + * Returns the expanded macro as a reversed array of tokens and a macro + * argument count. Or returns `null` if no such macro. + */ + + + _getExpansion(name) { + const definition = this.macros.get(name); + + if (definition == null) { + // mainly checking for undefined here + return definition; + } + + const expansion = typeof definition === "function" ? definition(this) : definition; + + if (typeof expansion === "string") { + let numArgs = 0; + + if (expansion.indexOf("#") !== -1) { + const stripped = expansion.replace(/##/g, ""); + + while (stripped.indexOf("#" + (numArgs + 1)) !== -1) { + ++numArgs; + } + } + + const bodyLexer = new Lexer(expansion, this.settings); + const tokens = []; + let tok = bodyLexer.lex(); + + while (tok.text !== "EOF") { + tokens.push(tok); + tok = bodyLexer.lex(); + } + + tokens.reverse(); // to fit in with stack using push and pop + + const expanded = { + tokens, + numArgs + }; + return expanded; + } + + return expansion; + } + /** + * Determine whether a command is currently "defined" (has some + * functionality), meaning that it's a macro (in the current group), + * a function, a symbol, or one of the special commands listed in + * `implicitCommands`. + */ + + + isDefined(name) { + return this.macros.has(name) || functions.hasOwnProperty(name) || symbols.math.hasOwnProperty(name) || symbols.text.hasOwnProperty(name) || implicitCommands.hasOwnProperty(name); + } + +} + +// Mapping of Unicode accent characters to their LaTeX equivalent in text and +// math mode (when they exist). +var unicodeAccents = { + '\u0301': { + text: "\\'", + math: '\\acute' + }, + '\u0300': { + text: '\\`', + math: '\\grave' + }, + '\u0308': { + text: '\\"', + math: '\\ddot' + }, + '\u0303': { + text: '\\~', + math: '\\tilde' + }, + '\u0304': { + text: '\\=', + math: '\\bar' + }, + '\u0306': { + text: '\\u', + math: '\\breve' + }, + '\u030c': { + text: '\\v', + math: '\\check' + }, + '\u0302': { + text: '\\^', + math: '\\hat' + }, + '\u0307': { + text: '\\.', + math: '\\dot' + }, + '\u030a': { + text: '\\r', + math: '\\mathring' + }, + '\u030b': { + text: '\\H' + } +}; + +// This file is GENERATED by unicodeMake.js. DO NOT MODIFY. +var unicodeSymbols = { + "\u00e1": "\u0061\u0301", + // á = \'{a} + "\u00e0": "\u0061\u0300", + // à = \`{a} + "\u00e4": "\u0061\u0308", + // ä = \"{a} + "\u01df": "\u0061\u0308\u0304", + // ǟ = \"\={a} + "\u00e3": "\u0061\u0303", + // ã = \~{a} + "\u0101": "\u0061\u0304", + // ā = \={a} + "\u0103": "\u0061\u0306", + // ă = \u{a} + "\u1eaf": "\u0061\u0306\u0301", + // ắ = \u\'{a} + "\u1eb1": "\u0061\u0306\u0300", + // ằ = \u\`{a} + "\u1eb5": "\u0061\u0306\u0303", + // ẵ = \u\~{a} + "\u01ce": "\u0061\u030c", + // ǎ = \v{a} + "\u00e2": "\u0061\u0302", + // â = \^{a} + "\u1ea5": "\u0061\u0302\u0301", + // ấ = \^\'{a} + "\u1ea7": "\u0061\u0302\u0300", + // ầ = \^\`{a} + "\u1eab": "\u0061\u0302\u0303", + // ẫ = \^\~{a} + "\u0227": "\u0061\u0307", + // ȧ = \.{a} + "\u01e1": "\u0061\u0307\u0304", + // ǡ = \.\={a} + "\u00e5": "\u0061\u030a", + // å = \r{a} + "\u01fb": "\u0061\u030a\u0301", + // ǻ = \r\'{a} + "\u1e03": "\u0062\u0307", + // ḃ = \.{b} + "\u0107": "\u0063\u0301", + // ć = \'{c} + "\u010d": "\u0063\u030c", + // č = \v{c} + "\u0109": "\u0063\u0302", + // ĉ = \^{c} + "\u010b": "\u0063\u0307", + // ċ = \.{c} + "\u010f": "\u0064\u030c", + // ď = \v{d} + "\u1e0b": "\u0064\u0307", + // ḋ = \.{d} + "\u00e9": "\u0065\u0301", + // é = \'{e} + "\u00e8": "\u0065\u0300", + // è = \`{e} + "\u00eb": "\u0065\u0308", + // ë = \"{e} + "\u1ebd": "\u0065\u0303", + // ẽ = \~{e} + "\u0113": "\u0065\u0304", + // ē = \={e} + "\u1e17": "\u0065\u0304\u0301", + // ḗ = \=\'{e} + "\u1e15": "\u0065\u0304\u0300", + // ḕ = \=\`{e} + "\u0115": "\u0065\u0306", + // ĕ = \u{e} + "\u011b": "\u0065\u030c", + // ě = \v{e} + "\u00ea": "\u0065\u0302", + // ê = \^{e} + "\u1ebf": "\u0065\u0302\u0301", + // ế = \^\'{e} + "\u1ec1": "\u0065\u0302\u0300", + // ề = \^\`{e} + "\u1ec5": "\u0065\u0302\u0303", + // ễ = \^\~{e} + "\u0117": "\u0065\u0307", + // ė = \.{e} + "\u1e1f": "\u0066\u0307", + // ḟ = \.{f} + "\u01f5": "\u0067\u0301", + // ǵ = \'{g} + "\u1e21": "\u0067\u0304", + // ḡ = \={g} + "\u011f": "\u0067\u0306", + // ğ = \u{g} + "\u01e7": "\u0067\u030c", + // ǧ = \v{g} + "\u011d": "\u0067\u0302", + // ĝ = \^{g} + "\u0121": "\u0067\u0307", + // ġ = \.{g} + "\u1e27": "\u0068\u0308", + // ḧ = \"{h} + "\u021f": "\u0068\u030c", + // ȟ = \v{h} + "\u0125": "\u0068\u0302", + // ĥ = \^{h} + "\u1e23": "\u0068\u0307", + // ḣ = \.{h} + "\u00ed": "\u0069\u0301", + // í = \'{i} + "\u00ec": "\u0069\u0300", + // ì = \`{i} + "\u00ef": "\u0069\u0308", + // ï = \"{i} + "\u1e2f": "\u0069\u0308\u0301", + // ḯ = \"\'{i} + "\u0129": "\u0069\u0303", + // ĩ = \~{i} + "\u012b": "\u0069\u0304", + // ī = \={i} + "\u012d": "\u0069\u0306", + // ĭ = \u{i} + "\u01d0": "\u0069\u030c", + // ǐ = \v{i} + "\u00ee": "\u0069\u0302", + // î = \^{i} + "\u01f0": "\u006a\u030c", + // ǰ = \v{j} + "\u0135": "\u006a\u0302", + // ĵ = \^{j} + "\u1e31": "\u006b\u0301", + // ḱ = \'{k} + "\u01e9": "\u006b\u030c", + // ǩ = \v{k} + "\u013a": "\u006c\u0301", + // ĺ = \'{l} + "\u013e": "\u006c\u030c", + // ľ = \v{l} + "\u1e3f": "\u006d\u0301", + // ḿ = \'{m} + "\u1e41": "\u006d\u0307", + // ṁ = \.{m} + "\u0144": "\u006e\u0301", + // ń = \'{n} + "\u01f9": "\u006e\u0300", + // ǹ = \`{n} + "\u00f1": "\u006e\u0303", + // ñ = \~{n} + "\u0148": "\u006e\u030c", + // ň = \v{n} + "\u1e45": "\u006e\u0307", + // ṅ = \.{n} + "\u00f3": "\u006f\u0301", + // ó = \'{o} + "\u00f2": "\u006f\u0300", + // ò = \`{o} + "\u00f6": "\u006f\u0308", + // ö = \"{o} + "\u022b": "\u006f\u0308\u0304", + // ȫ = \"\={o} + "\u00f5": "\u006f\u0303", + // õ = \~{o} + "\u1e4d": "\u006f\u0303\u0301", + // ṍ = \~\'{o} + "\u1e4f": "\u006f\u0303\u0308", + // ṏ = \~\"{o} + "\u022d": "\u006f\u0303\u0304", + // ȭ = \~\={o} + "\u014d": "\u006f\u0304", + // ō = \={o} + "\u1e53": "\u006f\u0304\u0301", + // ṓ = \=\'{o} + "\u1e51": "\u006f\u0304\u0300", + // ṑ = \=\`{o} + "\u014f": "\u006f\u0306", + // ŏ = \u{o} + "\u01d2": "\u006f\u030c", + // ǒ = \v{o} + "\u00f4": "\u006f\u0302", + // ô = \^{o} + "\u1ed1": "\u006f\u0302\u0301", + // ố = \^\'{o} + "\u1ed3": "\u006f\u0302\u0300", + // ồ = \^\`{o} + "\u1ed7": "\u006f\u0302\u0303", + // ỗ = \^\~{o} + "\u022f": "\u006f\u0307", + // ȯ = \.{o} + "\u0231": "\u006f\u0307\u0304", + // ȱ = \.\={o} + "\u0151": "\u006f\u030b", + // ő = \H{o} + "\u1e55": "\u0070\u0301", + // ṕ = \'{p} + "\u1e57": "\u0070\u0307", + // ṗ = \.{p} + "\u0155": "\u0072\u0301", + // ŕ = \'{r} + "\u0159": "\u0072\u030c", + // ř = \v{r} + "\u1e59": "\u0072\u0307", + // ṙ = \.{r} + "\u015b": "\u0073\u0301", + // ś = \'{s} + "\u1e65": "\u0073\u0301\u0307", + // ṥ = \'\.{s} + "\u0161": "\u0073\u030c", + // š = \v{s} + "\u1e67": "\u0073\u030c\u0307", + // ṧ = \v\.{s} + "\u015d": "\u0073\u0302", + // ŝ = \^{s} + "\u1e61": "\u0073\u0307", + // ṡ = \.{s} + "\u1e97": "\u0074\u0308", + // ẗ = \"{t} + "\u0165": "\u0074\u030c", + // ť = \v{t} + "\u1e6b": "\u0074\u0307", + // ṫ = \.{t} + "\u00fa": "\u0075\u0301", + // ú = \'{u} + "\u00f9": "\u0075\u0300", + // ù = \`{u} + "\u00fc": "\u0075\u0308", + // ü = \"{u} + "\u01d8": "\u0075\u0308\u0301", + // ǘ = \"\'{u} + "\u01dc": "\u0075\u0308\u0300", + // ǜ = \"\`{u} + "\u01d6": "\u0075\u0308\u0304", + // ǖ = \"\={u} + "\u01da": "\u0075\u0308\u030c", + // ǚ = \"\v{u} + "\u0169": "\u0075\u0303", + // ũ = \~{u} + "\u1e79": "\u0075\u0303\u0301", + // ṹ = \~\'{u} + "\u016b": "\u0075\u0304", + // ū = \={u} + "\u1e7b": "\u0075\u0304\u0308", + // ṻ = \=\"{u} + "\u016d": "\u0075\u0306", + // ŭ = \u{u} + "\u01d4": "\u0075\u030c", + // ǔ = \v{u} + "\u00fb": "\u0075\u0302", + // û = \^{u} + "\u016f": "\u0075\u030a", + // ů = \r{u} + "\u0171": "\u0075\u030b", + // ű = \H{u} + "\u1e7d": "\u0076\u0303", + // ṽ = \~{v} + "\u1e83": "\u0077\u0301", + // ẃ = \'{w} + "\u1e81": "\u0077\u0300", + // ẁ = \`{w} + "\u1e85": "\u0077\u0308", + // ẅ = \"{w} + "\u0175": "\u0077\u0302", + // ŵ = \^{w} + "\u1e87": "\u0077\u0307", + // ẇ = \.{w} + "\u1e98": "\u0077\u030a", + // ẘ = \r{w} + "\u1e8d": "\u0078\u0308", + // ẍ = \"{x} + "\u1e8b": "\u0078\u0307", + // ẋ = \.{x} + "\u00fd": "\u0079\u0301", + // ý = \'{y} + "\u1ef3": "\u0079\u0300", + // ỳ = \`{y} + "\u00ff": "\u0079\u0308", + // ÿ = \"{y} + "\u1ef9": "\u0079\u0303", + // ỹ = \~{y} + "\u0233": "\u0079\u0304", + // ȳ = \={y} + "\u0177": "\u0079\u0302", + // ŷ = \^{y} + "\u1e8f": "\u0079\u0307", + // ẏ = \.{y} + "\u1e99": "\u0079\u030a", + // ẙ = \r{y} + "\u017a": "\u007a\u0301", + // ź = \'{z} + "\u017e": "\u007a\u030c", + // ž = \v{z} + "\u1e91": "\u007a\u0302", + // ẑ = \^{z} + "\u017c": "\u007a\u0307", + // ż = \.{z} + "\u00c1": "\u0041\u0301", + // Á = \'{A} + "\u00c0": "\u0041\u0300", + // À = \`{A} + "\u00c4": "\u0041\u0308", + // Ä = \"{A} + "\u01de": "\u0041\u0308\u0304", + // Ǟ = \"\={A} + "\u00c3": "\u0041\u0303", + // Ã = \~{A} + "\u0100": "\u0041\u0304", + // Ā = \={A} + "\u0102": "\u0041\u0306", + // Ă = \u{A} + "\u1eae": "\u0041\u0306\u0301", + // Ắ = \u\'{A} + "\u1eb0": "\u0041\u0306\u0300", + // Ằ = \u\`{A} + "\u1eb4": "\u0041\u0306\u0303", + // Ẵ = \u\~{A} + "\u01cd": "\u0041\u030c", + // Ǎ = \v{A} + "\u00c2": "\u0041\u0302", + // Â = \^{A} + "\u1ea4": "\u0041\u0302\u0301", + // Ấ = \^\'{A} + "\u1ea6": "\u0041\u0302\u0300", + // Ầ = \^\`{A} + "\u1eaa": "\u0041\u0302\u0303", + // Ẫ = \^\~{A} + "\u0226": "\u0041\u0307", + // Ȧ = \.{A} + "\u01e0": "\u0041\u0307\u0304", + // Ǡ = \.\={A} + "\u00c5": "\u0041\u030a", + // Å = \r{A} + "\u01fa": "\u0041\u030a\u0301", + // Ǻ = \r\'{A} + "\u1e02": "\u0042\u0307", + // Ḃ = \.{B} + "\u0106": "\u0043\u0301", + // Ć = \'{C} + "\u010c": "\u0043\u030c", + // Č = \v{C} + "\u0108": "\u0043\u0302", + // Ĉ = \^{C} + "\u010a": "\u0043\u0307", + // Ċ = \.{C} + "\u010e": "\u0044\u030c", + // Ď = \v{D} + "\u1e0a": "\u0044\u0307", + // Ḋ = \.{D} + "\u00c9": "\u0045\u0301", + // É = \'{E} + "\u00c8": "\u0045\u0300", + // È = \`{E} + "\u00cb": "\u0045\u0308", + // Ë = \"{E} + "\u1ebc": "\u0045\u0303", + // Ẽ = \~{E} + "\u0112": "\u0045\u0304", + // Ē = \={E} + "\u1e16": "\u0045\u0304\u0301", + // Ḗ = \=\'{E} + "\u1e14": "\u0045\u0304\u0300", + // Ḕ = \=\`{E} + "\u0114": "\u0045\u0306", + // Ĕ = \u{E} + "\u011a": "\u0045\u030c", + // Ě = \v{E} + "\u00ca": "\u0045\u0302", + // Ê = \^{E} + "\u1ebe": "\u0045\u0302\u0301", + // Ế = \^\'{E} + "\u1ec0": "\u0045\u0302\u0300", + // Ề = \^\`{E} + "\u1ec4": "\u0045\u0302\u0303", + // Ễ = \^\~{E} + "\u0116": "\u0045\u0307", + // Ė = \.{E} + "\u1e1e": "\u0046\u0307", + // Ḟ = \.{F} + "\u01f4": "\u0047\u0301", + // Ǵ = \'{G} + "\u1e20": "\u0047\u0304", + // Ḡ = \={G} + "\u011e": "\u0047\u0306", + // Ğ = \u{G} + "\u01e6": "\u0047\u030c", + // Ǧ = \v{G} + "\u011c": "\u0047\u0302", + // Ĝ = \^{G} + "\u0120": "\u0047\u0307", + // Ġ = \.{G} + "\u1e26": "\u0048\u0308", + // Ḧ = \"{H} + "\u021e": "\u0048\u030c", + // Ȟ = \v{H} + "\u0124": "\u0048\u0302", + // Ĥ = \^{H} + "\u1e22": "\u0048\u0307", + // Ḣ = \.{H} + "\u00cd": "\u0049\u0301", + // Í = \'{I} + "\u00cc": "\u0049\u0300", + // Ì = \`{I} + "\u00cf": "\u0049\u0308", + // Ï = \"{I} + "\u1e2e": "\u0049\u0308\u0301", + // Ḯ = \"\'{I} + "\u0128": "\u0049\u0303", + // Ĩ = \~{I} + "\u012a": "\u0049\u0304", + // Ī = \={I} + "\u012c": "\u0049\u0306", + // Ĭ = \u{I} + "\u01cf": "\u0049\u030c", + // Ǐ = \v{I} + "\u00ce": "\u0049\u0302", + // Î = \^{I} + "\u0130": "\u0049\u0307", + // İ = \.{I} + "\u0134": "\u004a\u0302", + // Ĵ = \^{J} + "\u1e30": "\u004b\u0301", + // Ḱ = \'{K} + "\u01e8": "\u004b\u030c", + // Ǩ = \v{K} + "\u0139": "\u004c\u0301", + // Ĺ = \'{L} + "\u013d": "\u004c\u030c", + // Ľ = \v{L} + "\u1e3e": "\u004d\u0301", + // Ḿ = \'{M} + "\u1e40": "\u004d\u0307", + // Ṁ = \.{M} + "\u0143": "\u004e\u0301", + // Ń = \'{N} + "\u01f8": "\u004e\u0300", + // Ǹ = \`{N} + "\u00d1": "\u004e\u0303", + // Ñ = \~{N} + "\u0147": "\u004e\u030c", + // Ň = \v{N} + "\u1e44": "\u004e\u0307", + // Ṅ = \.{N} + "\u00d3": "\u004f\u0301", + // Ó = \'{O} + "\u00d2": "\u004f\u0300", + // Ò = \`{O} + "\u00d6": "\u004f\u0308", + // Ö = \"{O} + "\u022a": "\u004f\u0308\u0304", + // Ȫ = \"\={O} + "\u00d5": "\u004f\u0303", + // Õ = \~{O} + "\u1e4c": "\u004f\u0303\u0301", + // Ṍ = \~\'{O} + "\u1e4e": "\u004f\u0303\u0308", + // Ṏ = \~\"{O} + "\u022c": "\u004f\u0303\u0304", + // Ȭ = \~\={O} + "\u014c": "\u004f\u0304", + // Ō = \={O} + "\u1e52": "\u004f\u0304\u0301", + // Ṓ = \=\'{O} + "\u1e50": "\u004f\u0304\u0300", + // Ṑ = \=\`{O} + "\u014e": "\u004f\u0306", + // Ŏ = \u{O} + "\u01d1": "\u004f\u030c", + // Ǒ = \v{O} + "\u00d4": "\u004f\u0302", + // Ô = \^{O} + "\u1ed0": "\u004f\u0302\u0301", + // Ố = \^\'{O} + "\u1ed2": "\u004f\u0302\u0300", + // Ồ = \^\`{O} + "\u1ed6": "\u004f\u0302\u0303", + // Ỗ = \^\~{O} + "\u022e": "\u004f\u0307", + // Ȯ = \.{O} + "\u0230": "\u004f\u0307\u0304", + // Ȱ = \.\={O} + "\u0150": "\u004f\u030b", + // Ő = \H{O} + "\u1e54": "\u0050\u0301", + // Ṕ = \'{P} + "\u1e56": "\u0050\u0307", + // Ṗ = \.{P} + "\u0154": "\u0052\u0301", + // Ŕ = \'{R} + "\u0158": "\u0052\u030c", + // Ř = \v{R} + "\u1e58": "\u0052\u0307", + // Ṙ = \.{R} + "\u015a": "\u0053\u0301", + // Ś = \'{S} + "\u1e64": "\u0053\u0301\u0307", + // Ṥ = \'\.{S} + "\u0160": "\u0053\u030c", + // Š = \v{S} + "\u1e66": "\u0053\u030c\u0307", + // Ṧ = \v\.{S} + "\u015c": "\u0053\u0302", + // Ŝ = \^{S} + "\u1e60": "\u0053\u0307", + // Ṡ = \.{S} + "\u0164": "\u0054\u030c", + // Ť = \v{T} + "\u1e6a": "\u0054\u0307", + // Ṫ = \.{T} + "\u00da": "\u0055\u0301", + // Ú = \'{U} + "\u00d9": "\u0055\u0300", + // Ù = \`{U} + "\u00dc": "\u0055\u0308", + // Ü = \"{U} + "\u01d7": "\u0055\u0308\u0301", + // Ǘ = \"\'{U} + "\u01db": "\u0055\u0308\u0300", + // Ǜ = \"\`{U} + "\u01d5": "\u0055\u0308\u0304", + // Ǖ = \"\={U} + "\u01d9": "\u0055\u0308\u030c", + // Ǚ = \"\v{U} + "\u0168": "\u0055\u0303", + // Ũ = \~{U} + "\u1e78": "\u0055\u0303\u0301", + // Ṹ = \~\'{U} + "\u016a": "\u0055\u0304", + // Ū = \={U} + "\u1e7a": "\u0055\u0304\u0308", + // Ṻ = \=\"{U} + "\u016c": "\u0055\u0306", + // Ŭ = \u{U} + "\u01d3": "\u0055\u030c", + // Ǔ = \v{U} + "\u00db": "\u0055\u0302", + // Û = \^{U} + "\u016e": "\u0055\u030a", + // Ů = \r{U} + "\u0170": "\u0055\u030b", + // Ű = \H{U} + "\u1e7c": "\u0056\u0303", + // Ṽ = \~{V} + "\u1e82": "\u0057\u0301", + // Ẃ = \'{W} + "\u1e80": "\u0057\u0300", + // Ẁ = \`{W} + "\u1e84": "\u0057\u0308", + // Ẅ = \"{W} + "\u0174": "\u0057\u0302", + // Ŵ = \^{W} + "\u1e86": "\u0057\u0307", + // Ẇ = \.{W} + "\u1e8c": "\u0058\u0308", + // Ẍ = \"{X} + "\u1e8a": "\u0058\u0307", + // Ẋ = \.{X} + "\u00dd": "\u0059\u0301", + // Ý = \'{Y} + "\u1ef2": "\u0059\u0300", + // Ỳ = \`{Y} + "\u0178": "\u0059\u0308", + // Ÿ = \"{Y} + "\u1ef8": "\u0059\u0303", + // Ỹ = \~{Y} + "\u0232": "\u0059\u0304", + // Ȳ = \={Y} + "\u0176": "\u0059\u0302", + // Ŷ = \^{Y} + "\u1e8e": "\u0059\u0307", + // Ẏ = \.{Y} + "\u0179": "\u005a\u0301", + // Ź = \'{Z} + "\u017d": "\u005a\u030c", + // Ž = \v{Z} + "\u1e90": "\u005a\u0302", + // Ẑ = \^{Z} + "\u017b": "\u005a\u0307", + // Ż = \.{Z} + "\u03ac": "\u03b1\u0301", + // ά = \'{α} + "\u1f70": "\u03b1\u0300", + // ὰ = \`{α} + "\u1fb1": "\u03b1\u0304", + // ᾱ = \={α} + "\u1fb0": "\u03b1\u0306", + // ᾰ = \u{α} + "\u03ad": "\u03b5\u0301", + // έ = \'{ε} + "\u1f72": "\u03b5\u0300", + // ὲ = \`{ε} + "\u03ae": "\u03b7\u0301", + // ή = \'{η} + "\u1f74": "\u03b7\u0300", + // ὴ = \`{η} + "\u03af": "\u03b9\u0301", + // ί = \'{ι} + "\u1f76": "\u03b9\u0300", + // ὶ = \`{ι} + "\u03ca": "\u03b9\u0308", + // ϊ = \"{ι} + "\u0390": "\u03b9\u0308\u0301", + // ΐ = \"\'{ι} + "\u1fd2": "\u03b9\u0308\u0300", + // ῒ = \"\`{ι} + "\u1fd1": "\u03b9\u0304", + // ῑ = \={ι} + "\u1fd0": "\u03b9\u0306", + // ῐ = \u{ι} + "\u03cc": "\u03bf\u0301", + // ό = \'{ο} + "\u1f78": "\u03bf\u0300", + // ὸ = \`{ο} + "\u03cd": "\u03c5\u0301", + // ύ = \'{υ} + "\u1f7a": "\u03c5\u0300", + // ὺ = \`{υ} + "\u03cb": "\u03c5\u0308", + // ϋ = \"{υ} + "\u03b0": "\u03c5\u0308\u0301", + // ΰ = \"\'{υ} + "\u1fe2": "\u03c5\u0308\u0300", + // ῢ = \"\`{υ} + "\u1fe1": "\u03c5\u0304", + // ῡ = \={υ} + "\u1fe0": "\u03c5\u0306", + // ῠ = \u{υ} + "\u03ce": "\u03c9\u0301", + // ώ = \'{ω} + "\u1f7c": "\u03c9\u0300", + // ὼ = \`{ω} + "\u038e": "\u03a5\u0301", + // Ύ = \'{Υ} + "\u1fea": "\u03a5\u0300", + // Ὺ = \`{Υ} + "\u03ab": "\u03a5\u0308", + // Ϋ = \"{Υ} + "\u1fe9": "\u03a5\u0304", + // Ῡ = \={Υ} + "\u1fe8": "\u03a5\u0306", + // Ῠ = \u{Υ} + "\u038f": "\u03a9\u0301", + // Ώ = \'{Ω} + "\u1ffa": "\u03a9\u0300" // Ὼ = \`{Ω} + +}; + +/* eslint no-constant-condition:0 */ + +/** + * This file contains the parser used to parse out a TeX expression from the + * input. Since TeX isn't context-free, standard parsers don't work particularly + * well. + * + * The strategy of this parser is as such: + * + * The main functions (the `.parse...` ones) take a position in the current + * parse string to parse tokens from. The lexer (found in Lexer.js, stored at + * this.gullet.lexer) also supports pulling out tokens at arbitrary places. When + * individual tokens are needed at a position, the lexer is called to pull out a + * token, which is then used. + * + * The parser has a property called "mode" indicating the mode that + * the parser is currently in. Currently it has to be one of "math" or + * "text", which denotes whether the current environment is a math-y + * one or a text-y one (e.g. inside \text). Currently, this serves to + * limit the functions which can be used in text mode. + * + * The main functions then return an object which contains the useful data that + * was parsed at its given point, and a new position at the end of the parsed + * data. The main functions can call each other and continue the parsing by + * using the returned position as a new starting point. + * + * There are also extra `.handle...` functions, which pull out some reused + * functionality into self-contained functions. + * + * The functions return ParseNodes. + */ +class Parser { + constructor(input, settings) { + this.mode = void 0; + this.gullet = void 0; + this.settings = void 0; + this.leftrightDepth = void 0; + this.nextToken = void 0; + // Start in math mode + this.mode = "math"; // Create a new macro expander (gullet) and (indirectly via that) also a + // new lexer (mouth) for this parser (stomach, in the language of TeX) + + this.gullet = new MacroExpander(input, settings, this.mode); // Store the settings for use in parsing + + this.settings = settings; // Count leftright depth (for \middle errors) + + this.leftrightDepth = 0; + } + /** + * Checks a result to make sure it has the right type, and throws an + * appropriate error otherwise. + */ + + + expect(text, consume) { + if (consume === void 0) { + consume = true; + } + + if (this.fetch().text !== text) { + throw new ParseError(`Expected '${text}', got '${this.fetch().text}'`, this.fetch()); + } + + if (consume) { + this.consume(); + } + } + /** + * Discards the current lookahead token, considering it consumed. + */ + + + consume() { + this.nextToken = null; + } + /** + * Return the current lookahead token, or if there isn't one (at the + * beginning, or if the previous lookahead token was consume()d), + * fetch the next token as the new lookahead token and return it. + */ + + + fetch() { + if (this.nextToken == null) { + this.nextToken = this.gullet.expandNextToken(); + } + + return this.nextToken; + } + /** + * Switches between "text" and "math" modes. + */ + + + switchMode(newMode) { + this.mode = newMode; + this.gullet.switchMode(newMode); + } + /** + * Main parsing function, which parses an entire input. + */ + + + parse() { + // Create a group namespace for the math expression. + // (LaTeX creates a new group for every $...$, $$...$$, \[...\].) + this.gullet.beginGroup(); // Use old \color behavior (same as LaTeX's \textcolor) if requested. + // We do this within the group for the math expression, so it doesn't + // pollute settings.macros. + + if (this.settings.colorIsTextColor) { + this.gullet.macros.set("\\color", "\\textcolor"); + } // Try to parse the input + + + const parse = this.parseExpression(false); // If we succeeded, make sure there's an EOF at the end + + this.expect("EOF"); // End the group namespace for the expression + + this.gullet.endGroup(); + return parse; + } + + parseExpression(breakOnInfix, breakOnTokenText) { + const body = []; // Keep adding atoms to the body until we can't parse any more atoms (either + // we reached the end, a }, or a \right) + + while (true) { + // Ignore spaces in math mode + if (this.mode === "math") { + this.consumeSpaces(); + } + + const lex = this.fetch(); + + if (Parser.endOfExpression.indexOf(lex.text) !== -1) { + break; + } + + if (breakOnTokenText && lex.text === breakOnTokenText) { + break; + } + + if (breakOnInfix && functions[lex.text] && functions[lex.text].infix) { + break; + } + + const atom = this.parseAtom(breakOnTokenText); + + if (!atom) { + break; + } + + body.push(atom); + } + + if (this.mode === "text") { + this.formLigatures(body); + } + + return this.handleInfixNodes(body); + } + /** + * Rewrites infix operators such as \over with corresponding commands such + * as \frac. + * + * There can only be one infix operator per group. If there's more than one + * then the expression is ambiguous. This can be resolved by adding {}. + */ + + + handleInfixNodes(body) { + let overIndex = -1; + let funcName; + + for (let i = 0; i < body.length; i++) { + const node = checkNodeType(body[i], "infix"); + + if (node) { + if (overIndex !== -1) { + throw new ParseError("only one infix operator per group", node.token); + } + + overIndex = i; + funcName = node.replaceWith; + } + } + + if (overIndex !== -1 && funcName) { + let numerNode; + let denomNode; + const numerBody = body.slice(0, overIndex); + const denomBody = body.slice(overIndex + 1); + + if (numerBody.length === 1 && numerBody[0].type === "ordgroup") { + numerNode = numerBody[0]; + } else { + numerNode = { + type: "ordgroup", + mode: this.mode, + body: numerBody + }; + } + + if (denomBody.length === 1 && denomBody[0].type === "ordgroup") { + denomNode = denomBody[0]; + } else { + denomNode = { + type: "ordgroup", + mode: this.mode, + body: denomBody + }; + } + + let node; + + if (funcName === "\\\\abovefrac") { + node = this.callFunction(funcName, [numerNode, body[overIndex], denomNode], []); + } else { + node = this.callFunction(funcName, [numerNode, denomNode], []); + } + + return [node]; + } else { + return body; + } + } // The greediness of a superscript or subscript + + + /** + * Handle a subscript or superscript with nice errors. + */ + handleSupSubscript(name) { + const symbolToken = this.fetch(); + const symbol = symbolToken.text; + this.consume(); + const group = this.parseGroup(name, false, Parser.SUPSUB_GREEDINESS, undefined, undefined, true); // ignore spaces before sup/subscript argument + + if (!group) { + throw new ParseError("Expected group after '" + symbol + "'", symbolToken); + } + + return group; + } + /** + * Converts the textual input of an unsupported command into a text node + * contained within a color node whose color is determined by errorColor + */ + + + formatUnsupportedCmd(text) { + const textordArray = []; + + for (let i = 0; i < text.length; i++) { + textordArray.push({ + type: "textord", + mode: "text", + text: text[i] + }); + } + + const textNode = { + type: "text", + mode: this.mode, + body: textordArray + }; + const colorNode = { + type: "color", + mode: this.mode, + color: this.settings.errorColor, + body: [textNode] + }; + return colorNode; + } + /** + * Parses a group with optional super/subscripts. + */ + + + parseAtom(breakOnTokenText) { + // The body of an atom is an implicit group, so that things like + // \left(x\right)^2 work correctly. + const base = this.parseGroup("atom", false, null, breakOnTokenText); // In text mode, we don't have superscripts or subscripts + + if (this.mode === "text") { + return base; + } // Note that base may be empty (i.e. null) at this point. + + + let superscript; + let subscript; + + while (true) { + // Guaranteed in math mode, so eat any spaces first. + this.consumeSpaces(); // Lex the first token + + const lex = this.fetch(); + + if (lex.text === "\\limits" || lex.text === "\\nolimits") { + // We got a limit control + let opNode = checkNodeType(base, "op"); + + if (opNode) { + const limits = lex.text === "\\limits"; + opNode.limits = limits; + opNode.alwaysHandleSupSub = true; + } else { + opNode = checkNodeType(base, "operatorname"); + + if (opNode && opNode.alwaysHandleSupSub) { + const limits = lex.text === "\\limits"; + opNode.limits = limits; + } else { + throw new ParseError("Limit controls must follow a math operator", lex); + } + } + + this.consume(); + } else if (lex.text === "^") { + // We got a superscript start + if (superscript) { + throw new ParseError("Double superscript", lex); + } + + superscript = this.handleSupSubscript("superscript"); + } else if (lex.text === "_") { + // We got a subscript start + if (subscript) { + throw new ParseError("Double subscript", lex); + } + + subscript = this.handleSupSubscript("subscript"); + } else if (lex.text === "'") { + // We got a prime + if (superscript) { + throw new ParseError("Double superscript", lex); + } + + const prime = { + type: "textord", + mode: this.mode, + text: "\\prime" + }; // Many primes can be grouped together, so we handle this here + + const primes = [prime]; + this.consume(); // Keep lexing tokens until we get something that's not a prime + + while (this.fetch().text === "'") { + // For each one, add another prime to the list + primes.push(prime); + this.consume(); + } // If there's a superscript following the primes, combine that + // superscript in with the primes. + + + if (this.fetch().text === "^") { + primes.push(this.handleSupSubscript("superscript")); + } // Put everything into an ordgroup as the superscript + + + superscript = { + type: "ordgroup", + mode: this.mode, + body: primes + }; + } else { + // If it wasn't ^, _, or ', stop parsing super/subscripts + break; + } + } // Base must be set if superscript or subscript are set per logic above, + // but need to check here for type check to pass. + + + if (superscript || subscript) { + // If we got either a superscript or subscript, create a supsub + return { + type: "supsub", + mode: this.mode, + base: base, + sup: superscript, + sub: subscript + }; + } else { + // Otherwise return the original body + return base; + } + } + /** + * Parses an entire function, including its base and all of its arguments. + */ + + + parseFunction(breakOnTokenText, name, // For error reporting. + greediness) { + const token = this.fetch(); + const func = token.text; + const funcData = functions[func]; + + if (!funcData) { + return null; + } + + this.consume(); // consume command token + + if (greediness != null && funcData.greediness <= greediness) { + throw new ParseError("Got function '" + func + "' with no arguments" + (name ? " as " + name : ""), token); + } else if (this.mode === "text" && !funcData.allowedInText) { + throw new ParseError("Can't use function '" + func + "' in text mode", token); + } else if (this.mode === "math" && funcData.allowedInMath === false) { + throw new ParseError("Can't use function '" + func + "' in math mode", token); + } + + const _this$parseArguments = this.parseArguments(func, funcData), + args = _this$parseArguments.args, + optArgs = _this$parseArguments.optArgs; + + return this.callFunction(func, args, optArgs, token, breakOnTokenText); + } + /** + * Call a function handler with a suitable context and arguments. + */ + + + callFunction(name, args, optArgs, token, breakOnTokenText) { + const context = { + funcName: name, + parser: this, + token, + breakOnTokenText + }; + const func = functions[name]; + + if (func && func.handler) { + return func.handler(context, args, optArgs); + } else { + throw new ParseError(`No function handler for ${name}`); + } + } + /** + * Parses the arguments of a function or environment + */ + + + parseArguments(func, // Should look like "\name" or "\begin{name}". + funcData) { + const totalArgs = funcData.numArgs + funcData.numOptionalArgs; + + if (totalArgs === 0) { + return { + args: [], + optArgs: [] + }; + } + + const baseGreediness = funcData.greediness; + const args = []; + const optArgs = []; + + for (let i = 0; i < totalArgs; i++) { + const argType = funcData.argTypes && funcData.argTypes[i]; + const isOptional = i < funcData.numOptionalArgs; // Ignore spaces between arguments. As the TeXbook says: + // "After you have said ‘\def\row#1#2{...}’, you are allowed to + // put spaces between the arguments (e.g., ‘\row x n’), because + // TeX doesn’t use single spaces as undelimited arguments." + + const consumeSpaces = i > 0 && !isOptional || // Also consume leading spaces in math mode, as parseSymbol + // won't know what to do with them. This can only happen with + // macros, e.g. \frac\foo\foo where \foo expands to a space symbol. + // In LaTeX, the \foo's get treated as (blank) arguments. + // In KaTeX, for now, both spaces will get consumed. + // TODO(edemaine) + i === 0 && !isOptional && this.mode === "math"; + const arg = this.parseGroupOfType(`argument to '${func}'`, argType, isOptional, baseGreediness, consumeSpaces); + + if (!arg) { + if (isOptional) { + optArgs.push(null); + continue; + } + + throw new ParseError(`Expected group after '${func}'`, this.fetch()); + } + + (isOptional ? optArgs : args).push(arg); + } + + return { + args, + optArgs + }; + } + /** + * Parses a group when the mode is changing. + */ + + + parseGroupOfType(name, type, optional, greediness, consumeSpaces) { + switch (type) { + case "color": + if (consumeSpaces) { + this.consumeSpaces(); + } + + return this.parseColorGroup(optional); + + case "size": + if (consumeSpaces) { + this.consumeSpaces(); + } + + return this.parseSizeGroup(optional); + + case "url": + return this.parseUrlGroup(optional, consumeSpaces); + + case "math": + case "text": + return this.parseGroup(name, optional, greediness, undefined, type, consumeSpaces); + + case "hbox": + { + // hbox argument type wraps the argument in the equivalent of + // \hbox, which is like \text but switching to \textstyle size. + const group = this.parseGroup(name, optional, greediness, undefined, "text", consumeSpaces); + + if (!group) { + return group; + } + + const styledGroup = { + type: "styling", + mode: group.mode, + body: [group], + style: "text" // simulate \textstyle + + }; + return styledGroup; + } + + case "raw": + { + if (consumeSpaces) { + this.consumeSpaces(); + } + + if (optional && this.fetch().text === "{") { + return null; + } + + const token = this.parseStringGroup("raw", optional, true); + + if (token) { + return { + type: "raw", + mode: "text", + string: token.text + }; + } else { + throw new ParseError("Expected raw group", this.fetch()); + } + } + + case "original": + case null: + case undefined: + return this.parseGroup(name, optional, greediness, undefined, undefined, consumeSpaces); + + default: + throw new ParseError("Unknown group type as " + name, this.fetch()); + } + } + /** + * Discard any space tokens, fetching the next non-space token. + */ + + + consumeSpaces() { + while (this.fetch().text === " ") { + this.consume(); + } + } + /** + * Parses a group, essentially returning the string formed by the + * brace-enclosed tokens plus some position information. + */ + + + parseStringGroup(modeName, // Used to describe the mode in error messages. + optional, raw) { + const groupBegin = optional ? "[" : "{"; + const groupEnd = optional ? "]" : "}"; + const beginToken = this.fetch(); + + if (beginToken.text !== groupBegin) { + if (optional) { + return null; + } else if (raw && beginToken.text !== "EOF" && /[^{}[\]]/.test(beginToken.text)) { + this.consume(); + return beginToken; + } + } + + const outerMode = this.mode; + this.mode = "text"; + this.expect(groupBegin); + let str = ""; + const firstToken = this.fetch(); + let nested = 0; // allow nested braces in raw string group + + let lastToken = firstToken; + let nextToken; + + while ((nextToken = this.fetch()).text !== groupEnd || raw && nested > 0) { + switch (nextToken.text) { + case "EOF": + throw new ParseError("Unexpected end of input in " + modeName, firstToken.range(lastToken, str)); + + case groupBegin: + nested++; + break; + + case groupEnd: + nested--; + break; + } + + lastToken = nextToken; + str += lastToken.text; + this.consume(); + } + + this.expect(groupEnd); + this.mode = outerMode; + return firstToken.range(lastToken, str); + } + /** + * Parses a regex-delimited group: the largest sequence of tokens + * whose concatenated strings match `regex`. Returns the string + * formed by the tokens plus some position information. + */ + + + parseRegexGroup(regex, modeName) { + const outerMode = this.mode; + this.mode = "text"; + const firstToken = this.fetch(); + let lastToken = firstToken; + let str = ""; + let nextToken; + + while ((nextToken = this.fetch()).text !== "EOF" && regex.test(str + nextToken.text)) { + lastToken = nextToken; + str += lastToken.text; + this.consume(); + } + + if (str === "") { + throw new ParseError("Invalid " + modeName + ": '" + firstToken.text + "'", firstToken); + } + + this.mode = outerMode; + return firstToken.range(lastToken, str); + } + /** + * Parses a color description. + */ + + + parseColorGroup(optional) { + const res = this.parseStringGroup("color", optional); + + if (!res) { + return null; + } + + const match = /^(#[a-f0-9]{3}|#?[a-f0-9]{6}|[a-z]+)$/i.exec(res.text); + + if (!match) { + throw new ParseError("Invalid color: '" + res.text + "'", res); + } + + let color = match[0]; + + if (/^[0-9a-f]{6}$/i.test(color)) { + // We allow a 6-digit HTML color spec without a leading "#". + // This follows the xcolor package's HTML color model. + // Predefined color names are all missed by this RegEx pattern. + color = "#" + color; + } + + return { + type: "color-token", + mode: this.mode, + color + }; + } + /** + * Parses a size specification, consisting of magnitude and unit. + */ + + + parseSizeGroup(optional) { + let res; + let isBlank = false; + + if (!optional && this.fetch().text !== "{") { + res = this.parseRegexGroup(/^[-+]? *(?:$|\d+|\d+\.\d*|\.\d*) *[a-z]{0,2} *$/, "size"); + } else { + res = this.parseStringGroup("size", optional); + } + + if (!res) { + return null; + } + + if (!optional && res.text.length === 0) { + // Because we've tested for what is !optional, this block won't + // affect \kern, \hspace, etc. It will capture the mandatory arguments + // to \genfrac and \above. + res.text = "0pt"; // Enable \above{} + + isBlank = true; // This is here specifically for \genfrac + } + + const match = /([-+]?) *(\d+(?:\.\d*)?|\.\d+) *([a-z]{2})/.exec(res.text); + + if (!match) { + throw new ParseError("Invalid size: '" + res.text + "'", res); + } + + const data = { + number: +(match[1] + match[2]), + // sign + magnitude, cast to number + unit: match[3] + }; + + if (!validUnit(data)) { + throw new ParseError("Invalid unit: '" + data.unit + "'", res); + } + + return { + type: "size", + mode: this.mode, + value: data, + isBlank + }; + } + /** + * Parses an URL, checking escaped letters and allowed protocols, + * and setting the catcode of % as an active character (as in \hyperref). + */ + + + parseUrlGroup(optional, consumeSpaces) { + this.gullet.lexer.setCatcode("%", 13); // active character + + const res = this.parseStringGroup("url", optional, true); // get raw string + + this.gullet.lexer.setCatcode("%", 14); // comment character + + if (!res) { + return null; + } // hyperref package allows backslashes alone in href, but doesn't + // generate valid links in such cases; we interpret this as + // "undefined" behaviour, and keep them as-is. Some browser will + // replace backslashes with forward slashes. + + + const url = res.text.replace(/\\([#$%&~_^{}])/g, '$1'); + return { + type: "url", + mode: this.mode, + url + }; + } + /** + * If `optional` is false or absent, this parses an ordinary group, + * which is either a single nucleus (like "x") or an expression + * in braces (like "{x+y}") or an implicit group, a group that starts + * at the current position, and ends right before a higher explicit + * group ends, or at EOF. + * If `optional` is true, it parses either a bracket-delimited expression + * (like "[x+y]") or returns null to indicate the absence of a + * bracket-enclosed group. + * If `mode` is present, switches to that mode while parsing the group, + * and switches back after. + */ + + + parseGroup(name, // For error reporting. + optional, greediness, breakOnTokenText, mode, consumeSpaces) { + // Switch to specified mode + const outerMode = this.mode; + + if (mode) { + this.switchMode(mode); + } // Consume spaces if requested, crucially *after* we switch modes, + // so that the next non-space token is parsed in the correct mode. + + + if (consumeSpaces) { + this.consumeSpaces(); + } // Get first token + + + const firstToken = this.fetch(); + const text = firstToken.text; + let result; // Try to parse an open brace or \begingroup + + if (optional ? text === "[" : text === "{" || text === "\\begingroup") { + this.consume(); + const groupEnd = Parser.endOfGroup[text]; // Start a new group namespace + + this.gullet.beginGroup(); // If we get a brace, parse an expression + + const expression = this.parseExpression(false, groupEnd); + const lastToken = this.fetch(); // Check that we got a matching closing brace + + this.expect(groupEnd); // End group namespace + + this.gullet.endGroup(); + result = { + type: "ordgroup", + mode: this.mode, + loc: SourceLocation.range(firstToken, lastToken), + body: expression, + // A group formed by \begingroup...\endgroup is a semi-simple group + // which doesn't affect spacing in math mode, i.e., is transparent. + // https://tex.stackexchange.com/questions/1930/when-should-one- + // use-begingroup-instead-of-bgroup + semisimple: text === "\\begingroup" || undefined + }; + } else if (optional) { + // Return nothing for an optional group + result = null; + } else { + // If there exists a function with this name, parse the function. + // Otherwise, just return a nucleus + result = this.parseFunction(breakOnTokenText, name, greediness) || this.parseSymbol(); + + if (result == null && text[0] === "\\" && !implicitCommands.hasOwnProperty(text)) { + if (this.settings.throwOnError) { + throw new ParseError("Undefined control sequence: " + text, firstToken); + } + + result = this.formatUnsupportedCmd(text); + this.consume(); + } + } // Switch mode back + + + if (mode) { + this.switchMode(outerMode); + } + + return result; + } + /** + * Form ligature-like combinations of characters for text mode. + * This includes inputs like "--", "---", "``" and "''". + * The result will simply replace multiple textord nodes with a single + * character in each value by a single textord node having multiple + * characters in its value. The representation is still ASCII source. + * The group will be modified in place. + */ + + + formLigatures(group) { + let n = group.length - 1; + + for (let i = 0; i < n; ++i) { + const a = group[i]; // $FlowFixMe: Not every node type has a `text` property. + + const v = a.text; + + if (v === "-" && group[i + 1].text === "-") { + if (i + 1 < n && group[i + 2].text === "-") { + group.splice(i, 3, { + type: "textord", + mode: "text", + loc: SourceLocation.range(a, group[i + 2]), + text: "---" + }); + n -= 2; + } else { + group.splice(i, 2, { + type: "textord", + mode: "text", + loc: SourceLocation.range(a, group[i + 1]), + text: "--" + }); + n -= 1; + } + } + + if ((v === "'" || v === "`") && group[i + 1].text === v) { + group.splice(i, 2, { + type: "textord", + mode: "text", + loc: SourceLocation.range(a, group[i + 1]), + text: v + v + }); + n -= 1; + } + } + } + /** + * Parse a single symbol out of the string. Here, we handle single character + * symbols and special functions like \verb. + */ + + + parseSymbol() { + const nucleus = this.fetch(); + let text = nucleus.text; + + if (/^\\verb[^a-zA-Z]/.test(text)) { + this.consume(); + let arg = text.slice(5); + const star = arg.charAt(0) === "*"; + + if (star) { + arg = arg.slice(1); + } // Lexer's tokenRegex is constructed to always have matching + // first/last characters. + + + if (arg.length < 2 || arg.charAt(0) !== arg.slice(-1)) { + throw new ParseError(`\\verb assertion failed -- + please report what input caused this bug`); + } + + arg = arg.slice(1, -1); // remove first and last char + + return { + type: "verb", + mode: "text", + body: arg, + star + }; + } // At this point, we should have a symbol, possibly with accents. + // First expand any accented base symbol according to unicodeSymbols. + + + if (unicodeSymbols.hasOwnProperty(text[0]) && !symbols[this.mode][text[0]]) { + // This behavior is not strict (XeTeX-compatible) in math mode. + if (this.settings.strict && this.mode === "math") { + this.settings.reportNonstrict("unicodeTextInMathMode", `Accented Unicode text character "${text[0]}" used in ` + `math mode`, nucleus); + } + + text = unicodeSymbols[text[0]] + text.substr(1); + } // Strip off any combining characters + + + const match = combiningDiacriticalMarksEndRegex.exec(text); + + if (match) { + text = text.substring(0, match.index); + + if (text === 'i') { + text = '\u0131'; // dotless i, in math and text mode + } else if (text === 'j') { + text = '\u0237'; // dotless j, in math and text mode + } + } // Recognize base symbol + + + let symbol; + + if (symbols[this.mode][text]) { + if (this.settings.strict && this.mode === 'math' && extraLatin.indexOf(text) >= 0) { + this.settings.reportNonstrict("unicodeTextInMathMode", `Latin-1/Unicode text character "${text[0]}" used in ` + `math mode`, nucleus); + } + + const group = symbols[this.mode][text].group; + const loc = SourceLocation.range(nucleus); + let s; + + if (ATOMS.hasOwnProperty(group)) { + // $FlowFixMe + const family = group; + s = { + type: "atom", + mode: this.mode, + family, + loc, + text + }; + } else { + // $FlowFixMe + s = { + type: group, + mode: this.mode, + loc, + text + }; + } + + symbol = s; + } else if (text.charCodeAt(0) >= 0x80) { + // no symbol for e.g. ^ + if (this.settings.strict) { + if (!supportedCodepoint(text.charCodeAt(0))) { + this.settings.reportNonstrict("unknownSymbol", `Unrecognized Unicode character "${text[0]}"` + ` (${text.charCodeAt(0)})`, nucleus); + } else if (this.mode === "math") { + this.settings.reportNonstrict("unicodeTextInMathMode", `Unicode text character "${text[0]}" used in math mode`, nucleus); + } + } // All nonmathematical Unicode characters are rendered as if they + // are in text mode (wrapped in \text) because that's what it + // takes to render them in LaTeX. Setting `mode: this.mode` is + // another natural choice (the user requested math mode), but + // this makes it more difficult for getCharacterMetrics() to + // distinguish Unicode characters without metrics and those for + // which we want to simulate the letter M. + + + symbol = { + type: "textord", + mode: "text", + loc: SourceLocation.range(nucleus), + text + }; + } else { + return null; // EOF, ^, _, {, }, etc. + } + + this.consume(); // Transform combining characters into accents + + if (match) { + for (let i = 0; i < match[0].length; i++) { + const accent = match[0][i]; + + if (!unicodeAccents[accent]) { + throw new ParseError(`Unknown accent ' ${accent}'`, nucleus); + } + + const command = unicodeAccents[accent][this.mode]; + + if (!command) { + throw new ParseError(`Accent ${accent} unsupported in ${this.mode} mode`, nucleus); + } + + symbol = { + type: "accent", + mode: this.mode, + loc: SourceLocation.range(nucleus), + label: command, + isStretchy: false, + isShifty: true, + base: symbol + }; + } + } + + return symbol; + } + +} +Parser.endOfExpression = ["}", "\\endgroup", "\\end", "\\right", "&"]; +Parser.endOfGroup = { + "[": "]", + "{": "}", + "\\begingroup": "\\endgroup" + /** + * Parses an "expression", which is a list of atoms. + * + * `breakOnInfix`: Should the parsing stop when we hit infix nodes? This + * happens when functions have higher precendence han infix + * nodes in implicit parses. + * + * `breakOnTokenText`: The text of the token that the expression should end + * with, or `null` if something else should end the + * expression. + */ + +}; +Parser.SUPSUB_GREEDINESS = 1; + +/** + * Provides a single function for parsing an expression using a Parser + * TODO(emily): Remove this + */ + +/** + * Parses an expression using a Parser, then returns the parsed result. + */ +const parseTree = function parseTree(toParse, settings) { + if (!(typeof toParse === 'string' || toParse instanceof String)) { + throw new TypeError('KaTeX can only parse string typed expression'); + } + + const parser = new Parser(toParse, settings); // Blank out any \df@tag to avoid spurious "Duplicate \tag" errors + + delete parser.gullet.macros.current["\\df@tag"]; + let tree = parser.parse(); // If the input used \tag, it will set the \df@tag macro to the tag. + // In this case, we separately parse the tag and wrap the tree. + + if (parser.gullet.macros.get("\\df@tag")) { + if (!settings.displayMode) { + throw new ParseError("\\tag works only in display equations"); + } + + parser.gullet.feed("\\df@tag"); + tree = [{ + type: "tag", + mode: "text", + body: tree, + tag: parser.parse() + }]; + } + + return tree; +}; + +/* eslint no-console:0 */ + +/** + * Parse and build an expression, and place that expression in the DOM node + * given. + */ +let render = function render(expression, baseNode, options) { + baseNode.textContent = ""; + const node = renderToDomTree(expression, options).toNode(); + baseNode.appendChild(node); +}; // KaTeX's styles don't work properly in quirks mode. Print out an error, and +// disable rendering. + + +if (typeof document !== "undefined") { + if (document.compatMode !== "CSS1Compat") { + typeof console !== "undefined" && console.warn("Warning: KaTeX doesn't work in quirks mode. Make sure your " + "website has a suitable doctype."); + + render = function render() { + throw new ParseError("KaTeX doesn't work in quirks mode."); + }; + } +} +/** + * Parse and build an expression, and return the markup for that. + */ + + +const renderToString = function renderToString(expression, options) { + const markup = renderToDomTree(expression, options).toMarkup(); + return markup; +}; +/** + * Parse an expression and return the parse tree. + */ + + +const generateParseTree = function generateParseTree(expression, options) { + const settings = new Settings(options); + return parseTree(expression, settings); +}; +/** + * If the given error is a KaTeX ParseError and options.throwOnError is false, + * renders the invalid LaTeX as a span with hover title giving the KaTeX + * error message. Otherwise, simply throws the error. + */ + + +const renderError = function renderError(error, expression, options) { + if (options.throwOnError || !(error instanceof ParseError)) { + throw error; + } + + const node = buildCommon.makeSpan(["katex-error"], [new SymbolNode(expression)]); + node.setAttribute("title", error.toString()); + node.setAttribute("style", `color:${options.errorColor}`); + return node; +}; +/** + * Generates and returns the katex build tree. This is used for advanced + * use cases (like rendering to custom output). + */ + + +const renderToDomTree = function renderToDomTree(expression, options) { + const settings = new Settings(options); + + try { + const tree = parseTree(expression, settings); + return buildTree(tree, expression, settings); + } catch (error) { + return renderError(error, expression, settings); + } +}; +/** + * Generates and returns the katex build tree, with just HTML (no MathML). + * This is used for advanced use cases (like rendering to custom output). + */ + + +const renderToHTMLTree = function renderToHTMLTree(expression, options) { + const settings = new Settings(options); + + try { + const tree = parseTree(expression, settings); + return buildHTMLTree(tree, expression, settings); + } catch (error) { + return renderError(error, expression, settings); + } +}; + +var katex = { + /** + * Current KaTeX version + */ + version: "0.11.1", + + /** + * Renders the given LaTeX into an HTML+MathML combination, and adds + * it as a child to the specified DOM node. + */ + render, + + /** + * Renders the given LaTeX into an HTML+MathML combination string, + * for sending to the client. + */ + renderToString, + + /** + * KaTeX error, usually during parsing. + */ + ParseError, + + /** + * Parses the given LaTeX into KaTeX's internal parse tree structure, + * without rendering to HTML or MathML. + * + * NOTE: This method is not currently recommended for public use. + * The internal tree representation is unstable and is very likely + * to change. Use at your own risk. + */ + __parse: generateParseTree, + + /** + * Renders the given LaTeX into an HTML+MathML internal DOM tree + * representation, without flattening that representation to a string. + * + * NOTE: This method is not currently recommended for public use. + * The internal tree representation is unstable and is very likely + * to change. Use at your own risk. + */ + __renderToDomTree: renderToDomTree, + + /** + * Renders the given LaTeX into an HTML internal DOM tree representation, + * without MathML and without flattening that representation to a string. + * + * NOTE: This method is not currently recommended for public use. + * The internal tree representation is unstable and is very likely + * to change. Use at your own risk. + */ + __renderToHTMLTree: renderToHTMLTree, + + /** + * extends internal font metrics object with a new object + * each key in the new object represents a font name + */ + __setFontMetrics: setFontMetrics, + + /** + * adds a new symbol to builtin symbols table + */ + __defineSymbol: defineSymbol, + + /** + * adds a new macro to builtin macro list + */ + __defineMacro: defineMacro, + + /** + * Expose the dom tree node types, which can be useful for type checking nodes. + * + * NOTE: This method is not currently recommended for public use. + * The internal tree representation is unstable and is very likely + * to change. Use at your own risk. + */ + __domTree: { + Span, + Anchor, + SymbolNode, + SvgNode, + PathNode, + LineNode + } +}; + +export default katex; diff --git a/adoc/logos/Khronos_Tagline_500px_June18.png b/adoc/logos/Khronos_Tagline_500px_June18.png new file mode 100644 index 00000000..41eb490e Binary files /dev/null and b/adoc/logos/Khronos_Tagline_500px_June18.png differ diff --git a/adoc/logos/SYCL_RGB_June16-inkscape-1500.png b/adoc/logos/SYCL_RGB_June16-inkscape-1500.png new file mode 100644 index 00000000..68cbf126 Binary files /dev/null and b/adoc/logos/SYCL_RGB_June16-inkscape-1500.png differ diff --git a/adoc/rewriteTable.py b/adoc/rewriteTable.py new file mode 100755 index 00000000..c20b7181 --- /dev/null +++ b/adoc/rewriteTable.py @@ -0,0 +1,383 @@ +#!/usr/bin/python3 +# rewriteTable.py - rewrite SYCL LaTeX tables as asciidoctor. +# +# Usage: rewritePname.py < file > file + +import argparse +import copy +import sys +import re +import string +import pdb + +global curLine + +# Non-standard table column separator, which must be a character that +# doesn't appear in any table content. The default '|' shows up in imbedded +# C++ source and can't be used. +global tableSep +tableSep = '@' + +# Match \startTable +def startRegularTable(line): + match = re.match(r'\\startTable\{',line) + return match is not None + +# Match start of a table +def startTable(line): + match = re.match(r'\\start(|Info)Table\{',line) + return match is not None + +# Match end of a table +def endTable(line): + match = re.match(r'\\complete(|Info)Table',line) + return match is not None + +# Match \addInfoRow +def startInfoRow(line): + match = re.match(r'\\addInfoRow',line) + return match is not None + +# Match \addRow* +def startRegularRow(line): + match = re.match(r'\\addRow(|Two|Three|Four|Five|Six|Seven)(|L|SL)',line) + return match is not None + +# Match a row command +def startRow(line): + if startInfoRow(line): + return True + elif startRegularRow(line): + return True + else: + return False + +# Map string numeric names in a \addRow macro to numbers +colDict = { + '' : 1, + 'Two' : 2, + 'Three' : 3, + 'Four' : 4, + 'Five' : 5, + 'Six' : 6, + 'Seven' : 7, + 'Eight' : 8, +} + +# Parse a row macro +# Returns (isInfoRow, firstColArgs, firstIndent) +# isInfoRow -> True if \addInfoRow macro (3 column table) +# firstColArgs -> number of following arguments merged into first column +# firstIndent -> which first column argument starts indentation +# Thus: +# \addInfoRow -> (True, 1, 1000) (never indent) +# \addRow -> (False, 1, 1000) (never indent) +# \addRow(nargs)L -> (False, nargs, 2) (indent 2nd & later) +# \addRow(nargs)SL -> (False, nargs, 3) (indent 3rd & later) +def parseRowFormat(format): + if format.startswith('\\addInfoRow'): + return (True, 0, 1000) + elif format.startswith('\\addRow'): + format = format[len('\\addRow'):] + + if format.endswith('SL'): + firstIndent = 3 + format = format[0:-2] + elif format.endswith('L'): + firstIndent = 2 + format = format[0:-1] + else: + # Just an \addRow macro, never indent + firstIndent = 1000 + + # Remainder must match a text number + if format in colDict: + firstColArgs = colDict[format] + else: + print('ERROR: row format macro has unrecognized number of columns:', + format, file=sys.stderr) + sys.exit(1) + + return (False, firstColArgs, firstIndent) + else: + print('ERROR: row format macro "' + format + '" unrecognized', + file=sys.stderr) + sys.exit(1) + +# Parse arguments following a row macro +# Passed a single string 'text' (may span multiple lines) containing {} +# bracketed arguments, which may themselves contain nested brackets. +# Returns a list of debracketed strings with leading and trailing whitespace +# stripped from each. +def parseBrackets(text): + # Uses yet another simple state machine tracking bracket depth + args = [] + bracketDepth = 0 + pos = 0 + + for c in text: + if bracketDepth == 0: + if c == '{': + # Begin accumulating an argument inside {} + curArg = '' + bracketDepth = 1 + elif c not in string.whitespace: + print('ERROR: disallowed character "' + c + '"outside brackets in:', + text, file=sys.stderr) + sys.exit(1) + else: + if c == '{': + # Handle nested brackets + bracketDepth += 1 + curArg += c + elif c == '}': + bracketDepth -= 1 + if bracketDepth > 0: + curArg += c + else: + # End this argument + args.append(curArg.strip()) + else: + curArg += c + + # Increment string position + pos += 1 + + # At end, if we're not at bracket depth 0, something bad happened + if bracketDepth > 0: + print('ERROR: inside brackets at depth', bracketDepth, + 'at end of args:', text, file=sys.stderr) + sys.exit(1) + + return args + +# Format multiline description, indenting by 'prefix' on second line +# and beyond (except after the first paragraph). +def formatDescription(txt, prefix): + firstLine = True + indent = True + result = '' + + for line in txt.split('\n'): + if line == '' or line == '--' or line.startswith('[source'): + indent = False + + if indent and not firstLine: + result += prefix + line.strip() + '\n' + else: + result += line.rstrip() + '\n' + firstLine = False + + return result + +# Process table content +# (just print it, for now) +def processTable(head, body, tail, file): + global curLine, tableSep + + # Accumulate list of rows + # This is another simple state machine + tableRows = [] + curRowFormat = '' + curRow = '' + inRow = False + + for line in body: + # Skip blank lines + if line.strip() == '' and not inRow: + continue + + if startRow(line): + # Begin a row with an \add*Row* macro + # Flush previous row, if present + + if curRow != '': + tableRows.append([curRowFormat, curRow]) + + curRowFormat = line + curRow = '' + inRow = True + else: + # Just accumulate the line + if not inRow: + print('ERROR following line', curLine, + ': line not in row macro:', line, file=sys.stderr) + sys.exit(1) + curRow += line + + # Flush final row, if present + if curRow != '': + tableRows.append([curRowFormat, curRow]) + + # Just print the table out unchanged + # print(head, end='', file=file) + # for (rowFormat, row) in tableRows: + # print(rowFormat, end='', file=file) + # print(row, end='', file=file) + # print(tail, end='', file=file) + + start = head.find('{') + end = head.rfind('}') + macro = head[0:start] + caption = head[start+1:end] + + # If the head is \startInfoTable, table is 3 columns and macros are 3 + # arguments. Otherwise table is 2 columns and macros are varying + # arguments. + if macro == r'\startTable': + # Two column table + infoTable = False + + # Don't print out the LaTeX table start macro + # print('// {}'.format(macro), file=file) + + print('[width="100%",options="header",separator="{}",cols="65%,35%"]'.format(tableSep), + file=file) + print('|====', file=file) + print('{0} {1} {0} {2}'.format( + tableSep, caption, 'Description'), + file=file) + elif macro == r'\startInfoTable': + # Three-column 'info' table + infoTable = True + + # Don't print out the LaTeX table start macro + # print('// {}'.format(macro), file=file) + + print('[width="100%",options="header",separator="{}",cols="37%,19%,44%"]'.format(tableSep), + file=file) + print('|====', file=file) + print('{0} {1} {0} {2} {0} {3}'.format( + tableSep, caption, 'Return type', 'Description'), + file=file) + else: + print('ERROR: unrecognized table macro', macro, file=sys.stderr) + sys.exit(1) + + for (rowFormat, row) in tableRows: + format = rowFormat.strip() + + # Parse LaTeX row format macro + (infoRow, firstColArgs, firstIndent) = parseRowFormat(format) + + args = parseBrackets(row) + nargs = len(args) + + if infoRow: + if nargs != 3: + print('ERROR: InfoRow with wrong # of columns {}'.format(nargs), + file=sys.stderr) + sys.exit(1) + + # Don't print out the LaTeX table row macro + # print('// {}'.format(format), file=file) + + print('a{}\n'.format(tableSep) + + '[source,c++]\n' + + '----\n' + + args[0] + '\n' + + '----\n', + file=file) + # Might need to be in a source block if not a simple term + if args[1].find(' ') != -1: + print('// WARNING: following argument contains spaces', file=file) + print(' {} [.code]#{}#'.format(tableSep, args[1]), + file=file) + print(' a{}'.format(tableSep), + formatDescription(args[2], 6 * ' '), + file=file) + else: + if nargs != firstColArgs + 1: + print('ERROR: Row with wrong # of columns {} expected {}'.format( + nargs, firstColArgs + 1), file=file) + sys.exit(1) + + # Don't print out the LaTeX table row macro + # print('// {}'.format(format), file=file) + + # Print firstColArgs worth of the arguments in a source block + # for the first column, indenting arguments firstIndent and + # beyond. + print('a{}\n'.format(tableSep) + + '[source,c++]\n' + + '----\n', + end='', file=file) + for i in range(0, firstColArgs): + if i < firstIndent - 1: + print(args[i], file=file) + else: + print(' ' + args[i], file=file) + print('----\n', + end='', file=file) + + # Print second column argument + print(' a{}'.format(tableSep), + formatDescription(args[firstColArgs], 6 * ' '), + file=file) + + # Now the fancy brace-matching parsing to find each individual macro + # argument, strip them, indent the properly, etc. + # print('//# {} -> infoRow {} firstColArgs {} firstIndent {}'.format( + # format, infoRow, firstColArgs, firstIndent), file=file) + # n = 1 + # for arg in args: + # print('//#@ arg{}: {}'.format(n, arg), file=file) + # n += 1 + + # End the table + print('|====', file=file) + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + + parser.add_argument('-in', action='store', dest='inpath', default=None, + help='Set the input path') + parser.add_argument('-out', action='store', dest='outpath', default=None, + help='Set the output path') + + results = parser.parse_args() + + if results.inpath is not None: + ifp = open(results.inpath, 'r', encoding='utf-8') + else: + ifp = sys.stdin + + if results.outpath is not None: + ofp = open(results.outpath, 'w', encoding='utf-8') + else: + ofp = sys.stdout + + global curLine + curLine = 0 + + # Simple state machine tracking whether outside a table (just emit the + # line) or inside (accumulate), with an action at table end. + + inTable = False + tableHead = '' + tableBody = [] + + for line in ifp: + curLine = curLine + 1 + + if startTable(line): + if inTable: + write('ERROR: table inside table at line', curLine, file=sys.stderr) + sys.exit(1) + inTable = True + tableHead = line + tableBody = [] + elif endTable(line): + if not inTable: + write('ERROR: end table when not inside table at line', curLine, file=sys.stderr) + sys.exit(1) + processTable(head=tableHead, body=tableBody, tail=line, file=ofp) + inTable = False + tableHead = '' + tableBody = [] + elif inTable: + # Accumulate this line + tableBody.append(line) + else: + # Emit lines outside tables + print(line, end='', file=ofp) diff --git a/adoc/samples/example.adoc b/adoc/samples/example.adoc new file mode 100644 index 00000000..e43f9086 --- /dev/null +++ b/adoc/samples/example.adoc @@ -0,0 +1,45 @@ +:listing-caption: + += Example Samples + +This contains two examples of automatically numbered "`example blocks`", +followed by a source code block which isn't an example, to show the +differences: + + * <> + * <> + * <> + + +:sep: ¦ + +[[example-1]] +[example] +.Miscellaneous text example +==== +Miscellaneous text in a numbered example block. +==== + +[[example-2]] +[example] +.Source code example +==== +Source code in a numbered example block. + +[source,c++] +---- +main() { + printf("Hello, world\n"); +} +---- +==== + +[[example-3]] +.Source code in a numbered source block +[source,c++] +---- +main() { + printf("Hello, world\n"); +} +---- + diff --git a/adoc/scripts/genanchorlinks.py b/adoc/scripts/genanchorlinks.py new file mode 100644 index 00000000..08b7eab2 --- /dev/null +++ b/adoc/scripts/genanchorlinks.py @@ -0,0 +1,25 @@ +#!/usr/bin/python3 +# +# Copyright (c) 2020-2021 The Khronos Group, Inc. +# SPDX-License-Identifier: Apache-2.0 + +# Script that adds href to anchors + +import os,sys,re + +def genAnchorLinks(in_file, out_file): + try: + with open(in_file, 'r', encoding='utf8') as f: data = f.read() + except FileNotFoundError: + print('Error: File %s does not exist.' % in_file) + sys.exit(2) + + data = re.sub( r'()', '\g<1>\g<2> href="#\g<3>"\g<4>', data) + with open(out_file, 'w', encoding='utf8') as f: data = f.write(data) + +if __name__ == '__main__': + if len(sys.argv) != 3: + print('Error: genanchorlinks.py requires two arguments.') + print('Usage: genanchorlinks.py infile.html outfile.html') + sys.exit(1) + genAnchorLinks(sys.argv[1], sys.argv[2]) diff --git a/adoc/scripts/install-rouge.sh b/adoc/scripts/install-rouge.sh new file mode 100755 index 00000000..76db3f03 --- /dev/null +++ b/adoc/scripts/install-rouge.sh @@ -0,0 +1,25 @@ +#! /bin/bash -vx + +# Update the Docker image and run a command for a given user/group + + +apt install sudo + +# To allow the bash configuration to be read by another user +chmod 755 /root + +# Update obsolete Docker image to latest gems +gem update + +# This one is completely missing from the Docker image +gem install text-hyphen + +# Install latest ruby rouge with SYCL support from Git +cd /tmp +git clone --branch sycl https://github.com/keryell/rouge.git +cd rouge +gem build rouge.gemspec +gem install ./rouge-3.26.0.gem + +# Execute as the original user, preserve the PATH explicitly for the gem bundle +sudo --preserve-env --user \#$USER_ID --group \#$GROUP_ID PATH=$PATH $* diff --git a/adoc/scripts/reflib.py b/adoc/scripts/reflib.py new file mode 100644 index 00000000..13d2de54 --- /dev/null +++ b/adoc/scripts/reflib.py @@ -0,0 +1,637 @@ +#!/usr/bin/python3 +# +# Copyright (c) 2011-2021 The Khronos Group, Inc. +# SPDX-License-Identifier: Apache-2.0 + +# Utility functions for automatic ref page generation + +import io +import re +import sys + +# global errFile, warnFile, diagFile + +errFile = sys.stderr +warnFile = sys.stdout +diagFile = None +logSourcefile = None +logProcname = None +logLine = None + +def unescapeQuotes(s): + """Remove \' escape sequences in a string (refpage description)""" + return s.replace('\\\'', '\'') + +def write(*args, **kwargs ): + file = kwargs.pop('file',sys.stdout) + end = kwargs.pop('end','\n') + file.write(' '.join(str(arg) for arg in args)) + file.write(end) + +def setLogSourcefile(filename): + """Metadata which may be printed (if not None) for diagnostic messages""" + global logSourcefile + logSourcefile = filename + +def setLogProcname(procname): + global logProcname + logProcname = procname + +def setLogLine(line): + global logLine + logLine = line + +def logHeader(severity): + """Generate prefix for a diagnostic line using metadata and severity""" + global logSourcefile, logProcname, logLine + + msg = severity + ': ' + if logProcname: + msg = msg + ' in ' + logProcname + if logSourcefile: + msg = msg + ' for ' + logSourcefile + if logLine: + msg = msg + ' line ' + str(logLine) + return msg + ' ' + +def setLogFile(setDiag, setWarn, filename): + """Set the file handle to log either or both warnings and diagnostics to. + + - setDiag and setWarn are True if the corresponding handle is to be set. + - filename is None for no logging, '-' for stdout, or a pathname.""" + global diagFile, warnFile + + if filename is None: + return + + if filename == '-': + fp = sys.stdout + else: + fp = open(filename, 'w', encoding='utf-8') + + if setDiag: + diagFile = fp + if setWarn: + warnFile = fp + +def logDiag(*args, **kwargs): + file = kwargs.pop('file', diagFile) + end = kwargs.pop('end','\n') + if file is not None: + file.write(logHeader('DIAG') + ' '.join(str(arg) for arg in args)) + file.write(end) + +def logWarn(*args, **kwargs): + file = kwargs.pop('file', warnFile) + end = kwargs.pop('end','\n') + if file is not None: + file.write(logHeader('WARN') + ' '.join(str(arg) for arg in args)) + file.write(end) + +def logErr(*args, **kwargs): + file = kwargs.pop('file', errFile) + end = kwargs.pop('end','\n') + + strfile = io.StringIO() + strfile.write(logHeader('ERROR') + ' '.join(str(arg) for arg in args)) + strfile.write(end) + + if file is not None: + file.write(strfile.getvalue()) + sys.exit(1) + +def isempty(s): + """Return True if s is nothing but white space, False otherwise""" + return len(''.join(s.split())) == 0 + +class pageInfo: + """Information about a ref page relative to the file it's extracted from.""" + def __init__(self): + self.extractPage = True + """True if page should be extracted""" + + self.Warning = None + """string warning if page is suboptimal or can't be generated""" + + self.embed = False + """False or the name of the ref page this include is embedded within""" + + self.type = None + """'structs', 'protos', 'funcpointers', 'flags', 'enums'""" + + self.name = None + """struct/proto/enumerant/etc. name""" + + self.desc = None + """short description of ref page""" + + self.begin = None + """index of first line of the page (heuristic or // refBegin)""" + + self.include = None + """index of include:: line defining the page""" + + self.param = None + """index of first line of parameter/member definitions""" + + self.body = None + """index of first line of body text""" + + self.validity = None + """index of validity include""" + + self.end = None + """index of last line of the page (heuristic validity include, or // refEnd)""" + + self.alias = '' + """aliases of this name, if supplied, or ''""" + + self.refs = '' + """cross-references on // refEnd line, if supplied""" + + self.spec = None + """'spec' attribute in refpage open block, if supplied, or None for the default ('api') type""" + + self.anchor = None + """'anchor' attribute in refpage open block, if supplied, or inferred to be the same as the 'name'""" + +def printPageInfoField(desc, line, file): + """Print a single field of a pageInfo struct, possibly None. + + - desc - string description of field + - line - field value or None + - file - indexed by line""" + if line is not None: + logDiag(desc + ':', line + 1, '\t-> ', file[line], end='') + else: + logDiag(desc + ':', line) + +def printPageInfo(pi, file): + """Print out fields of a pageInfo struct + + - pi - pageInfo + - file - indexed by pageInfo""" + logDiag('TYPE: ', pi.type) + logDiag('NAME: ', pi.name) + logDiag('WARNING:', pi.Warning) + logDiag('EXTRACT:', pi.extractPage) + logDiag('EMBED: ', pi.embed) + logDiag('DESC: ', pi.desc) + printPageInfoField('BEGIN ', pi.begin, file) + printPageInfoField('INCLUDE ', pi.include, file) + printPageInfoField('PARAM ', pi.param, file) + printPageInfoField('BODY ', pi.body, file) + printPageInfoField('VALIDITY', pi.validity, file) + printPageInfoField('END ', pi.end, file) + logDiag('REFS: "' + pi.refs + '"') + +def prevPara(file, line): + """Go back one paragraph from the specified line and return the line number + of the first line of that paragraph. + + Paragraphs are delimited by blank lines. It is assumed that the + current line is the first line of a paragraph. + + - file is an array of strings + - line is the starting point (zero-based)""" + # Skip over current paragraph + while (line >= 0 and not isempty(file[line])): + line = line - 1 + # Skip over white space + while (line >= 0 and isempty(file[line])): + line = line - 1 + # Skip to first line of previous paragraph + while (line >= 1 and not isempty(file[line-1])): + line = line - 1 + return line + +def nextPara(file, line): + """Go forward one paragraph from the specified line and return the line + number of the first line of that paragraph. + + Paragraphs are delimited by blank lines. It is assumed that the + current line is standalone (which is bogus). + + - file is an array of strings + - line is the starting point (zero-based)""" + maxLine = len(file) - 1 + # Skip over current paragraph + while (line != maxLine and not isempty(file[line])): + line = line + 1 + # Skip over white space + while (line != maxLine and isempty(file[line])): + line = line + 1 + return line + +def lookupPage(pageMap, name): + """Return (creating if needed) the pageInfo entry in pageMap for name""" + if name not in pageMap: + pi = pageInfo() + pi.name = name + pageMap[name] = pi + else: + pi = pageMap[name] + return pi + +def loadFile(filename): + """Load a file into a list of strings. Return the list or None on failure""" + try: + fp = open(filename, 'r', encoding='utf-8') + except: + logWarn('Cannot open file', filename, ':', sys.exc_info()[0]) + return None + + file = fp.readlines() + fp.close() + + return file + +def clampToBlock(line, minline, maxline): + """Clamp a line number to be in the range [minline,maxline]. + + If the line number is None, just return it. + If minline is None, don't clamp to that value.""" + if line is None: + return line + if minline and line < minline: + return minline + if line > maxline: + return maxline + + return line + +def fixupRefs(pageMap, specFile, file): + """Fill in missing fields in pageInfo structures, to the extent they can be + inferred. + + - pageMap - dictionary of pageInfo structures + - specFile - filename + - file - list of strings making up the file, indexed by pageInfo""" + # All potential ref pages are now in pageMap. Process them to + # identify actual page start/end/description boundaries, if + # not already determined from the text. + for name in sorted(pageMap.keys()): + pi = pageMap[name] + + # # If nothing is found but an include line with no begin, validity, + # # or end, this is not intended as a ref page (yet). Set the begin + # # line to the include line, so autogeneration can at least + # # pull the include out, but mark it not to be extracted. + # # Examples include the host sync table includes in + # # chapters/fundamentals.txt and the table of Vk*Flag types in + # # appendices/boilerplate.txt. + # if pi.begin is None and pi.validity is None and pi.end is None: + # pi.begin = pi.include + # pi.extractPage = False + # pi.Warning = 'No begin, validity, or end lines identified' + # continue + + # Using open block delimiters, ref pages must *always* have a + # defined begin and end. If either is undefined, that's fatal. + if pi.begin is None: + pi.extractPage = False + pi.Warning = 'Can\'t identify begin of ref page open block' + continue + + if pi.end is None: + pi.extractPage = False + pi.Warning = 'Can\'t identify end of ref page open block' + continue + + # If there's no description of the page, infer one from the type + if pi.desc is None: + if pi.type is not None: + # pi.desc = pi.type[0:len(pi.type)-1] + ' (no short description available)' + pi.Warning = 'No short description available; could infer from the type and name' + else: + pi.extractPage = False + pi.Warning = 'No short description available, cannot infer from the type' + continue + + # Try to determine where the parameter and body sections of the page + # begin. funcpointer, proto, and struct pages infer the location of + # the parameter and body sections. Other pages infer the location of + # the body, but have no parameter sections. + if pi.include is not None: + if pi.type in ['funcpointers', 'protos', 'structs']: + pi.param = nextPara(file, pi.include) + if pi.body is None: + pi.body = nextPara(file, pi.param) + else: + if pi.body is None: + pi.body = nextPara(file, pi.include) + else: + pi.Warning = 'Page does not have an API definition include::' + + # It's possible for the inferred param and body lines to run past + # the end of block, if, for example, there is no parameter section. + pi.param = clampToBlock(pi.param, pi.include, pi.end) + pi.body = clampToBlock(pi.body, pi.param, pi.end) + + # We can get to this point with .include, .param, and .validity + # all being None, indicating those sections weren't found. + + logDiag('fixupRefs: after processing,', pi.name, 'looks like:') + printPageInfo(pi, file) + + # Now that all the valid pages have been found, try to make some + # inferences about invalid pages. + # + # If a reference without a .end is entirely inside a valid reference, + # then it's intentionally embedded - may want to create an indirect + # page that links into the embedding page. This is done by a very + # inefficient double loop, but the loop depth is small. + for name in sorted(pageMap.keys()): + pi = pageMap[name] + + if pi.end is None: + for embedName in sorted(pageMap.keys()): + logDiag('fixupRefs: comparing', pi.name, 'to', embedName) + embed = pageMap[embedName] + # Don't check embeddings which are themselves invalid + if not embed.extractPage: + logDiag('Skipping check for embedding in:', embed.name) + continue + if embed.begin is None or embed.end is None: + logDiag('fixupRefs:', name + ':', + 'can\'t compare to unanchored ref:', embed.name, + 'in', specFile, 'at line', pi.include ) + printPageInfo(pi, file) + printPageInfo(embed, file) + # If an embed is found, change the error to a warning + elif (pi.include is not None and pi.include >= embed.begin and + pi.include <= embed.end): + logDiag('fixupRefs: Found embed for:', name, + 'inside:', embedName, + 'in', specFile, 'at line', pi.include ) + pi.embed = embed.name + pi.Warning = 'Embedded in definition for ' + embed.name + break + else: + logDiag('fixupRefs: No embed match for:', name, + 'inside:', embedName, 'in', specFile, + 'at line', pi.include) + + +# Patterns used to recognize interesting lines in an asciidoc source file. +# These patterns are only compiled once. +INCSVAR_DEF = re.compile(r':INCS-VAR: (?P.*)') +endifPat = re.compile(r'^endif::(?P[\w_+,]+)\[\]') +beginPat = re.compile(r'^\[open,(?Prefpage=.*)\]') +# attribute key/value pairs of an open block +attribStr = r"([a-z]+)='([^'\\]*(?:\\.[^'\\]*)*)'" +attribPat = re.compile(attribStr) +bodyPat = re.compile(r'^// *refBody') +errorPat = re.compile(r'^// *refError') + +# This regex transplanted from check_spec_links +# It looks for either OpenXR or Vulkan generated file conventions, and for +# the api/validity include (generated_type), protos/struct/etc path +# (category), and API name (entity_name). It could be put into the API +# conventions object. +INCLUDE = re.compile( + r'include::(?P((../){1,4}|\{INCS-VAR\}/|\{generated\}/)(generated/)?)(?P[\w]+)/(?P\w+)/(?P[^./]+).txt[\[][\]]') + + +def findRefs(file, filename): + """Identify reference pages in a list of strings, returning a dictionary of + pageInfo entries for each one found, or None on failure.""" + setLogSourcefile(filename) + setLogProcname('findRefs') + + # To reliably detect the open blocks around reference pages, we must + # first detect the '[open,refpage=...]' markup delimiting the block; + # skip past the '--' block delimiter on the next line; and identify the + # '--' block delimiter closing the page. + # This can't be done solely with pattern matching, and requires state to + # track 'inside/outside block'. + # When looking for open blocks, possible states are: + # 'outside' - outside a block + # 'start' - have found the '[open...]' line + # 'inside' - have found the following '--' line + openBlockState = 'outside' + + # Dictionary of interesting line numbers and strings related to an API + # name + pageMap = {} + + numLines = len(file) + line = 0 + + # Track the pageInfo object corresponding to the current open block + pi = None + incsvar = None + + while (line < numLines): + setLogLine(line) + + # Look for a file-wide definition + matches = INCSVAR_DEF.match(file[line]) + if matches: + incsvar = matches.group('value') + logDiag('Matched INCS-VAR definition:', incsvar) + + line = line + 1 + continue + + # Perform INCS-VAR substitution immediately. + if incsvar and '{INCS-VAR}' in file[line]: + newLine = file[line].replace('{INCS-VAR}', incsvar) + logDiag('PERFORMING SUBSTITUTION', file[line], '->', newLine) + file[line] = newLine + + # Only one of the patterns can possibly match. Add it to + # the dictionary for that name. + + # [open,refpage=...] starting a refpage block + matches = beginPat.search(file[line]) + if matches is not None: + logDiag('Matched open block pattern') + attribs = matches.group('attribs') + + # If the previous open block wasn't closed, raise an error + if openBlockState != 'outside': + logErr('Nested open block starting at line', line, 'of', + filename) + + openBlockState = 'start' + + # Parse the block attributes + matches = attribPat.findall(attribs) + + # Extract each attribute + name = None + desc = None + refpage_type = None + spec_type = None + anchor = None + alias = None + xrefs = None + + for (key,value) in matches: + logDiag('got attribute', key, '=', value) + if key == 'refpage': + name = value + elif key == 'desc': + desc = unescapeQuotes(value) + elif key == 'type': + refpage_type = value + elif key == 'spec': + spec_type = value + elif key == 'anchor': + anchor = value + elif key == 'alias': + alias = value + elif key == 'xrefs': + xrefs = value + else: + logWarn('unknown open block attribute:', key) + + if name is None or desc is None or refpage_type is None: + logWarn('missing one or more required open block attributes:' + 'refpage, desc, or type') + # Leave pi is None so open block delimiters are ignored + else: + pi = lookupPage(pageMap, name) + pi.desc = desc + # Must match later type definitions in interface/validity includes + pi.type = refpage_type + pi.spec = spec_type + pi.anchor = anchor + if alias: + pi.alias = alias + if xrefs: + pi.refs = xrefs + logDiag('open block for', name, 'added DESC =', desc, + 'TYPE =', refpage_type, 'ALIAS =', alias, + 'XREFS =', xrefs, 'SPEC =', spec_type, + 'ANCHOR =', anchor) + + line = line + 1 + continue + + # '--' starting or ending and open block + if file[line].rstrip() == '--': + if openBlockState == 'outside': + # Only refpage open blocks should use -- delimiters + logWarn('Unexpected double-dash block delimiters') + elif openBlockState == 'start': + # -- delimiter following [open,refpage=...] + openBlockState = 'inside' + + if pi is None: + logWarn('no pageInfo available for opening -- delimiter') + else: + pi.begin = line + 1 + logDiag('opening -- delimiter: added BEGIN =', pi.begin) + elif openBlockState == 'inside': + # -- delimiter ending an open block + if pi is None: + logWarn('no pageInfo available for closing -- delimiter') + else: + pi.end = line - 1 + logDiag('closing -- delimiter: added END =', pi.end) + + openBlockState = 'outside' + pi = None + else: + logWarn('unknown openBlockState:', openBlockState) + + line = line + 1 + continue + + matches = INCLUDE.search(file[line]) + if matches is not None: + # Something got included, not sure what yet. + gen_type = matches.group('generated_type') + refpage_type = matches.group('category') + name = matches.group('entity_name') + + # This will never match in OpenCL + if gen_type == 'validity': + logDiag('Matched validity pattern') + if pi is not None: + if pi.type and refpage_type != pi.type: + logWarn('ERROR: pageMap[' + name + '] type:', + pi.type, 'does not match type:', refpage_type) + pi.type = refpage_type + pi.validity = line + logDiag('added TYPE =', pi.type, 'VALIDITY =', pi.validity) + else: + logWarn('validity include:: line NOT inside block') + + line = line + 1 + continue + + if gen_type == 'api': + logDiag('Matched include pattern') + if pi is not None: + if pi.include is not None: + logDiag('found multiple includes for this block') + if pi.type and refpage_type != pi.type: + logWarn('ERROR: pageMap[' + name + '] type:', + pi.type, 'does not match type:', refpage_type) + pi.type = refpage_type + pi.include = line + logDiag('added TYPE =', pi.type, 'INCLUDE =', pi.include) + else: + logWarn('interface include:: line NOT inside block') + + line = line + 1 + continue + + logDiag('ignoring unrecognized include line ', matches.group()) + + # Vulkan 1.1 markup allows the last API include construct to be + # followed by an asciidoctor endif:: construct (and also preceded, + # at some distance). + # This looks for endif:: immediately following an include:: line + # and, if found, moves the include boundary to this line. + matches = endifPat.search(file[line]) + if matches is not None and pi is not None: + if pi.include == line - 1: + logDiag('Matched endif pattern following include; moving include') + pi.include = line + else: + logDiag('Matched endif pattern (not following include)') + + line = line + 1 + continue + + matches = bodyPat.search(file[line]) + if matches is not None: + logDiag('Matched // refBody pattern') + if pi is not None: + pi.body = line + logDiag('added BODY =', pi.body) + else: + logWarn('// refBody line NOT inside block') + + line = line + 1 + continue + + # OpenCL spec uses // refError to tag "validity" (Errors) language, + # instead of /validity/ includes. + matches = errorPat.search(file[line]) + if matches is not None: + logDiag('Matched // refError pattern') + if pi is not None: + pi.validity = line + logDiag('added VALIDITY (refError) =', pi.validity) + else: + logWarn('// refError line NOT inside block') + + line = line + 1 + continue + + line = line + 1 + continue + + if pi is not None: + logErr('Unclosed open block at EOF!') + + setLogSourcefile(None) + setLogProcname(None) + setLogLine(None) + + return pageMap diff --git a/adoc/scripts/reflow.py b/adoc/scripts/reflow.py new file mode 100755 index 00000000..cd8709e0 --- /dev/null +++ b/adoc/scripts/reflow.py @@ -0,0 +1,814 @@ +#!/usr/bin/python3 +# +# Copyright (c) 2011-2021 The Khronos Group, Inc. +# SPDX-License-Identifier: Apache-2.0 + +"""Used for automatic reflow of spec sources to satisfy the agreed layout to +minimize git churn. Most of the logic has to do with detecting asciidoc +markup or block types that *shouldn't* be reflowed (tables, code) and +ignoring them. It's very likely there are many asciidoc constructs not yet +accounted for in the script, our usage of asciidoc markup is intentionally +somewhat limited. + +Also used to insert identifying tags on explicit Valid Usage statements. + +Usage: `reflow.py [-noflow] [-tagvu] [-nextvu #] [-overwrite] [-out dir] [-suffix str] files` + +- `-noflow` acts as a passthrough, instead of reflowing text. Other + processing may occur. +- `-tagvu` generates explicit VUID tag for Valid Usage statements which + don't already have them. +- `-nextvu #` starts VUID tag generation at the specified # instead of + the value wired into the `reflow.py` script. +- `-overwrite` updates in place (can be risky, make sure there are backups) +- `-out` specifies directory to create output file in, default 'out' +- `-suffix` specifies suffix to add to output files, default '' +- `files` are asciidoc source files from the spec to reflow. +""" +# For error and file-loading interfaces only +import argparse +import os +import re +import subprocess +import sys +from reflib import loadFile, logDiag, logWarn, logErr, setLogFile +from vuidCounts import vuidCounts + +# Vulkan-specific - will consolidate into scripts/ like OpenXR soon +sys.path.insert(0, 'xml') + +from vkconventions import VulkanConventions as APIConventions +conventions = APIConventions() + +# Markup that always ends a paragraph +# empty line or whitespace +# [block options] +# [[anchor]] +# // comment +# <<<< page break +# :attribute-setting +# macro-directive::terms +# + standalone list item continuation +# label:: labelled list - label must be standalone +endPara = re.compile(r'^( *|\[.*\]|//.*|<<<<|:.*|[a-z]+::.*|\+|.*::)$') + +# Special case of markup ending a paragraph, used to track the current +# command/structure. This allows for either OpenXR or Vulkan API path +# conventions. Nominally it should use the file suffix defined by the API +# conventions (conventions.file_suffix), except that XR uses '.txt' for +# generated API include files, not '.adoc' like its other includes. +includePat = re.compile( + r'include::(?P((../){1,4}|\{INCS-VAR\}/|\{generated\}/)(generated/)?)(?P[\w]+)/(?P\w+)/(?P[^./]+).txt[\[][\]]') + +# Find the first pname: pattern in a Valid Usage statement +pnamePat = re.compile(r'pname:(?P\w+)') + +# Markup that's OK in a contiguous paragraph but otherwise passed through +# .anything +# === Section Titles +endParaContinue = re.compile(r'^(\..*|=+ .*)$') + +# Markup for block delimiters whose contents *should* be reformatted +# -- (exactly two) (open block) +# **** (4 or more) (sidebar block - why do we have these?!) +# ==== (4 or more) (example block) +# ____ (4 or more) (quote block) +blockReflow = re.compile(r'^(--|[*=_]{4,})$') + +# Fake block delimiters for "common" VU statements +blockCommonReflow = '// Common Valid Usage\n' + +# Markup for block delimiters whose contents should *not* be reformatted +# |=== (3 or more) (table) +# ++++ (4 or more) (passthrough block) +# .... (4 or more) (literal block) +# //// (4 or more) (comment block) +# ---- (4 or more) (listing block) +# ``` (3 or more) (listing block) +# **** (4 or more) (sidebar block) +blockPassthrough = re.compile(r'^(\|={3,}|[`]{3}|[-+./]{4,})$') + +# Markup for introducing lists (hanging paragraphs) +# * bullet +# ** bullet +# -- bullet +# . bullet +# :: bullet (no longer supported by asciidoctor 2) +# {empty}:: bullet +# 1. list item +beginBullet = re.compile(r'^ *([*-.]+|\{empty\}::|::|[0-9]+[.]) ') + +# Text that (may) not end sentences + +# A single letter followed by a period, typically a middle initial. +endInitial = re.compile(r'^[A-Z]\.$') +# An abbreviation, which doesn't (usually) end a line. +endAbbrev = re.compile(r'(e\.g|i\.e|c\.f|vs)\.$', re.IGNORECASE) + +class ReflowState: + """State machine for reflowing. + + Represents the state of the reflow operation""" + def __init__(self, + filename, + margin = 76, + file = sys.stdout, + breakPeriod = True, + reflow = True, + nextvu = None, + maxvu = None): + + self.blockStack = [ None ] + """The last element is a line with the asciidoc block delimiter that's currently in effect, + such as '--', '----', '****', '======', or '+++++++++'. + This affects whether or not the block contents should be formatted.""" + + self.reflowStack = [ True ] + """The last element is True or False if the current blockStack contents + should be reflowed.""" + self.vuStack = [ False ] + """the last element is True or False if the current blockStack contents + are an explicit Valid Usage block.""" + + self.margin = margin + """margin to reflow text to.""" + + self.para = [] + """list of lines in the paragraph being accumulated. + When this is non-empty, there is a current paragraph.""" + + self.lastTitle = False + """true if the previous line was a document title line + (e.g. :leveloffset: 0 - no attempt to track changes to this is made).""" + + self.leadIndent = 0 + """indent level (in spaces) of the first line of a paragraph.""" + + self.hangIndent = 0 + """indent level of the remaining lines of a paragraph.""" + + self.file = file + """file pointer to write to.""" + + self.filename = filename + """base name of file being read from.""" + + self.lineNumber = 0 + """line number being read from the input file.""" + + self.breakPeriod = breakPeriod + """True if justification should break to a new line after the end of a sentence.""" + + self.breakInitial = True + """True if justification should break to a new line after + something that appears to be an initial in someone's name. **TBD**""" + + self.reflow = reflow + """True if text should be reflowed, False to pass through unchanged.""" + + self.vuPrefix = 'VUID' + """Prefix of generated Valid Usage tags""" + + self.vuFormat = '{0}-{1}-{2}-{3:0>5d}' + """Format string for generating Valid Usage tags. + First argument is vuPrefix, second is command/struct name, third is parameter name, fourth is the tag number.""" + + self.nextvu = nextvu + """Integer to start tagging un-numbered Valid Usage statements with, + or None if no tagging should be done.""" + + self.maxvu = maxvu + """Maximum tag to use for Valid Usage statements, or None if no + tagging should be done.""" + + self.apiName = '' + """String name of a Vulkan structure or command for VUID tag generation, + or None if one hasn't been included in this file yet.""" + + def incrLineNumber(self): + self.lineNumber = self.lineNumber + 1 + + def printLines(self, lines): + """Print an array of lines with newlines already present""" + logDiag(':: printLines:', len(lines), 'lines: ', lines[0], end='') + for line in lines: + print(line, file=self.file, end='') + + def endSentence(self, word): + """Return True if word ends with a sentence-period, False otherwise. + + Allows for contraction cases which won't end a line: + + - A single letter (if breakInitial is True) + - Abbreviations: 'c.f.', 'e.g.', 'i.e.' (or mixed-case versions)""" + if (word[-1:] != '.' or + endAbbrev.search(word) or + (self.breakInitial and endInitial.match(word))): + return False + + return True + + def vuidAnchor(self, word): + """Return True if word is a Valid Usage ID Tag anchor.""" + return (word[0:7] == '[[VUID-') + + def isOpenBlockDelimiter(self, line): + """Returns True if line is an open block delimiter.""" + return line[0:2] == '--' + + def reflowPara(self): + """Reflow the current paragraph, respecting the paragraph lead and + hanging indentation levels. + + The algorithm also respects trailing '+' signs that indicate embedded newlines, + and will not reflow a very long word immediately after a bullet point. + + Just return the paragraph unchanged if the -noflow argument was + given.""" + if not self.reflow: + return self.para + + logDiag('reflowPara lead indent = ', self.leadIndent, + 'hangIndent =', self.hangIndent, + 'para:', self.para[0], end='') + + # Total words processed (we care about the *first* word vs. others) + wordCount = 0 + + # Tracks the *previous* word processed. It must not be empty. + prevWord = ' ' + + #import pdb; pdb.set_trace() + + for line in self.para: + line = line.rstrip() + words = line.split() + + # logDiag('reflowPara: input line =', line) + numWords = len(words) - 1 + + for i in range(0, numWords + 1): + word = words[i] + wordLen = len(word) + wordCount += 1 + + endEscape = False + if i == numWords and word == '+': + # Trailing ' +' must stay on the same line + endEscape = word + # logDiag('reflowPara last word of line =', word, 'prevWord =', prevWord, 'endEscape =', endEscape) + else: + pass + # logDiag('reflowPara wordCount =', wordCount, 'word =', word, 'prevWord =', prevWord) + + if wordCount == 1: + # The first word of the paragraph is treated specially. + # The loop logic becomes trickier if all this code is + # done prior to looping over lines and words, so all the + # setup logic is done here. + + outPara = [] + outLine = ''.ljust(self.leadIndent) + word + outLineLen = self.leadIndent + wordLen + + # If the paragraph begins with a bullet point, generate + # a hanging indent level if there isn't one already. + if beginBullet.match(self.para[0]): + bulletPoint = True + if len(self.para) > 1: + logDiag('reflowPara first line matches bullet point', + 'but indent already hanging @ input line', + self.lineNumber) + else: + logDiag('reflowPara first line matches bullet point -' + 'single line, assuming hangIndent @ input line', + self.lineNumber) + self.hangIndent = outLineLen + 1 + else: + bulletPoint = False + else: + # Possible actions to take with this word + # + # addWord - add word to current line + # closeLine - append line and start a new (null) one + # startLine - add word to a new line + + # Default behavior if all the tests below fail is to add + # this word to the current line, and keep accumulating + # that line. + (addWord, closeLine, startLine) = (True, False, False) + + # How long would this line be if the word were added? + newLen = outLineLen + 1 + wordLen + + # Are we on the first word following a bullet point? + firstBullet = (wordCount == 2 and bulletPoint) + + if endEscape: + # If the new word ends the input line with ' +', + # add it to the current line. + + (addWord, closeLine, startLine) = (True, True, False) + elif self.vuidAnchor(word): + # If the new word is a Valid Usage anchor, break the + # line afterwards. Note that this should only happen + # immediately after a bullet point, but we don't + # currently check for this. + (addWord, closeLine, startLine) = (True, True, False) + elif newLen > self.margin: + if firstBullet: + # If the word follows a bullet point, add it to + # the current line no matter its length. + + (addWord, closeLine, startLine) = (True, True, False) + else: + # The word overflows, so add it to a new line. + + (addWord, closeLine, startLine) = (False, True, True) + elif (self.breakPeriod and + (wordCount > 2 or not firstBullet) and + self.endSentence(prevWord)): + # If the previous word ends a sentence and + # breakPeriod is set, start a new line. + # The complicated logic allows for leading bullet + # points which are periods (implicitly numbered lists). + # @@@ But not yet for explicitly numbered lists. + + (addWord, closeLine, startLine) = (False, True, True) + + # Add a word to the current line + if addWord: + if outLine: + outLine += ' ' + word + outLineLen = newLen + else: + # Fall through to startLine case if there's no + # current line yet. + startLine = True + + # Add current line to the output paragraph. Force + # starting a new line, although we don't yet know if it + # will ever have contents. + if closeLine: + if outLine: + outPara.append(outLine + '\n') + outLine = None + + # Start a new line and add a word to it + if startLine: + outLine = ''.ljust(self.hangIndent) + word + outLineLen = self.hangIndent + wordLen + + # Track the previous word, for use in breaking at end of + # a sentence + prevWord = word + + # Add this line to the output paragraph. + if outLine: + outPara.append(outLine + '\n') + + return outPara + + def emitPara(self): + """Emit a paragraph, possibly reflowing it depending on the block context. + + Resets the paragraph accumulator.""" + if self.para != []: + if self.vuStack[-1] and self.nextvu is not None: + # If: + # - this paragraph is in a Valid Usage block, + # - VUID tags are being assigned, + # Try to assign VUIDs + + if nestedVuPat.search(self.para[0]): + # Check for nested bullet points. These should not be + # assigned VUIDs, nor present at all, because they break + # the VU extractor. + logWarn(self.filename + ': Invalid nested bullet point in VU block:', self.para[0]) + elif self.vuPrefix not in self.para[0]: + # If: + # - a tag is not already present, and + # - the paragraph is a properly marked-up list item + # Then add a VUID tag starting with the next free ID. + + # Split the first line after the bullet point + matches = vuPat.search(self.para[0]) + if matches is not None: + logDiag('findRefs: Matched vuPat on line:', self.para[0], end='') + head = matches.group('head') + tail = matches.group('tail') + + # Use the first pname: statement in the paragraph as + # the parameter name in the VUID tag. This won't always + # be correct, but should be highly reliable. + for vuLine in self.para: + matches = pnamePat.search(vuLine) + if matches is not None: + break + + if matches is not None: + paramName = matches.group('param') + else: + paramName = 'None' + logWarn(self.filename, + 'No param name found for VUID tag on line:', + self.para[0]) + + newline = (head + ' [[' + + self.vuFormat.format(self.vuPrefix, + self.apiName, + paramName, + self.nextvu) + ']] ' + tail) + + logDiag('Assigning', self.vuPrefix, self.apiName, self.nextvu, + ' on line:', self.para[0], '->', newline, 'END') + + # Don't actually assign the VUID unless it's in the reserved range + if self.nextvu <= self.maxvu: + if self.nextvu == self.maxvu: + logWarn('Skipping VUID assignment, no more VUIDs available') + self.para[0] = newline + self.nextvu = self.nextvu + 1 + # else: + # There are only a few cases of this, and they're all + # legitimate. Leave detecting this case to another tool + # or hand inspection. + # logWarn(self.filename + ': Unexpected non-bullet item in VU block (harmless if following an ifdef):', + # self.para[0]) + + if self.reflowStack[-1]: + self.printLines(self.reflowPara()) + else: + self.printLines(self.para) + + # Reset the paragraph, including its indentation level + self.para = [] + self.leadIndent = 0 + self.hangIndent = 0 + + def endPara(self, line): + """'line' ends a paragraph and should itself be emitted. + line may be None to indicate EOF or other exception.""" + logDiag('endPara line', self.lineNumber, ': emitting paragraph') + + # Emit current paragraph, this line, and reset tracker + self.emitPara() + + if line: + self.printLines( [ line ] ) + + def endParaContinue(self, line): + """'line' ends a paragraph (unless there's already a paragraph being + accumulated, e.g. len(para) > 0 - currently not implemented)""" + self.endPara(line) + + def endBlock(self, line, reflow = False, vuBlock = False): + """'line' begins or ends a block. + + If beginning a block, tag whether or not to reflow the contents. + + vuBlock is True if the previous line indicates this is a Valid Usage block.""" + self.endPara(line) + + if self.blockStack[-1] == line: + logDiag('endBlock line', self.lineNumber, + ': popping block end depth:', len(self.blockStack), + ':', line, end='') + + # Reset apiName at the end of an open block. + # Open blocks cannot be nested, so this is safe. + if self.isOpenBlockDelimiter(line): + logDiag('reset apiName to empty at line', self.lineNumber) + self.apiName = '' + else: + logDiag('NOT resetting apiName to empty at line', self.lineNumber) + + self.blockStack.pop() + self.reflowStack.pop() + self.vuStack.pop() + else: + # Start a block + self.blockStack.append(line) + self.reflowStack.append(reflow) + self.vuStack.append(vuBlock) + + logDiag('endBlock reflow =', reflow, ' line', self.lineNumber, + ': pushing block start depth', len(self.blockStack), + ':', line, end='') + + def endParaBlockReflow(self, line, vuBlock): + """'line' begins or ends a block. The paragraphs in the block *should* be + reformatted (e.g. a NOTE).""" + self.endBlock(line, reflow = True, vuBlock = vuBlock) + + def endParaBlockPassthrough(self, line): + """'line' begins or ends a block. The paragraphs in the block should + *not* be reformatted (e.g. a code listing).""" + self.endBlock(line, reflow = False) + + def addLine(self, line): + """'line' starts or continues a paragraph. + + Paragraphs may have "hanging indent", e.g. + + ``` + * Bullet point... + ... continued + ``` + + In this case, when the higher indentation level ends, so does the + paragraph.""" + logDiag('addLine line', self.lineNumber, ':', line, end='') + + # See https://stackoverflow.com/questions/13648813/what-is-the-pythonic-way-to-count-the-leading-spaces-in-a-string + indent = len(line) - len(line.lstrip()) + + # A hanging paragraph ends due to a less-indented line. + if self.para != [] and indent < self.hangIndent: + logDiag('addLine: line reduces indentation, emit paragraph') + self.emitPara() + + # A bullet point (or something that looks like one) always ends the + # current paragraph. + if beginBullet.match(line): + logDiag('addLine: line matches beginBullet, emit paragraph') + self.emitPara() + + if self.para == []: + # Begin a new paragraph + self.para = [ line ] + self.leadIndent = indent + self.hangIndent = indent + else: + # Add a line to a paragraph. Increase the hanging indentation + # level - once. + if self.hangIndent == self.leadIndent: + self.hangIndent = indent + self.para.append(line) + +def apiMatch(oldname, newname): + """Returns whether oldname and newname match, up to an API suffix.""" + upper = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + return oldname.rstrip(upper) == newname.rstrip(upper) + +def reflowFile(filename, args): + logDiag('reflow: filename', filename) + + lines = loadFile(filename) + if lines is None: + return + + # Output file handle and reflow object for this file. There are no race + # conditions on overwriting the input, but it's not recommended unless + # you have backing store such as git. + + if args.overwrite: + outFilename = filename + else: + outFilename = args.outDir + '/' + os.path.basename(filename) + args.suffix + + try: + fp = open(outFilename, 'w', encoding='utf8') + except: + logWarn('Cannot open output file', filename, ':', sys.exc_info()[0]) + return + + state = ReflowState(filename, + file = fp, + reflow = not args.noflow, + nextvu = args.nextvu, + maxvu = args.maxvu) + + for line in lines: + state.incrLineNumber() + + # Is this a title line (leading '= ' followed by text)? + thisTitle = False + + # The logic here is broken. If we're in a non-reflowable block and + # this line *doesn't* end the block, it should always be + # accumulated. + + # Test for a blockCommonReflow delimiter comment first, to avoid + # treating it solely as a end-Paragraph marker comment. + if line == blockCommonReflow: + # Starting or ending a pseudo-block for "common" VU statements. + + # Common VU statements use an Asciidoc variable as the apiName, + # instead of inferring it from the most recent API include. + state.apiName = '{refpage}' + state.endParaBlockReflow(line, vuBlock = True) + + elif blockReflow.match(line): + # Starting or ending a block whose contents may be reflowed. + # Blocks cannot be nested. + + # Is this is an explicit Valid Usage block? + vuBlock = (state.lineNumber > 1 and + lines[state.lineNumber-2] == '.Valid Usage\n') + + state.endParaBlockReflow(line, vuBlock) + + elif endPara.match(line): + # Ending a paragraph. Emit the current paragraph, if any, and + # prepare to begin a new paragraph. + + state.endPara(line) + + # If this is an include:: line starting the definition of a + # structure or command, track that for use in VUID generation. + + matches = includePat.search(line) + if matches is not None: + generated_type = matches.group('generated_type') + include_type = matches.group('category') + if generated_type == 'api' and include_type in ('protos', 'structs'): + apiName = matches.group('entity_name') + if state.apiName != '': + # This happens when there are multiple API include + # lines in a single block. The style guideline is to + # always place the API which others are promoted to + # first. In virtually all cases, the promoted API + # will differ solely in the vendor suffix (or + # absence of it), which is benign. + if not apiMatch(state.apiName, apiName): + logWarn('Promoted API name mismatch at line', + state.lineNumber, + ':', + 'apiName:', apiName, + 'does not match state.apiName:', + state.apiName) + else: + state.apiName = apiName + + elif endParaContinue.match(line): + # For now, always just end the paragraph. + # Could check see if len(para) > 0 to accumulate. + + state.endParaContinue(line) + + # If it's a title line, track that + if line[0:2] == '= ': + thisTitle = True + + elif blockPassthrough.match(line): + # Starting or ending a block whose contents must not be reflowed. + # These are tables, etc. Blocks cannot be nested. + + state.endParaBlockPassthrough(line) + elif state.lastTitle: + # The previous line was a document title line. This line + # is the author / credits line and must not be reflowed. + + state.endPara(line) + else: + # Just accumulate a line to the current paragraph. Watch out for + # hanging indents / bullet-points and track that indent level. + + state.addLine(line) + + state.lastTitle = thisTitle + + # Cleanup at end of file + state.endPara(None) + + # Sanity check on block nesting + if len(state.blockStack) > 1: + logWarn('file', filename, + 'mismatched asciidoc block delimiters at EOF:', + state.blockStack[-1]) + + fp.close() + + # Update the 'nextvu' value + if args.nextvu != state.nextvu: + logWarn('Updated nextvu to', state.nextvu, 'after file', filename) + args.nextvu = state.nextvu + +def reflowAllAdocFiles(folder_to_reflow, args): + for root, subdirs, files in os.walk(folder_to_reflow): + for file in files: + if file.endswith(conventions.file_suffix): + file_path = os.path.join(root, file) + reflowFile(file_path, args) + for subdir in subdirs: + sub_folder = os.path.join(root, subdir) + print('Sub-folder = %s' % sub_folder) + if subdir.lower() not in conventions.spec_no_reflow_dirs: + print(' Parsing = %s' % sub_folder) + reflowAllAdocFiles(sub_folder, args) + else: + print(' Skipping = %s' % sub_folder) + +# Patterns used to recognize interesting lines in an asciidoc source file. +# These patterns are only compiled once. + +# Explicit Valid Usage list item with one or more leading asterisks +# The re.DOTALL is needed to prevent vuPat.search() from stripping +# the trailing newline. +vuPat = re.compile(r'^(?P [*]+)( *)(?P.*)', re.DOTALL) + +# Pattern matching leading nested bullet points +global nestedVuPat +nestedVuPat = re.compile(r'^ \*\*') + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + + parser.add_argument('-diag', action='store', dest='diagFile', + help='Set the diagnostic file') + parser.add_argument('-warn', action='store', dest='warnFile', + help='Set the warning file') + parser.add_argument('-log', action='store', dest='logFile', + help='Set the log file for both diagnostics and warnings') + parser.add_argument('-overwrite', action='store_true', + help='Overwrite input filenames instead of writing different output filenames') + parser.add_argument('-out', action='store', dest='outDir', + default='out', + help='Set the output directory in which updated files are generated (default: out)') + parser.add_argument('-tagvu', action='store_true', + help='Tag un-tagged Valid Usage statements starting at the value wired into reflow.py') + parser.add_argument('-nextvu', action='store', dest='nextvu', type=int, + default=None, + help='Specify start VUID to use instead of the value wired into vuidCounts.py') + parser.add_argument('-maxvu', action='store', dest='maxvu', type=int, + default=None, + help='Specify maximum VUID instead of the value wired into vuidCounts.py') + parser.add_argument('-branch', action='store', dest='branch', + help='Specify branch to assign VUIDs for.') + parser.add_argument('-noflow', action='store_true', dest='noflow', + help='Do not reflow text. Other actions may apply.') + parser.add_argument('-suffix', action='store', dest='suffix', + default='', + help='Set the suffix added to updated file names (default: none)') + parser.add_argument('files', metavar='filename', nargs='*', + help='a filename to reflow text in') + parser.add_argument('--version', action='version', version='%(prog)s 1.0') + + args = parser.parse_args() + + setLogFile(True, True, args.logFile) + setLogFile(True, False, args.diagFile) + setLogFile(False, True, args.warnFile) + + if args.overwrite: + logWarn("reflow.py: will overwrite all input files") + + if args.branch is None: + # Determine current git branch + command = [ 'git', 'symbolic-ref', '--short', 'HEAD' ] + results = subprocess.run(command, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + if len(results.stderr) > 0: + logErr('Cannot determine current git branch:', results.stderr) + + # Remove newline from output and convert to a string + branch = results.stdout.rstrip().decode() + if len(branch) > 0: + # Strip trailing newline + branch = results.stdout.decode()[0:-1] + args.branch = branch + + if args.tagvu and args.nextvu is None: + if args.branch not in vuidCounts: + logErr('Branch', args.branch, 'not in vuidCounts, cannot continue') + maxVUID = vuidCounts[args.branch][1] + startVUID = vuidCounts[args.branch][2] + args.nextvu = startVUID + args.maxvu = maxVUID + + if args.nextvu is not None: + logWarn('Tagging untagged Valid Usage statements starting at', args.nextvu) + + # If no files are specified, reflow the entire specification chapters folder + if not args.files: + folder_to_reflow = conventions.spec_reflow_path + logWarn('Reflowing all asciidoc files under', folder_to_reflow) + reflowAllAdocFiles(folder_to_reflow, args) + else: + for file in args.files: + reflowFile(file, args) + + if args.nextvu is not None and args.nextvu != startVUID: + # Update next free VUID to assign + vuidCounts[args.branch][2] = args.nextvu + try: + reflow_count_file_path = os.path.dirname(os.path.realpath(__file__)) + reflow_count_file_path += '/vuidCounts.py' + reflow_count_file = open(reflow_count_file_path, 'w', encoding='utf8') + print('# Do not edit this file!', file=reflow_count_file) + print('# VUID ranges reserved for branches', file=reflow_count_file) + print('# Key is branch name, value is [ start, end, nextfree ]', file=reflow_count_file) + print('vuidCounts = {', file=reflow_count_file) + for key in sorted(vuidCounts): + print(" '{}': [ {}, {}, {} ],".format( + key, + vuidCounts[key][0], + vuidCounts[key][1], + vuidCounts[key][2]), + file=reflow_count_file) + print('}', file=reflow_count_file) + reflow_count_file.close() + except: + logWarn('Cannot open output count file vuidCounts.py', ':', sys.exc_info()[0]) diff --git a/adoc/scripts/vuidCounts.py b/adoc/scripts/vuidCounts.py new file mode 100644 index 00000000..c9e0831e --- /dev/null +++ b/adoc/scripts/vuidCounts.py @@ -0,0 +1,8 @@ +# Do not edit this file! +# VUID ranges reserved for branches +# Key is branch name, value is [ start, end, nextfree ] +vuidCounts = { + 'branch-vuids': [ 4000, 4999, 4052 ], + 'devel': [ 3000, 3999, 3570 ], + 'master': [ 4000, 4999, 4052 ], +} diff --git a/adoc/sycl-2020.pdf b/adoc/sycl-2020.pdf new file mode 100644 index 00000000..5e3a2bf4 Binary files /dev/null and b/adoc/sycl-2020.pdf differ diff --git a/adoc/syclbase.adoc b/adoc/syclbase.adoc new file mode 100644 index 00000000..56caaa62 --- /dev/null +++ b/adoc/syclbase.adoc @@ -0,0 +1,138 @@ +// Copyright (c) 2011-2021 Khronos Group, Inc. +// +// SPDX-License-Identifier: CC-BY-4.0 + +// This should be set by the Makefile based on values in +// ../sycl_version.txt, passed into the asciidoctor command line. +:OPENCL_VERSION: [red]#Unknown OPENCL_VERSION!# +:SYCL_LANGUAGE_VERSION: [red]#Unknown SYCL_LANGUAGE_VERSION!# +:SYCL_NAMEA: [red]#Unknown SYCL_NAME!# +:SYCL_VERSION: [red]#Unknown SYCL_VERSION!# +:SYCL_REVISION: [red]#Unknown SYCL_REVISION!# + +:tmtitle: pass:q,r[^™^] +// :regtitle: is explained in +// http://discuss.asciidoctor.org/How-to-add-markup-to-author-information-in-document-title-td6488.html +:regtitle: pass:q,r[^®^] + += {SYCL_NAME}{tmtitle} {SYCL_VERSION} Specification (revision {SYCL_REVISION}) +The Khronos{regtitle} {SYCL_NAME}{tmtitle} Working Group +:data-uri: +:icons: font +:toc2: +:toclevels: 10 +:sectnumlevels: 10 +:max-width: 100% +:numbered: +//:source-highlighter: coderay +//:coderay-linenums-mode: inline +// rouge is the only source highlighter in release version allowing +// somehow correct line numbering in HTML & PDF: +:source-highlighter: rouge +// Use the "sycl" language in any highlighted source block +:source-language: sycl +//:source-language: c++ +//:rouge-style: monokai +//:rouge-style: base16 +//:rouge-style: colorful +//dark++:rouge-style: tulip +//:rouge-style: igorpro +//:rouge-style: base16.solarized +//:rouge-style: github +:rouge-style: sycl.spec +//:rouge-style: pastie +//:rouge-style: magritte +//:source-highlighter: pygments +// Line numbering on source highlighting is wrong with line wrapping, +// so do not apply wrapping according to +// https://docs.asciidoctor.org/asciidoctor/latest/html-backend/verbatim-line-wrap/ +:prewrap!: +:title-logo-image: image:logos/SYCL_RGB_June16-inkscape-1500.png[Logo,pdfwidth=4in,align=right] +// Various special / math symbols. This is easier to edit with than Unicode. +include::config/attribs.adoc[] + +// Default TikZ conversion to SVG, not PDF (default), per email from Pepijn +// Van Eeckhoudt +:tikz-format: svg + +// Necessary workaround for putting '#include' in a [code]## block +// like [code]#{hash}include # +:hash: # + +// Asciidoctor uses ++ to denote spans, so use these attributes instead +:cpp17: pass:[C++17] +:cpp20: pass:[C++20] +// Fortunately, the cpp macro for C++ is defined by default in AsciiDoctor + +// SYCL Algebraic definitions +:SYCLeval: Satisfied +:SYCLperform: Perform + +// This causes cross references to chapters, sections, and tables to be +// rendered as "Section A.B" (for example) rather than rendering the reference +// as the text of the section title. It also enables cross references to +// [source] blocks as "Listing N", but only if the [source] block has a title. +:xrefstyle: short +:listing-caption: Listing + +// Original SYCL title page has: +// image:logos/Khronos_Tagline_500px_June18.png (upper right) +// image:logos/SYCL_RGB_June16-inkscape-1500.png (upper center) +// SYCL^TM^ Specification +// Generic heterogeneous computing for modern C++ +// +// Version 2020 provisional +// Revision Date: May 14, 2020 +// Git revision: heads/SYCL-2020/master-gibberish +// +// Khronos^{reg}^ SYCL^TM^ Working Group +// Editors: Ronan Keryell, Maria Rovatsou & Lee Howes +// +// Copyright 2011-2021 The Khronos Group, Inc. All Rights Reserved + +<<<< + +include::chapters/copyright-spec.adoc[] + +<<<< + +// Table of contents is inserted here +toc::[] + +:leveloffset: 1 + +include::chapters/acknowledgements.adoc[][] + +// \include{introduction} +include::chapters/introduction.adoc[] + +// \include{architecture} +include::chapters/architecture.adoc[] +//ifdef::skip-this[] +// \include{programming_interface} +include::chapters/programming_interface.adoc[] + +// \include{compiler_abi} +include::chapters/device_compiler.adoc[] + +// \include{extensions} +include::chapters/extensions.adoc[] + +// Appendices start here + +// \input{descriptors} +include::chapters/information_descriptors.adoc[] + +// \include{feature_sets} +include::chapters/feature_sets.adoc[] + +// \input{opencl_backend} +include::chapters/opencl_backend.adoc[] + +// \input{what_changed} +include::chapters/what_changed.adoc[] + +include::chapters/references.adoc[] + +include::chapters/glossary.adoc[] +//endif::[] diff --git a/adoc/translate_math.js b/adoc/translate_math.js new file mode 100644 index 00000000..dfb652c6 --- /dev/null +++ b/adoc/translate_math.js @@ -0,0 +1,26 @@ +const katex = require("./katex/katex.js"); +const fs = require("fs"); +const escapeRegex = require("escape-string-regexp"); +const he = require('he'); + +const filepath = process.argv[2]; + +var html = fs.readFileSync(filepath, "utf8"); + +const delimiters = [ + //{ left: "$$", right: "$$", display: true}, + { left: "\\[", right: "\\]", display: true}, + //{ left: "$", right: "$", display: false}, + { left: "\\(", right: "\\)", display: false} + ] + +for( var delim of delimiters ) { + const regex = new RegExp( escapeRegex(delim.left) + "([\\S\\s]*?)" + escapeRegex(delim.right), "g"); + html = html.replace( regex, + function(match, g1) { + return katex.renderToString( he.decode(g1, {'strict': true}), {displayMode: delim.display, output: 'html', strict: true} ); + } + ); +} + +fs.writeFileSync(filepath, html, 'utf8'); diff --git a/sycl_version.txt b/sycl_version.txt new file mode 100644 index 00000000..cfa41bbb --- /dev/null +++ b/sycl_version.txt @@ -0,0 +1,5 @@ +OPENCLVERSION=3.0 +SYCLLANGVERSION=2020 +SYCLNAME=SYCL +SYCLVERSION=2020 +SYCLREVISION=2